diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b64522017472334c133d8d7ad3d78d3cb549463c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/abstract_nodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/abstract_nodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb373ede119c94f11de05b49dce653c86e44ac6a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/abstract_nodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/algorithms.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/algorithms.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a803ea46a3c4b62e837c487847818ed138db5e6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/algorithms.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/approximations.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/approximations.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6198659e490965b559115fab0e17f1d16cfe8339 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/approximations.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/ast.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/ast.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..306b3ee078ac646af9fed2b60cdddc0aa92ee973 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/ast.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cfunctions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cfunctions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2e0cf6513e8365e7bbc3c1e2a60eabd3edd78dde Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cfunctions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cnodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cnodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a9c044b5f2e55414d780b551a719015c6f7c3fd Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cnodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cutils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cutils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f0683c5b7ff21cc631b049f13604e19b6fbd0cb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cutils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cxxnodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cxxnodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4874ea97e5e3bedb73a2aa130879726cb6ea0e37 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/cxxnodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/fnodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/fnodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..60a6c919fa276284b6f1ffe9686a4d81fd86b395 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/fnodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/futils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/futils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6cb8e46fdf724dd6926e0f47331ba791d6d40184 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/futils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/matrix_nodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/matrix_nodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..538c2da2ae7f73a604c0a29dc76a26ac183624d9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/matrix_nodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/numpy_nodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/numpy_nodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90181c73e80b8cb3854a74525edc18f0f95bd0bf Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/numpy_nodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/pynodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/pynodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..486039d0fdc41851f823af8e7e721bc453bcbedc Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/pynodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/pyutils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/pyutils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38282516ff008190c27f1c405f92e9647dad1144 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/pyutils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/rewriting.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/rewriting.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d790254e9a0cba932c0a3d06def1ebb616865c8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/rewriting.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/scipy_nodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/scipy_nodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..26e2311c07a65e5a92c3dfa7332d02ee331dd7e0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/__pycache__/scipy_nodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..382b1b56fb783711194343dea87b8c75dc7e2c14 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_abstract_nodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_abstract_nodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1acda1cd75851bbff71f51b7ca644c0f3fbaaadc Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_abstract_nodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_algorithms.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_algorithms.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d08ca314f40ad9dc248e0aa26be88d21bcd0df0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_algorithms.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_applications.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_applications.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..49023683e2898433cb563fbf83e8cedd776de680 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_applications.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_approximations.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_approximations.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db016c03cefa9392e55aafa9ca795811b863c058 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_approximations.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_ast.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_ast.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d141528f117143d564009c4160a785cb2725c95 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_ast.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_cfunctions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_cfunctions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de042354058f6643b11e25a1ad5272695d8eeb52 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_cfunctions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_cnodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_cnodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59953f5e7270fc8f0d55443c9d8e792148ce1f3c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_cnodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_cxxnodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_cxxnodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13bf1c7525bb4a5b9788ed78d39d1a7e50b6b5b2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_cxxnodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_fnodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_fnodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..56e1b12ef5190124484e1d3d8e3febc6485b1dcd Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_fnodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_matrix_nodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_matrix_nodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d844d62ee0c92f50dd6c597a748bbb958e64446e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_matrix_nodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_numpy_nodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_numpy_nodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a4990e07b6c992a25d72c4d8955cb47cbce7608 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_numpy_nodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_pynodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_pynodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e01b49e4375bb6f7bf43661a4bad7cdd6b0420ae Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_pynodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_pyutils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_pyutils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c08862004d1076e2ddc18a4efb86a3e60b0919a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_pyutils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_rewriting.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_rewriting.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..920f0852bfce973e7a711f0e25d2c1c4564c6d73 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_rewriting.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_scipy_nodes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_scipy_nodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e81914af37a89e393cc6bbd5e5f9b0ebda34d0b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/__pycache__/test_scipy_nodes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_abstract_nodes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_abstract_nodes.py new file mode 100644 index 0000000000000000000000000000000000000000..89e1f73ff8cb24a4a865aa51304ec66e9901e3cb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_abstract_nodes.py @@ -0,0 +1,14 @@ +from sympy.core.symbol import symbols +from sympy.codegen.abstract_nodes import List + + +def test_List(): + l = List(2, 3, 4) + assert l == List(2, 3, 4) + assert str(l) == "[2, 3, 4]" + x, y, z = symbols('x y z') + l = List(x**2,y**3,z**4) + # contrary to python's built-in list, we can call e.g. "replace" on List. + m = l.replace(lambda arg: arg.is_Pow and arg.exp>2, lambda p: p.base-p.exp) + assert m == [x**2, y-3, z-4] + hash(m) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_algorithms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_algorithms.py new file mode 100644 index 0000000000000000000000000000000000000000..c684229ec18a1e02a97eee6db8537b8d12af0582 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_algorithms.py @@ -0,0 +1,180 @@ +import tempfile +from sympy import log, Min, Max, sqrt +from sympy.core.numbers import Float +from sympy.core.symbol import Symbol, symbols +from sympy.functions.elementary.trigonometric import cos +from sympy.codegen.ast import Assignment, Raise, RuntimeError_, QuotedString +from sympy.codegen.algorithms import newtons_method, newtons_method_function +from sympy.codegen.cfunctions import expm1 +from sympy.codegen.fnodes import bind_C +from sympy.codegen.futils import render_as_module as f_module +from sympy.codegen.pyutils import render_as_module as py_module +from sympy.external import import_module +from sympy.printing.codeprinter import ccode +from sympy.utilities._compilation import compile_link_import_strings, has_c, has_fortran +from sympy.utilities._compilation.util import may_xfail +from sympy.testing.pytest import skip, raises, skip_under_pyodide + +cython = import_module('cython') +wurlitzer = import_module('wurlitzer') + +def test_newtons_method(): + x, dx, atol = symbols('x dx atol') + expr = cos(x) - x**3 + algo = newtons_method(expr, x, atol, dx) + assert algo.has(Assignment(dx, -expr/expr.diff(x))) + + +@may_xfail +def test_newtons_method_function__ccode(): + x = Symbol('x', real=True) + expr = cos(x) - x**3 + func = newtons_method_function(expr, x) + + if not cython: + skip("cython not installed.") + if not has_c(): + skip("No C compiler found.") + + compile_kw = {"std": 'c99'} + with tempfile.TemporaryDirectory() as folder: + mod, info = compile_link_import_strings([ + ('newton.c', ('#include \n' + '#include \n') + ccode(func)), + ('_newton.pyx', ("#cython: language_level={}\n".format("3") + + "cdef extern double newton(double)\n" + "def py_newton(x):\n" + " return newton(x)\n")) + ], build_dir=folder, compile_kwargs=compile_kw) + assert abs(mod.py_newton(0.5) - 0.865474033102) < 1e-12 + + +@may_xfail +def test_newtons_method_function__fcode(): + x = Symbol('x', real=True) + expr = cos(x) - x**3 + func = newtons_method_function(expr, x, attrs=[bind_C(name='newton')]) + + if not cython: + skip("cython not installed.") + if not has_fortran(): + skip("No Fortran compiler found.") + + f_mod = f_module([func], 'mod_newton') + with tempfile.TemporaryDirectory() as folder: + mod, info = compile_link_import_strings([ + ('newton.f90', f_mod), + ('_newton.pyx', ("#cython: language_level={}\n".format("3") + + "cdef extern double newton(double*)\n" + "def py_newton(double x):\n" + " return newton(&x)\n")) + ], build_dir=folder) + assert abs(mod.py_newton(0.5) - 0.865474033102) < 1e-12 + + +def test_newtons_method_function__pycode(): + x = Symbol('x', real=True) + expr = cos(x) - x**3 + func = newtons_method_function(expr, x) + py_mod = py_module(func) + namespace = {} + exec(py_mod, namespace, namespace) + res = eval('newton(0.5)', namespace) + assert abs(res - 0.865474033102) < 1e-12 + + +@may_xfail +@skip_under_pyodide("Emscripten does not support process spawning") +def test_newtons_method_function__ccode_parameters(): + args = x, A, k, p = symbols('x A k p') + expr = A*cos(k*x) - p*x**3 + raises(ValueError, lambda: newtons_method_function(expr, x)) + use_wurlitzer = wurlitzer + + func = newtons_method_function(expr, x, args, debug=use_wurlitzer) + + if not has_c(): + skip("No C compiler found.") + if not cython: + skip("cython not installed.") + + compile_kw = {"std": 'c99'} + with tempfile.TemporaryDirectory() as folder: + mod, info = compile_link_import_strings([ + ('newton_par.c', ('#include \n' + '#include \n') + ccode(func)), + ('_newton_par.pyx', ("#cython: language_level={}\n".format("3") + + "cdef extern double newton(double, double, double, double)\n" + "def py_newton(x, A=1, k=1, p=1):\n" + " return newton(x, A, k, p)\n")) + ], compile_kwargs=compile_kw, build_dir=folder) + + if use_wurlitzer: + with wurlitzer.pipes() as (out, err): + result = mod.py_newton(0.5) + else: + result = mod.py_newton(0.5) + + assert abs(result - 0.865474033102) < 1e-12 + + if not use_wurlitzer: + skip("C-level output only tested when package 'wurlitzer' is available.") + + out, err = out.read(), err.read() + assert err == '' + assert out == """\ +x= 0.5 +x= 1.1121 d_x= 0.61214 +x= 0.90967 d_x= -0.20247 +x= 0.86726 d_x= -0.042409 +x= 0.86548 d_x= -0.0017867 +x= 0.86547 d_x= -3.1022e-06 +x= 0.86547 d_x= -9.3421e-12 +x= 0.86547 d_x= 3.6902e-17 +""" # try to run tests with LC_ALL=C if this assertion fails + + +def test_newtons_method_function__rtol_cse_nan(): + a, b, c, N_geo, N_tot = symbols('a b c N_geo N_tot', real=True, nonnegative=True) + i = Symbol('i', integer=True, nonnegative=True) + N_ari = N_tot - N_geo - 1 + delta_ari = (c-b)/N_ari + ln_delta_geo = log(b) + log(-expm1((log(a)-log(b))/N_geo)) + eqb_log = ln_delta_geo - log(delta_ari) + + def _clamp(low, expr, high): + return Min(Max(low, expr), high) + + meth_kw = { + 'clamped_newton': {'delta_fn': lambda e, x: _clamp( + (sqrt(a*x)-x)*0.99, + -e/e.diff(x), + (sqrt(c*x)-x)*0.99 + )}, + 'halley': {'delta_fn': lambda e, x: (-2*(e*e.diff(x))/(2*e.diff(x)**2 - e*e.diff(x, 2)))}, + 'halley_alt': {'delta_fn': lambda e, x: (-e/e.diff(x)/(1-e/e.diff(x)*e.diff(x,2)/2/e.diff(x)))}, + } + args = eqb_log, b + for use_cse in [False, True]: + kwargs = { + 'params': (b, a, c, N_geo, N_tot), 'itermax': 60, 'debug': True, 'cse': use_cse, + 'counter': i, 'atol': 1e-100, 'rtol': 2e-16, 'bounds': (a,c), + 'handle_nan': Raise(RuntimeError_(QuotedString("encountered NaN."))) + } + func = {k: newtons_method_function(*args, func_name=f"{k}_b", **dict(kwargs, **kw)) for k, kw in meth_kw.items()} + py_mod = {k: py_module(v) for k, v in func.items()} + namespace = {} + root_find_b = {} + for k, v in py_mod.items(): + ns = namespace[k] = {} + exec(v, ns, ns) + root_find_b[k] = ns[f'{k}_b'] + ref = Float('13.2261515064168768938151923226496') + reftol = {'clamped_newton': 2e-16, 'halley': 2e-16, 'halley_alt': 3e-16} + guess = 4.0 + for meth, func in root_find_b.items(): + result = func(guess, 1e-2, 1e2, 50, 100) + req = ref*reftol[meth] + if use_cse: + req *= 2 + assert abs(result - ref) < req diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_applications.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_applications.py new file mode 100644 index 0000000000000000000000000000000000000000..9519c06b96042b383314ef928d2ad0c1a2f92650 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_applications.py @@ -0,0 +1,58 @@ +# This file contains tests that exercise multiple AST nodes + +import tempfile + +from sympy.external import import_module +from sympy.printing.codeprinter import ccode +from sympy.utilities._compilation import compile_link_import_strings, has_c +from sympy.utilities._compilation.util import may_xfail +from sympy.testing.pytest import skip, skip_under_pyodide +from sympy.codegen.ast import ( + FunctionDefinition, FunctionPrototype, Variable, Pointer, real, Assignment, + integer, CodeBlock, While +) +from sympy.codegen.cnodes import void, PreIncrement +from sympy.codegen.cutils import render_as_source_file + +cython = import_module('cython') +np = import_module('numpy') + +def _mk_func1(): + declars = n, inp, out = Variable('n', integer), Pointer('inp', real), Pointer('out', real) + i = Variable('i', integer) + whl = While(i2, lambda p: p.base-p.exp) + assert m == [x**2, y-3, z-4] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_pyutils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_pyutils.py new file mode 100644 index 0000000000000000000000000000000000000000..0a2f0ff358f333635c8d44195a5c39d63ac8f16f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_pyutils.py @@ -0,0 +1,7 @@ +from sympy.codegen.ast import Print +from sympy.codegen.pyutils import render_as_module + +def test_standard(): + ast = Print('x y'.split(), r"coordinate: %12.5g %12.5g\n") + assert render_as_module(ast, standard='python3') == \ + '\n\nprint("coordinate: %12.5g %12.5g\\n" % (x, y), end="")' diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_rewriting.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_rewriting.py new file mode 100644 index 0000000000000000000000000000000000000000..51e0c9ecc940f60186cc04d4bf15650281d31cd8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_rewriting.py @@ -0,0 +1,479 @@ +import tempfile +from sympy.core.numbers import pi, Rational +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.trigonometric import (cos, sin, sinc) +from sympy.matrices.expressions.matexpr import MatrixSymbol +from sympy.assumptions import assuming, Q +from sympy.external import import_module +from sympy.printing.codeprinter import ccode +from sympy.codegen.matrix_nodes import MatrixSolve +from sympy.codegen.cfunctions import log2, exp2, expm1, log1p +from sympy.codegen.numpy_nodes import logaddexp, logaddexp2 +from sympy.codegen.scipy_nodes import cosm1, powm1 +from sympy.codegen.rewriting import ( + optimize, cosm1_opt, log2_opt, exp2_opt, expm1_opt, log1p_opt, powm1_opt, optims_c99, + create_expand_pow_optimization, matinv_opt, logaddexp_opt, logaddexp2_opt, + optims_numpy, optims_scipy, sinc_opts, FuncMinusOneOptim +) +from sympy.testing.pytest import XFAIL, skip +from sympy.utilities import lambdify +from sympy.utilities._compilation import compile_link_import_strings, has_c +from sympy.utilities._compilation.util import may_xfail + +cython = import_module('cython') +numpy = import_module('numpy') +scipy = import_module('scipy') + + +def test_log2_opt(): + x = Symbol('x') + expr1 = 7*log(3*x + 5)/(log(2)) + opt1 = optimize(expr1, [log2_opt]) + assert opt1 == 7*log2(3*x + 5) + assert opt1.rewrite(log) == expr1 + + expr2 = 3*log(5*x + 7)/(13*log(2)) + opt2 = optimize(expr2, [log2_opt]) + assert opt2 == 3*log2(5*x + 7)/13 + assert opt2.rewrite(log) == expr2 + + expr3 = log(x)/log(2) + opt3 = optimize(expr3, [log2_opt]) + assert opt3 == log2(x) + assert opt3.rewrite(log) == expr3 + + expr4 = log(x)/log(2) + log(x+1) + opt4 = optimize(expr4, [log2_opt]) + assert opt4 == log2(x) + log(2)*log2(x+1) + assert opt4.rewrite(log) == expr4 + + expr5 = log(17) + opt5 = optimize(expr5, [log2_opt]) + assert opt5 == expr5 + + expr6 = log(x + 3)/log(2) + opt6 = optimize(expr6, [log2_opt]) + assert str(opt6) == 'log2(x + 3)' + assert opt6.rewrite(log) == expr6 + + +def test_exp2_opt(): + x = Symbol('x') + expr1 = 1 + 2**x + opt1 = optimize(expr1, [exp2_opt]) + assert opt1 == 1 + exp2(x) + assert opt1.rewrite(Pow) == expr1 + + expr2 = 1 + 3**x + assert expr2 == optimize(expr2, [exp2_opt]) + + +def test_expm1_opt(): + x = Symbol('x') + + expr1 = exp(x) - 1 + opt1 = optimize(expr1, [expm1_opt]) + assert expm1(x) - opt1 == 0 + assert opt1.rewrite(exp) == expr1 + + expr2 = 3*exp(x) - 3 + opt2 = optimize(expr2, [expm1_opt]) + assert 3*expm1(x) == opt2 + assert opt2.rewrite(exp) == expr2 + + expr3 = 3*exp(x) - 5 + opt3 = optimize(expr3, [expm1_opt]) + assert 3*expm1(x) - 2 == opt3 + assert opt3.rewrite(exp) == expr3 + expm1_opt_non_opportunistic = FuncMinusOneOptim(exp, expm1, opportunistic=False) + assert expr3 == optimize(expr3, [expm1_opt_non_opportunistic]) + assert opt1 == optimize(expr1, [expm1_opt_non_opportunistic]) + assert opt2 == optimize(expr2, [expm1_opt_non_opportunistic]) + + expr4 = 3*exp(x) + log(x) - 3 + opt4 = optimize(expr4, [expm1_opt]) + assert 3*expm1(x) + log(x) == opt4 + assert opt4.rewrite(exp) == expr4 + + expr5 = 3*exp(2*x) - 3 + opt5 = optimize(expr5, [expm1_opt]) + assert 3*expm1(2*x) == opt5 + assert opt5.rewrite(exp) == expr5 + + expr6 = (2*exp(x) + 1)/(exp(x) + 1) + 1 + opt6 = optimize(expr6, [expm1_opt]) + assert opt6.count_ops() <= expr6.count_ops() + + def ev(e): + return e.subs(x, 3).evalf() + assert abs(ev(expr6) - ev(opt6)) < 1e-15 + + y = Symbol('y') + expr7 = (2*exp(x) - 1)/(1 - exp(y)) - 1/(1-exp(y)) + opt7 = optimize(expr7, [expm1_opt]) + assert -2*expm1(x)/expm1(y) == opt7 + assert (opt7.rewrite(exp) - expr7).factor() == 0 + + expr8 = (1+exp(x))**2 - 4 + opt8 = optimize(expr8, [expm1_opt]) + tgt8a = (exp(x) + 3)*expm1(x) + tgt8b = 2*expm1(x) + expm1(2*x) + # Both tgt8a & tgt8b seem to give full precision (~16 digits for double) + # for x=1e-7 (compare with expr8 which only achieves ~8 significant digits). + # If we can show that either tgt8a or tgt8b is preferable, we can + # change this test to ensure the preferable version is returned. + assert (tgt8a - tgt8b).rewrite(exp).factor() == 0 + assert opt8 in (tgt8a, tgt8b) + assert (opt8.rewrite(exp) - expr8).factor() == 0 + + expr9 = sin(expr8) + opt9 = optimize(expr9, [expm1_opt]) + tgt9a = sin(tgt8a) + tgt9b = sin(tgt8b) + assert opt9 in (tgt9a, tgt9b) + assert (opt9.rewrite(exp) - expr9.rewrite(exp)).factor().is_zero + + +def test_expm1_two_exp_terms(): + x, y = map(Symbol, 'x y'.split()) + expr1 = exp(x) + exp(y) - 2 + opt1 = optimize(expr1, [expm1_opt]) + assert opt1 == expm1(x) + expm1(y) + + +def test_cosm1_opt(): + x = Symbol('x') + + expr1 = cos(x) - 1 + opt1 = optimize(expr1, [cosm1_opt]) + assert cosm1(x) - opt1 == 0 + assert opt1.rewrite(cos) == expr1 + + expr2 = 3*cos(x) - 3 + opt2 = optimize(expr2, [cosm1_opt]) + assert 3*cosm1(x) == opt2 + assert opt2.rewrite(cos) == expr2 + + expr3 = 3*cos(x) - 5 + opt3 = optimize(expr3, [cosm1_opt]) + assert 3*cosm1(x) - 2 == opt3 + assert opt3.rewrite(cos) == expr3 + cosm1_opt_non_opportunistic = FuncMinusOneOptim(cos, cosm1, opportunistic=False) + assert expr3 == optimize(expr3, [cosm1_opt_non_opportunistic]) + assert opt1 == optimize(expr1, [cosm1_opt_non_opportunistic]) + assert opt2 == optimize(expr2, [cosm1_opt_non_opportunistic]) + + expr4 = 3*cos(x) + log(x) - 3 + opt4 = optimize(expr4, [cosm1_opt]) + assert 3*cosm1(x) + log(x) == opt4 + assert opt4.rewrite(cos) == expr4 + + expr5 = 3*cos(2*x) - 3 + opt5 = optimize(expr5, [cosm1_opt]) + assert 3*cosm1(2*x) == opt5 + assert opt5.rewrite(cos) == expr5 + + expr6 = 2 - 2*cos(x) + opt6 = optimize(expr6, [cosm1_opt]) + assert -2*cosm1(x) == opt6 + assert opt6.rewrite(cos) == expr6 + + +def test_cosm1_two_cos_terms(): + x, y = map(Symbol, 'x y'.split()) + expr1 = cos(x) + cos(y) - 2 + opt1 = optimize(expr1, [cosm1_opt]) + assert opt1 == cosm1(x) + cosm1(y) + + +def test_expm1_cosm1_mixed(): + x = Symbol('x') + expr1 = exp(x) + cos(x) - 2 + opt1 = optimize(expr1, [expm1_opt, cosm1_opt]) + assert opt1 == cosm1(x) + expm1(x) + + +def _check_num_lambdify(expr, opt, val_subs, approx_ref, lambdify_kw=None, poorness=1e10): + """ poorness=1e10 signifies that `expr` loses precision of at least ten decimal digits. """ + num_ref = expr.subs(val_subs).evalf() + eps = numpy.finfo(numpy.float64).eps + assert abs(num_ref - approx_ref) < approx_ref*eps + f1 = lambdify(list(val_subs.keys()), opt, **(lambdify_kw or {})) + args_float = tuple(map(float, val_subs.values())) + num_err1 = abs(f1(*args_float) - approx_ref) + assert num_err1 < abs(num_ref*eps) + f2 = lambdify(list(val_subs.keys()), expr, **(lambdify_kw or {})) + num_err2 = abs(f2(*args_float) - approx_ref) + assert num_err2 > abs(num_ref*eps*poorness) # this only ensures that the *test* works as intended + + +def test_cosm1_apart(): + x = Symbol('x') + + expr1 = 1/cos(x) - 1 + opt1 = optimize(expr1, [cosm1_opt]) + assert opt1 == -cosm1(x)/cos(x) + if scipy: + _check_num_lambdify(expr1, opt1, {x: S(10)**-30}, 5e-61, lambdify_kw={"modules": 'scipy'}) + + expr2 = 2/cos(x) - 2 + opt2 = optimize(expr2, optims_scipy) + assert opt2 == -2*cosm1(x)/cos(x) + if scipy: + _check_num_lambdify(expr2, opt2, {x: S(10)**-30}, 1e-60, lambdify_kw={"modules": 'scipy'}) + + expr3 = pi/cos(3*x) - pi + opt3 = optimize(expr3, [cosm1_opt]) + assert opt3 == -pi*cosm1(3*x)/cos(3*x) + if scipy: + _check_num_lambdify(expr3, opt3, {x: S(10)**-30/3}, float(5e-61*pi), lambdify_kw={"modules": 'scipy'}) + + +def test_powm1(): + args = x, y = map(Symbol, "xy") + + expr1 = x**y - 1 + opt1 = optimize(expr1, [powm1_opt]) + assert opt1 == powm1(x, y) + for arg in args: + assert expr1.diff(arg) == opt1.diff(arg) + if scipy and tuple(map(int, scipy.version.version.split('.')[:3])) >= (1, 10, 0): + subs1_a = {x: Rational(*(1.0+1e-13).as_integer_ratio()), y: pi} + ref1_f64_a = 3.139081648208105e-13 + _check_num_lambdify(expr1, opt1, subs1_a, ref1_f64_a, lambdify_kw={"modules": 'scipy'}, poorness=10**11) + + subs1_b = {x: pi, y: Rational(*(1e-10).as_integer_ratio())} + ref1_f64_b = 1.1447298859149205e-10 + _check_num_lambdify(expr1, opt1, subs1_b, ref1_f64_b, lambdify_kw={"modules": 'scipy'}, poorness=10**9) + + +def test_log1p_opt(): + x = Symbol('x') + expr1 = log(x + 1) + opt1 = optimize(expr1, [log1p_opt]) + assert log1p(x) - opt1 == 0 + assert opt1.rewrite(log) == expr1 + + expr2 = log(3*x + 3) + opt2 = optimize(expr2, [log1p_opt]) + assert log1p(x) + log(3) == opt2 + assert (opt2.rewrite(log) - expr2).simplify() == 0 + + expr3 = log(2*x + 1) + opt3 = optimize(expr3, [log1p_opt]) + assert log1p(2*x) - opt3 == 0 + assert opt3.rewrite(log) == expr3 + + expr4 = log(x+3) + opt4 = optimize(expr4, [log1p_opt]) + assert str(opt4) == 'log(x + 3)' + + +def test_optims_c99(): + x = Symbol('x') + + expr1 = 2**x + log(x)/log(2) + log(x + 1) + exp(x) - 1 + opt1 = optimize(expr1, optims_c99).simplify() + assert opt1 == exp2(x) + log2(x) + log1p(x) + expm1(x) + assert opt1.rewrite(exp).rewrite(log).rewrite(Pow) == expr1 + + expr2 = log(x)/log(2) + log(x + 1) + opt2 = optimize(expr2, optims_c99) + assert opt2 == log2(x) + log1p(x) + assert opt2.rewrite(log) == expr2 + + expr3 = log(x)/log(2) + log(17*x + 17) + opt3 = optimize(expr3, optims_c99) + delta3 = opt3 - (log2(x) + log(17) + log1p(x)) + assert delta3 == 0 + assert (opt3.rewrite(log) - expr3).simplify() == 0 + + expr4 = 2**x + 3*log(5*x + 7)/(13*log(2)) + 11*exp(x) - 11 + log(17*x + 17) + opt4 = optimize(expr4, optims_c99).simplify() + delta4 = opt4 - (exp2(x) + 3*log2(5*x + 7)/13 + 11*expm1(x) + log(17) + log1p(x)) + assert delta4 == 0 + assert (opt4.rewrite(exp).rewrite(log).rewrite(Pow) - expr4).simplify() == 0 + + expr5 = 3*exp(2*x) - 3 + opt5 = optimize(expr5, optims_c99) + delta5 = opt5 - 3*expm1(2*x) + assert delta5 == 0 + assert opt5.rewrite(exp) == expr5 + + expr6 = exp(2*x) - 3 + opt6 = optimize(expr6, optims_c99) + assert opt6 in (expm1(2*x) - 2, expr6) # expm1(2*x) - 2 is not better or worse + + expr7 = log(3*x + 3) + opt7 = optimize(expr7, optims_c99) + delta7 = opt7 - (log(3) + log1p(x)) + assert delta7 == 0 + assert (opt7.rewrite(log) - expr7).simplify() == 0 + + expr8 = log(2*x + 3) + opt8 = optimize(expr8, optims_c99) + assert opt8 == expr8 + + +def test_create_expand_pow_optimization(): + cc = lambda x: ccode( + optimize(x, [create_expand_pow_optimization(4)])) + x = Symbol('x') + assert cc(x**4) == 'x*x*x*x' + assert cc(x**4 + x**2) == 'x*x + x*x*x*x' + assert cc(x**5 + x**4) == 'pow(x, 5) + x*x*x*x' + assert cc(sin(x)**4) == 'pow(sin(x), 4)' + # gh issue 15335 + assert cc(x**(-4)) == '1.0/(x*x*x*x)' + assert cc(x**(-5)) == 'pow(x, -5)' + assert cc(-x**4) == '-(x*x*x*x)' + assert cc(x**4 - x**2) == '-(x*x) + x*x*x*x' + i = Symbol('i', integer=True) + assert cc(x**i - x**2) == 'pow(x, i) - (x*x)' + y = Symbol('y', real=True) + assert cc(Abs(exp(y**4))) == "exp(y*y*y*y)" + + # gh issue 20753 + cc2 = lambda x: ccode(optimize(x, [create_expand_pow_optimization( + 4, base_req=lambda b: b.is_Function)])) + assert cc2(x**3 + sin(x)**3) == "pow(x, 3) + sin(x)*sin(x)*sin(x)" + + +def test_matsolve(): + n = Symbol('n', integer=True) + A = MatrixSymbol('A', n, n) + x = MatrixSymbol('x', n, 1) + + with assuming(Q.fullrank(A)): + assert optimize(A**(-1) * x, [matinv_opt]) == MatrixSolve(A, x) + assert optimize(A**(-1) * x + x, [matinv_opt]) == MatrixSolve(A, x) + x + + +def test_logaddexp_opt(): + x, y = map(Symbol, 'x y'.split()) + expr1 = log(exp(x) + exp(y)) + opt1 = optimize(expr1, [logaddexp_opt]) + assert logaddexp(x, y) - opt1 == 0 + assert logaddexp(y, x) - opt1 == 0 + assert opt1.rewrite(log) == expr1 + + +def test_logaddexp2_opt(): + x, y = map(Symbol, 'x y'.split()) + expr1 = log(2**x + 2**y)/log(2) + opt1 = optimize(expr1, [logaddexp2_opt]) + assert logaddexp2(x, y) - opt1 == 0 + assert logaddexp2(y, x) - opt1 == 0 + assert opt1.rewrite(log) == expr1 + + +def test_sinc_opts(): + def check(d): + for k, v in d.items(): + assert optimize(k, sinc_opts) == v + + x = Symbol('x') + check({ + sin(x)/x : sinc(x), + sin(2*x)/(2*x) : sinc(2*x), + sin(3*x)/x : 3*sinc(3*x), + x*sin(x) : x*sin(x) + }) + + y = Symbol('y') + check({ + sin(x*y)/(x*y) : sinc(x*y), + y*sin(x/y)/x : sinc(x/y), + sin(sin(x))/sin(x) : sinc(sin(x)), + sin(3*sin(x))/sin(x) : 3*sinc(3*sin(x)), + sin(x)/y : sin(x)/y + }) + + +def test_optims_numpy(): + def check(d): + for k, v in d.items(): + assert optimize(k, optims_numpy) == v + + x = Symbol('x') + check({ + sin(2*x)/(2*x) + exp(2*x) - 1: sinc(2*x) + expm1(2*x), + log(x+3)/log(2) + log(x**2 + 1): log1p(x**2) + log2(x+3) + }) + + +@XFAIL # room for improvement, ideally this test case should pass. +def test_optims_numpy_TODO(): + def check(d): + for k, v in d.items(): + assert optimize(k, optims_numpy) == v + + x, y = map(Symbol, 'x y'.split()) + check({ + log(x*y)*sin(x*y)*log(x*y+1)/(log(2)*x*y): log2(x*y)*sinc(x*y)*log1p(x*y), + exp(x*sin(y)/y) - 1: expm1(x*sinc(y)) + }) + + +@may_xfail +def test_compiled_ccode_with_rewriting(): + if not cython: + skip("cython not installed.") + if not has_c(): + skip("No C compiler found.") + + x = Symbol('x') + about_two = 2**(58/S(117))*3**(97/S(117))*5**(4/S(39))*7**(92/S(117))/S(30)*pi + # about_two: 1.999999999999581826 + unchanged = 2*exp(x) - about_two + xval = S(10)**-11 + ref = unchanged.subs(x, xval).n(19) # 2.0418173913673213e-11 + + rewritten = optimize(2*exp(x) - about_two, [expm1_opt]) + + # Unfortunately, we need to call ``.n()`` on our expressions before we hand them + # to ``ccode``, and we need to request a large number of significant digits. + # In this test, results converged for double precision when the following number + # of significant digits were chosen: + NUMBER_OF_DIGITS = 25 # TODO: this should ideally be automatically handled. + + func_c = ''' +#include + +double func_unchanged(double x) { + return %(unchanged)s; +} +double func_rewritten(double x) { + return %(rewritten)s; +} +''' % {"unchanged": ccode(unchanged.n(NUMBER_OF_DIGITS)), + "rewritten": ccode(rewritten.n(NUMBER_OF_DIGITS))} + + func_pyx = ''' +#cython: language_level=3 +cdef extern double func_unchanged(double) +cdef extern double func_rewritten(double) +def py_unchanged(x): + return func_unchanged(x) +def py_rewritten(x): + return func_rewritten(x) +''' + with tempfile.TemporaryDirectory() as folder: + mod, info = compile_link_import_strings( + [('func.c', func_c), ('_func.pyx', func_pyx)], + build_dir=folder, compile_kwargs={"std": 'c99'} + ) + err_rewritten = abs(mod.py_rewritten(1e-11) - ref) + err_unchanged = abs(mod.py_unchanged(1e-11) - ref) + assert 1e-27 < err_rewritten < 1e-25 # highly accurate. + assert 1e-19 < err_unchanged < 1e-16 # quite poor. + + # Tolerances used above were determined as follows: + # >>> no_opt = unchanged.subs(x, xval.evalf()).evalf() + # >>> with_opt = rewritten.n(25).subs(x, 1e-11).evalf() + # >>> with_opt - ref, no_opt - ref + # (1.1536301877952077e-26, 1.6547074214222335e-18) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_scipy_nodes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_scipy_nodes.py new file mode 100644 index 0000000000000000000000000000000000000000..c0d1461037eec81ade0c99b18fbbf5a4517ce0b7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/codegen/tests/test_scipy_nodes.py @@ -0,0 +1,44 @@ +from itertools import product +from sympy.core.power import Pow +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.trigonometric import cos +from sympy.core.numbers import pi +from sympy.codegen.scipy_nodes import cosm1, powm1 + +x, y, z = symbols('x y z') + + +def test_cosm1(): + cm1_xy = cosm1(x*y) + ref_xy = cos(x*y) - 1 + for wrt, deriv_order in product([x, y, z], range(3)): + assert ( + cm1_xy.diff(wrt, deriv_order) - + ref_xy.diff(wrt, deriv_order) + ).rewrite(cos).simplify() == 0 + + expr_minus2 = cosm1(pi) + assert expr_minus2.rewrite(cos) == -2 + assert cosm1(3.14).simplify() == cosm1(3.14) # cannot simplify with 3.14 + assert cosm1(pi/2).simplify() == -1 + assert (1/cos(x) - 1 + cosm1(x)/cos(x)).simplify() == 0 + + +def test_powm1(): + cases = { + powm1(x, y): x**y - 1, + powm1(x*y, z): (x*y)**z - 1, + powm1(x, y*z): x**(y*z)-1, + powm1(x*y*z, x*y*z): (x*y*z)**(x*y*z)-1 + } + for pm1_e, ref_e in cases.items(): + for wrt, deriv_order in product([x, y, z], range(3)): + der = pm1_e.diff(wrt, deriv_order) + ref = ref_e.diff(wrt, deriv_order) + delta = (der - ref).rewrite(Pow) + assert delta.simplify() == 0 + + eulers_constant_m1 = powm1(x, 1/log(x)) + assert eulers_constant_m1.rewrite(Pow) == exp(1) - 1 + assert eulers_constant_m1.simplify() == exp(1) - 1 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b532f28cf49506ebcb3a030322c086ad087d814 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/_print_helpers.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/_print_helpers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd1536c845bc8a47262220855ebe551ac3f96f9d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/_print_helpers.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/add.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/add.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..328d75aebb755fc072205e0a81b6e9828ecd2cb2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/add.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/alphabets.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/alphabets.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66767260ce8ff42dff66a16ab3ec9ad4d137a3ef Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/alphabets.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/assumptions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/assumptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8290efdcae70fc416a3783d5b21a89cde3c0133 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/assumptions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/assumptions_generated.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/assumptions_generated.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3c44871305f8d97d142e31196b82b334ffbafe7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/assumptions_generated.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/backend.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/backend.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc624e9b557133384717435efa65cf0a1d8efd51 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/backend.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/basic.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/basic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b5fc489d6cc27891f6dfd555c804eb87893b1b59 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/basic.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/cache.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/cache.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14ae38a525893e205a2a4a3b69771380f8dc1e30 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/cache.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/compatibility.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/compatibility.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d01bf2bddfc2c6baa48a8be433d61518ba11b7f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/compatibility.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/containers.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/containers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34a01f6c3845beeb712bf8f1842bcd718626ea6c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/containers.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/core.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/core.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..673731422e369ddcd5fd7db36db1a5c655c6e0d7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/core.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/coreerrors.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/coreerrors.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9962aff10a5979d58a87fd8caaac5295feed47f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/coreerrors.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/decorators.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/decorators.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b1f9878a221dc8fa735a95b4629a52fc1412a40 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/decorators.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/evalf.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/evalf.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c740b587cf059fd1d9bda53d68a0f037129350a7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/evalf.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/exprtools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/exprtools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88adea22498e2f01e2f1c1bc2b4b97cd89160ebd Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/exprtools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/facts.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/facts.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba16da17e188c30ddc57db8a315fb1e5014bf2ff Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/facts.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/intfunc.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/intfunc.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9265466d8b79aaf8bf5ff0027e4834136c3ea7b3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/intfunc.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/kind.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/kind.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..492a66bd8e3d25f47598f0b7dcbbb6432714a182 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/kind.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/logic.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/logic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a1ab217c05d8860420f7b2945cb9185c5d4534e0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/logic.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/mod.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/mod.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..417515983d59a464224b6c436ec8c1e6cb820868 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/mod.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/mul.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/mul.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..094f9fb27c68fe5ac0f40eedc7f92d8702e58956 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/mul.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/multidimensional.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/multidimensional.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72621bc0c32d2fc3c340a40c2644ffcef7850422 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/multidimensional.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/operations.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/operations.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c075a0df123b113bfac08fd88577f7f97a74a57 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/operations.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/parameters.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/parameters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93aa5278fee810cb51089759ba6ac59f020c4083 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/parameters.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/power.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/power.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fba3f1d4814ed135eaaf7bb922720ee712a260ec Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/power.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/random.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/random.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1779bda408d86609ee206ef334a93b2bcbe8d846 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/random.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/relational.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/relational.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2fb4edc20e30ac948fa984262a416ee7fcdf48c3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/relational.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/rules.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/rules.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..652e43c04af0b19cbf1a10332e7fbdb9d11e92c7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/rules.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/singleton.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/singleton.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..778766aff07992d20688d85002cde15ba54ce5f3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/singleton.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/sorting.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/sorting.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f15e806f1e0612173965d0789916528c922d9b1 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/sorting.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/symbol.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/symbol.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4215ce030e57190adc56d450949e0dc6623b7a8c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/symbol.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/sympify.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/sympify.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..664cabc0c03bf538f47e0abfb037e9ded4f0dde1 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/sympify.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/trace.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/trace.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c22b38599769a83b6e8f2b92631c4de57925cc6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/trace.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/traversal.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/traversal.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9695ad477ab63eced88344169f3f5a9a70f706b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/__pycache__/traversal.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bacc14b2edb92f478739fec539cea1b1fcdf7691 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_arit.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_arit.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..20148dd5d0111863fd264dff71413b351a0cf82d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_arit.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_assumptions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_assumptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9cb8862f7194e9ddbb29c4ad685fa81b0818cecc Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_assumptions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_basic.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_basic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f07dc1683822a0e305cb15eb5039b711a29e7430 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_basic.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_expand.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_expand.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bb2dcdeefd1489b4854e88cc074543d84147b4f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_expand.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_numbers.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_numbers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f5b35083ea1d741a852687745442d9277390c1b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_numbers.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_sympify.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_sympify.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76e4cdcb59e484c5c69079910a6c118e4988e008 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/__pycache__/bench_sympify.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_arit.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_arit.py new file mode 100644 index 0000000000000000000000000000000000000000..39860943b763a30cf4f91578dbac37dc7e6e444e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_arit.py @@ -0,0 +1,43 @@ +from sympy.core import Add, Mul, symbols + +x, y, z = symbols('x,y,z') + + +def timeit_neg(): + -x + + +def timeit_Add_x1(): + x + 1 + + +def timeit_Add_1x(): + 1 + x + + +def timeit_Add_x05(): + x + 0.5 + + +def timeit_Add_xy(): + x + y + + +def timeit_Add_xyz(): + Add(*[x, y, z]) + + +def timeit_Mul_xy(): + x*y + + +def timeit_Mul_xyz(): + Mul(*[x, y, z]) + + +def timeit_Div_xy(): + x/y + + +def timeit_Div_2y(): + 2/y diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_assumptions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_assumptions.py new file mode 100644 index 0000000000000000000000000000000000000000..1a8e47928b76034dd1d7ba8b8f87bd527bb1cdeb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_assumptions.py @@ -0,0 +1,12 @@ +from sympy.core import Symbol, Integer + +x = Symbol('x') +i3 = Integer(3) + + +def timeit_x_is_integer(): + x.is_integer + + +def timeit_Integer_is_irrational(): + i3.is_irrational diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_basic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_basic.py new file mode 100644 index 0000000000000000000000000000000000000000..df2a382ecbd3cf6eb1f8555577dabb5e07c6643b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_basic.py @@ -0,0 +1,15 @@ +from sympy.core import symbols, S + +x, y = symbols('x,y') + + +def timeit_Symbol_meth_lookup(): + x.diff # no call, just method lookup + + +def timeit_S_lookup(): + S.Exp1 + + +def timeit_Symbol_eq_xy(): + x == y diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_expand.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_expand.py new file mode 100644 index 0000000000000000000000000000000000000000..4f5ac513e368cb7e9b542926bc25a5695de6d914 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_expand.py @@ -0,0 +1,23 @@ +from sympy.core import symbols, I + +x, y, z = symbols('x,y,z') + +p = 3*x**2*y*z**7 + 7*x*y*z**2 + 4*x + x*y**4 +e = (x + y + z + 1)**32 + + +def timeit_expand_nothing_todo(): + p.expand() + + +def bench_expand_32(): + """(x+y+z+1)**32 -> expand""" + e.expand() + + +def timeit_expand_complex_number_1(): + ((2 + 3*I)**1000).expand(complex=True) + + +def timeit_expand_complex_number_2(): + ((2 + 3*I/4)**1000).expand(complex=True) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_numbers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_numbers.py new file mode 100644 index 0000000000000000000000000000000000000000..5c7484c389232b3622fb4b6724e4ab8534dde382 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_numbers.py @@ -0,0 +1,92 @@ +from sympy.core.numbers import Integer, Rational, pi, oo +from sympy.core.intfunc import integer_nthroot, igcd +from sympy.core.singleton import S + +i3 = Integer(3) +i4 = Integer(4) +r34 = Rational(3, 4) +q45 = Rational(4, 5) + + +def timeit_Integer_create(): + Integer(2) + + +def timeit_Integer_int(): + int(i3) + + +def timeit_neg_one(): + -S.One + + +def timeit_Integer_neg(): + -i3 + + +def timeit_Integer_abs(): + abs(i3) + + +def timeit_Integer_sub(): + i3 - i3 + + +def timeit_abs_pi(): + abs(pi) + + +def timeit_neg_oo(): + -oo + + +def timeit_Integer_add_i1(): + i3 + 1 + + +def timeit_Integer_add_ij(): + i3 + i4 + + +def timeit_Integer_add_Rational(): + i3 + r34 + + +def timeit_Integer_mul_i4(): + i3*4 + + +def timeit_Integer_mul_ij(): + i3*i4 + + +def timeit_Integer_mul_Rational(): + i3*r34 + + +def timeit_Integer_eq_i3(): + i3 == 3 + + +def timeit_Integer_ed_Rational(): + i3 == r34 + + +def timeit_integer_nthroot(): + integer_nthroot(100, 2) + + +def timeit_number_igcd_23_17(): + igcd(23, 17) + + +def timeit_number_igcd_60_3600(): + igcd(60, 3600) + + +def timeit_Rational_add_r1(): + r34 + 1 + + +def timeit_Rational_add_rq(): + r34 + q45 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_sympify.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_sympify.py new file mode 100644 index 0000000000000000000000000000000000000000..d8cc0abc1e35439a1a495454abf87769d5b40d04 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/benchmarks/bench_sympify.py @@ -0,0 +1,11 @@ +from sympy.core import sympify, Symbol + +x = Symbol('x') + + +def timeit_sympify_1(): + sympify(1) + + +def timeit_sympify_x(): + sympify(x) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cedbad731e9170ef2c3edba80404072de37cc067 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_assumptions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_assumptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3d6c45a75bb6020fad4de8664bd87056eb1eedc Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_assumptions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_basic.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_basic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f86ed209835cd954d751afbf33561b6510cf81d6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_basic.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_cache.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_cache.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3890dcf585618389d5893532e04ffc86ec42249 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_cache.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_compatibility.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_compatibility.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b35cee8347154ed61a53fe6d790933568e4a51b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_compatibility.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_complex.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_complex.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9488ce8d3ce149f1998fa7d41a1a83788673a352 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_complex.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_constructor_postprocessor.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_constructor_postprocessor.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b56a8c98a78937bbf809badb93111a1542807ba Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_constructor_postprocessor.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_containers.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_containers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a7734a2de213499edbb0a057f05c66557432c0e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_containers.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_count_ops.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_count_ops.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..676a308f71cb5f7c5a047f087cc8a62ad7372503 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_count_ops.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_diff.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_diff.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0597fc5efdab6b84e9f0249dbfd4a8885a49d81 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_diff.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_equal.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_equal.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa2d90812a38523250b73c0aaf1346b9b3a448a3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_equal.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_eval.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_eval.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0812e53a6b5caebfaf36317c937d3e5316e478f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_eval.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_evalf.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_evalf.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f3f608ac1a5b5a43e674f82e2dd10ed37af9c39 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_evalf.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_expand.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_expand.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9241c629ebf02d7b9993014519984069a1e7ff35 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_expand.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_exprtools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_exprtools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9917b85afb0dc30983d8f043240b945030d24713 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_exprtools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_facts.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_facts.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..90fedfd549c3736dd35bebb06ff08327187726e3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_facts.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_kind.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_kind.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df954083422acdba1ee08286a3187856fe425824 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_kind.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_logic.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_logic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69b0084f040840a8e4602c97b6f422ad8d6c37af Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_logic.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_match.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_match.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06b791800e2aa04608306bdaa50d4bd5b60b108c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_match.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_multidimensional.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_multidimensional.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d7753fe22b5e98ab7d38a841221cea068a4dce8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_multidimensional.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_noncommutative.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_noncommutative.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36b48c29ed024d37a0e0c003675ee8df1fd741f1 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_noncommutative.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_operations.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_operations.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..018c046f69d261af7e25bb2d1b5885c70ea98011 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_operations.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_parameters.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_parameters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..96f1da8dcc03c354b2cb190ca709d8a202e5fa3b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_parameters.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_power.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_power.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca2f652c9ce0b4ab8242cf20a7715a9b2d94b2c0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_power.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_priority.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_priority.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13b9efbd89212804214d8003bff2977e5e3fea46 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_priority.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_random.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_random.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc3ceceb341c64097dca97fd16683ec7d30c2b14 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_random.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_rules.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_rules.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b6717ff9ed98c111719c1bea3b80d50f03f06afb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_rules.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_singleton.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_singleton.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..00ea0418a42f418e5be3d633483a4e1db7dfc951 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_singleton.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_sorting.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_sorting.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ce5de766590fc6ee909ebcd32951543a2bf45df Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_sorting.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_subs.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_subs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1810b7f926d24fade822368e3acce19aff87f794 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_subs.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_symbol.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_symbol.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27d4ed5664f49ff9a51a8ca145a633f0c957fb47 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_symbol.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_sympify.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_sympify.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..81d8f9ba249efa9c34c45308260e5fcb89bccad3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_sympify.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_traversal.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_traversal.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d35ceadef5dfa0bc2111e2c73e3079e564fbdf36 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_traversal.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_truediv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_truediv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6886ad99f97aafbce5694a76db976faccd963563 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_truediv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_var.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_var.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ade250850bfc3e700e2a88c81c2c79e8185af2b2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/__pycache__/test_var.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_args.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_args.py new file mode 100644 index 0000000000000000000000000000000000000000..75b326146e1cc645a27e26ba13d44c92d56d5efb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_args.py @@ -0,0 +1,5517 @@ +"""Test whether all elements of cls.args are instances of Basic. """ + +# NOTE: keep tests sorted by (module, class name) key. If a class can't +# be instantiated, add it here anyway with @SKIP("abstract class) (see +# e.g. Function). + +import os +import re +from pathlib import Path + +from sympy.assumptions.ask import Q +from sympy.core.basic import Basic +from sympy.core.function import (Function, Lambda) +from sympy.core.numbers import (Rational, oo, pi) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin + +from sympy.testing.pytest import SKIP, warns_deprecated_sympy + +a, b, c, x, y, z, s = symbols('a,b,c,x,y,z,s') + + +whitelist = [ + "sympy.assumptions.predicates", # tested by test_predicates() + "sympy.assumptions.relation.equality", # tested by test_predicates() +] + +def test_all_classes_are_tested(): + this = os.path.split(__file__)[0] + path = os.path.join(this, os.pardir, os.pardir) + sympy_path = os.path.abspath(path) + prefix = os.path.split(sympy_path)[0] + os.sep + + re_cls = re.compile(r"^class ([A-Za-z][A-Za-z0-9_]*)\s*\(", re.MULTILINE) + + modules = {} + + for root, dirs, files in os.walk(sympy_path): + module = root.replace(prefix, "").replace(os.sep, ".") + + for file in files: + if file.startswith(("_", "test_", "bench_")): + continue + if not file.endswith(".py"): + continue + + text = Path(os.path.join(root, file)).read_text(encoding='utf-8') + + submodule = module + '.' + file[:-3] + + if any(submodule.startswith(wpath) for wpath in whitelist): + continue + + names = re_cls.findall(text) + + if not names: + continue + + try: + mod = __import__(submodule, fromlist=names) + except ImportError: + continue + + def is_Basic(name): + cls = getattr(mod, name) + if hasattr(cls, '_sympy_deprecated_func'): + cls = cls._sympy_deprecated_func + if not isinstance(cls, type): + # check instance of singleton class with same name + cls = type(cls) + return issubclass(cls, Basic) + + names = list(filter(is_Basic, names)) + + if names: + modules[submodule] = names + + ns = globals() + failed = [] + + for module, names in modules.items(): + mod = module.replace('.', '__') + + for name in names: + test = 'test_' + mod + '__' + name + + if test not in ns: + failed.append(module + '.' + name) + + assert not failed, "Missing classes: %s. Please add tests for these to sympy/core/tests/test_args.py." % ", ".join(failed) + + +def _test_args(obj): + all_basic = all(isinstance(arg, Basic) for arg in obj.args) + # Ideally obj.func(*obj.args) would always recreate the object, but for + # now, we only require it for objects with non-empty .args + recreatable = not obj.args or obj.func(*obj.args) == obj + return all_basic and recreatable + + +def test_sympy__algebras__quaternion__Quaternion(): + from sympy.algebras.quaternion import Quaternion + assert _test_args(Quaternion(x, 1, 2, 3)) + + +def test_sympy__assumptions__assume__AppliedPredicate(): + from sympy.assumptions.assume import AppliedPredicate, Predicate + assert _test_args(AppliedPredicate(Predicate("test"), 2)) + assert _test_args(Q.is_true(True)) + +@SKIP("abstract class") +def test_sympy__assumptions__assume__Predicate(): + pass + +def test_predicates(): + predicates = [ + getattr(Q, attr) + for attr in Q.__class__.__dict__ + if not attr.startswith('__')] + for p in predicates: + assert _test_args(p) + +def test_sympy__assumptions__assume__UndefinedPredicate(): + from sympy.assumptions.assume import Predicate + assert _test_args(Predicate("test")) + +@SKIP('abstract class') +def test_sympy__assumptions__relation__binrel__BinaryRelation(): + pass + +def test_sympy__assumptions__relation__binrel__AppliedBinaryRelation(): + assert _test_args(Q.eq(1, 2)) + +def test_sympy__assumptions__wrapper__AssumptionsWrapper(): + from sympy.assumptions.wrapper import AssumptionsWrapper + assert _test_args(AssumptionsWrapper(x, Q.positive(x))) + +@SKIP("abstract Class") +def test_sympy__codegen__ast__CodegenAST(): + from sympy.codegen.ast import CodegenAST + assert _test_args(CodegenAST()) + +@SKIP("abstract Class") +def test_sympy__codegen__ast__AssignmentBase(): + from sympy.codegen.ast import AssignmentBase + assert _test_args(AssignmentBase(x, 1)) + +@SKIP("abstract Class") +def test_sympy__codegen__ast__AugmentedAssignment(): + from sympy.codegen.ast import AugmentedAssignment + assert _test_args(AugmentedAssignment(x, 1)) + +def test_sympy__codegen__ast__AddAugmentedAssignment(): + from sympy.codegen.ast import AddAugmentedAssignment + assert _test_args(AddAugmentedAssignment(x, 1)) + +def test_sympy__codegen__ast__SubAugmentedAssignment(): + from sympy.codegen.ast import SubAugmentedAssignment + assert _test_args(SubAugmentedAssignment(x, 1)) + +def test_sympy__codegen__ast__MulAugmentedAssignment(): + from sympy.codegen.ast import MulAugmentedAssignment + assert _test_args(MulAugmentedAssignment(x, 1)) + +def test_sympy__codegen__ast__DivAugmentedAssignment(): + from sympy.codegen.ast import DivAugmentedAssignment + assert _test_args(DivAugmentedAssignment(x, 1)) + +def test_sympy__codegen__ast__ModAugmentedAssignment(): + from sympy.codegen.ast import ModAugmentedAssignment + assert _test_args(ModAugmentedAssignment(x, 1)) + +def test_sympy__codegen__ast__CodeBlock(): + from sympy.codegen.ast import CodeBlock, Assignment + assert _test_args(CodeBlock(Assignment(x, 1), Assignment(y, 2))) + +def test_sympy__codegen__ast__For(): + from sympy.codegen.ast import For, CodeBlock, AddAugmentedAssignment + from sympy.sets import Range + assert _test_args(For(x, Range(10), CodeBlock(AddAugmentedAssignment(y, 1)))) + + +def test_sympy__codegen__ast__Token(): + from sympy.codegen.ast import Token + assert _test_args(Token()) + + +def test_sympy__codegen__ast__ContinueToken(): + from sympy.codegen.ast import ContinueToken + assert _test_args(ContinueToken()) + +def test_sympy__codegen__ast__BreakToken(): + from sympy.codegen.ast import BreakToken + assert _test_args(BreakToken()) + +def test_sympy__codegen__ast__NoneToken(): + from sympy.codegen.ast import NoneToken + assert _test_args(NoneToken()) + +def test_sympy__codegen__ast__String(): + from sympy.codegen.ast import String + assert _test_args(String('foobar')) + +def test_sympy__codegen__ast__QuotedString(): + from sympy.codegen.ast import QuotedString + assert _test_args(QuotedString('foobar')) + +def test_sympy__codegen__ast__Comment(): + from sympy.codegen.ast import Comment + assert _test_args(Comment('this is a comment')) + +def test_sympy__codegen__ast__Node(): + from sympy.codegen.ast import Node + assert _test_args(Node()) + assert _test_args(Node(attrs={1, 2, 3})) + + +def test_sympy__codegen__ast__Type(): + from sympy.codegen.ast import Type + assert _test_args(Type('float128')) + + +def test_sympy__codegen__ast__IntBaseType(): + from sympy.codegen.ast import IntBaseType + assert _test_args(IntBaseType('bigint')) + + +def test_sympy__codegen__ast___SizedIntType(): + from sympy.codegen.ast import _SizedIntType + assert _test_args(_SizedIntType('int128', 128)) + + +def test_sympy__codegen__ast__SignedIntType(): + from sympy.codegen.ast import SignedIntType + assert _test_args(SignedIntType('int128_with_sign', 128)) + + +def test_sympy__codegen__ast__UnsignedIntType(): + from sympy.codegen.ast import UnsignedIntType + assert _test_args(UnsignedIntType('unt128', 128)) + + +def test_sympy__codegen__ast__FloatBaseType(): + from sympy.codegen.ast import FloatBaseType + assert _test_args(FloatBaseType('positive_real')) + + +def test_sympy__codegen__ast__FloatType(): + from sympy.codegen.ast import FloatType + assert _test_args(FloatType('float242', 242, nmant=142, nexp=99)) + + +def test_sympy__codegen__ast__ComplexBaseType(): + from sympy.codegen.ast import ComplexBaseType + assert _test_args(ComplexBaseType('positive_cmplx')) + +def test_sympy__codegen__ast__ComplexType(): + from sympy.codegen.ast import ComplexType + assert _test_args(ComplexType('complex42', 42, nmant=15, nexp=5)) + + +def test_sympy__codegen__ast__Attribute(): + from sympy.codegen.ast import Attribute + assert _test_args(Attribute('noexcept')) + + +def test_sympy__codegen__ast__Variable(): + from sympy.codegen.ast import Variable, Type, value_const + assert _test_args(Variable(x)) + assert _test_args(Variable(y, Type('float32'), {value_const})) + assert _test_args(Variable(z, type=Type('float64'))) + + +def test_sympy__codegen__ast__Pointer(): + from sympy.codegen.ast import Pointer, Type, pointer_const + assert _test_args(Pointer(x)) + assert _test_args(Pointer(y, type=Type('float32'))) + assert _test_args(Pointer(z, Type('float64'), {pointer_const})) + + +def test_sympy__codegen__ast__Declaration(): + from sympy.codegen.ast import Declaration, Variable, Type + vx = Variable(x, type=Type('float')) + assert _test_args(Declaration(vx)) + + +def test_sympy__codegen__ast__While(): + from sympy.codegen.ast import While, AddAugmentedAssignment + assert _test_args(While(abs(x) < 1, [AddAugmentedAssignment(x, -1)])) + + +def test_sympy__codegen__ast__Scope(): + from sympy.codegen.ast import Scope, AddAugmentedAssignment + assert _test_args(Scope([AddAugmentedAssignment(x, -1)])) + + +def test_sympy__codegen__ast__Stream(): + from sympy.codegen.ast import Stream + assert _test_args(Stream('stdin')) + +def test_sympy__codegen__ast__Print(): + from sympy.codegen.ast import Print + assert _test_args(Print([x, y])) + assert _test_args(Print([x, y], "%d %d")) + + +def test_sympy__codegen__ast__FunctionPrototype(): + from sympy.codegen.ast import FunctionPrototype, real, Declaration, Variable + inp_x = Declaration(Variable(x, type=real)) + assert _test_args(FunctionPrototype(real, 'pwer', [inp_x])) + + +def test_sympy__codegen__ast__FunctionDefinition(): + from sympy.codegen.ast import FunctionDefinition, real, Declaration, Variable, Assignment + inp_x = Declaration(Variable(x, type=real)) + assert _test_args(FunctionDefinition(real, 'pwer', [inp_x], [Assignment(x, x**2)])) + + +def test_sympy__codegen__ast__Raise(): + from sympy.codegen.ast import Raise + assert _test_args(Raise(x)) + + +def test_sympy__codegen__ast__Return(): + from sympy.codegen.ast import Return + assert _test_args(Return(x)) + + +def test_sympy__codegen__ast__RuntimeError_(): + from sympy.codegen.ast import RuntimeError_ + assert _test_args(RuntimeError_('"message"')) + + +def test_sympy__codegen__ast__FunctionCall(): + from sympy.codegen.ast import FunctionCall + assert _test_args(FunctionCall('pwer', [x])) + + +def test_sympy__codegen__ast__Element(): + from sympy.codegen.ast import Element + assert _test_args(Element('x', range(3))) + + +def test_sympy__codegen__cnodes__CommaOperator(): + from sympy.codegen.cnodes import CommaOperator + assert _test_args(CommaOperator(1, 2)) + + +def test_sympy__codegen__cnodes__goto(): + from sympy.codegen.cnodes import goto + assert _test_args(goto('early_exit')) + + +def test_sympy__codegen__cnodes__Label(): + from sympy.codegen.cnodes import Label + assert _test_args(Label('early_exit')) + + +def test_sympy__codegen__cnodes__PreDecrement(): + from sympy.codegen.cnodes import PreDecrement + assert _test_args(PreDecrement(x)) + + +def test_sympy__codegen__cnodes__PostDecrement(): + from sympy.codegen.cnodes import PostDecrement + assert _test_args(PostDecrement(x)) + + +def test_sympy__codegen__cnodes__PreIncrement(): + from sympy.codegen.cnodes import PreIncrement + assert _test_args(PreIncrement(x)) + + +def test_sympy__codegen__cnodes__PostIncrement(): + from sympy.codegen.cnodes import PostIncrement + assert _test_args(PostIncrement(x)) + + +def test_sympy__codegen__cnodes__struct(): + from sympy.codegen.ast import real, Variable + from sympy.codegen.cnodes import struct + assert _test_args(struct(declarations=[ + Variable(x, type=real), + Variable(y, type=real) + ])) + + +def test_sympy__codegen__cnodes__union(): + from sympy.codegen.ast import float32, int32, Variable + from sympy.codegen.cnodes import union + assert _test_args(union(declarations=[ + Variable(x, type=float32), + Variable(y, type=int32) + ])) + + +def test_sympy__codegen__cxxnodes__using(): + from sympy.codegen.cxxnodes import using + assert _test_args(using('std::vector')) + assert _test_args(using('std::vector', 'vec')) + + +def test_sympy__codegen__fnodes__Program(): + from sympy.codegen.fnodes import Program + assert _test_args(Program('foobar', [])) + +def test_sympy__codegen__fnodes__Module(): + from sympy.codegen.fnodes import Module + assert _test_args(Module('foobar', [], [])) + + +def test_sympy__codegen__fnodes__Subroutine(): + from sympy.codegen.fnodes import Subroutine + x = symbols('x', real=True) + assert _test_args(Subroutine('foo', [x], [])) + + +def test_sympy__codegen__fnodes__GoTo(): + from sympy.codegen.fnodes import GoTo + assert _test_args(GoTo([10])) + assert _test_args(GoTo([10, 20], x > 1)) + + +def test_sympy__codegen__fnodes__FortranReturn(): + from sympy.codegen.fnodes import FortranReturn + assert _test_args(FortranReturn(10)) + + +def test_sympy__codegen__fnodes__Extent(): + from sympy.codegen.fnodes import Extent + assert _test_args(Extent()) + assert _test_args(Extent(None)) + assert _test_args(Extent(':')) + assert _test_args(Extent(-3, 4)) + assert _test_args(Extent(x, y)) + + +def test_sympy__codegen__fnodes__use_rename(): + from sympy.codegen.fnodes import use_rename + assert _test_args(use_rename('loc', 'glob')) + + +def test_sympy__codegen__fnodes__use(): + from sympy.codegen.fnodes import use + assert _test_args(use('modfoo', only='bar')) + + +def test_sympy__codegen__fnodes__SubroutineCall(): + from sympy.codegen.fnodes import SubroutineCall + assert _test_args(SubroutineCall('foo', ['bar', 'baz'])) + + +def test_sympy__codegen__fnodes__Do(): + from sympy.codegen.fnodes import Do + assert _test_args(Do([], 'i', 1, 42)) + + +def test_sympy__codegen__fnodes__ImpliedDoLoop(): + from sympy.codegen.fnodes import ImpliedDoLoop + assert _test_args(ImpliedDoLoop('i', 'i', 1, 42)) + + +def test_sympy__codegen__fnodes__ArrayConstructor(): + from sympy.codegen.fnodes import ArrayConstructor + assert _test_args(ArrayConstructor([1, 2, 3])) + from sympy.codegen.fnodes import ImpliedDoLoop + idl = ImpliedDoLoop('i', 'i', 1, 42) + assert _test_args(ArrayConstructor([1, idl, 3])) + + +def test_sympy__codegen__fnodes__sum_(): + from sympy.codegen.fnodes import sum_ + assert _test_args(sum_('arr')) + + +def test_sympy__codegen__fnodes__product_(): + from sympy.codegen.fnodes import product_ + assert _test_args(product_('arr')) + + +def test_sympy__codegen__numpy_nodes__logaddexp(): + from sympy.codegen.numpy_nodes import logaddexp + assert _test_args(logaddexp(x, y)) + + +def test_sympy__codegen__numpy_nodes__logaddexp2(): + from sympy.codegen.numpy_nodes import logaddexp2 + assert _test_args(logaddexp2(x, y)) + + +def test_sympy__codegen__numpy_nodes__amin(): + from sympy.codegen.numpy_nodes import amin + assert _test_args(amin(x)) + + +def test_sympy__codegen__numpy_nodes__amax(): + from sympy.codegen.numpy_nodes import amax + assert _test_args(amax(x)) + + +def test_sympy__codegen__numpy_nodes__minimum(): + from sympy.codegen.numpy_nodes import minimum + assert _test_args(minimum(x, y, z)) + + +def test_sympy__codegen__numpy_nodes__maximum(): + from sympy.codegen.numpy_nodes import maximum + assert _test_args(maximum(x, y, z)) + + +def test_sympy__codegen__pynodes__List(): + from sympy.codegen.pynodes import List + assert _test_args(List(1, 2, 3)) + + +def test_sympy__codegen__pynodes__NumExprEvaluate(): + from sympy.codegen.pynodes import NumExprEvaluate + assert _test_args(NumExprEvaluate(x)) + + +def test_sympy__codegen__scipy_nodes__cosm1(): + from sympy.codegen.scipy_nodes import cosm1 + assert _test_args(cosm1(x)) + + +def test_sympy__codegen__scipy_nodes__powm1(): + from sympy.codegen.scipy_nodes import powm1 + assert _test_args(powm1(x, y)) + + +def test_sympy__codegen__abstract_nodes__List(): + from sympy.codegen.abstract_nodes import List + assert _test_args(List(1, 2, 3)) + +def test_sympy__combinatorics__graycode__GrayCode(): + from sympy.combinatorics.graycode import GrayCode + # an integer is given and returned from GrayCode as the arg + assert _test_args(GrayCode(3, start='100')) + assert _test_args(GrayCode(3, rank=1)) + + +def test_sympy__combinatorics__permutations__Permutation(): + from sympy.combinatorics.permutations import Permutation + assert _test_args(Permutation([0, 1, 2, 3])) + +def test_sympy__combinatorics__permutations__AppliedPermutation(): + from sympy.combinatorics.permutations import Permutation + from sympy.combinatorics.permutations import AppliedPermutation + p = Permutation([0, 1, 2, 3]) + assert _test_args(AppliedPermutation(p, x)) + +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]]), + Permutation([[0, 1, 2, 3]])] + corners = [w, x, y, z] + faces = [(w, x, y), (w, y, z), (w, z, x), (x, y, z)] + assert _test_args(Polyhedron(corners, faces, pgroup)) + + +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])) + + +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))) + + +@SKIP("abstract Class") +def test_sympy__concrete__expr_with_limits__ExprWithLimits(): + from sympy.concrete.expr_with_limits import ExprWithLimits + assert _test_args(ExprWithLimits(x, (x, 0, 10))) + assert _test_args(ExprWithLimits(x*y, (x, 0, 10.),(y,1.,3))) + + +@SKIP("abstract Class") +def test_sympy__concrete__expr_with_limits__AddWithLimits(): + from sympy.concrete.expr_with_limits import AddWithLimits + assert _test_args(AddWithLimits(x, (x, 0, 10))) + assert _test_args(AddWithLimits(x*y, (x, 0, 10),(y,1,3))) + + +@SKIP("abstract Class") +def test_sympy__concrete__expr_with_intlimits__ExprWithIntLimits(): + from sympy.concrete.expr_with_intlimits import ExprWithIntLimits + assert _test_args(ExprWithIntLimits(x, (x, 0, 10))) + assert _test_args(ExprWithIntLimits(x*y, (x, 0, 10),(y,1,3))) + + +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__expr__UnevaluatedExpr(): + from sympy.core.expr import UnevaluatedExpr + from sympy.abc import x + assert _test_args(UnevaluatedExpr(x)) + + +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__DefinedFunction(): + from sympy.core.function import DefinedFunction + assert _test_args(DefinedFunction(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(): + 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__TribonacciConstant(): + from sympy.core.numbers import TribonacciConstant + assert _test_args(TribonacciConstant()) + + +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)) + + +@SKIP("abstract class") +def test_sympy__core__numbers__RationalConstant(): + pass + + +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__sandbox__indexed_integrals__IndexedIntegral(): + from sympy.tensor import IndexedBase, Idx + from sympy.sandbox.indexed_integrals import IndexedIntegral + A = IndexedBase('A') + i, j = symbols('i j', integer=True) + a1, a2 = symbols('a1:3', cls=Idx) + assert _test_args(IndexedIntegral(A[a1], A[a2])) + assert _test_args(IndexedIntegral(A[i], A[j])) + + +def test_sympy__calculus__accumulationbounds__AccumulationBounds(): + from sympy.calculus.accumulationbounds import AccumulationBounds + assert _test_args(AccumulationBounds(0, 1)) + + +def test_sympy__sets__ordinals__OmegaPower(): + from sympy.sets.ordinals import OmegaPower + assert _test_args(OmegaPower(1, 1)) + +def test_sympy__sets__ordinals__Ordinal(): + from sympy.sets.ordinals import Ordinal, OmegaPower + assert _test_args(Ordinal(OmegaPower(2, 1))) + +def test_sympy__sets__ordinals__OrdinalOmega(): + from sympy.sets.ordinals import OrdinalOmega + assert _test_args(OrdinalOmega()) + +def test_sympy__sets__ordinals__OrdinalZero(): + from sympy.sets.ordinals import OrdinalZero + assert _test_args(OrdinalZero()) + + +def test_sympy__sets__powerset__PowerSet(): + from sympy.sets.powerset import PowerSet + from sympy.core.singleton import S + assert _test_args(PowerSet(S.EmptySet)) + + +def test_sympy__sets__sets__EmptySet(): + from sympy.sets.sets import EmptySet + assert _test_args(EmptySet()) + + +def test_sympy__sets__sets__UniversalSet(): + from sympy.sets.sets import UniversalSet + assert _test_args(UniversalSet()) + + +def test_sympy__sets__sets__FiniteSet(): + from sympy.sets.sets import FiniteSet + assert _test_args(FiniteSet(x, y, z)) + + +def test_sympy__sets__sets__Interval(): + from sympy.sets.sets import Interval + assert _test_args(Interval(0, 1)) + + +def test_sympy__sets__sets__ProductSet(): + from sympy.sets.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__sets__sets__Set(): + from sympy.sets.sets import Set + assert _test_args(Set()) + + +def test_sympy__sets__sets__Intersection(): + from sympy.sets.sets import Intersection, Interval + from sympy.core.symbol import Symbol + x = Symbol('x') + y = Symbol('y') + S = Intersection(Interval(0, x), Interval(y, 1)) + assert isinstance(S, Intersection) + assert _test_args(S) + + +def test_sympy__sets__sets__Union(): + from sympy.sets.sets import Union, Interval + assert _test_args(Union(Interval(0, 1), Interval(2, 3))) + + +def test_sympy__sets__sets__Complement(): + from sympy.sets.sets import Complement, Interval + assert _test_args(Complement(Interval(0, 2), Interval(0, 1))) + + +def test_sympy__sets__sets__SymmetricDifference(): + from sympy.sets.sets import FiniteSet, SymmetricDifference + assert _test_args(SymmetricDifference(FiniteSet(1, 2, 3), \ + FiniteSet(2, 3, 4))) + +def test_sympy__sets__sets__DisjointUnion(): + from sympy.sets.sets import FiniteSet, DisjointUnion + assert _test_args(DisjointUnion(FiniteSet(1, 2, 3), \ + FiniteSet(2, 3, 4))) + + +def test_sympy__physics__quantum__trace__Tr(): + from sympy.physics.quantum.trace import Tr + a, b = symbols('a b', commutative=False) + assert _test_args(Tr(a + b)) + + +def test_sympy__sets__setexpr__SetExpr(): + from sympy.sets.setexpr import SetExpr + from sympy.sets.sets import Interval + assert _test_args(SetExpr(Interval(0, 1))) + + +def test_sympy__sets__fancysets__Rationals(): + from sympy.sets.fancysets import Rationals + assert _test_args(Rationals()) + + +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()) + + +def test_sympy__sets__fancysets__Reals(): + from sympy.sets.fancysets import Reals + assert _test_args(Reals()) + + +def test_sympy__sets__fancysets__Complexes(): + from sympy.sets.fancysets import Complexes + assert _test_args(Complexes()) + + +def test_sympy__sets__fancysets__ComplexRegion(): + from sympy.sets.fancysets import ComplexRegion + from sympy.core.singleton import S + from sympy.sets import Interval + a = Interval(0, 1) + b = Interval(2, 3) + theta = Interval(0, 2*S.Pi) + assert _test_args(ComplexRegion(a*b)) + assert _test_args(ComplexRegion(a*theta, polar=True)) + + +def test_sympy__sets__fancysets__CartesianComplexRegion(): + from sympy.sets.fancysets import CartesianComplexRegion + from sympy.sets import Interval + a = Interval(0, 1) + b = Interval(2, 3) + assert _test_args(CartesianComplexRegion(a*b)) + + +def test_sympy__sets__fancysets__PolarComplexRegion(): + from sympy.sets.fancysets import PolarComplexRegion + from sympy.core.singleton import S + from sympy.sets import Interval + a = Interval(0, 1) + theta = Interval(0, 2*S.Pi) + assert _test_args(PolarComplexRegion(a*theta)) + + +def test_sympy__sets__fancysets__ImageSet(): + from sympy.sets.fancysets import ImageSet + from sympy.core.singleton import S + from sympy.core.symbol import Symbol + x = Symbol('x') + assert _test_args(ImageSet(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)) + + +def test_sympy__sets__conditionset__ConditionSet(): + from sympy.sets.conditionset import ConditionSet + from sympy.core.singleton import S + from sympy.core.symbol import Symbol + x = Symbol('x') + assert _test_args(ConditionSet(x, Eq(x**2, 1), S.Reals)) + + +def test_sympy__sets__contains__Contains(): + from sympy.sets.fancysets import Range + from sympy.sets.contains import Contains + assert _test_args(Contains(x, Range(0, 10, 2))) + + +# STATS + + +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.sets.sets import Interval + from sympy.stats.crv import ContinuousDomain + assert _test_args(ContinuousDomain({x}, Interval(-oo, oo))) + + +def test_sympy__stats__crv__SingleContinuousDomain(): + from sympy.sets.sets import Interval + from sympy.stats.crv import SingleContinuousDomain + assert _test_args(SingleContinuousDomain(x, Interval(-oo, oo))) + + +def test_sympy__stats__crv__ProductContinuousDomain(): + from sympy.sets.sets import Interval + from sympy.stats.crv import SingleContinuousDomain, ProductContinuousDomain + 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.sets.sets import Interval + from sympy.stats.crv import (SingleContinuousDomain, + ConditionalContinuousDomain) + D = SingleContinuousDomain(x, Interval(-oo, oo)) + assert _test_args(ConditionalContinuousDomain(D, x > 0)) + + +def test_sympy__stats__crv__ContinuousPSpace(): + from sympy.sets.sets import Interval + from sympy.stats.crv import ContinuousPSpace, SingleContinuousDomain + D = SingleContinuousDomain(x, Interval(-oo, oo)) + assert _test_args(ContinuousPSpace(D, nd)) + + +def test_sympy__stats__crv__SingleContinuousPSpace(): + from sympy.stats.crv import SingleContinuousPSpace + assert _test_args(SingleContinuousPSpace(x, nd)) + +@SKIP("abstract class") +def test_sympy__stats__rv__Distribution(): + pass + +@SKIP("abstract class") +def test_sympy__stats__crv__SingleContinuousDistribution(): + pass + + +def test_sympy__stats__drv__SingleDiscreteDomain(): + from sympy.stats.drv import SingleDiscreteDomain + assert _test_args(SingleDiscreteDomain(x, S.Naturals)) + + +def test_sympy__stats__drv__ProductDiscreteDomain(): + from sympy.stats.drv import SingleDiscreteDomain, ProductDiscreteDomain + X = SingleDiscreteDomain(x, S.Naturals) + Y = SingleDiscreteDomain(y, S.Integers) + assert _test_args(ProductDiscreteDomain(X, Y)) + + +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))) + +def test_sympy__stats__drv__DiscretePSpace(): + from sympy.stats.drv import DiscretePSpace, SingleDiscreteDomain + density = Lambda(x, 2**(-x)) + domain = SingleDiscreteDomain(x, S.Naturals) + assert _test_args(DiscretePSpace(domain, density)) + +def test_sympy__stats__drv__ConditionalDiscreteDomain(): + from sympy.stats.drv import ConditionalDiscreteDomain, SingleDiscreteDomain + X = SingleDiscreteDomain(x, S.Naturals0) + assert _test_args(ConditionalDiscreteDomain(X, x > 2)) + +def test_sympy__stats__joint_rv__JointPSpace(): + from sympy.stats.joint_rv import JointPSpace, JointDistribution + assert _test_args(JointPSpace('X', JointDistribution(1))) + +def test_sympy__stats__joint_rv__JointRandomSymbol(): + from sympy.stats.joint_rv import JointRandomSymbol + assert _test_args(JointRandomSymbol(x)) + +def test_sympy__stats__joint_rv_types__JointDistributionHandmade(): + from sympy.tensor.indexed import Indexed + from sympy.stats.joint_rv_types import JointDistributionHandmade + x1, x2 = (Indexed('x', i) for i in (1, 2)) + assert _test_args(JointDistributionHandmade(x1 + x2, S.Reals**2)) + + +def test_sympy__stats__joint_rv__MarginalDistribution(): + from sympy.stats.rv import RandomSymbol + from sympy.stats.joint_rv import MarginalDistribution + r = RandomSymbol(S('r')) + assert _test_args(MarginalDistribution(r, (r,))) + + +def test_sympy__stats__compound_rv__CompoundDistribution(): + from sympy.stats.compound_rv import CompoundDistribution + from sympy.stats.drv_types import PoissonDistribution, Poisson + r = Poisson('r', 10) + assert _test_args(CompoundDistribution(PoissonDistribution(r))) + + +def test_sympy__stats__compound_rv__CompoundPSpace(): + from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution + from sympy.stats.drv_types import PoissonDistribution, Poisson + r = Poisson('r', 5) + C = CompoundDistribution(PoissonDistribution(r)) + assert _test_args(CompoundPSpace('C', C)) + + +@SKIP("abstract class") +def test_sympy__stats__drv__SingleDiscreteDistribution(): + pass + +@SKIP("abstract class") +def test_sympy__stats__drv__DiscreteDistribution(): + pass + +@SKIP("abstract class") +def test_sympy__stats__drv__DiscreteDomain(): + pass + + +def test_sympy__stats__rv__RandomDomain(): + from sympy.stats.rv import RandomDomain + from sympy.sets.sets import FiniteSet + assert _test_args(RandomDomain(FiniteSet(x), FiniteSet(1, 2, 3))) + + +def test_sympy__stats__rv__SingleDomain(): + from sympy.stats.rv import SingleDomain + from sympy.sets.sets import FiniteSet + assert _test_args(SingleDomain(x, FiniteSet(1, 2, 3))) + + +def test_sympy__stats__rv__ConditionalDomain(): + from sympy.stats.rv import ConditionalDomain, RandomDomain + from sympy.sets.sets import FiniteSet + D = RandomDomain(FiniteSet(x), FiniteSet(1, 2)) + assert _test_args(ConditionalDomain(D, x > 1)) + +def test_sympy__stats__rv__MatrixDomain(): + from sympy.stats.rv import MatrixDomain + from sympy.matrices import MatrixSet + from sympy.core.singleton import S + assert _test_args(MatrixDomain(x, MatrixSet(2, 2, S.Reals))) + +def test_sympy__stats__rv__PSpace(): + from sympy.stats.rv import PSpace, RandomDomain + from sympy.sets.sets import FiniteSet + 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(): + pass + + +def test_sympy__stats__rv__RandomSymbol(): + from sympy.stats.rv import RandomSymbol + from sympy.stats.crv import SingleContinuousPSpace + A = SingleContinuousPSpace(x, nd) + assert _test_args(RandomSymbol(x, A)) + + +@SKIP("abstract Class") +def test_sympy__stats__rv__ProductPSpace(): + pass + + +def test_sympy__stats__rv__IndependentProductPSpace(): + from sympy.stats.rv import IndependentProductPSpace + from sympy.stats.crv import SingleContinuousPSpace + A = SingleContinuousPSpace(x, nd) + B = SingleContinuousPSpace(y, nd) + assert _test_args(IndependentProductPSpace(A, B)) + + +def test_sympy__stats__rv__ProductDomain(): + from sympy.sets.sets import Interval + from sympy.stats.rv import ProductDomain, SingleDomain + D = SingleDomain(x, Interval(-oo, oo)) + E = SingleDomain(y, Interval(0, oo)) + assert _test_args(ProductDomain(D, E)) + + +def test_sympy__stats__symbolic_probability__Probability(): + from sympy.stats.symbolic_probability import Probability + from sympy.stats import Normal + X = Normal('X', 0, 1) + assert _test_args(Probability(X > 0)) + + +def test_sympy__stats__symbolic_probability__Expectation(): + from sympy.stats.symbolic_probability import Expectation + from sympy.stats import Normal + X = Normal('X', 0, 1) + assert _test_args(Expectation(X > 0)) + + +def test_sympy__stats__symbolic_probability__Covariance(): + from sympy.stats.symbolic_probability import Covariance + from sympy.stats import Normal + X = Normal('X', 0, 1) + Y = Normal('Y', 0, 3) + assert _test_args(Covariance(X, Y)) + + +def test_sympy__stats__symbolic_probability__Variance(): + from sympy.stats.symbolic_probability import Variance + from sympy.stats import Normal + X = Normal('X', 0, 1) + assert _test_args(Variance(X)) + + +def test_sympy__stats__symbolic_probability__Moment(): + from sympy.stats.symbolic_probability import Moment + from sympy.stats import Normal + X = Normal('X', 0, 1) + assert _test_args(Moment(X, 3, 2, X > 3)) + + +def test_sympy__stats__symbolic_probability__CentralMoment(): + from sympy.stats.symbolic_probability import CentralMoment + from sympy.stats import Normal + X = Normal('X', 0, 1) + assert _test_args(CentralMoment(X, 2, X > 1)) + + +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(): + assert _test_args(die) + + +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__BetaBinomialDistribution(): + from sympy.stats.frv_types import BetaBinomialDistribution + assert _test_args(BetaBinomialDistribution(5, 1, 1)) + + +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_types__RademacherDistribution(): + from sympy.stats.frv_types import RademacherDistribution + assert _test_args(RademacherDistribution()) + +def test_sympy__stats__frv_types__IdealSolitonDistribution(): + from sympy.stats.frv_types import IdealSolitonDistribution + assert _test_args(IdealSolitonDistribution(10)) + +def test_sympy__stats__frv_types__RobustSolitonDistribution(): + from sympy.stats.frv_types import RobustSolitonDistribution + assert _test_args(RobustSolitonDistribution(1000, 0.5, 0.1)) + +def test_sympy__stats__frv__FiniteDomain(): + from sympy.stats.frv import FiniteDomain + assert _test_args(FiniteDomain({(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, {1, 2})) # x can be 1 or 2 + + +def test_sympy__stats__frv__ProductFiniteDomain(): + from sympy.stats.frv import SingleFiniteDomain, ProductFiniteDomain + xd = SingleFiniteDomain(x, {1, 2}) + yd = SingleFiniteDomain(y, {1, 2}) + assert _test_args(ProductFiniteDomain(xd, yd)) + + +def test_sympy__stats__frv__ConditionalFiniteDomain(): + from sympy.stats.frv import SingleFiniteDomain, ConditionalFiniteDomain + xd = SingleFiniteDomain(x, {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, {1, 2, 3, 4, 5, 6}) + assert _test_args(FinitePSpace(xd, {(x, 1): S.Half, (x, 2): S.Half})) + + xd = SingleFiniteDomain(x, {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 + from sympy.core.symbol import Symbol + + assert _test_args(SingleFinitePSpace(Symbol('x'), die)) + + +def test_sympy__stats__frv__ProductFinitePSpace(): + from sympy.stats.frv import SingleFinitePSpace, ProductFinitePSpace + from sympy.core.symbol import Symbol + xp = SingleFinitePSpace(Symbol('x'), die) + yp = SingleFinitePSpace(Symbol('y'), die) + assert _test_args(ProductFinitePSpace(xp, yp)) + +@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 + from sympy.core.containers import Dict + assert _test_args(FiniteDistributionHandmade(Dict({1: 1}))) + + +def test_sympy__stats__crv_types__ContinuousDistributionHandmade(): + from sympy.stats.crv_types import ContinuousDistributionHandmade + from sympy.core.function import Lambda + from sympy.sets.sets import Interval + from sympy.abc import x + assert _test_args(ContinuousDistributionHandmade(Lambda(x, 2*x), + Interval(0, 1))) + + +def test_sympy__stats__drv_types__DiscreteDistributionHandmade(): + from sympy.stats.drv_types import DiscreteDistributionHandmade + from sympy.core.function import Lambda + from sympy.sets.sets import FiniteSet + from sympy.abc import x + assert _test_args(DiscreteDistributionHandmade(Lambda(x, Rational(1, 10)), + FiniteSet(*range(10)))) + + +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__BetaNoncentralDistribution(): + from sympy.stats.crv_types import BetaNoncentralDistribution + assert _test_args(BetaNoncentralDistribution(1, 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__BoundedParetoDistribution(): + from sympy.stats.crv_types import BoundedParetoDistribution + assert _test_args(BoundedParetoDistribution(1, 1, 2)) + +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__DavisDistribution(): + from sympy.stats.crv_types import DavisDistribution + assert _test_args(DavisDistribution(1, 1, 1)) + + +def test_sympy__stats__crv_types__ExGaussianDistribution(): + from sympy.stats.crv_types import ExGaussianDistribution + assert _test_args(ExGaussianDistribution(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__ExponentialPowerDistribution(): + from sympy.stats.crv_types import ExponentialPowerDistribution + assert _test_args(ExponentialPowerDistribution(0, 1, 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__GumbelDistribution(): + from sympy.stats.crv_types import GumbelDistribution + assert _test_args(GumbelDistribution(1, 1, False)) + +def test_sympy__stats__crv_types__GompertzDistribution(): + from sympy.stats.crv_types import GompertzDistribution + assert _test_args(GompertzDistribution(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__LevyDistribution(): + from sympy.stats.crv_types import LevyDistribution + assert _test_args(LevyDistribution(0, 1)) + +def test_sympy__stats__crv_types__LogCauchyDistribution(): + from sympy.stats.crv_types import LogCauchyDistribution + assert _test_args(LogCauchyDistribution(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__LogLogisticDistribution(): + from sympy.stats.crv_types import LogLogisticDistribution + assert _test_args(LogLogisticDistribution(1, 1)) + +def test_sympy__stats__crv_types__LogitNormalDistribution(): + from sympy.stats.crv_types import LogitNormalDistribution + assert _test_args(LogitNormalDistribution(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__LomaxDistribution(): + from sympy.stats.crv_types import LomaxDistribution + assert _test_args(LomaxDistribution(1, 2)) + +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__MoyalDistribution(): + from sympy.stats.crv_types import MoyalDistribution + assert _test_args(MoyalDistribution(1,2)) + +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__GaussianInverseDistribution(): + from sympy.stats.crv_types import GaussianInverseDistribution + assert _test_args(GaussianInverseDistribution(1, 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__PowerFunctionDistribution(): + from sympy.stats.crv_types import PowerFunctionDistribution + assert _test_args(PowerFunctionDistribution(2,0,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__ReciprocalDistribution(): + from sympy.stats.crv_types import ReciprocalDistribution + assert _test_args(ReciprocalDistribution(5, 30)) + +def test_sympy__stats__crv_types__ShiftedGompertzDistribution(): + from sympy.stats.crv_types import ShiftedGompertzDistribution + assert _test_args(ShiftedGompertzDistribution(1, 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__TrapezoidalDistribution(): + from sympy.stats.crv_types import TrapezoidalDistribution + assert _test_args(TrapezoidalDistribution(1, 2, 3, 4)) + +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__GeometricDistribution(): + from sympy.stats.drv_types import GeometricDistribution + assert _test_args(GeometricDistribution(.5)) + +def test_sympy__stats__drv_types__HermiteDistribution(): + from sympy.stats.drv_types import HermiteDistribution + assert _test_args(HermiteDistribution(1, 2)) + +def test_sympy__stats__drv_types__LogarithmicDistribution(): + from sympy.stats.drv_types import LogarithmicDistribution + assert _test_args(LogarithmicDistribution(.5)) + + +def test_sympy__stats__drv_types__NegativeBinomialDistribution(): + from sympy.stats.drv_types import NegativeBinomialDistribution + assert _test_args(NegativeBinomialDistribution(.5, .5)) + +def test_sympy__stats__drv_types__FlorySchulzDistribution(): + from sympy.stats.drv_types import FlorySchulzDistribution + assert _test_args(FlorySchulzDistribution(.5)) + +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__SkellamDistribution(): + from sympy.stats.drv_types import SkellamDistribution + assert _test_args(SkellamDistribution(1, 1)) + + +def test_sympy__stats__drv_types__YuleSimonDistribution(): + from sympy.stats.drv_types import YuleSimonDistribution + assert _test_args(YuleSimonDistribution(.5)) + + +def test_sympy__stats__drv_types__ZetaDistribution(): + from sympy.stats.drv_types import ZetaDistribution + assert _test_args(ZetaDistribution(1.5)) + + +def test_sympy__stats__joint_rv__JointDistribution(): + from sympy.stats.joint_rv import JointDistribution + assert _test_args(JointDistribution(1, 2, 3, 4)) + + +def test_sympy__stats__joint_rv_types__MultivariateNormalDistribution(): + from sympy.stats.joint_rv_types import MultivariateNormalDistribution + assert _test_args( + MultivariateNormalDistribution([0, 1], [[1, 0],[0, 1]])) + +def test_sympy__stats__joint_rv_types__MultivariateLaplaceDistribution(): + from sympy.stats.joint_rv_types import MultivariateLaplaceDistribution + assert _test_args(MultivariateLaplaceDistribution([0, 1], [[1, 0],[0, 1]])) + + +def test_sympy__stats__joint_rv_types__MultivariateTDistribution(): + from sympy.stats.joint_rv_types import MultivariateTDistribution + assert _test_args(MultivariateTDistribution([0, 1], [[1, 0],[0, 1]], 1)) + + +def test_sympy__stats__joint_rv_types__NormalGammaDistribution(): + from sympy.stats.joint_rv_types import NormalGammaDistribution + assert _test_args(NormalGammaDistribution(1, 2, 3, 4)) + +def test_sympy__stats__joint_rv_types__GeneralizedMultivariateLogGammaDistribution(): + from sympy.stats.joint_rv_types import GeneralizedMultivariateLogGammaDistribution + v, l, mu = (4, [1, 2, 3, 4], [1, 2, 3, 4]) + assert _test_args(GeneralizedMultivariateLogGammaDistribution(S.Half, v, l, mu)) + +def test_sympy__stats__joint_rv_types__MultivariateBetaDistribution(): + from sympy.stats.joint_rv_types import MultivariateBetaDistribution + assert _test_args(MultivariateBetaDistribution([1, 2, 3])) + +def test_sympy__stats__joint_rv_types__MultivariateEwensDistribution(): + from sympy.stats.joint_rv_types import MultivariateEwensDistribution + assert _test_args(MultivariateEwensDistribution(5, 1)) + +def test_sympy__stats__joint_rv_types__MultinomialDistribution(): + from sympy.stats.joint_rv_types import MultinomialDistribution + assert _test_args(MultinomialDistribution(5, [0.5, 0.1, 0.3])) + +def test_sympy__stats__joint_rv_types__NegativeMultinomialDistribution(): + from sympy.stats.joint_rv_types import NegativeMultinomialDistribution + assert _test_args(NegativeMultinomialDistribution(5, [0.5, 0.1, 0.3])) + +def test_sympy__stats__rv__RandomIndexedSymbol(): + from sympy.stats.rv import RandomIndexedSymbol, pspace + from sympy.stats.stochastic_process_types import DiscreteMarkovChain + X = DiscreteMarkovChain("X") + assert _test_args(RandomIndexedSymbol(X[0].symbol, pspace(X[0]))) + +def test_sympy__stats__rv__RandomMatrixSymbol(): + from sympy.stats.rv import RandomMatrixSymbol + from sympy.stats.random_matrix import RandomMatrixPSpace + pspace = RandomMatrixPSpace('P') + assert _test_args(RandomMatrixSymbol('M', 3, 3, pspace)) + +def test_sympy__stats__stochastic_process__StochasticPSpace(): + from sympy.stats.stochastic_process import StochasticPSpace + from sympy.stats.stochastic_process_types import StochasticProcess + from sympy.stats.frv_types import BernoulliDistribution + assert _test_args(StochasticPSpace("Y", StochasticProcess("Y", [1, 2, 3]), BernoulliDistribution(S.Half, 1, 0))) + +def test_sympy__stats__stochastic_process_types__StochasticProcess(): + from sympy.stats.stochastic_process_types import StochasticProcess + assert _test_args(StochasticProcess("Y", [1, 2, 3])) + +def test_sympy__stats__stochastic_process_types__MarkovProcess(): + from sympy.stats.stochastic_process_types import MarkovProcess + assert _test_args(MarkovProcess("Y", [1, 2, 3])) + +def test_sympy__stats__stochastic_process_types__DiscreteTimeStochasticProcess(): + from sympy.stats.stochastic_process_types import DiscreteTimeStochasticProcess + assert _test_args(DiscreteTimeStochasticProcess("Y", [1, 2, 3])) + +def test_sympy__stats__stochastic_process_types__ContinuousTimeStochasticProcess(): + from sympy.stats.stochastic_process_types import ContinuousTimeStochasticProcess + assert _test_args(ContinuousTimeStochasticProcess("Y", [1, 2, 3])) + +def test_sympy__stats__stochastic_process_types__TransitionMatrixOf(): + from sympy.stats.stochastic_process_types import TransitionMatrixOf, DiscreteMarkovChain + from sympy.matrices.expressions.matexpr import MatrixSymbol + DMC = DiscreteMarkovChain("Y") + assert _test_args(TransitionMatrixOf(DMC, MatrixSymbol('T', 3, 3))) + +def test_sympy__stats__stochastic_process_types__GeneratorMatrixOf(): + from sympy.stats.stochastic_process_types import GeneratorMatrixOf, ContinuousMarkovChain + from sympy.matrices.expressions.matexpr import MatrixSymbol + DMC = ContinuousMarkovChain("Y") + assert _test_args(GeneratorMatrixOf(DMC, MatrixSymbol('T', 3, 3))) + +def test_sympy__stats__stochastic_process_types__StochasticStateSpaceOf(): + from sympy.stats.stochastic_process_types import StochasticStateSpaceOf, DiscreteMarkovChain + DMC = DiscreteMarkovChain("Y") + assert _test_args(StochasticStateSpaceOf(DMC, [0, 1, 2])) + +def test_sympy__stats__stochastic_process_types__DiscreteMarkovChain(): + from sympy.stats.stochastic_process_types import DiscreteMarkovChain + from sympy.matrices.expressions.matexpr import MatrixSymbol + assert _test_args(DiscreteMarkovChain("Y", [0, 1, 2], MatrixSymbol('T', 3, 3))) + +def test_sympy__stats__stochastic_process_types__ContinuousMarkovChain(): + from sympy.stats.stochastic_process_types import ContinuousMarkovChain + from sympy.matrices.expressions.matexpr import MatrixSymbol + assert _test_args(ContinuousMarkovChain("Y", [0, 1, 2], MatrixSymbol('T', 3, 3))) + +def test_sympy__stats__stochastic_process_types__BernoulliProcess(): + from sympy.stats.stochastic_process_types import BernoulliProcess + assert _test_args(BernoulliProcess("B", 0.5, 1, 0)) + +def test_sympy__stats__stochastic_process_types__CountingProcess(): + from sympy.stats.stochastic_process_types import CountingProcess + assert _test_args(CountingProcess("C")) + +def test_sympy__stats__stochastic_process_types__PoissonProcess(): + from sympy.stats.stochastic_process_types import PoissonProcess + assert _test_args(PoissonProcess("X", 2)) + +def test_sympy__stats__stochastic_process_types__WienerProcess(): + from sympy.stats.stochastic_process_types import WienerProcess + assert _test_args(WienerProcess("X")) + +def test_sympy__stats__stochastic_process_types__GammaProcess(): + from sympy.stats.stochastic_process_types import GammaProcess + assert _test_args(GammaProcess("X", 1, 2)) + +def test_sympy__stats__random_matrix__RandomMatrixPSpace(): + from sympy.stats.random_matrix import RandomMatrixPSpace + from sympy.stats.random_matrix_models import RandomMatrixEnsembleModel + model = RandomMatrixEnsembleModel('R', 3) + assert _test_args(RandomMatrixPSpace('P', model=model)) + +def test_sympy__stats__random_matrix_models__RandomMatrixEnsembleModel(): + from sympy.stats.random_matrix_models import RandomMatrixEnsembleModel + assert _test_args(RandomMatrixEnsembleModel('R', 3)) + +def test_sympy__stats__random_matrix_models__GaussianEnsembleModel(): + from sympy.stats.random_matrix_models import GaussianEnsembleModel + assert _test_args(GaussianEnsembleModel('G', 3)) + +def test_sympy__stats__random_matrix_models__GaussianUnitaryEnsembleModel(): + from sympy.stats.random_matrix_models import GaussianUnitaryEnsembleModel + assert _test_args(GaussianUnitaryEnsembleModel('U', 3)) + +def test_sympy__stats__random_matrix_models__GaussianOrthogonalEnsembleModel(): + from sympy.stats.random_matrix_models import GaussianOrthogonalEnsembleModel + assert _test_args(GaussianOrthogonalEnsembleModel('U', 3)) + +def test_sympy__stats__random_matrix_models__GaussianSymplecticEnsembleModel(): + from sympy.stats.random_matrix_models import GaussianSymplecticEnsembleModel + assert _test_args(GaussianSymplecticEnsembleModel('U', 3)) + +def test_sympy__stats__random_matrix_models__CircularEnsembleModel(): + from sympy.stats.random_matrix_models import CircularEnsembleModel + assert _test_args(CircularEnsembleModel('C', 3)) + +def test_sympy__stats__random_matrix_models__CircularUnitaryEnsembleModel(): + from sympy.stats.random_matrix_models import CircularUnitaryEnsembleModel + assert _test_args(CircularUnitaryEnsembleModel('U', 3)) + +def test_sympy__stats__random_matrix_models__CircularOrthogonalEnsembleModel(): + from sympy.stats.random_matrix_models import CircularOrthogonalEnsembleModel + assert _test_args(CircularOrthogonalEnsembleModel('O', 3)) + +def test_sympy__stats__random_matrix_models__CircularSymplecticEnsembleModel(): + from sympy.stats.random_matrix_models import CircularSymplecticEnsembleModel + assert _test_args(CircularSymplecticEnsembleModel('S', 3)) + +def test_sympy__stats__symbolic_multivariate_probability__ExpectationMatrix(): + from sympy.stats import ExpectationMatrix + from sympy.stats.rv import RandomMatrixSymbol + assert _test_args(ExpectationMatrix(RandomMatrixSymbol('R', 2, 1))) + +def test_sympy__stats__symbolic_multivariate_probability__VarianceMatrix(): + from sympy.stats import VarianceMatrix + from sympy.stats.rv import RandomMatrixSymbol + assert _test_args(VarianceMatrix(RandomMatrixSymbol('R', 3, 1))) + +def test_sympy__stats__symbolic_multivariate_probability__CrossCovarianceMatrix(): + from sympy.stats import CrossCovarianceMatrix + from sympy.stats.rv import RandomMatrixSymbol + assert _test_args(CrossCovarianceMatrix(RandomMatrixSymbol('R', 3, 1), + RandomMatrixSymbol('X', 3, 1))) + +def test_sympy__stats__matrix_distributions__MatrixPSpace(): + from sympy.stats.matrix_distributions import MatrixDistribution, MatrixPSpace + from sympy.matrices.dense import Matrix + M = MatrixDistribution(1, Matrix([[1, 0], [0, 1]])) + assert _test_args(MatrixPSpace('M', M, 2, 2)) + +def test_sympy__stats__matrix_distributions__MatrixDistribution(): + from sympy.stats.matrix_distributions import MatrixDistribution + from sympy.matrices.dense import Matrix + assert _test_args(MatrixDistribution(1, Matrix([[1, 0], [0, 1]]))) + +def test_sympy__stats__matrix_distributions__MatrixGammaDistribution(): + from sympy.stats.matrix_distributions import MatrixGammaDistribution + from sympy.matrices.dense import Matrix + assert _test_args(MatrixGammaDistribution(3, 4, Matrix([[1, 0], [0, 1]]))) + +def test_sympy__stats__matrix_distributions__WishartDistribution(): + from sympy.stats.matrix_distributions import WishartDistribution + from sympy.matrices.dense import Matrix + assert _test_args(WishartDistribution(3, Matrix([[1, 0], [0, 1]]))) + +def test_sympy__stats__matrix_distributions__MatrixNormalDistribution(): + from sympy.stats.matrix_distributions import MatrixNormalDistribution + from sympy.matrices.expressions.matexpr import MatrixSymbol + L = MatrixSymbol('L', 1, 2) + S1 = MatrixSymbol('S1', 1, 1) + S2 = MatrixSymbol('S2', 2, 2) + assert _test_args(MatrixNormalDistribution(L, S1, S2)) + +def test_sympy__stats__matrix_distributions__MatrixStudentTDistribution(): + from sympy.stats.matrix_distributions import MatrixStudentTDistribution + from sympy.matrices.expressions.matexpr import MatrixSymbol + v = symbols('v', positive=True) + Omega = MatrixSymbol('Omega', 3, 3) + Sigma = MatrixSymbol('Sigma', 1, 1) + Location = MatrixSymbol('Location', 1, 3) + assert _test_args(MatrixStudentTDistribution(v, Location, Omega, Sigma)) + +def test_sympy__utilities__matchpy_connector__WildDot(): + from sympy.utilities.matchpy_connector import WildDot + assert _test_args(WildDot("w_")) + + +def test_sympy__utilities__matchpy_connector__WildPlus(): + from sympy.utilities.matchpy_connector import WildPlus + assert _test_args(WildPlus("w__")) + + +def test_sympy__utilities__matchpy_connector__WildStar(): + from sympy.utilities.matchpy_connector import WildStar + assert _test_args(WildStar("w___")) + + +def test_sympy__core__symbol__Str(): + from sympy.core.symbol import Str + assert _test_args(Str('t')) + +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(x)) + + +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__genocchi(): + from sympy.functions.combinatorial.numbers import genocchi + assert _test_args(genocchi(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__andre(): + from sympy.functions.combinatorial.numbers import andre + assert _test_args(andre(x)) + + +def test_sympy__functions__combinatorial__numbers__carmichael(): + from sympy.functions.combinatorial.numbers import carmichael + assert _test_args(carmichael(x)) + + +def test_sympy__functions__combinatorial__numbers__divisor_sigma(): + from sympy.functions.combinatorial.numbers import divisor_sigma + k = symbols('k', integer=True) + n = symbols('n', integer=True) + t = divisor_sigma(n, k) + assert _test_args(t) + + +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__jacobi_symbol(): + from sympy.functions.combinatorial.numbers import jacobi_symbol + assert _test_args(jacobi_symbol(2, 3)) + + +def test_sympy__functions__combinatorial__numbers__kronecker_symbol(): + from sympy.functions.combinatorial.numbers import kronecker_symbol + assert _test_args(kronecker_symbol(2, 3)) + + +def test_sympy__functions__combinatorial__numbers__legendre_symbol(): + from sympy.functions.combinatorial.numbers import legendre_symbol + assert _test_args(legendre_symbol(2, 3)) + + +def test_sympy__functions__combinatorial__numbers__mobius(): + from sympy.functions.combinatorial.numbers import mobius + assert _test_args(mobius(2)) + + +def test_sympy__functions__combinatorial__numbers__motzkin(): + from sympy.functions.combinatorial.numbers import motzkin + assert _test_args(motzkin(5)) + + +def test_sympy__functions__combinatorial__numbers__partition(): + from sympy.core.symbol import Symbol + from sympy.functions.combinatorial.numbers import partition + assert _test_args(partition(Symbol('a', integer=True))) + + +def test_sympy__functions__combinatorial__numbers__primenu(): + from sympy.functions.combinatorial.numbers import primenu + n = symbols('n', integer=True) + t = primenu(n) + assert _test_args(t) + + +def test_sympy__functions__combinatorial__numbers__primeomega(): + from sympy.functions.combinatorial.numbers import primeomega + n = symbols('n', integer=True) + t = primeomega(n) + assert _test_args(t) + + +def test_sympy__functions__combinatorial__numbers__primepi(): + from sympy.functions.combinatorial.numbers import primepi + n = symbols('n') + t = primepi(n) + assert _test_args(t) + + +def test_sympy__functions__combinatorial__numbers__reduced_totient(): + from sympy.functions.combinatorial.numbers import reduced_totient + k = symbols('k', integer=True) + t = reduced_totient(k) + assert _test_args(t) + + +def test_sympy__functions__combinatorial__numbers__totient(): + from sympy.functions.combinatorial.numbers import totient + k = symbols('k', integer=True) + t = totient(k) + assert _test_args(t) + + +def test_sympy__functions__combinatorial__numbers__tribonacci(): + from sympy.functions.combinatorial.numbers import tribonacci + assert _test_args(tribonacci(x)) + + +def test_sympy__functions__combinatorial__numbers__udivisor_sigma(): + from sympy.functions.combinatorial.numbers import udivisor_sigma + k = symbols('k', integer=True) + n = symbols('n', integer=True) + t = udivisor_sigma(n, k) + assert _test_args(t) + + +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 + + +@SKIP("abstract class") +def test_sympy__functions__elementary__hyperbolic__ReciprocalHyperbolicFunction(): + pass + + +@SKIP("abstract class") +def test_sympy__functions__elementary__hyperbolic__InverseHyperbolicFunction(): + 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__asech(): + from sympy.functions.elementary.hyperbolic import asech + assert _test_args(asech(x)) + +def test_sympy__functions__elementary__hyperbolic__acsch(): + from sympy.functions.elementary.hyperbolic import acsch + assert _test_args(acsch(x)) + +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__csch(): + from sympy.functions.elementary.hyperbolic import csch + assert _test_args(csch(2)) + + +def test_sympy__functions__elementary__hyperbolic__sech(): + from sympy.functions.elementary.hyperbolic import sech + assert _test_args(sech(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("abstract class") +def test_sympy__functions__elementary__integers__RoundFunction(): + pass + + +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__integers__frac(): + from sympy.functions.elementary.integers import frac + assert _test_args(frac(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__miscellaneous__Rem(): + from sympy.functions.elementary.miscellaneous import Rem + assert _test_args(Rem(x, 2)) + + +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 + +@SKIP("abstract class") +def test_sympy__functions__elementary__trigonometric__ReciprocalTrigonometricFunction(): + pass + +@SKIP("abstract class") +def test_sympy__functions__elementary__trigonometric__InverseTrigonometricFunction(): + 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__asec(): + from sympy.functions.elementary.trigonometric import asec + assert _test_args(asec(x)) + + +def test_sympy__functions__elementary__trigonometric__acsc(): + from sympy.functions.elementary.trigonometric import acsc + assert _test_args(acsc(x)) + + +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__sinc(): + from sympy.functions.elementary.trigonometric import sinc + assert _test_args(sinc(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 + + +@SKIP("abstract class") +def test_sympy__functions__special__bessel__SphericalHankelBase(): + 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__bessel__hn1(): + from sympy.functions.special.bessel import hn1 + assert _test_args(hn1(0, x)) + + +def test_sympy__functions__special__bessel__hn2(): + from sympy.functions.special.bessel import hn2 + assert _test_args(hn2(0, x)) + + +def test_sympy__functions__special__bessel__AiryBase(): + pass + + +def test_sympy__functions__special__bessel__airyai(): + from sympy.functions.special.bessel import airyai + assert _test_args(airyai(2)) + + +def test_sympy__functions__special__bessel__airybi(): + from sympy.functions.special.bessel import airybi + assert _test_args(airybi(2)) + + +def test_sympy__functions__special__bessel__airyaiprime(): + from sympy.functions.special.bessel import airyaiprime + assert _test_args(airyaiprime(2)) + + +def test_sympy__functions__special__bessel__airybiprime(): + from sympy.functions.special.bessel import airybiprime + assert _test_args(airybiprime(2)) + + +def test_sympy__functions__special__bessel__marcumq(): + from sympy.functions.special.bessel import marcumq + assert _test_args(marcumq(x, y, z)) + + +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__singularity_functions__SingularityFunction(): + from sympy.functions.special.singularity_functions import SingularityFunction + assert _test_args(SingularityFunction(x, y, z)) + + +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(5)) + + +@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(x)) + + +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__digamma(): + from sympy.functions.special.gamma_functions import digamma + assert _test_args(digamma(x)) + +def test_sympy__functions__special__gamma_functions__trigamma(): + from sympy.functions.special.gamma_functions import trigamma + assert _test_args(trigamma(x)) + +def test_sympy__functions__special__gamma_functions__uppergamma(): + from sympy.functions.special.gamma_functions import uppergamma + assert _test_args(uppergamma(x, 2)) + +def test_sympy__functions__special__gamma_functions__multigamma(): + from sympy.functions.special.gamma_functions import multigamma + assert _test_args(multigamma(x, 1)) + + +def test_sympy__functions__special__beta_functions__beta(): + from sympy.functions.special.beta_functions import beta + assert _test_args(beta(x)) + assert _test_args(beta(x, x)) + +def test_sympy__functions__special__beta_functions__betainc(): + from sympy.functions.special.beta_functions import betainc + assert _test_args(betainc(a, b, x, y)) + +def test_sympy__functions__special__beta_functions__betainc_regularized(): + from sympy.functions.special.beta_functions import betainc_regularized + assert _test_args(betainc_regularized(a, b, x, y)) + + +def test_sympy__functions__special__mathieu_functions__MathieuBase(): + pass + + +def test_sympy__functions__special__mathieu_functions__mathieus(): + from sympy.functions.special.mathieu_functions import mathieus + assert _test_args(mathieus(1, 1, 1)) + + +def test_sympy__functions__special__mathieu_functions__mathieuc(): + from sympy.functions.special.mathieu_functions import mathieuc + assert _test_args(mathieuc(1, 1, 1)) + + +def test_sympy__functions__special__mathieu_functions__mathieusprime(): + from sympy.functions.special.mathieu_functions import mathieusprime + assert _test_args(mathieusprime(1, 1, 1)) + + +def test_sympy__functions__special__mathieu_functions__mathieucprime(): + from sympy.functions.special.mathieu_functions import mathieucprime + assert _test_args(mathieucprime(1, 1, 1)) + + +@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)) + +def test_sympy__functions__special__hyper__appellf1(): + from sympy.functions.special.hyper import appellf1 + a, b1, b2, c, x, y = symbols('a b1 b2 c x y') + assert _test_args(appellf1(a, b1, b2, c, 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, y, 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(3, 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(3, 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__hermite_prob(): + from sympy.functions.special.polynomials import hermite_prob + assert _test_args(hermite_prob(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(x, y, 1, 1)) + + +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__riemann_xi(): + from sympy.functions.special.zeta_functions import riemann_xi + assert _test_args(riemann_xi(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__functions__special__zeta_functions__stieltjes(): + from sympy.functions.special.zeta_functions import stieltjes + assert _test_args(stieltjes(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__laplace__LaplaceTransform(): + from sympy.integrals.laplace import LaplaceTransform + assert _test_args(LaplaceTransform(2, x, y)) + + +def test_sympy__integrals__laplace__InverseLaplaceTransform(): + from sympy.integrals.laplace 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__liealgebras__cartan_type__Standard_Cartan(): + from sympy.liealgebras.cartan_type import Standard_Cartan + assert _test_args(Standard_Cartan("A", 2)) + +def test_sympy__liealgebras__weyl_group__WeylGroup(): + from sympy.liealgebras.weyl_group import WeylGroup + assert _test_args(WeylGroup("B4")) + +def test_sympy__liealgebras__root_system__RootSystem(): + from sympy.liealgebras.root_system import RootSystem + assert _test_args(RootSystem("A2")) + +def test_sympy__liealgebras__type_a__TypeA(): + from sympy.liealgebras.type_a import TypeA + assert _test_args(TypeA(2)) + +def test_sympy__liealgebras__type_b__TypeB(): + from sympy.liealgebras.type_b import TypeB + assert _test_args(TypeB(4)) + +def test_sympy__liealgebras__type_c__TypeC(): + from sympy.liealgebras.type_c import TypeC + assert _test_args(TypeC(4)) + +def test_sympy__liealgebras__type_d__TypeD(): + from sympy.liealgebras.type_d import TypeD + assert _test_args(TypeD(4)) + +def test_sympy__liealgebras__type_e__TypeE(): + from sympy.liealgebras.type_e import TypeE + assert _test_args(TypeE(6)) + +def test_sympy__liealgebras__type_f__TypeF(): + from sympy.liealgebras.type_f import TypeF + assert _test_args(TypeF(4)) + +def test_sympy__liealgebras__type_g__TypeG(): + from sympy.liealgebras.type_g import TypeG + assert _test_args(TypeG(2)) + + +def test_sympy__logic__boolalg__And(): + from sympy.logic.boolalg import And + assert _test_args(And(x, y, 1)) + + +@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)) + +@SKIP("abstract class") +def test_sympy__logic__boolalg__BooleanAtom(): + pass + +def test_sympy__logic__boolalg__BooleanTrue(): + from sympy.logic.boolalg import true + assert _test_args(true) + +def test_sympy__logic__boolalg__BooleanFalse(): + from sympy.logic.boolalg import false + assert _test_args(false) + +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, 1)) + + +def test_sympy__logic__boolalg__Implies(): + from sympy.logic.boolalg import Implies + assert _test_args(Implies(x, y)) + + +def test_sympy__logic__boolalg__Nand(): + from sympy.logic.boolalg import Nand + assert _test_args(Nand(x, y, 1)) + + +def test_sympy__logic__boolalg__Nor(): + from sympy.logic.boolalg import Nor + assert _test_args(Nor(x, y)) + + +def test_sympy__logic__boolalg__Not(): + from sympy.logic.boolalg import Not + assert _test_args(Not(x)) + + +def test_sympy__logic__boolalg__Or(): + from sympy.logic.boolalg import Or + 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__logic__boolalg__Xnor(): + from sympy.logic.boolalg import Xnor + assert _test_args(Xnor(x, y, 2)) + +def test_sympy__logic__boolalg__Exclusive(): + from sympy.logic.boolalg import Exclusive + assert _test_args(Exclusive(x, y, z)) + + +def test_sympy__matrices__matrixbase__DeferredVector(): + from sympy.matrices.matrixbase import DeferredVector + assert _test_args(DeferredVector("X")) + + +@SKIP("abstract class") +def test_sympy__matrices__expressions__matexpr__MatrixBase(): + pass + + +@SKIP("abstract class") +def test_sympy__matrices__immutable__ImmutableRepMatrix(): + pass + + +def test_sympy__matrices__immutable__ImmutableDenseMatrix(): + from sympy.matrices.immutable import ImmutableDenseMatrix + m = ImmutableDenseMatrix([[1, 2], [3, 4]]) + assert _test_args(m) + assert _test_args(Basic(*list(m))) + m = ImmutableDenseMatrix(1, 1, [1]) + assert _test_args(m) + assert _test_args(Basic(*list(m))) + m = ImmutableDenseMatrix(2, 2, lambda i, j: 1) + assert m[0, 0] is S.One + m = ImmutableDenseMatrix(2, 2, lambda i, j: 1/(1 + i) + 1/(1 + j)) + assert m[1, 1] is S.One # true div. will give 1.0 if i,j not sympified + assert _test_args(m) + assert _test_args(Basic(*list(m))) + + +def test_sympy__matrices__immutable__ImmutableSparseMatrix(): + from sympy.matrices.immutable import ImmutableSparseMatrix + m = ImmutableSparseMatrix([[1, 2], [3, 4]]) + assert _test_args(m) + assert _test_args(Basic(*list(m))) + m = ImmutableSparseMatrix(1, 1, {(0, 0): 1}) + assert _test_args(m) + assert _test_args(Basic(*list(m))) + m = ImmutableSparseMatrix(1, 1, [1]) + assert _test_args(m) + assert _test_args(Basic(*list(m))) + m = ImmutableSparseMatrix(2, 2, lambda i, j: 1) + assert m[0, 0] is S.One + m = ImmutableSparseMatrix(2, 2, lambda i, j: 1/(1 + i) + 1/(1 + j)) + assert m[1, 1] is S.One # true div. will give 1.0 if i,j not sympified + assert _test_args(m) + assert _test_args(Basic(*list(m))) + + +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__applyfunc__ElementwiseApplyFunction(): + from sympy.matrices.expressions.applyfunc import ElementwiseApplyFunction + from sympy.matrices.expressions import MatrixSymbol + X = MatrixSymbol("X", x, x) + func = Lambda(x, x**2) + assert _test_args(ElementwiseApplyFunction(func, X)) + + +def test_sympy__matrices__expressions__blockmatrix__BlockDiagMatrix(): + from sympy.matrices.expressions.blockmatrix import BlockDiagMatrix + from sympy.matrices.expressions import MatrixSymbol + X = MatrixSymbol('X', x, x) + 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 + X = MatrixSymbol('X', x, x) + Y = MatrixSymbol('Y', y, y) + Z = MatrixSymbol('Z', x, y) + 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 + X = MatrixSymbol('X', x, y) + Y = MatrixSymbol('Y', x, y) + assert _test_args(MatAdd(X, Y)) + + +@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.core.singleton import S + assert _test_args(MatrixElement(MatrixSymbol('A', 3, 5), S(2), S(3))) + +def test_sympy__matrices__expressions__matexpr__MatrixSymbol(): + from sympy.matrices.expressions.matexpr import MatrixSymbol + assert _test_args(MatrixSymbol('A', 3, 5)) + + +def test_sympy__matrices__expressions__special__OneMatrix(): + from sympy.matrices.expressions.special import OneMatrix + assert _test_args(OneMatrix(3, 5)) + + +def test_sympy__matrices__expressions__special__ZeroMatrix(): + from sympy.matrices.expressions.special import ZeroMatrix + assert _test_args(ZeroMatrix(3, 5)) + + +def test_sympy__matrices__expressions__special__GenericZeroMatrix(): + from sympy.matrices.expressions.special import GenericZeroMatrix + assert _test_args(GenericZeroMatrix()) + + +def test_sympy__matrices__expressions__special__Identity(): + from sympy.matrices.expressions.special import Identity + assert _test_args(Identity(3)) + + +def test_sympy__matrices__expressions__special__GenericIdentity(): + from sympy.matrices.expressions.special import GenericIdentity + assert _test_args(GenericIdentity()) + + +def test_sympy__matrices__expressions__sets__MatrixSet(): + from sympy.matrices.expressions.sets import MatrixSet + from sympy.core.singleton import S + assert _test_args(MatrixSet(2, 2, S.Reals)) + +def test_sympy__matrices__expressions__matmul__MatMul(): + from sympy.matrices.expressions.matmul import MatMul + from sympy.matrices.expressions import MatrixSymbol + X = MatrixSymbol('X', x, y) + Y = MatrixSymbol('Y', y, x) + assert _test_args(MatMul(X, Y)) + + +def test_sympy__matrices__expressions__dotproduct__DotProduct(): + from sympy.matrices.expressions.dotproduct import DotProduct + from sympy.matrices.expressions import MatrixSymbol + X = MatrixSymbol('X', x, 1) + Y = MatrixSymbol('Y', x, 1) + assert _test_args(DotProduct(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__diagonal__DiagMatrix(): + from sympy.matrices.expressions.diagonal import DiagMatrix + from sympy.matrices.expressions import MatrixSymbol + x = MatrixSymbol('x', 10, 1) + assert _test_args(DiagMatrix(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__hadamard__HadamardPower(): + from sympy.matrices.expressions.hadamard import HadamardPower + from sympy.matrices.expressions import MatrixSymbol + from sympy.core.symbol import Symbol + X = MatrixSymbol('X', x, y) + n = Symbol("n") + assert _test_args(HadamardPower(X, n)) + +def test_sympy__matrices__expressions__kronecker__KroneckerProduct(): + from sympy.matrices.expressions.kronecker import KroneckerProduct + from sympy.matrices.expressions import MatrixSymbol + X = MatrixSymbol('X', x, y) + Y = MatrixSymbol('Y', x, y) + assert _test_args(KroneckerProduct(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__determinant__Permanent(): + from sympy.matrices.expressions.determinant import Permanent + from sympy.matrices.expressions import MatrixSymbol + assert _test_args(Permanent(MatrixSymbol('A', 3, 4))) + +def test_sympy__matrices__expressions__funcmatrix__FunctionMatrix(): + from sympy.matrices.expressions.funcmatrix import FunctionMatrix + from sympy.core.symbol import symbols + i, j = symbols('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.core.singleton import S + assert _test_args(DFT(S(2))) + +def test_sympy__matrices__expressions__fourier__IDFT(): + from sympy.matrices.expressions.fourier import IDFT + from sympy.core.singleton 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__matrices__expressions__permutation__PermutationMatrix(): + from sympy.combinatorics import Permutation + from sympy.matrices.expressions.permutation import PermutationMatrix + assert _test_args(PermutationMatrix(Permutation([2, 0, 1]))) + +def test_sympy__matrices__expressions__permutation__MatrixPermute(): + from sympy.combinatorics import Permutation + from sympy.matrices.expressions.matexpr import MatrixSymbol + from sympy.matrices.expressions.permutation import MatrixPermute + A = MatrixSymbol('A', 3, 3) + assert _test_args(MatrixPermute(A, Permutation([2, 0, 1]))) + +def test_sympy__matrices__expressions__companion__CompanionMatrix(): + from sympy.core.symbol import Symbol + from sympy.matrices.expressions.companion import CompanionMatrix + from sympy.polys.polytools import Poly + + x = Symbol('x') + p = Poly([1, 2, 3], x) + assert _test_args(CompanionMatrix(p)) + +def test_sympy__physics__vector__frame__CoordinateSym(): + from sympy.physics.vector import CoordinateSym + from sympy.physics.vector import ReferenceFrame + assert _test_args(CoordinateSym('R_x', ReferenceFrame('R'), 0)) + + +@SKIP("abstract class") +def test_sympy__physics__biomechanics__curve__CharacteristicCurveFunction(): + pass + + +def test_sympy__physics__biomechanics__curve__TendonForceLengthDeGroote2016(): + from sympy.physics.biomechanics import TendonForceLengthDeGroote2016 + l_T_tilde, c0, c1, c2, c3 = symbols('l_T_tilde, c0, c1, c2, c3') + assert _test_args(TendonForceLengthDeGroote2016(l_T_tilde, c0, c1, c2, c3)) + + +def test_sympy__physics__biomechanics__curve__TendonForceLengthInverseDeGroote2016(): + from sympy.physics.biomechanics import TendonForceLengthInverseDeGroote2016 + fl_T, c0, c1, c2, c3 = symbols('fl_T, c0, c1, c2, c3') + assert _test_args(TendonForceLengthInverseDeGroote2016(fl_T, c0, c1, c2, c3)) + + +def test_sympy__physics__biomechanics__curve__FiberForceLengthPassiveDeGroote2016(): + from sympy.physics.biomechanics import FiberForceLengthPassiveDeGroote2016 + l_M_tilde, c0, c1 = symbols('l_M_tilde, c0, c1') + assert _test_args(FiberForceLengthPassiveDeGroote2016(l_M_tilde, c0, c1)) + + +def test_sympy__physics__biomechanics__curve__FiberForceLengthPassiveInverseDeGroote2016(): + from sympy.physics.biomechanics import FiberForceLengthPassiveInverseDeGroote2016 + fl_M_pas, c0, c1 = symbols('fl_M_pas, c0, c1') + assert _test_args(FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, c0, c1)) + + +def test_sympy__physics__biomechanics__curve__FiberForceLengthActiveDeGroote2016(): + from sympy.physics.biomechanics import FiberForceLengthActiveDeGroote2016 + l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 = symbols('l_M_tilde, c0:12') + assert _test_args(FiberForceLengthActiveDeGroote2016(l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11)) + + +def test_sympy__physics__biomechanics__curve__FiberForceVelocityDeGroote2016(): + from sympy.physics.biomechanics import FiberForceVelocityDeGroote2016 + v_M_tilde, c0, c1, c2, c3 = symbols('v_M_tilde, c0, c1, c2, c3') + assert _test_args(FiberForceVelocityDeGroote2016(v_M_tilde, c0, c1, c2, c3)) + + +def test_sympy__physics__biomechanics__curve__FiberForceVelocityInverseDeGroote2016(): + from sympy.physics.biomechanics import FiberForceVelocityInverseDeGroote2016 + fv_M, c0, c1, c2, c3 = symbols('fv_M, c0, c1, c2, c3') + assert _test_args(FiberForceVelocityInverseDeGroote2016(fv_M, c0, c1, c2, c3)) + + +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.core.singleton import S + assert _test_args(CG(Rational(3, 2), Rational(3, 2), S.Half, Rational(-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)) + + +def test_sympy__physics__quantum__cg__Wigner6j(): + from sympy.physics.quantum.cg import Wigner6j + 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, Rational(3, 2), S.Half, 1, S.Half, S.Half, 0)) + +def test_sympy__physics__quantum__circuitplot__Mz(): + from sympy.physics.quantum.circuitplot import Mz + assert _test_args(Mz(0)) + +def test_sympy__physics__quantum__circuitplot__Mx(): + from sympy.physics.quantum.circuitplot import Mx + assert _test_args(Mx(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))) + + +def test_sympy__physics__quantum__gate__CGateS(): + from sympy.physics.quantum.gate import CGateS, Gate + assert _test_args(CGateS((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 import ImmutableDenseMatrix + from sympy.core.containers import Tuple + from sympy.core.numbers import Integer + assert _test_args( + UGate(Tuple(Integer(1)), ImmutableDenseMatrix([[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)) + + +def test_sympy__physics__quantum__grover__OracleGateFunction(): + from sympy.physics.quantum.grover import OracleGateFunction + @OracleGateFunction + def f(qubit): + return + assert _test_args(f) + +def test_sympy__physics__quantum__grover__OracleGate(): + from sympy.physics.quantum.grover import OracleGate + def f(qubit): + return + assert _test_args(OracleGate(1,f)) + + +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.core.numbers import oo + from sympy.sets.sets import 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.core.function 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__IdentityOperator(): + with warns_deprecated_sympy(): + from sympy.physics.quantum.operator import IdentityOperator + assert _test_args(IdentityOperator(5)) + + +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 + b = Bra('b') + 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__boson__BosonOp(): + from sympy.physics.quantum.boson import BosonOp + assert _test_args(BosonOp('a')) + assert _test_args(BosonOp('a', False)) + + +def test_sympy__physics__quantum__boson__BosonFockKet(): + from sympy.physics.quantum.boson import BosonFockKet + assert _test_args(BosonFockKet(1)) + + +def test_sympy__physics__quantum__boson__BosonFockBra(): + from sympy.physics.quantum.boson import BosonFockBra + assert _test_args(BosonFockBra(1)) + + +def test_sympy__physics__quantum__boson__BosonCoherentKet(): + from sympy.physics.quantum.boson import BosonCoherentKet + assert _test_args(BosonCoherentKet(1)) + + +def test_sympy__physics__quantum__boson__BosonCoherentBra(): + from sympy.physics.quantum.boson import BosonCoherentBra + assert _test_args(BosonCoherentBra(1)) + + +def test_sympy__physics__quantum__fermion__FermionOp(): + from sympy.physics.quantum.fermion import FermionOp + assert _test_args(FermionOp('c')) + assert _test_args(FermionOp('c', False)) + + +def test_sympy__physics__quantum__fermion__FermionFockKet(): + from sympy.physics.quantum.fermion import FermionFockKet + assert _test_args(FermionFockKet(1)) + + +def test_sympy__physics__quantum__fermion__FermionFockBra(): + from sympy.physics.quantum.fermion import FermionFockBra + assert _test_args(FermionFockBra(1)) + + +def test_sympy__physics__quantum__pauli__SigmaOpBase(): + from sympy.physics.quantum.pauli import SigmaOpBase + assert _test_args(SigmaOpBase()) + + +def test_sympy__physics__quantum__pauli__SigmaX(): + from sympy.physics.quantum.pauli import SigmaX + assert _test_args(SigmaX()) + + +def test_sympy__physics__quantum__pauli__SigmaY(): + from sympy.physics.quantum.pauli import SigmaY + assert _test_args(SigmaY()) + + +def test_sympy__physics__quantum__pauli__SigmaZ(): + from sympy.physics.quantum.pauli import SigmaZ + assert _test_args(SigmaZ()) + + +def test_sympy__physics__quantum__pauli__SigmaMinus(): + from sympy.physics.quantum.pauli import SigmaMinus + assert _test_args(SigmaMinus()) + + +def test_sympy__physics__quantum__pauli__SigmaPlus(): + from sympy.physics.quantum.pauli import SigmaPlus + assert _test_args(SigmaPlus()) + + +def test_sympy__physics__quantum__pauli__SigmaZKet(): + from sympy.physics.quantum.pauli import SigmaZKet + assert _test_args(SigmaZKet(0)) + + +def test_sympy__physics__quantum__pauli__SigmaZBra(): + from sympy.physics.quantum.pauli import SigmaZBra + assert _test_args(SigmaZBra(0)) + + +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])) + + +@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.Half, S.Half))) + assert _test_args(CoupledSpinState( + 1, 0, (1, S.Half, S.Half), ((2, 3, S.Half), (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 + 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__OrthogonalBra(): + from sympy.physics.quantum.state import OrthogonalBra + assert _test_args(OrthogonalBra(0)) + + +def test_sympy__physics__quantum__state__OrthogonalKet(): + from sympy.physics.quantum.state import OrthogonalKet + assert _test_args(OrthogonalKet(0)) + + +def test_sympy__physics__quantum__state__OrthogonalState(): + from sympy.physics.quantum.state import OrthogonalState + assert _test_args(OrthogonalState(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 + from sympy.functions.elementary.piecewise import Piecewise + n = 1 + L = 1 + 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 + x, y = symbols("x y", commutative=False) + 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 + x, y = symbols('x y', commutative=False) + 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 + assert _test_args(Dagger(x)) + + +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__control__lti__LinearTimeInvariant(): + # Direct instances of LinearTimeInvariant class are not allowed. + # func(*args) tests for its derived classes (TransferFunction, + # Series, Parallel and TransferFunctionMatrix) should pass. + pass + + +def test_sympy__physics__control__lti__SISOLinearTimeInvariant(): + # Direct instances of SISOLinearTimeInvariant class are not allowed. + pass + + +def test_sympy__physics__control__lti__MIMOLinearTimeInvariant(): + # Direct instances of MIMOLinearTimeInvariant class are not allowed. + pass + + +def test_sympy__physics__control__lti__TransferFunction(): + from sympy.physics.control.lti import TransferFunction + assert _test_args(TransferFunction(2, 3, x)) + + +def _test_args_PIDController(obj): + from sympy.physics.control.lti import PIDController + if isinstance(obj, PIDController): + kp, ki, kd, tf = obj.kp, obj.ki, obj.kd, obj.tf + recreated_pid = PIDController(kp, ki, kd, tf, s) + return recreated_pid == obj + return False + + +def test_sympy__physics__control__lti__PIDController(): + from sympy.physics.control.lti import PIDController + kp, ki, kd, tf = 1, 0.1, 0.01, 0 + assert _test_args_PIDController(PIDController(kp, ki, kd, tf, s)) + + +def test_sympy__physics__control__lti__Series(): + from sympy.physics.control import Series, TransferFunction + tf1 = TransferFunction(x**2 - y**3, y - z, x) + tf2 = TransferFunction(y - x, z + y, x) + assert _test_args(Series(tf1, tf2)) + + +def test_sympy__physics__control__lti__MIMOSeries(): + from sympy.physics.control import MIMOSeries, TransferFunction, TransferFunctionMatrix + tf1 = TransferFunction(x**2 - y**3, y - z, x) + tf2 = TransferFunction(y - x, z + y, x) + tfm_1 = TransferFunctionMatrix([[tf2, tf1]]) + tfm_2 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) + tfm_3 = TransferFunctionMatrix([[tf1], [tf2]]) + assert _test_args(MIMOSeries(tfm_3, tfm_2, tfm_1)) + + +def test_sympy__physics__control__lti__Parallel(): + from sympy.physics.control import Parallel, TransferFunction + tf1 = TransferFunction(x**2 - y**3, y - z, x) + tf2 = TransferFunction(y - x, z + y, x) + assert _test_args(Parallel(tf1, tf2)) + + +def test_sympy__physics__control__lti__MIMOParallel(): + from sympy.physics.control import MIMOParallel, TransferFunction, TransferFunctionMatrix + tf1 = TransferFunction(x**2 - y**3, y - z, x) + tf2 = TransferFunction(y - x, z + y, x) + tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) + tfm_2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]]) + assert _test_args(MIMOParallel(tfm_1, tfm_2)) + + +def test_sympy__physics__control__lti__Feedback(): + from sympy.physics.control import TransferFunction, Feedback + tf1 = TransferFunction(x**2 - y**3, y - z, x) + tf2 = TransferFunction(y - x, z + y, x) + assert _test_args(Feedback(tf1, tf2)) + assert _test_args(Feedback(tf1, tf2, 1)) + + +def test_sympy__physics__control__lti__MIMOFeedback(): + from sympy.physics.control import TransferFunction, MIMOFeedback, TransferFunctionMatrix + tf1 = TransferFunction(x**2 - y**3, y - z, x) + tf2 = TransferFunction(y - x, z + y, x) + tfm_1 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]]) + tfm_2 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) + assert _test_args(MIMOFeedback(tfm_1, tfm_2)) + assert _test_args(MIMOFeedback(tfm_1, tfm_2, 1)) + + +def test_sympy__physics__control__lti__TransferFunctionMatrix(): + from sympy.physics.control import TransferFunction, TransferFunctionMatrix + tf1 = TransferFunction(x**2 - y**3, y - z, x) + tf2 = TransferFunction(y - x, z + y, x) + assert _test_args(TransferFunctionMatrix([[tf1, tf2]])) + + +def test_sympy__physics__control__lti__StateSpace(): + from sympy.matrices.dense import Matrix + from sympy.physics.control import StateSpace + A = Matrix([[-5, -1], [3, -1]]) + B = Matrix([2, 5]) + C = Matrix([[1, 2]]) + D = Matrix([0]) + assert _test_args(StateSpace(A, B, C, D)) + + +def test_sympy__physics__units__dimensions__Dimension(): + from sympy.physics.units.dimensions import Dimension + assert _test_args(Dimension("length", "L")) + + +def test_sympy__physics__units__dimensions__DimensionSystem(): + from sympy.physics.units.dimensions import DimensionSystem + from sympy.physics.units.definitions.dimension_definitions import length, time, velocity + assert _test_args(DimensionSystem((length, time), (velocity,))) + + +def test_sympy__physics__units__quantities__Quantity(): + from sympy.physics.units.quantities import Quantity + assert _test_args(Quantity("dam")) + + +def test_sympy__physics__units__quantities__PhysicalConstant(): + from sympy.physics.units.quantities import PhysicalConstant + assert _test_args(PhysicalConstant("foo")) + + +def test_sympy__physics__units__prefixes__Prefix(): + from sympy.physics.units.prefixes import Prefix + assert _test_args(Prefix('kilo', 'k', 3)) + + +def test_sympy__core__numbers__AlgebraicNumber(): + from sympy.core.numbers 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)) + + +@SKIP('abstract class') +def test_sympy__polys__rootoftools__RootOf(): + pass + + +def test_sympy__polys__rootoftools__ComplexRootOf(): + from sympy.polys.rootoftools import ComplexRootOf + assert _test_args(ComplexRootOf(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)) + + +@SKIP('Abstract Class') +def test_sympy__series__sequences__SeqBase(): + pass + + +def test_sympy__series__sequences__EmptySequence(): + # Need to import the instance from series not the class from + # series.sequence + from sympy.series import EmptySequence + assert _test_args(EmptySequence) + + +@SKIP('Abstract Class') +def test_sympy__series__sequences__SeqExpr(): + pass + + +def test_sympy__series__sequences__SeqPer(): + from sympy.series.sequences import SeqPer + assert _test_args(SeqPer((1, 2, 3), (0, 10))) + + +def test_sympy__series__sequences__SeqFormula(): + from sympy.series.sequences import SeqFormula + assert _test_args(SeqFormula(x**2, (0, 10))) + + +def test_sympy__series__sequences__RecursiveSeq(): + from sympy.series.sequences import RecursiveSeq + y = Function("y") + n = symbols("n") + assert _test_args(RecursiveSeq(y(n - 1) + y(n - 2), y(n), n, (0, 1))) + assert _test_args(RecursiveSeq(y(n - 1) + y(n - 2), y(n), n)) + + +def test_sympy__series__sequences__SeqExprOp(): + from sympy.series.sequences import SeqExprOp, sequence + s1 = sequence((1, 2, 3)) + s2 = sequence(x**2) + assert _test_args(SeqExprOp(s1, s2)) + + +def test_sympy__series__sequences__SeqAdd(): + from sympy.series.sequences import SeqAdd, sequence + s1 = sequence((1, 2, 3)) + s2 = sequence(x**2) + assert _test_args(SeqAdd(s1, s2)) + + +def test_sympy__series__sequences__SeqMul(): + from sympy.series.sequences import SeqMul, sequence + s1 = sequence((1, 2, 3)) + s2 = sequence(x**2) + assert _test_args(SeqMul(s1, s2)) + + +@SKIP('Abstract Class') +def test_sympy__series__series_class__SeriesBase(): + pass + + +def test_sympy__series__fourier__FourierSeries(): + from sympy.series.fourier import fourier_series + assert _test_args(fourier_series(x, (x, -pi, pi))) + +def test_sympy__series__fourier__FiniteFourierSeries(): + from sympy.series.fourier import fourier_series + assert _test_args(fourier_series(sin(pi*x), (x, -1, 1))) + + +def test_sympy__series__formal__FormalPowerSeries(): + from sympy.series.formal import fps + assert _test_args(fps(log(1 + x), x)) + + +def test_sympy__series__formal__Coeff(): + from sympy.series.formal import fps + assert _test_args(fps(x**2 + x + 1, x)) + + +@SKIP('Abstract Class') +def test_sympy__series__formal__FiniteFormalPowerSeries(): + pass + + +def test_sympy__series__formal__FormalPowerSeriesProduct(): + from sympy.series.formal import fps + f1, f2 = fps(sin(x)), fps(exp(x)) + assert _test_args(f1.product(f2, x)) + + +def test_sympy__series__formal__FormalPowerSeriesCompose(): + from sympy.series.formal import fps + f1, f2 = fps(exp(x)), fps(sin(x)) + assert _test_args(f1.compose(f2, x)) + + +def test_sympy__series__formal__FormalPowerSeriesInverse(): + from sympy.series.formal import fps + f1 = fps(exp(x)) + assert _test_args(f1.inverse(x)) + + +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], [], [])) + + +@SKIP("abstract class") +def test_sympy__tensor__array__ndim_array__ImmutableNDimArray(): + pass + + +def test_sympy__tensor__array__dense_ndim_array__ImmutableDenseNDimArray(): + from sympy.tensor.array.dense_ndim_array import ImmutableDenseNDimArray + densarr = ImmutableDenseNDimArray(range(10, 34), (2, 3, 4)) + assert _test_args(densarr) + + +def test_sympy__tensor__array__sparse_ndim_array__ImmutableSparseNDimArray(): + from sympy.tensor.array.sparse_ndim_array import ImmutableSparseNDimArray + sparr = ImmutableSparseNDimArray(range(10, 34), (2, 3, 4)) + assert _test_args(sparr) + + +def test_sympy__tensor__array__array_comprehension__ArrayComprehension(): + from sympy.tensor.array.array_comprehension import ArrayComprehension + arrcom = ArrayComprehension(x, (x, 1, 5)) + assert _test_args(arrcom) + +def test_sympy__tensor__array__array_comprehension__ArrayComprehensionMap(): + from sympy.tensor.array.array_comprehension import ArrayComprehensionMap + arrcomma = ArrayComprehensionMap(lambda: 0, (x, 1, 5)) + assert _test_args(arrcomma) + + +def test_sympy__tensor__array__array_derivatives__ArrayDerivative(): + from sympy.tensor.array.array_derivatives import ArrayDerivative + A = MatrixSymbol("A", 2, 2) + arrder = ArrayDerivative(A, A, evaluate=False) + assert _test_args(arrder) + +def test_sympy__tensor__array__expressions__array_expressions__ArraySymbol(): + from sympy.tensor.array.expressions.array_expressions import ArraySymbol + m, n, k = symbols("m n k") + array = ArraySymbol("A", (m, n, k, 2)) + assert _test_args(array) + +def test_sympy__tensor__array__expressions__array_expressions__ArrayElement(): + from sympy.tensor.array.expressions.array_expressions import ArrayElement + m, n, k = symbols("m n k") + ae = ArrayElement("A", (m, n, k, 2)) + assert _test_args(ae) + +def test_sympy__tensor__array__expressions__array_expressions__ZeroArray(): + from sympy.tensor.array.expressions.array_expressions import ZeroArray + m, n, k = symbols("m n k") + za = ZeroArray(m, n, k, 2) + assert _test_args(za) + +def test_sympy__tensor__array__expressions__array_expressions__OneArray(): + from sympy.tensor.array.expressions.array_expressions import OneArray + m, n, k = symbols("m n k") + za = OneArray(m, n, k, 2) + assert _test_args(za) + +def test_sympy__tensor__functions__TensorProduct(): + from sympy.tensor.functions import TensorProduct + A = MatrixSymbol('A', 3, 3) + B = MatrixSymbol('B', 3, 3) + tp = TensorProduct(A, B) + assert _test_args(tp) + + +def test_sympy__tensor__indexed__Idx(): + from sympy.tensor.indexed import Idx + assert _test_args(Idx('test')) + assert _test_args(Idx('test', (0, 10))) + assert _test_args(Idx('test', 2)) + assert _test_args(Idx('test', x)) + + +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]) + + +def test_sympy__tensor__tensor__TensorIndexType(): + from sympy.tensor.tensor import TensorIndexType + assert _test_args(TensorIndexType('Lorentz')) + + +@SKIP("deprecated class") +def test_sympy__tensor__tensor__TensorType(): + pass + + +def test_sympy__tensor__tensor__TensorSymmetry(): + from sympy.tensor.tensor import TensorSymmetry, get_symmetric_group_sgs + assert _test_args(TensorSymmetry(get_symmetric_group_sgs(2))) + + +def test_sympy__tensor__tensor__TensorHead(): + from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, TensorHead + Lorentz = TensorIndexType('Lorentz', dummy_name='L') + sym = TensorSymmetry(get_symmetric_group_sgs(1)) + assert _test_args(TensorHead('p', [Lorentz], sym, 0)) + + +def test_sympy__tensor__tensor__TensorIndex(): + from sympy.tensor.tensor import TensorIndexType, TensorIndex + Lorentz = TensorIndexType('Lorentz', dummy_name='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, get_symmetric_group_sgs, tensor_indices, TensAdd, tensor_heads + Lorentz = TensorIndexType('Lorentz', dummy_name='L') + a, b = tensor_indices('a,b', Lorentz) + sym = TensorSymmetry(get_symmetric_group_sgs(1)) + p, q = tensor_heads('p,q', [Lorentz], sym) + t1 = p(a) + t2 = q(a) + assert _test_args(TensAdd(t1, t2)) + + +def test_sympy__tensor__tensor__Tensor(): + from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, tensor_indices, TensorHead + Lorentz = TensorIndexType('Lorentz', dummy_name='L') + a, b = tensor_indices('a,b', Lorentz) + sym = TensorSymmetry(get_symmetric_group_sgs(1)) + p = TensorHead('p', [Lorentz], sym) + assert _test_args(p(a)) + + +def test_sympy__tensor__tensor__TensMul(): + from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, tensor_indices, tensor_heads + Lorentz = TensorIndexType('Lorentz', dummy_name='L') + a, b = tensor_indices('a,b', Lorentz) + sym = TensorSymmetry(get_symmetric_group_sgs(1)) + p, q = tensor_heads('p, q', [Lorentz], sym) + assert _test_args(3*p(a)*q(b)) + + +def test_sympy__tensor__tensor__TensorElement(): + from sympy.tensor.tensor import TensorIndexType, TensorHead, TensorElement + L = TensorIndexType("L") + A = TensorHead("A", [L, L]) + telem = TensorElement(A(x, y), {x: 1}) + assert _test_args(telem) + +def test_sympy__tensor__tensor__WildTensor(): + from sympy.tensor.tensor import TensorIndexType, WildTensorHead, TensorIndex + Lorentz = TensorIndexType('Lorentz', dummy_name='L') + a = TensorIndex('a', Lorentz) + p = WildTensorHead('p') + assert _test_args(p(a)) + +def test_sympy__tensor__tensor__WildTensorHead(): + from sympy.tensor.tensor import WildTensorHead + assert _test_args(WildTensorHead('p')) + +def test_sympy__tensor__tensor__WildTensorIndex(): + from sympy.tensor.tensor import TensorIndexType, WildTensorIndex + Lorentz = TensorIndexType('Lorentz', dummy_name='L') + assert _test_args(WildTensorIndex('i', Lorentz)) + +def test_sympy__tensor__toperators__PartialDerivative(): + from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead + from sympy.tensor.toperators import PartialDerivative + Lorentz = TensorIndexType('Lorentz', dummy_name='L') + a, b = tensor_indices('a,b', Lorentz) + A = TensorHead("A", [Lorentz]) + assert _test_args(PartialDerivative(A(a), A(b))) + + +def test_as_coeff_add(): + 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__point__Point2D(): + from sympy.geometry.point import Point2D + assert _test_args(Point2D(0, 1)) + + +def test_sympy__geometry__point__Point3D(): + from sympy.geometry.point import Point3D + assert _test_args(Point3D(0, 1, 2)) + + +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__parabola__Parabola(): + from sympy.geometry.parabola import Parabola + from sympy.geometry.line import Line + assert _test_args(Parabola((0, 0), Line((2, 3), (4, 3)))) + + +@SKIP("abstract class") +def test_sympy__geometry__line__LinearEntity(): + pass + + +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))) + +@SKIP("abstract class") +def test_sympy__geometry__line__LinearEntity2D(): + pass + + +def test_sympy__geometry__line__Line2D(): + from sympy.geometry.line import Line2D + assert _test_args(Line2D((0, 1), (2, 3))) + + +def test_sympy__geometry__line__Ray2D(): + from sympy.geometry.line import Ray2D + assert _test_args(Ray2D((0, 1), (2, 3))) + + +def test_sympy__geometry__line__Segment2D(): + from sympy.geometry.line import Segment2D + assert _test_args(Segment2D((0, 1), (2, 3))) + + +@SKIP("abstract class") +def test_sympy__geometry__line__LinearEntity3D(): + pass + + +def test_sympy__geometry__line__Line3D(): + from sympy.geometry.line import Line3D + assert _test_args(Line3D((0, 1, 1), (2, 3, 4))) + + +def test_sympy__geometry__line__Segment3D(): + from sympy.geometry.line import Segment3D + assert _test_args(Segment3D((0, 1, 1), (2, 3, 4))) + + +def test_sympy__geometry__line__Ray3D(): + from sympy.geometry.line import Ray3D + assert _test_args(Ray3D((0, 1, 1), (2, 3, 4))) + + +def test_sympy__geometry__plane__Plane(): + from sympy.geometry.plane import Plane + assert _test_args(Plane((1, 1, 1), (-3, 4, -2), (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, [1, 2])) + +@SKIP("abstract class") +def test_sympy__geometry__entity__GeometrySet(): + pass + +def test_sympy__diffgeom__diffgeom__Manifold(): + from sympy.diffgeom import Manifold + assert _test_args(Manifold('name', 3)) + + +def test_sympy__diffgeom__diffgeom__Patch(): + from sympy.diffgeom import Manifold, Patch + assert _test_args(Patch('name', Manifold('name', 3))) + + +def test_sympy__diffgeom__diffgeom__CoordSystem(): + from sympy.diffgeom import Manifold, Patch, CoordSystem + assert _test_args(CoordSystem('name', Patch('name', Manifold('name', 3)))) + assert _test_args(CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c])) + + +def test_sympy__diffgeom__diffgeom__CoordinateSymbol(): + from sympy.diffgeom import Manifold, Patch, CoordSystem, CoordinateSymbol + assert _test_args(CoordinateSymbol(CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]), 0)) + + +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)), [a, b, c]), [x, y])) + + +def test_sympy__diffgeom__diffgeom__BaseScalarField(): + from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField + cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) + assert _test_args(BaseScalarField(cs, 0)) + + +def test_sympy__diffgeom__diffgeom__BaseVectorField(): + from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseVectorField + cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) + 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)), [a, b, c]) + assert _test_args(Differential(BaseScalarField(cs, 0))) + + +def test_sympy__diffgeom__diffgeom__Commutator(): + from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseVectorField, Commutator + cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) + cs1 = CoordSystem('name1', Patch('name', Manifold('name', 3)), [a, b, c]) + v = BaseVectorField(cs, 0) + 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)), [a, b, c]) + 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)), [a, b, c]) + d = Differential(BaseScalarField(cs, 0)) + 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)), [a, b, c]) + d = Differential(BaseScalarField(cs, 0)) + v = BaseVectorField(cs, 0) + assert _test_args(LieDerivative(v, d)) + + +def test_sympy__diffgeom__diffgeom__BaseCovarDerivativeOp(): + from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseCovarDerivativeOp + cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) + 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)), [a, b, c]) + v = BaseVectorField(cs, 0) + _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")) + + +@SKIP("abstract class") +def test_sympy__categories__baseclasses__Morphism(): + pass + + +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") + B = Object("B") + C = Object("C") + f = NamedMorphism(A, B, "f") + g = NamedMorphism(B, C, "g") + assert _test_args(CompositeMorphism(f, g)) + + +def test_sympy__categories__baseclasses__Diagram(): + from sympy.categories import Object, NamedMorphism, Diagram + A = Object("A") + B = Object("B") + f = NamedMorphism(A, B, "f") + d = Diagram([f]) + assert _test_args(d) + + +def test_sympy__categories__baseclasses__Category(): + from sympy.categories import Object, NamedMorphism, Diagram, Category + A = Object("A") + B = Object("B") + C = Object("C") + f = NamedMorphism(A, B, "f") + g = NamedMorphism(B, C, "g") + d1 = Diagram([f, g]) + d2 = Diagram([f]) + K = Category("K", commutative_diagrams=[d1, d2]) + assert _test_args(K) + + +def test_sympy__physics__optics__waves__TWave(): + from sympy.physics.optics import TWave + A, f, phi = symbols('A, f, phi') + assert _test_args(TWave(A, f, phi)) + + +def test_sympy__physics__optics__gaussopt__BeamParameter(): + from sympy.physics.optics import BeamParameter + assert _test_args(BeamParameter(530e-9, 1, w=1e-3, n=1)) + + +def test_sympy__physics__optics__medium__Medium(): + from sympy.physics.optics import Medium + assert _test_args(Medium('m')) + + +def test_sympy__physics__optics__medium__MediumN(): + from sympy.physics.optics.medium import Medium + assert _test_args(Medium('m', n=2)) + + +def test_sympy__physics__optics__medium__MediumPP(): + from sympy.physics.optics.medium import Medium + assert _test_args(Medium('m', permittivity=2, permeability=2)) + + +def test_sympy__tensor__array__expressions__array_expressions__ArrayContraction(): + from sympy.tensor.array.expressions.array_expressions import ArrayContraction + from sympy.tensor.indexed import IndexedBase + A = symbols("A", cls=IndexedBase) + assert _test_args(ArrayContraction(A, (0, 1))) + + +def test_sympy__tensor__array__expressions__array_expressions__ArrayDiagonal(): + from sympy.tensor.array.expressions.array_expressions import ArrayDiagonal + from sympy.tensor.indexed import IndexedBase + A = symbols("A", cls=IndexedBase) + assert _test_args(ArrayDiagonal(A, (0, 1))) + + +def test_sympy__tensor__array__expressions__array_expressions__ArrayTensorProduct(): + from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct + from sympy.tensor.indexed import IndexedBase + A, B = symbols("A B", cls=IndexedBase) + assert _test_args(ArrayTensorProduct(A, B)) + + +def test_sympy__tensor__array__expressions__array_expressions__ArrayAdd(): + from sympy.tensor.array.expressions.array_expressions import ArrayAdd + from sympy.tensor.indexed import IndexedBase + A, B = symbols("A B", cls=IndexedBase) + assert _test_args(ArrayAdd(A, B)) + + +def test_sympy__tensor__array__expressions__array_expressions__PermuteDims(): + from sympy.tensor.array.expressions.array_expressions import PermuteDims + A = MatrixSymbol("A", 4, 4) + assert _test_args(PermuteDims(A, (1, 0))) + + +def test_sympy__tensor__array__expressions__array_expressions__ArrayElementwiseApplyFunc(): + from sympy.tensor.array.expressions.array_expressions import ArraySymbol, ArrayElementwiseApplyFunc + A = ArraySymbol("A", (4,)) + assert _test_args(ArrayElementwiseApplyFunc(exp, A)) + + +def test_sympy__tensor__array__expressions__array_expressions__Reshape(): + from sympy.tensor.array.expressions.array_expressions import ArraySymbol, Reshape + A = ArraySymbol("A", (4,)) + assert _test_args(Reshape(A, (2, 2))) + + +def test_sympy__codegen__ast__Assignment(): + from sympy.codegen.ast import Assignment + assert _test_args(Assignment(x, y)) + + +def test_sympy__codegen__cfunctions__expm1(): + from sympy.codegen.cfunctions import expm1 + assert _test_args(expm1(x)) + + +def test_sympy__codegen__cfunctions__log1p(): + from sympy.codegen.cfunctions import log1p + assert _test_args(log1p(x)) + + +def test_sympy__codegen__cfunctions__exp2(): + from sympy.codegen.cfunctions import exp2 + assert _test_args(exp2(x)) + + +def test_sympy__codegen__cfunctions__log2(): + from sympy.codegen.cfunctions import log2 + assert _test_args(log2(x)) + + +def test_sympy__codegen__cfunctions__fma(): + from sympy.codegen.cfunctions import fma + assert _test_args(fma(x, y, z)) + + +def test_sympy__codegen__cfunctions__log10(): + from sympy.codegen.cfunctions import log10 + assert _test_args(log10(x)) + + +def test_sympy__codegen__cfunctions__Sqrt(): + from sympy.codegen.cfunctions import Sqrt + assert _test_args(Sqrt(x)) + +def test_sympy__codegen__cfunctions__Cbrt(): + from sympy.codegen.cfunctions import Cbrt + assert _test_args(Cbrt(x)) + +def test_sympy__codegen__cfunctions__hypot(): + from sympy.codegen.cfunctions import hypot + assert _test_args(hypot(x, y)) + + +def test_sympy__codegen__cfunctions__isnan(): + from sympy.codegen.cfunctions import isnan + assert _test_args(isnan(x)) + + +def test_sympy__codegen__cfunctions__isinf(): + from sympy.codegen.cfunctions import isinf + assert _test_args(isinf(x)) + + +def test_sympy__codegen__fnodes__FFunction(): + from sympy.codegen.fnodes import FFunction + assert _test_args(FFunction('f')) + + +def test_sympy__codegen__fnodes__F95Function(): + from sympy.codegen.fnodes import F95Function + assert _test_args(F95Function('f')) + + +def test_sympy__codegen__fnodes__isign(): + from sympy.codegen.fnodes import isign + assert _test_args(isign(1, x)) + + +def test_sympy__codegen__fnodes__dsign(): + from sympy.codegen.fnodes import dsign + assert _test_args(dsign(1, x)) + + +def test_sympy__codegen__fnodes__cmplx(): + from sympy.codegen.fnodes import cmplx + assert _test_args(cmplx(x, y)) + + +def test_sympy__codegen__fnodes__kind(): + from sympy.codegen.fnodes import kind + assert _test_args(kind(x)) + + +def test_sympy__codegen__fnodes__merge(): + from sympy.codegen.fnodes import merge + assert _test_args(merge(1, 2, Eq(x, 0))) + + +def test_sympy__codegen__fnodes___literal(): + from sympy.codegen.fnodes import _literal + assert _test_args(_literal(1)) + + +def test_sympy__codegen__fnodes__literal_sp(): + from sympy.codegen.fnodes import literal_sp + assert _test_args(literal_sp(1)) + + +def test_sympy__codegen__fnodes__literal_dp(): + from sympy.codegen.fnodes import literal_dp + assert _test_args(literal_dp(1)) + + +def test_sympy__codegen__matrix_nodes__MatrixSolve(): + from sympy.matrices import MatrixSymbol + from sympy.codegen.matrix_nodes import MatrixSolve + A = MatrixSymbol('A', 3, 3) + v = MatrixSymbol('x', 3, 1) + assert _test_args(MatrixSolve(A, v)) + + +def test_sympy__printing__rust__TypeCast(): + from sympy.printing.rust import TypeCast + from sympy.codegen.ast import real + assert _test_args(TypeCast(x, real)) + + +def test_sympy__printing__rust__float_floor(): + from sympy.printing.rust import float_floor + assert _test_args(float_floor(x)) + + +def test_sympy__printing__rust__float_ceiling(): + from sympy.printing.rust import float_ceiling + assert _test_args(float_ceiling(x)) + + +def test_sympy__vector__coordsysrect__CoordSys3D(): + from sympy.vector.coordsysrect import CoordSys3D + assert _test_args(CoordSys3D('C')) + + +def test_sympy__vector__point__Point(): + from sympy.vector.point import Point + assert _test_args(Point('P')) + + +def test_sympy__vector__basisdependent__BasisDependent(): + #from sympy.vector.basisdependent import BasisDependent + #These classes have been created to maintain an OOP hierarchy + #for Vectors and Dyadics. Are NOT meant to be initialized + pass + + +def test_sympy__vector__basisdependent__BasisDependentMul(): + #from sympy.vector.basisdependent import BasisDependentMul + #These classes have been created to maintain an OOP hierarchy + #for Vectors and Dyadics. Are NOT meant to be initialized + pass + + +def test_sympy__vector__basisdependent__BasisDependentAdd(): + #from sympy.vector.basisdependent import BasisDependentAdd + #These classes have been created to maintain an OOP hierarchy + #for Vectors and Dyadics. Are NOT meant to be initialized + pass + + +def test_sympy__vector__basisdependent__BasisDependentZero(): + #from sympy.vector.basisdependent import BasisDependentZero + #These classes have been created to maintain an OOP hierarchy + #for Vectors and Dyadics. Are NOT meant to be initialized + pass + + +def test_sympy__vector__vector__BaseVector(): + from sympy.vector.vector import BaseVector + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + assert _test_args(BaseVector(0, C, ' ', ' ')) + + +def test_sympy__vector__vector__VectorAdd(): + from sympy.vector.vector import VectorAdd, VectorMul + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + from sympy.abc import a, b, c, x, y, z + v1 = a*C.i + b*C.j + c*C.k + v2 = x*C.i + y*C.j + z*C.k + assert _test_args(VectorAdd(v1, v2)) + assert _test_args(VectorMul(x, v1)) + + +def test_sympy__vector__vector__VectorMul(): + from sympy.vector.vector import VectorMul + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + from sympy.abc import a + assert _test_args(VectorMul(a, C.i)) + + +def test_sympy__vector__vector__VectorZero(): + from sympy.vector.vector import VectorZero + assert _test_args(VectorZero()) + + +def test_sympy__vector__vector__Vector(): + #from sympy.vector.vector import Vector + #Vector is never to be initialized using args + pass + + +def test_sympy__vector__vector__Cross(): + from sympy.vector.vector import Cross + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + _test_args(Cross(C.i, C.j)) + + +def test_sympy__vector__vector__Dot(): + from sympy.vector.vector import Dot + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + _test_args(Dot(C.i, C.j)) + + +def test_sympy__vector__dyadic__Dyadic(): + #from sympy.vector.dyadic import Dyadic + #Dyadic is never to be initialized using args + pass + + +def test_sympy__vector__dyadic__BaseDyadic(): + from sympy.vector.dyadic import BaseDyadic + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + assert _test_args(BaseDyadic(C.i, C.j)) + + +def test_sympy__vector__dyadic__DyadicMul(): + from sympy.vector.dyadic import BaseDyadic, DyadicMul + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + assert _test_args(DyadicMul(3, BaseDyadic(C.i, C.j))) + + +def test_sympy__vector__dyadic__DyadicAdd(): + from sympy.vector.dyadic import BaseDyadic, DyadicAdd + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + assert _test_args(2 * DyadicAdd(BaseDyadic(C.i, C.i), + BaseDyadic(C.i, C.j))) + + +def test_sympy__vector__dyadic__DyadicZero(): + from sympy.vector.dyadic import DyadicZero + assert _test_args(DyadicZero()) + + +def test_sympy__vector__deloperator__Del(): + from sympy.vector.deloperator import Del + assert _test_args(Del()) + + +def test_sympy__vector__implicitregion__ImplicitRegion(): + from sympy.vector.implicitregion import ImplicitRegion + from sympy.abc import x, y + assert _test_args(ImplicitRegion((x, y), y**3 - 4*x)) + + +def test_sympy__vector__integrals__ParametricIntegral(): + from sympy.vector.integrals import ParametricIntegral + from sympy.vector.parametricregion import ParametricRegion + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + assert _test_args(ParametricIntegral(C.y*C.i - 10*C.j,\ + ParametricRegion((x, y), (x, 1, 3), (y, -2, 2)))) + +def test_sympy__vector__operators__Curl(): + from sympy.vector.operators import Curl + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + assert _test_args(Curl(C.i)) + + +def test_sympy__vector__operators__Laplacian(): + from sympy.vector.operators import Laplacian + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + assert _test_args(Laplacian(C.i)) + + +def test_sympy__vector__operators__Divergence(): + from sympy.vector.operators import Divergence + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + assert _test_args(Divergence(C.i)) + + +def test_sympy__vector__operators__Gradient(): + from sympy.vector.operators import Gradient + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + assert _test_args(Gradient(C.x)) + + +def test_sympy__vector__orienters__Orienter(): + #from sympy.vector.orienters import Orienter + #Not to be initialized + pass + + +def test_sympy__vector__orienters__ThreeAngleOrienter(): + #from sympy.vector.orienters import ThreeAngleOrienter + #Not to be initialized + pass + + +def test_sympy__vector__orienters__AxisOrienter(): + from sympy.vector.orienters import AxisOrienter + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + assert _test_args(AxisOrienter(x, C.i)) + + +def test_sympy__vector__orienters__BodyOrienter(): + from sympy.vector.orienters import BodyOrienter + assert _test_args(BodyOrienter(x, y, z, '123')) + + +def test_sympy__vector__orienters__SpaceOrienter(): + from sympy.vector.orienters import SpaceOrienter + assert _test_args(SpaceOrienter(x, y, z, '123')) + + +def test_sympy__vector__orienters__QuaternionOrienter(): + from sympy.vector.orienters import QuaternionOrienter + a, b, c, d = symbols('a b c d') + assert _test_args(QuaternionOrienter(a, b, c, d)) + + +def test_sympy__vector__parametricregion__ParametricRegion(): + from sympy.abc import t + from sympy.vector.parametricregion import ParametricRegion + assert _test_args(ParametricRegion((t, t**3), (t, 0, 2))) + + +def test_sympy__vector__scalar__BaseScalar(): + from sympy.vector.scalar import BaseScalar + from sympy.vector.coordsysrect import CoordSys3D + C = CoordSys3D('C') + assert _test_args(BaseScalar(0, C, ' ', ' ')) + + +def test_sympy__physics__wigner__Wigner3j(): + from sympy.physics.wigner import Wigner3j + assert _test_args(Wigner3j(0, 0, 0, 0, 0, 0)) + + +def test_sympy__combinatorics__schur_number__SchurNumber(): + from sympy.combinatorics.schur_number import SchurNumber + assert _test_args(SchurNumber(x)) + + +def test_sympy__combinatorics__perm_groups__SymmetricPermutationGroup(): + from sympy.combinatorics.perm_groups import SymmetricPermutationGroup + assert _test_args(SymmetricPermutationGroup(5)) + + +def test_sympy__combinatorics__perm_groups__Coset(): + from sympy.combinatorics.permutations import Permutation + from sympy.combinatorics.perm_groups import PermutationGroup, Coset + a = Permutation(1, 2) + b = Permutation(0, 1) + G = PermutationGroup([a, b]) + assert _test_args(Coset(a, G)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_arit.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_arit.py new file mode 100644 index 0000000000000000000000000000000000000000..251fc4c4234cbd6e82adc9a24ccea536ed6a37b7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_arit.py @@ -0,0 +1,2489 @@ +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.mod import Mod +from sympy.core.mul import Mul +from sympy.core.numbers import (Float, I, Integer, Rational, comp, nan, + oo, pi, zoo) +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol, symbols) +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.complexes import (im, re, sign) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.integers import floor +from sympy.functions.elementary.miscellaneous import (Max, sqrt) +from sympy.functions.elementary.trigonometric import (atan, cos, sin) +from sympy.integrals.integrals import Integral +from sympy.polys.polytools import Poly +from sympy.sets.sets import FiniteSet + +from sympy.core.parameters import distribute, evaluate +from sympy.core.expr import unchanged +from sympy.utilities.iterables import permutations +from sympy.testing.pytest import XFAIL, raises, warns +from sympy.utilities.exceptions import SymPyDeprecationWarning +from sympy.core.random import verify_numerically +from sympy.functions.elementary.trigonometric import asin + +from itertools import product + +a, c, x, y, z = symbols('a,c,x,y,z') +b = Symbol("b", positive=True) + + +def same_and_same_prec(a, b): + # stricter matching for Floats + return a == b and a._prec == b._prec + + +def test_bug1(): + assert re(x) != x + x.series(x, 0, 1) + assert re(x) != x + + +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 + + x = Symbol('x', complex=True, real=False) + assert x.is_imaginary is None # could be I or 1 + I + x = Symbol('x', complex=True, imaginary=False) + assert x.is_real is None # could be 1 or 1 + I + x = Symbol('x', real=True) + assert x.is_complex + x = Symbol('x', imaginary=True) + assert x.is_complex + x = Symbol('x', real=False, imaginary=False) + assert x.is_complex is None # might be a non-number + + +def test_arit0(): + p = Rational(5) + e = a*b + assert e == a*b + e = a*b + b*a + assert e == 2*a*b + 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 + 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 + assert e == 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) + assert e == Rational(0) + 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 + assert e == a*b**(-1) + e = a*2*2 + assert e == 4*a + e = 2 + a*2/2 + assert e == 2 + a + e = 2 - a - 2 + assert e == -a + e = 2*a*2 + assert e == 4*a + e = 2/a/2 + assert e == a**(-1) + e = 2**a**2 + assert e == 2**(a**2) + e = -(1 + a) + assert e == -1 - a + e = S.Half*(1 + a) + assert e == S.Half + a/2 + + +def test_div(): + 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) + + +def test_pow_arit(): + n1 = Rational(1) + n2 = Rational(2) + n5 = Rational(5) + e = a*a + assert e == a**2 + e = a*a*a + assert e == a**3 + e = a*a*a*a**Rational(6) + assert e == a**9 + e = a*a*a*a**Rational(6) - a**Rational(9) + assert e == Rational(0) + e = a**(b - b) + assert e == Rational(1) + 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) + + n = n5**(n1/n2) + assert n == sqrt(5) + e = n*a*b - n*b*a + assert e == Rational(0) + 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 + assert e == a*b**(-2) + + assert sqrt(2*(1 + sqrt(2))) == (2*(1 + 2**S.Half))**S.Half + + x = Symbol('x') + y = Symbol('y') + + assert ((x*y)**3).expand() == y**3 * x**3 + assert ((x*y)**-3).expand() == y**-3 * x**-3 + + 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() == x**2 * Rational(1, 27) + assert (x**5*(-3*x)**(-3)).expand() == x**2 * Rational(-1, 27) + + # expand_power_exp + _x = Symbol('x', zero=False) + _y = Symbol('y', zero=False) + 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('n', even=False) + k = Symbol('k', even=True) + o = Symbol('o', odd=True) + + assert unchanged(Pow, -1, x) + assert unchanged(Pow, -1, n) + assert (-2)**k == 2**k + assert (-1)**k == 1 + assert (-1)**o == -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)**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 sqrt(x**2) != x + + +def test_pow3(): + assert sqrt(2)**3 == 2 * sqrt(2) + assert sqrt(2)**3 == sqrt(8) + + +def test_mod_pow(): + for s, t, u, v in [(4, 13, 497, 445), (4, -3, 497, 365), + (3.2, 2.1, 1.9, 0.1031015682350942), (S(3)/2, 5, S(5)/6, S(3)/32)]: + assert pow(S(s), t, u) == v + assert pow(S(s), S(t), u) == v + assert pow(S(s), t, S(u)) == v + assert pow(S(s), S(t), S(u)) == v + assert pow(S(2), S(10000000000), S(3)) == 1 + assert pow(x, y, z) == x**y%z + raises(TypeError, lambda: pow(S(4), "13", 497)) + raises(TypeError, lambda: pow(S(4), 13, "497")) + + +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 verify_numerically(b**(1/(log(-b) + sign(i)*I*pi).n()), S.Exp1) + + +def test_pow_issue_3516(): + assert 4**Rational(1, 4) == sqrt(2) + + +def test_pow_im(): + for m in (-2, -1, 2): + for d in (3, 4, 5): + b = m*I + for i in range(1, 4*d + 1): + e = Rational(i, d) + 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 + im = symbols('im', imaginary=True) + assert (2*im*I)**e == 4*2**Rational(1, 3)*(I*im)**e + + args = [I, I, I, I, 2] + e = Rational(1, 3) + ans = 2**e + assert Mul(*args, evaluate=False)**e == ans + assert Mul(*args)**e == ans + args = [I, I, I, 2] + e = Rational(1, 3) + ans = 2**e*(-I)**e + assert Mul(*args, evaluate=False)**e == ans + assert Mul(*args)**e == ans + args.append(-3) + ans = (6*I)**e + assert Mul(*args, evaluate=False)**e == ans + assert Mul(*args)**e == ans + args.append(-1) + ans = (-6*I)**e + assert Mul(*args, evaluate=False)**e == ans + assert Mul(*args)**e == ans + + args = [I, I, 2] + e = Rational(1, 3) + ans = (-2)**e + assert Mul(*args, evaluate=False)**e == ans + assert Mul(*args)**e == ans + args.append(-3) + ans = (6)**e + assert Mul(*args, evaluate=False)**e == ans + assert Mul(*args)**e == ans + args.append(-1) + ans = (-6)**e + assert Mul(*args, 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)) == sqrt(I)*I + + +def test_real_mul(): + assert Float(0) * pi * x == 0 + assert set((Float(1) * pi * x).args) == {Float(1), pi, x} + + +def test_ncmul(): + A = Symbol("A", commutative=False) + B = Symbol("B", commutative=False) + C = Symbol("C", commutative=False) + assert A*B != B*A + assert A*B*C != C*B*A + assert A*b*B*3*C == 3*b*A*B*C + 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*A == A**2 + assert (A + B)*(A + B) == (A + B)**2 + + assert A**-1 * A == 1 + assert A/A == 1 + assert A/(A**2) == 1/A + + assert A/(1 + A) == A/(1 + A) + + assert set((A + B + 2*(A + B)).args) == \ + {A, B, 2*(A + B)} + + +def test_mul_add_identity(): + m = Mul(1, 2) + assert isinstance(m, Rational) and m.p == 2 and m.q == 1 + m = Mul(1, 2, evaluate=False) + assert isinstance(m, Mul) and m.args == (1, 2) + m = Mul(0, 1) + assert m is S.Zero + m = Mul(0, 1, evaluate=False) + assert isinstance(m, Mul) and m.args == (0, 1) + m = Add(0, 1) + assert m is S.One + m = Add(0, 1, evaluate=False) + assert isinstance(m, Add) and m.args == (0, 1) + + +def test_ncpow(): + x = Symbol('x', commutative=False) + y = Symbol('y', commutative=False) + z = Symbol('z', commutative=False) + a = Symbol('a') + b = Symbol('b') + c = Symbol('c') + + 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**(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 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") + assert x**1 != (-x)**1 + assert x**2 == (-x)**2 + assert x**3 != (-x)**3 + assert x**4 == (-x)**4 + assert x**5 != (-x)**5 + assert x**6 == (-x)**6 + + assert x**128 == (-x)**128 + assert x**129 != (-x)**129 + + assert (2*x)**2 == (-2*x)**2 + + +def test_Mul_doesnt_expand_exp(): + x = Symbol('x') + y = Symbol('y') + assert unchanged(Mul, exp(x), exp(y)) + assert unchanged(Mul, 2**x, 2**y) + assert x**2*x**3 == x**5 + assert 2**x*3**x == 6**x + 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 (x**(-log(5)/log(3))*x)/(x*x**( - log(5)/log(3))) == sympify(1) + + +def test_Mul_is_integer(): + k = Symbol('k', integer=True) + n = Symbol('n', integer=True) + nr = Symbol('nr', rational=False) + ir = Symbol('ir', irrational=True) + nz = Symbol('nz', integer=True, zero=False) + e = Symbol('e', even=True) + o = Symbol('o', odd=True) + i2 = Symbol('2', prime=True, even=True) + + assert (k/3).is_integer is None + assert (nz/3).is_integer is None + assert (nr/3).is_integer is False + assert (ir/3).is_integer is False + assert (x*k*n).is_integer is None + assert (e/2).is_integer is True + assert (e**2/2).is_integer is True + assert (2/k).is_integer is None + assert (2/k**2).is_integer is None + assert ((-1)**k*n).is_integer is True + assert (3*k*e/2).is_integer is True + assert (2*k*e/3).is_integer is None + assert (e/o).is_integer is None + assert (o/e).is_integer is False + assert (o/i2).is_integer is False + assert Mul(k, 1/k, evaluate=False).is_integer is None + assert Mul(2., S.Half, evaluate=False).is_integer is None + assert (2*sqrt(k)).is_integer is None + assert (2*k**n).is_integer is None + + s = 2**2**2**Pow(2, 1000, evaluate=False) + m = Mul(s, s, evaluate=False) + assert m.is_integer + + # broken in 1.6 and before, see #20161 + xq = Symbol('xq', rational=True) + yq = Symbol('yq', rational=True) + assert (xq*yq).is_integer is None + e_20161 = Mul(-1,Mul(1,Pow(2,-1,evaluate=False),evaluate=False),evaluate=False) + assert e_20161.is_integer is not True # expand(e_20161) -> -1/2, but no need to see that in the assumption without evaluation + + +def test_Add_Mul_is_integer(): + x = Symbol('x') + + k = Symbol('k', integer=True) + n = Symbol('n', integer=True) + nk = Symbol('nk', integer=False) + nr = Symbol('nr', rational=False) + nz = Symbol('nz', integer=True, zero=False) + + assert (-nk).is_integer is None + assert (-nr).is_integer is False + assert (2*k).is_integer is True + assert (-k).is_integer is True + + assert (k + nk).is_integer is False + 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 (k + nz/3).is_integer is None + assert (k + nr/3).is_integer is False + + 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 + + +def test_Add_Mul_is_finite(): + x = Symbol('x', extended_real=True, finite=False) + + assert sin(x).is_finite is True + assert (x*sin(x)).is_finite is None + assert (x*atan(x)).is_finite is False + assert (1024*sin(x)).is_finite is True + assert (sin(x)*exp(x)).is_finite is None + assert (sin(x)*cos(x)).is_finite is True + assert (x*sin(x)*exp(x)).is_finite is None + + assert (sin(x) - 67).is_finite is True + assert (sin(x) + exp(x)).is_finite is not True + assert (1 + x).is_finite is False + assert (1 + x**2 + (1 + x)*(1 - x)).is_finite is None + assert (sqrt(2)*(1 + x)).is_finite is False + assert (sqrt(2)*(1 + x)*(1 - x)).is_finite is False + + +def test_Mul_is_even_odd(): + x = Symbol('x', integer=True) + y = Symbol('y', integer=True) + + k = Symbol('k', odd=True) + n = Symbol('n', odd=True) + m = Symbol('m', even=True) + + 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 (2*m).is_even is True + assert (2*m).is_odd is False + + assert (-n).is_even is False + assert (-n).is_odd is True + + assert (k*n).is_even is False + assert (k*n).is_odd is True + + assert (k*m).is_even is True + assert (k*m).is_odd is False + + assert (k*n*m).is_even is True + assert (k*n*m).is_odd is False + + assert (k*m*x).is_even is True + assert (k*m*x).is_odd is False + + # issue 6791: + assert (x/2).is_integer is None + assert (k/2).is_integer is False + assert (m/2).is_integer is True + + assert (x*y).is_even is None + assert (x*x).is_even is None + assert (x*(x + k)).is_even is True + assert (x*(x + m)).is_even is None + + assert (x*y).is_odd is None + assert (x*x).is_odd is None + assert (x*(x + k)).is_odd is False + assert (x*(x + m)).is_odd is None + + # issue 8648 + assert (m**2/2).is_even + assert (m**2/3).is_even is False + assert (2/m**2).is_odd is False + assert (2/m).is_odd is None + + +@XFAIL +def test_evenness_in_ternary_integer_product_with_odd(): + # Tests that oddness inference is independent of term ordering. + # Term ordering at the point of testing depends on SymPy's symbol order, so + # we try to force a different order by modifying symbol names. + x = Symbol('x', integer=True) + y = Symbol('y', integer=True) + k = Symbol('k', odd=True) + assert (x*y*(y + k)).is_even is True + assert (y*x*(x + k)).is_even is True + + +def test_evenness_in_ternary_integer_product_with_even(): + x = Symbol('x', integer=True) + y = Symbol('y', integer=True) + m = Symbol('m', even=True) + assert (x*y*(y + m)).is_even is None + + +@XFAIL +def test_oddness_in_ternary_integer_product_with_odd(): + # Tests that oddness inference is independent of term ordering. + # Term ordering at the point of testing depends on SymPy's symbol order, so + # we try to force a different order by modifying symbol names. + x = Symbol('x', integer=True) + y = Symbol('y', integer=True) + k = Symbol('k', odd=True) + assert (x*y*(y + k)).is_odd is False + assert (y*x*(x + k)).is_odd is False + + +def test_oddness_in_ternary_integer_product_with_even(): + x = Symbol('x', integer=True) + y = Symbol('y', integer=True) + m = Symbol('m', even=True) + assert (x*y*(y + m)).is_odd is None + + +def test_Mul_is_rational(): + x = Symbol('x') + n = Symbol('n', integer=True) + m = Symbol('m', integer=True, nonzero=True) + + assert (n/m).is_rational is True + assert (x/pi).is_rational is None + assert (x/n).is_rational is None + assert (m/pi).is_rational is False + + r = Symbol('r', rational=True) + assert (pi*r).is_rational is None + + # issue 8008 + z = Symbol('z', zero=True) + i = Symbol('i', imaginary=True) + assert (z*i).is_rational is True + bi = Symbol('i', imaginary=True, finite=True) + assert (z*bi).is_zero is True + + +def test_Add_is_rational(): + x = Symbol('x') + n = Symbol('n', rational=True) + m = Symbol('m', rational=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) + + k = Symbol('k', odd=True) + n = Symbol('n', odd=True) + m = Symbol('m', even=True) + + 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 - 12).is_even is False + assert (k - 12).is_odd is True + + assert (-k - 12).is_even is False + assert (-k - 12).is_odd is True + + assert (k + n).is_even is True + assert (k + n).is_odd is False + + assert (k + m).is_even is False + assert (k + m).is_odd is True + + assert (k + n + m).is_even is True + assert (k + n + m).is_odd is False + + assert (k + n + x + m).is_even is None + assert (k + n + x + m).is_odd is None + + +def test_Mul_is_negative_positive(): + x = Symbol('x', real=True) + y = Symbol('y', extended_real=False, complex=True) + z = Symbol('z', zero=True) + + e = 2*z + assert e.is_Mul and e.is_positive is False and e.is_negative is False + + neg = Symbol('neg', negative=True) + pos = Symbol('pos', positive=True) + nneg = Symbol('nneg', nonnegative=True) + npos = Symbol('npos', nonpositive=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_extended_negative() is False + assert (2*pos).is_negative is False + + assert pos.is_negative is False + assert (-pos).is_negative is True + assert (2*pos).is_negative is 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 nneg.is_negative is False + assert (-nneg).is_negative is None + assert (2*nneg).is_negative is False + + assert npos.is_negative is None + assert (-npos).is_negative is False + assert (2*npos).is_negative is None + + assert (nneg*npos).is_negative is None + + assert (neg*nneg).is_negative is None + assert (neg*npos).is_negative is False + + assert (pos*nneg).is_negative is False + assert (pos*npos).is_negative is None + + assert (npos*neg*nneg).is_negative is False + assert (npos*pos*nneg).is_negative is None + + assert (-npos*neg*nneg).is_negative is None + assert (-npos*pos*nneg).is_negative is False + + assert (17*npos*neg*nneg).is_negative is False + assert (17*npos*pos*nneg).is_negative is None + + assert (neg*npos*pos*nneg).is_negative is False + + assert (x*neg).is_negative is None + assert (nneg*npos*pos*x*neg).is_negative is None + + assert neg.is_positive is False + assert (-neg).is_positive is True + assert (2*neg).is_positive is False + + assert pos.is_positive is True + assert (-pos).is_positive is False + assert (2*pos).is_positive is 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 nneg.is_positive is None + assert (-nneg).is_positive is False + assert (2*nneg).is_positive is None + + assert npos.is_positive is False + assert (-npos).is_positive is None + assert (2*npos).is_positive is False + + assert (nneg*npos).is_positive is False + + assert (neg*nneg).is_positive is False + assert (neg*npos).is_positive is None + + assert (pos*nneg).is_positive is None + assert (pos*npos).is_positive is False + + assert (npos*neg*nneg).is_positive is None + assert (npos*pos*nneg).is_positive is False + + assert (-npos*neg*nneg).is_positive is False + assert (-npos*pos*nneg).is_positive is None + + assert (17*npos*neg*nneg).is_positive is None + assert (17*npos*pos*nneg).is_positive is False + + assert (neg*npos*pos*nneg).is_positive is None + + assert (x*neg).is_positive is None + assert (nneg*npos*pos*x*neg).is_positive is None + + +def test_Mul_is_negative_positive_2(): + a = Symbol('a', nonnegative=True) + b = Symbol('b', nonnegative=True) + c = Symbol('c', nonpositive=True) + d = Symbol('d', nonpositive=True) + + 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(): + x = Symbol('x', real=True) + + k = Symbol('k', negative=True) + n = Symbol('n', positive=True) + u = Symbol('u', nonnegative=True) + v = Symbol('v', 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 is False + assert (-n).is_nonpositive is True + assert (2*n).is_nonpositive is 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 is None + assert (-u).is_nonpositive is True + assert (2*u).is_nonpositive is None + + assert v.is_nonpositive is True + assert (-v).is_nonpositive is None + assert (2*v).is_nonpositive is True + + assert (u*v).is_nonpositive is True + + assert (k*u).is_nonpositive is True + assert (k*v).is_nonpositive is None + + assert (n*u).is_nonpositive is None + assert (n*v).is_nonpositive is True + + assert (v*k*u).is_nonpositive is None + assert (v*n*u).is_nonpositive is True + + assert (-v*k*u).is_nonpositive is True + assert (-v*n*u).is_nonpositive is None + + 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 is None + + assert (x*k).is_nonpositive is None + assert (u*v*n*x*k).is_nonpositive is None + + assert k.is_nonnegative is False + assert (-k).is_nonnegative is True + assert (2*k).is_nonnegative is False + + assert n.is_nonnegative is True + assert (-n).is_nonnegative is False + assert (2*n).is_nonnegative is 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 is True + assert (-u).is_nonnegative is None + assert (2*u).is_nonnegative is True + + assert v.is_nonnegative is None + assert (-v).is_nonnegative is True + assert (2*v).is_nonnegative is None + + assert (u*v).is_nonnegative is None + + assert (k*u).is_nonnegative is None + assert (k*v).is_nonnegative is True + + assert (n*u).is_nonnegative is True + assert (n*v).is_nonnegative is None + + assert (v*k*u).is_nonnegative is True + assert (v*n*u).is_nonnegative is None + + assert (-v*k*u).is_nonnegative is None + assert (-v*n*u).is_nonnegative is True + + 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 is True + + assert (x*k).is_nonnegative is None + assert (u*v*n*x*k).is_nonnegative is None + + +def test_Add_is_negative_positive(): + x = Symbol('x', real=True) + + k = Symbol('k', negative=True) + n = Symbol('n', positive=True) + u = Symbol('u', nonnegative=True) + v = Symbol('v', nonpositive=True) + + 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 + + z = (-3 - sqrt(5) + (-sqrt(10)/2 - sqrt(2)/2)**2) + assert z.is_zero + z = sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3)) - sqrt(10 + 6*sqrt(3)) + assert z.is_zero + + +def test_Add_is_nonpositive_nonnegative(): + x = Symbol('x', real=True) + + k = Symbol('k', negative=True) + n = Symbol('n', positive=True) + u = Symbol('u', nonnegative=True) + v = Symbol('v', nonpositive=True) + + 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 + + +def test_Pow_is_integer(): + x = Symbol('x') + + k = Symbol('k', integer=True) + n = Symbol('n', integer=True, nonnegative=True) + m = Symbol('m', integer=True, positive=True) + + assert (k**2).is_integer is True + assert (k**(-2)).is_integer is None + assert ((m + 1)**(-2)).is_integer is False + assert (m**(-1)).is_integer is None # issue 8580 + + assert (2**k).is_integer is None + assert (2**(-k)).is_integer is None + + assert (2**n).is_integer is True + assert (2**(-n)).is_integer is None + + assert (2**m).is_integer is True + assert (2**(-m)).is_integer is False + + assert (x**2).is_integer is None + assert (2**x).is_integer is None + + assert (k**n).is_integer is True + assert (k**(-n)).is_integer is None + + assert (k**x).is_integer is None + assert (x**k).is_integer is 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 + assert Pow(3, 2, evaluate=False).is_integer is True + assert Pow(3, 0, evaluate=False).is_integer is True + assert Pow(3, -2, evaluate=False).is_integer is False + assert Pow(S.Half, 3, evaluate=False).is_integer is False + # decided by re-evaluating + assert Pow(3, S.Half, evaluate=False).is_integer is False + assert Pow(3, S.Half, evaluate=False).is_integer is False + assert Pow(4, S.Half, evaluate=False).is_integer is True + assert Pow(S.Half, -2, evaluate=False).is_integer is True + + assert ((-1)**k).is_integer + + # issue 8641 + x = Symbol('x', real=True, integer=False) + assert (x**2).is_integer is None + + # issue 10458 + x = Symbol('x', positive=True) + assert (1/(x + 1)).is_integer is False + assert (1/(-x - 1)).is_integer is False + assert (-1/(x + 1)).is_integer is False + # issue 23287 + assert (x**2/2).is_integer is None + + # issue 8648-like + k = Symbol('k', even=True) + assert (k**3/2).is_integer + assert (k**3/8).is_integer + assert (k**3/16).is_integer is None + assert (2/k).is_integer is None + assert (2/k**2).is_integer is False + o = Symbol('o', odd=True) + assert (k/o).is_integer is None + o = Symbol('o', odd=True, prime=True) + assert (k/o).is_integer is False + + +def test_Pow_is_real(): + x = Symbol('x', real=True) + y = Symbol('y', positive=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 is None + assert (y**Rational(1, 3)).is_real is True + + 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_extended_real is True + assert ((-I)**i).is_extended_real is True + 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_extended_real is True + assert (i**3).is_extended_real is False + 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) + assert (i**e).is_extended_real is True + assert (i**o).is_extended_real is False + assert (i**k).is_real is None + assert (i**(4*k)).is_extended_real is True + + x = Symbol("x", nonnegative=True) + y = Symbol("y", nonnegative=True) + assert im(x**y).expand(complex=True) is S.Zero + assert (x**y).is_real is True + i = Symbol('i', imaginary=True) + assert (exp(i)**I).is_extended_real is True + assert log(exp(i)).is_imaginary is None # i could be 2*pi*I + c = Symbol('c', complex=True) + assert log(c).is_real is None # c could be 0 or 2, too + assert log(exp(c)).is_real is None # log(0), log(E), ... + n = Symbol('n', negative=False) + assert log(n).is_real is None + n = Symbol('n', nonnegative=True) + assert log(n).is_real is None + + assert sqrt(-I).is_real is False # issue 7843 + + i = Symbol('i', integer=True) + assert (1/(i-1)).is_real is None + assert (1/(i-1)).is_extended_real is None + + # test issue 20715 + from sympy.core.parameters import evaluate + x = S(-1) + with evaluate(False): + assert x.is_negative is True + + f = Pow(x, -1) + with evaluate(False): + assert f.is_imaginary is False + + +def test_real_Pow(): + k = Symbol('k', integer=True, nonzero=True) + assert (k**(I*pi/log(k))).is_real + + +def test_Pow_is_finite(): + xe = Symbol('xe', extended_real=True) + xr = Symbol('xr', real=True) + p = Symbol('p', positive=True) + n = Symbol('n', negative=True) + i = Symbol('i', integer=True) + + assert (xe**2).is_finite is None # xe could be oo + assert (xr**2).is_finite is True + + assert (xe**xe).is_finite is None + assert (xr**xe).is_finite is None + assert (xe**xr).is_finite is None + # FIXME: The line below should be True rather than None + # assert (xr**xr).is_finite is True + assert (xr**xr).is_finite is None + + assert (p**xe).is_finite is None + assert (p**xr).is_finite is True + + assert (n**xe).is_finite is None + assert (n**xr).is_finite is True + + assert (sin(xe)**2).is_finite is True + assert (sin(xr)**2).is_finite is True + + assert (sin(xe)**xe).is_finite is None # xe, xr could be -pi + assert (sin(xr)**xr).is_finite is None + + # FIXME: Should the line below be True rather than None? + assert (sin(xe)**exp(xe)).is_finite is None + assert (sin(xr)**exp(xr)).is_finite is True + + assert (1/sin(xe)).is_finite is None # if zero, no, otherwise yes + assert (1/sin(xr)).is_finite is None + + assert (1/exp(xe)).is_finite is None # xe could be -oo + assert (1/exp(xr)).is_finite is True + + assert (1/S.Pi).is_finite is True + + assert (1/(i-1)).is_finite is None + + +def test_Pow_is_even_odd(): + x = Symbol('x') + + k = Symbol('k', even=True) + n = Symbol('n', odd=True) + m = Symbol('m', integer=True, nonnegative=True) + p = Symbol('p', integer=True, positive=True) + + assert ((-1)**n).is_odd + assert ((-1)**k).is_odd + assert ((-1)**(m - p)).is_odd + + 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**p).is_even is True + assert (n**p).is_even is False + + assert (m**k).is_even is None + assert (p**k).is_even is None + + assert (m**n).is_even is None + assert (p**n).is_even is None + + assert (k**x).is_even is None + assert (n**x).is_even is None + + assert (k**2).is_odd is False + assert (n**2).is_odd is True + assert (3**k).is_odd is None + + assert (k**m).is_odd is None + assert (n**m).is_odd is True + + assert (k**p).is_odd is False + assert (n**p).is_odd is True + + assert (m**k).is_odd is None + assert (p**k).is_odd is None + + assert (m**n).is_odd is None + assert (p**n).is_odd is None + + assert (k**x).is_odd is None + assert (n**x).is_odd is None + + +def test_Pow_is_negative_positive(): + r = Symbol('r', real=True) + + k = Symbol('k', integer=True, positive=True) + n = Symbol('n', even=True) + m = Symbol('m', odd=True) + + x = Symbol('x') + + assert (2**r).is_positive is True + assert ((-2)**r).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**r).is_positive is True + assert ((-k)**r).is_positive is None + assert ((-k)**n).is_positive is True + assert ((-k)**m).is_positive is False + + assert (2**r).is_negative is False + assert ((-2)**r).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**r).is_negative is False + assert ((-k)**r).is_negative is None + assert ((-k)**n).is_negative is False + assert ((-k)**m).is_negative is True + + assert (2**x).is_positive is None + assert (2**x).is_negative is None + + +def test_Pow_is_zero(): + z = Symbol('z', zero=True) + e = z**2 + assert e.is_zero + assert e.is_positive is False + assert e.is_negative is False + + assert Pow(0, 0, evaluate=False).is_zero is False + assert Pow(0, 3, evaluate=False).is_zero + assert Pow(0, oo, evaluate=False).is_zero + assert Pow(0, -3, evaluate=False).is_zero is False + assert Pow(0, -oo, evaluate=False).is_zero is False + assert Pow(2, 2, evaluate=False).is_zero is False + + a = Symbol('a', zero=False) + assert Pow(a, 3).is_zero is False # issue 7965 + + assert Pow(2, oo, evaluate=False).is_zero is False + assert Pow(2, -oo, evaluate=False).is_zero + assert Pow(S.Half, oo, evaluate=False).is_zero + assert Pow(S.Half, -oo, evaluate=False).is_zero is False + + # All combinations of real/complex base/exponent + h = S.Half + T = True + F = False + N = None + + pow_iszero = [ + ['**', 0, h, 1, 2, -h, -1,-2,-2*I,-I/2,I/2,1+I,oo,-oo,zoo], + [ 0, F, T, T, T, F, F, F, F, F, F, N, T, F, N], + [ h, F, F, F, F, F, F, F, F, F, F, F, T, F, N], + [ 1, F, F, F, F, F, F, F, F, F, F, F, F, F, N], + [ 2, F, F, F, F, F, F, F, F, F, F, F, F, T, N], + [ -h, F, F, F, F, F, F, F, F, F, F, F, T, F, N], + [ -1, F, F, F, F, F, F, F, F, F, F, F, F, F, N], + [ -2, F, F, F, F, F, F, F, F, F, F, F, F, T, N], + [-2*I, F, F, F, F, F, F, F, F, F, F, F, F, T, N], + [-I/2, F, F, F, F, F, F, F, F, F, F, F, T, F, N], + [ I/2, F, F, F, F, F, F, F, F, F, F, F, T, F, N], + [ 1+I, F, F, F, F, F, F, F, F, F, F, F, F, T, N], + [ oo, F, F, F, F, T, T, T, F, F, F, F, F, T, N], + [ -oo, F, F, F, F, T, T, T, F, F, F, F, F, T, N], + [ zoo, F, F, F, F, T, T, T, N, N, N, N, F, T, N] + ] + + def test_table(table): + n = len(table[0]) + for row in range(1, n): + base = table[row][0] + for col in range(1, n): + exp = table[0][col] + is_zero = table[row][col] + # The actual test here: + assert Pow(base, exp, evaluate=False).is_zero is is_zero + + test_table(pow_iszero) + + # A zero symbol... + zo, zo2 = symbols('zo, zo2', zero=True) + + # All combinations of finite symbols + zf, zf2 = symbols('zf, zf2', finite=True) + wf, wf2 = symbols('wf, wf2', nonzero=True) + xf, xf2 = symbols('xf, xf2', real=True) + yf, yf2 = symbols('yf, yf2', nonzero=True) + af, af2 = symbols('af, af2', positive=True) + bf, bf2 = symbols('bf, bf2', nonnegative=True) + cf, cf2 = symbols('cf, cf2', negative=True) + df, df2 = symbols('df, df2', nonpositive=True) + + # Without finiteness: + zi, zi2 = symbols('zi, zi2') + wi, wi2 = symbols('wi, wi2', zero=False) + xi, xi2 = symbols('xi, xi2', extended_real=True) + yi, yi2 = symbols('yi, yi2', zero=False, extended_real=True) + ai, ai2 = symbols('ai, ai2', extended_positive=True) + bi, bi2 = symbols('bi, bi2', extended_nonnegative=True) + ci, ci2 = symbols('ci, ci2', extended_negative=True) + di, di2 = symbols('di, di2', extended_nonpositive=True) + + pow_iszero_sym = [ + ['**',zo,wf,yf,af,cf,zf,xf,bf,df,zi,wi,xi,yi,ai,bi,ci,di], + [ zo2, F, N, N, T, F, N, N, N, F, N, N, N, N, T, N, F, F], + [ wf2, F, F, F, F, F, F, F, F, F, N, N, N, N, N, N, N, N], + [ yf2, F, F, F, F, F, F, F, F, F, N, N, N, N, N, N, N, N], + [ af2, F, F, F, F, F, F, F, F, F, N, N, N, N, N, N, N, N], + [ cf2, F, F, F, F, F, F, F, F, F, N, N, N, N, N, N, N, N], + [ zf2, N, N, N, N, F, N, N, N, N, N, N, N, N, N, N, N, N], + [ xf2, N, N, N, N, F, N, N, N, N, N, N, N, N, N, N, N, N], + [ bf2, N, N, N, N, F, N, N, N, N, N, N, N, N, N, N, N, N], + [ df2, N, N, N, N, F, N, N, N, N, N, N, N, N, N, N, N, N], + [ zi2, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N], + [ wi2, F, N, N, F, N, N, N, F, N, N, N, N, N, N, N, N, N], + [ xi2, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N], + [ yi2, F, N, N, F, N, N, N, F, N, N, N, N, N, N, N, N, N], + [ ai2, F, N, N, F, N, N, N, F, N, N, N, N, N, N, N, N, N], + [ bi2, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N], + [ ci2, F, N, N, F, N, N, N, F, N, N, N, N, N, N, N, N, N], + [ di2, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N] + ] + + test_table(pow_iszero_sym) + + # In some cases (x**x).is_zero is different from (x**y).is_zero even if y + # has the same assumptions as x. + assert (zo ** zo).is_zero is False + assert (wf ** wf).is_zero is False + assert (yf ** yf).is_zero is False + assert (af ** af).is_zero is False + assert (cf ** cf).is_zero is False + assert (zf ** zf).is_zero is None + assert (xf ** xf).is_zero is None + assert (bf ** bf).is_zero is False # None in table + assert (df ** df).is_zero is None + assert (zi ** zi).is_zero is None + assert (wi ** wi).is_zero is None + assert (xi ** xi).is_zero is None + assert (yi ** yi).is_zero is None + assert (ai ** ai).is_zero is False # None in table + assert (bi ** bi).is_zero is False # None in table + assert (ci ** ci).is_zero is None + assert (di ** di).is_zero is None + + +def test_Pow_is_nonpositive_nonnegative(): + x = Symbol('x', real=True) + + k = Symbol('k', integer=True, nonnegative=True) + l = Symbol('l', integer=True, positive=True) + n = Symbol('n', even=True) + m = Symbol('m', odd=True) + + assert (x**(4*k)).is_nonnegative is 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 None + assert (k**k).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)**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 (x**2).is_nonnegative is True + i = symbols('i', imaginary=True) + assert (i**2).is_nonpositive is True + assert (i**4).is_nonpositive is False + assert (i**3).is_nonpositive is False + assert (I**i).is_nonnegative is True + assert (exp(I)**i).is_nonnegative is True + + assert ((-l)**n).is_nonnegative is True + assert ((-l)**m).is_nonpositive is True + assert ((-k)**n).is_nonnegative is None + assert ((-k)**m).is_nonpositive is None + + +def test_Mul_is_imaginary_real(): + r = Symbol('r', real=True) + p = Symbol('p', positive=True) + i1 = Symbol('i1', imaginary=True) + i2 = Symbol('i2', imaginary=True) + x = Symbol('x') + + 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 + + e = (p + p*I) + j = Symbol('j', integer=True, zero=False) + assert (e**j).is_real is None + assert (e**(2*j)).is_real is None + assert (e**j).is_imaginary is None + assert (e**(2*j)).is_imaginary is None + + assert (e**-1).is_imaginary is False + assert (e**2).is_imaginary + assert (e**3).is_imaginary is False + assert (e**4).is_imaginary is False + assert (e**5).is_imaginary is False + assert (e**-1).is_real is False + assert (e**2).is_real is False + assert (e**3).is_real is False + assert (e**4).is_real is True + assert (e**5).is_real is False + assert (e**3).is_complex + + assert (r*i1).is_imaginary is None + assert (r*i1).is_real is None + + assert (x*i1).is_imaginary is None + assert (x*i1).is_real is None + + assert (i1*i2).is_imaginary is False + assert (i1*i2).is_real is True + + assert (r*i1*i2).is_imaginary is False + assert (r*i1*i2).is_real is True + + # Github's issue 5874: + nr = Symbol('nr', real=False, complex=True) # e.g. I or 1 + I + a = Symbol('a', real=True, nonzero=True) + b = Symbol('b', real=True) + assert (i1*nr).is_real is None + assert (a*nr).is_real is False + assert (b*nr).is_real is None + + ni = Symbol('ni', imaginary=False, complex=True) # e.g. 2 or 1 + I + a = Symbol('a', real=True, nonzero=True) + b = Symbol('b', real=True) + assert (i1*ni).is_real is False + assert (a*ni).is_real is None + assert (b*ni).is_real is None + + +def test_Mul_hermitian_antihermitian(): + xz, yz = symbols('xz, yz', zero=True, antihermitian=True) + xf, yf = symbols('xf, yf', hermitian=False, antihermitian=False, finite=True) + xh, yh = symbols('xh, yh', hermitian=True, antihermitian=False, nonzero=True) + xa, ya = symbols('xa, ya', hermitian=False, antihermitian=True, zero=False, finite=True) + assert (xz*xh).is_hermitian is True + assert (xz*xh).is_antihermitian is True + assert (xz*xa).is_hermitian is True + assert (xz*xa).is_antihermitian is True + assert (xf*yf).is_hermitian is None + assert (xf*yf).is_antihermitian is None + assert (xh*yh).is_hermitian is True + assert (xh*yh).is_antihermitian is False + assert (xh*ya).is_hermitian is False + assert (xh*ya).is_antihermitian is True + assert (xa*ya).is_hermitian is True + assert (xa*ya).is_antihermitian is False + + a = Symbol('a', hermitian=True, zero=False) + b = Symbol('b', hermitian=True) + c = Symbol('c', hermitian=False) + d = Symbol('d', antihermitian=True) + e1 = Mul(a, b, c, evaluate=False) + e2 = Mul(b, a, c, evaluate=False) + e3 = Mul(a, b, c, d, evaluate=False) + e4 = Mul(b, a, c, d, evaluate=False) + e5 = Mul(a, c, evaluate=False) + e6 = Mul(a, c, d, evaluate=False) + assert e1.is_hermitian is None + assert e2.is_hermitian is None + assert e1.is_antihermitian is None + assert e2.is_antihermitian is None + assert e3.is_antihermitian is None + assert e4.is_antihermitian is None + assert e5.is_antihermitian is None + assert e6.is_antihermitian is None + + +def test_Add_is_comparable(): + 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 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 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 is False + assert e.is_negative is True + + e = pi - 1 + 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 is True + assert i.is_rational is False + + assert (i + 1).is_irrational is True + assert (i + 1).is_rational is False + + +def test_Mul_is_irrational(): + expr = Mul(1, 2, 3, evaluate=False) + assert expr.is_irrational is False + expr = Mul(1, I, I, evaluate=False) + assert expr.is_rational is None # I * I = -1 but *no evaluation allowed* + # sqrt(2) * I * I = -sqrt(2) is irrational but + # this can't be determined without evaluating the + # expression and the eval_is routines shouldn't do that + expr = Mul(sqrt(2), I, I, evaluate=False) + assert expr.is_irrational is None + + +def test_issue_3531(): + # https://github.com/sympy/sympy/issues/3531 + # https://github.com/sympy/sympy/pull/18116 + class MightyNumeric(tuple): + __slots__ = () + + def __rtruediv__(self, other): + return "something" + + assert sympify(1)/MightyNumeric((1, 2)) == "something" + + +def test_issue_3531b(): + 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) + e = 2*a + b + 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) + assert a != 6 + assert a.func is Add + assert a.args == (0, 3, 2) + assert b != 6 + assert b.func is Mul + assert b.args == (1, 3, 2) + assert c != 9 + assert c.func is Pow + assert c.args == (3, 2) + + +def test_AssocOp_doit(): + a = Add(x,x, evaluate=False) + b = Mul(y,y, evaluate=False) + c = Add(b,b, evaluate=False) + d = Mul(a,a, evaluate=False) + assert c.doit(deep=False).func == Mul + assert c.doit(deep=False).args == (2,y,y) + assert c.doit().func == Mul + assert c.doit().args == (2, Pow(y,2)) + assert d.doit(deep=False).func == Pow + assert d.doit(deep=False).args == (a, 2*S.One) + assert d.doit().func == Mul + assert d.doit().args == (4*S.One, Pow(x,2)) + + +def test_Add_Mul_Expr_args(): + nonexpr = [Basic(), Poly(x, x), FiniteSet(x)] + for typ in [Add, Mul]: + for obj in nonexpr: + # The cache can mess with the stacklevel check + with warns(SymPyDeprecationWarning, test_stacklevel=False): + typ(obj, 1) + + +def test_Add_as_coeff_mul(): + # issue 5524. 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,)) + + 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,)) + + +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_issue_24751(): + expr = Add(-2, -3, evaluate=False) + expr1 = Add(-1, expr, evaluate=False) + assert int(expr1) == int((-3 - 2) - 1) + + +def test_issue_3514_18626(): + assert sqrt(S.Half) * sqrt(6) == 2 * sqrt(3)/2 + assert S.Half*sqrt(6)*sqrt(2) == sqrt(3) + assert sqrt(6)/2*sqrt(2) == sqrt(3) + assert sqrt(6)*sqrt(2)/2 == sqrt(3) + assert sqrt(8)**Rational(2, 3) == 2 + + +def test_make_args(): + assert Add.make_args(x) == (x,) + assert Mul.make_args(x) == (x,) + + 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,) + assert Mul.make_args((x + y)**z) == ((x + y)**z,) + + +def test_issue_5126(): + 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.One, S.Zero + assert (c*p).as_content_primitive() == (c, p) + c, p = S.Half, S.One + assert (c*p).as_content_primitive() == (c, p) + + +def test_Add_as_content_primitive(): + assert (x + 2).as_content_primitive() == (1, x + 2) + + assert (3*x + 2).as_content_primitive() == (1, 3*x + 2) + assert (3*x + 3).as_content_primitive() == (3, x + 1) + assert (3*x + 6).as_content_primitive() == (3, x + 2) + + assert (3*x + 2*y).as_content_primitive() == (1, 3*x + 2*y) + assert (3*x + 3*y).as_content_primitive() == (3, x + y) + assert (3*x + 6*y).as_content_primitive() == (3, x + 2*y) + + assert (3/x + 2*x*y*z**2).as_content_primitive() == (1, 3/x + 2*x*y*z**2) + 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) + + # the coefficient may sort to a position other than 0 + p = 3 + x + y + assert (2*p).expand().as_content_primitive() == (2, p) + assert (2.0*p).expand().as_content_primitive() == (1, 2.*p) + 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) + + +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)**3).as_content_primitive() == (8, (x + 1)**3) + + +def test_issue_5460(): + u = Mul(2, (1 + x), evaluate=False) + assert (2 + u).args == (2, u) + + +def test_product_irrational(): + assert (I*pi).is_irrational is False + # The following used to be deduced from the above bug: + assert (I*pi).is_positive is False + + +def test_issue_5919(): + assert (x/(y*(1 + y))).expand() == x/(y**2 + y) + + +def test_Mod(): + assert Mod(x, 1).func is Mod + assert pi % pi is S.Zero + assert Mod(5, 3) == 2 + assert Mod(-5, 3) == 1 + assert Mod(5, -3) == -1 + assert Mod(-5, -3) == -2 + assert type(Mod(3.2, 2, evaluate=False)) == Mod + assert 5 % x == Mod(5, x) + assert x % 5 == Mod(x, 5) + assert x % y == Mod(x, y) + assert (x % y).subs({x: 5, y: 3}) == 2 + assert Mod(nan, 1) is nan + assert Mod(1, nan) is nan + assert Mod(nan, nan) is nan + + assert Mod(0, x) == 0 + with raises(ZeroDivisionError): + Mod(x, 0) + + k = Symbol('k', integer=True) + m = Symbol('m', integer=True, positive=True) + assert (x**m % x).func is Mod + assert (k**(-m) % k).func is Mod + assert k**m % k == 0 + assert (-2*k)**m % k == 0 + + # 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 comp(e, .3) and e.is_Float + e = Mod(1.3, .7) + assert comp(e, .6) and e.is_Float + e = Mod(1.3, Rational(7, 10)) + assert comp(e, .6) and e.is_Float + e = Mod(Rational(13, 10), 0.7) + assert comp(e, .6) and e.is_Float + e = Mod(Rational(13, 10), Rational(7, 10)) + assert comp(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 verify_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 + t = Symbol('t', real=True) + assert Mod(Mod(x, t), t) == Mod(x, t) + assert Mod(-Mod(x, t), t) == Mod(-x, t) + assert Mod(Mod(x, 2*t), t) == Mod(x, t) + assert Mod(-Mod(x, 2*t), t) == Mod(-x, t) + assert Mod(Mod(x, t), 2*t) == Mod(x, t) + assert Mod(-Mod(x, t), -2*t) == -Mod(x, t) + for i in [-4, -2, 2, 4]: + for j in [-4, -2, 2, 4]: + for k in range(4): + assert Mod(Mod(x, i), j).subs({x: k}) == (k % i) % j + assert Mod(-Mod(x, i), j).subs({x: k}) == -(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(2, p + 3) == 2 + assert Mod(-2, p + 3) == p + 1 + assert Mod(2, -p - 3) == -p - 1 + assert Mod(-2, -p - 3) == -2 + assert Mod(p + 5, p + 3) == 2 + assert Mod(-p - 5, p + 3) == p + 1 + assert Mod(p + 5, -p - 3) == -p - 1 + assert Mod(-p - 5, -p - 3) == -2 + assert Mod(p + 1, p - 1).func is Mod + + # issue 27749 + n = symbols('n', integer=True, positive=True) + assert unchanged(Mod, 1, n) + n = symbols('n', prime=True) + assert Mod(1, n) == 1 + + # 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) + + a = Mod(.6*x + y, .3*y) + b = Mod(0.1*y + 0.6*x, 0.3*y) + # Test that a, b are equal, with 1e-14 accuracy in coefficients + eps = 1e-14 + assert abs((a.args[0] - b.args[0]).subs({x: 1, y: 1})) < eps + assert abs((a.args[1] - b.args[1]).subs({x: 1, y: 1})) < eps + + 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) == 0.3*pi*Mod(20, 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) + assert Mod(4*i, 4) == 0 + + # issue 8677 + n = Symbol('n', integer=True, positive=True) + assert factorial(n) % n == 0 + assert factorial(n + 2) % n == 0 + assert (factorial(n + 4) % (n + 5)).func is Mod + + # Wilson's theorem + assert factorial(18042, evaluate=False) % 18043 == 18042 + p = Symbol('n', prime=True) + assert factorial(p - 1) % p == p - 1 + assert factorial(p - 1) % -p == -1 + assert (factorial(3, evaluate=False) % 4).doit() == 2 + n = Symbol('n', composite=True, odd=True) + assert factorial(n - 1) % n == 0 + + # symbolic with known parity + n = Symbol('n', even=True) + assert Mod(n, 2) == 0 + n = Symbol('n', odd=True) + assert Mod(n, 2) == 1 + + # issue 10963 + assert (x**6000%400).args[1] == 400 + + #issue 13543 + assert Mod(Mod(x + 1, 2) + 1, 2) == Mod(x, 2) + + x1 = Symbol('x1', integer=True) + assert Mod(Mod(x1 + 2, 4)*(x1 + 4), 4) == Mod(x1*(x1 + 2), 4) + assert Mod(Mod(x1 + 2, 4)*4, 4) == 0 + + # issue 15493 + i, j = symbols('i j', integer=True, positive=True) + assert Mod(3*i, 2) == Mod(i, 2) + assert Mod(8*i/j, 4) == 4*Mod(2*i/j, 1) + assert Mod(8*i, 4) == 0 + + # rewrite + assert Mod(x, y).rewrite(floor) == x - y*floor(x/y) + assert ((x - Mod(x, y))/y).rewrite(floor) == floor(x/y) + + # issue 21373 + from sympy.functions.elementary.hyperbolic import sinh + from sympy.functions.elementary.piecewise import Piecewise + + x_r, y_r = symbols('x_r y_r', real=True) + assert (Piecewise((x_r, y_r > x_r), (y_r, True)) / z) % 1 + expr = exp(sinh(Piecewise((x_r, y_r > x_r), (y_r, True)) / z)) + expr.subs({1: 1.0}) + sinh(Piecewise((x_r, y_r > x_r), (y_r, True)) * z ** -1.0).is_zero + + # issue 24215 + from sympy.abc import phi + assert Mod(4.0*Mod(phi, 1) , 2) == 2.0*(Mod(2*(Mod(phi, 1)), 1)) + + xi = symbols('x', integer=True) + assert unchanged(Mod, xi, 2) + assert Mod(3*xi, 2) == Mod(xi, 2) + assert unchanged(Mod, 3*x, 2) + + +def test_Mod_Pow(): + # modular exponentiation + assert isinstance(Mod(Pow(2, 2, evaluate=False), 3), Integer) + + assert Mod(Pow(4, 13, evaluate=False), 497) == Mod(Pow(4, 13), 497) + assert Mod(Pow(2, 10000000000, evaluate=False), 3) == 1 + assert Mod(Pow(32131231232, 9**10**6, evaluate=False),10**12) == \ + pow(32131231232,9**10**6,10**12) + assert Mod(Pow(33284959323, 123**999, evaluate=False),11**13) == \ + pow(33284959323,123**999,11**13) + assert Mod(Pow(78789849597, 333**555, evaluate=False),12**9) == \ + pow(78789849597,333**555,12**9) + + # modular nested exponentiation + expr = Pow(2, 2, evaluate=False) + expr = Pow(2, expr, evaluate=False) + assert Mod(expr, 3**10) == 16 + expr = Pow(2, expr, evaluate=False) + assert Mod(expr, 3**10) == 6487 + expr = Pow(2, expr, evaluate=False) + assert Mod(expr, 3**10) == 32191 + expr = Pow(2, expr, evaluate=False) + assert Mod(expr, 3**10) == 18016 + expr = Pow(2, expr, evaluate=False) + assert Mod(expr, 3**10) == 5137 + + expr = Pow(2, 2, evaluate=False) + expr = Pow(expr, 2, evaluate=False) + assert Mod(expr, 3**10) == 16 + expr = Pow(expr, 2, evaluate=False) + assert Mod(expr, 3**10) == 256 + expr = Pow(expr, 2, evaluate=False) + assert Mod(expr, 3**10) == 6487 + expr = Pow(expr, 2, evaluate=False) + assert Mod(expr, 3**10) == 38281 + expr = Pow(expr, 2, evaluate=False) + assert Mod(expr, 3**10) == 15928 + + expr = Pow(2, 2, evaluate=False) + expr = Pow(expr, expr, evaluate=False) + assert Mod(expr, 3**10) == 256 + expr = Pow(expr, expr, evaluate=False) + assert Mod(expr, 3**10) == 9229 + expr = Pow(expr, expr, evaluate=False) + assert Mod(expr, 3**10) == 25708 + expr = Pow(expr, expr, evaluate=False) + assert Mod(expr, 3**10) == 26608 + expr = Pow(expr, expr, evaluate=False) + # XXX This used to fail in a nondeterministic way because of overflow + # error. + assert Mod(expr, 3**10) == 1966 + + +def test_Mod_is_integer(): + p = Symbol('p', integer=True) + q1 = Symbol('q1', integer=True) + q2 = Symbol('q2', integer=True, nonzero=True) + assert Mod(x, y).is_integer is None + assert Mod(p, q1).is_integer is None + assert Mod(x, q2).is_integer is None + assert Mod(p, q2).is_integer + + +def test_Mod_is_nonposneg(): + n = Symbol('n', integer=True) + k = Symbol('k', integer=True, positive=True) + assert (n%3).is_nonnegative + assert Mod(n, -3).is_nonpositive + assert Mod(n, k).is_nonnegative + assert Mod(n, -k).is_nonpositive + assert Mod(k, n).is_nonnegative is None + + +def test_issue_6001(): + A = Symbol("A", commutative=False) + eq = A + A**2 + # it doesn't matter whether it's True or False; they should + # just all be the same + assert ( + eq.is_commutative == + (eq + 1).is_commutative == + (A + 1).is_commutative) + + B = Symbol("B", commutative=False) + # Although commutative terms could cancel we return True + # meaning "there are non-commutative symbols; aftersubstitution + # that definition can change, e.g. (A*B).subs(B,A**-1) -> 1 + assert (sqrt(2)*A).is_commutative is False + assert (sqrt(2)*A*B).is_commutative is False + + +def test_polar(): + from sympy.functions.elementary.complexes import polar_lift + p = Symbol('p', polar=True) + x = Symbol('x') + assert p.is_polar + assert x.is_polar is None + assert S.One.is_polar is None + assert (p**x).is_polar is True + assert (x**p).is_polar is None + assert ((2*p)**x).is_polar is True + assert (2*p).is_polar is True + assert (-2*p).is_polar is not True + assert (polar_lift(-2)*p).is_polar is True + + q = Symbol('q', polar=True) + assert (p*q)**2 == p**2 * q**2 + assert (2*q)**2 == 4 * q**2 + assert ((p*q)**x).expand() == p**x * q**x + + +def test_issue_6040(): + a, b = Pow(1, 2, evaluate=False), S.One + assert a != b + assert b != a + assert not (a == b) + assert not (b == a) + + +def test_issue_6082(): + # Comparison is symmetric + assert Basic.compare(Max(x, 1), Max(x, 2)) == \ + - Basic.compare(Max(x, 2), Max(x, 1)) + # Equal expressions compare equal + assert Basic.compare(Max(x, 1), Max(x, 1)) == 0 + # Basic subtypes (such as Max) compare different than standard types + assert Basic.compare(Max(1, x), frozenset((1, x))) != 0 + + +def test_issue_6077(): + assert x**2.0/x == x**1.0 + assert x/x**2.0 == x**-1.0 + assert x*x**2.0 == x**3.0 + assert x**1.5*x**2.5 == x**4.0 + + assert 2**(2.0*x)/2**x == 2**(1.0*x) + assert 2**x/2**(2.0*x) == 2**(-1.0*x) + 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) + x_im = symbols('x_im', imaginary=True) + assert n*oo is -oo + assert n*m*oo is oo + assert p*oo is oo + assert x_im*oo != I*oo # i could be +/- 3*I -> +/-oo + + +def test_add_flatten(): + # see https://github.com/sympy/sympy/issues/2633#issuecomment-29545524 + a = oo + I*oo + b = oo - I*oo + assert a + b is nan + assert a - b is nan + # FIXME: This evaluates as: + # >>> 1/a + # 0*(oo + oo*I) + # which should not simplify to 0. Should be fixed in Pow.eval + #assert (1/a).simplify() == (1/b).simplify() == 0 + + a = Pow(2, 3, evaluate=False) + assert a + a == 16 + + +def test_issue_5160_6087_6089_6090(): + # issue 6087 + assert ((-2*x*y**y)**3.2).n(2) == (2**3.2*(-x*y**y)**3.2).n(2) + # issue 6089 + A, B, C = symbols('A,B,C', commutative=False) + assert (2.*B*C)**3 == 8.0*(B*C)**3 + assert (-2.*B*C)**3 == -8.0*(B*C)**3 + assert (-2*B*C)**2 == 4*(B*C)**2 + # issue 5160 + assert sqrt(-1.0*x) == 1.0*sqrt(-x) + assert sqrt(1.0*x) == 1.0*sqrt(x) + # issue 6090 + assert (-2*x*y*A*B)**2 == 4*x**2*y**2*(A*B)**2 + + +def test_float_int_round(): + assert int(float(sqrt(10))) == int(sqrt(10)) + assert int(pi**1000) % 10 == 2 + assert int(Float('1.123456789012345678901234567890e20', '')) == \ + int(112345678901234567890) + assert int(Float('1.123456789012345678901234567890e25', '')) == \ + int(11234567890123456789012345) + # 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', '')) == \ + 11234567890123456789012345 + # 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 same_and_same_prec(Float('123000e-2',''), Float('1230.00', '')) + assert same_and_same_prec(Float('123000e2',''), Float('12300000', '')) + + assert int(1 + Rational('.9999999999999999999999999')) == 1 + assert int(pi/1e20) == 0 + assert int(1 + pi/1e20) == 1 + assert int(Add(1.2, -2, evaluate=False)) == int(1.2 - 2) + assert int(Add(1.2, +2, evaluate=False)) == int(1.2 + 2) + assert int(Add(1 + Float('.99999999999999999', ''), evaluate=False)) == 1 + raises(TypeError, lambda: float(x)) + raises(TypeError, lambda: float(sqrt(-1))) + + assert int(12345678901234567890 + cos(1)**2 + sin(1)**2) == \ + 12345678901234567891 + + +def test_issue_6611a(): + 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 unnecessarily + eq = Mul(-2, x - 2, evaluate=False) + assert 2*eq == Mul(-4, x - 2, evaluate=False) + assert -eq == Mul(2, x - 2, evaluate=False) + + +def test_mul_coeff(): + # It is important that all Numbers be removed from the seq; + # This can be tricky when powers combine to produce those numbers + p = exp(I*pi/3) + assert p**2*x*p*y*p*x*p**2 == x**2*y + + +def test_mul_zero_detection(): + nz = Dummy(real=True, zero=False) + r = Dummy(extended_real=True) + c = Dummy(real=False, complex=True) + c2 = Dummy(real=False, complex=True) + i = Dummy(imaginary=True) + e = nz*r*c + assert e.is_imaginary is None + assert e.is_extended_real is None + e = nz*c + assert e.is_imaginary is None + assert e.is_extended_real is False + e = nz*i*c + assert e.is_imaginary is False + assert e.is_extended_real is None + # check for more than one complex; it is important to use + # uniquely named Symbols to ensure that two factors appear + # e.g. if the symbols have the same name they just become + # a single factor, a power. + e = nz*i*c*c2 + assert e.is_imaginary is None + assert e.is_extended_real is None + + # _eval_is_extended_real and _eval_is_zero both employ trapping of the + # zero value so args should be tested in both directions and + # TO AVOID GETTING THE CACHED RESULT, Dummy MUST BE USED + + # real is unknown + def test(z, b, e): + if z.is_zero and b.is_finite: + assert e.is_extended_real and e.is_zero + else: + assert e.is_extended_real is None + if b.is_finite: + if z.is_zero: + assert e.is_zero + else: + assert e.is_zero is None + elif b.is_finite is False: + if z.is_zero is None: + assert e.is_zero is None + else: + assert e.is_zero is False + + + for iz, ib in product(*[[True, False, None]]*2): + z = Dummy('z', nonzero=iz) + b = Dummy('f', finite=ib) + e = Mul(z, b, evaluate=False) + test(z, b, e) + z = Dummy('nz', nonzero=iz) + b = Dummy('f', finite=ib) + e = Mul(b, z, evaluate=False) + test(z, b, e) + + # real is True + def test(z, b, e): + if z.is_zero and not b.is_finite: + assert e.is_extended_real is None + else: + assert e.is_extended_real is True + + for iz, ib in product(*[[True, False, None]]*2): + z = Dummy('z', nonzero=iz, extended_real=True) + b = Dummy('b', finite=ib, extended_real=True) + e = Mul(z, b, evaluate=False) + test(z, b, e) + z = Dummy('z', nonzero=iz, extended_real=True) + b = Dummy('b', finite=ib, extended_real=True) + e = Mul(b, z, evaluate=False) + test(z, b, e) + + +def test_Mul_with_zero_infinite(): + zer = Dummy(zero=True) + inf = Dummy(finite=False) + + e = Mul(zer, inf, evaluate=False) + assert e.is_extended_positive is None + assert e.is_hermitian is None + + e = Mul(inf, zer, evaluate=False) + assert e.is_extended_positive is None + assert e.is_hermitian is None + + +def test_Mul_does_not_cancel_infinities(): + a, b = symbols('a b') + assert ((zoo + 3*a)/(3*a + zoo)) is nan + assert ((b - oo)/(b - oo)) is nan + # issue 13904 + expr = (1/(a+b) + 1/(a-b))/(1/(a+b) - 1/(a-b)) + assert expr.subs(b, a) is nan + + +def test_Mul_does_not_distribute_infinity(): + a, b = symbols('a b') + assert ((1 + I)*oo).is_Mul + assert ((a + b)*(-oo)).is_Mul + assert ((a + 1)*zoo).is_Mul + assert ((1 + I)*oo).is_finite is False + z = (1 + I)*oo + assert ((1 - I)*z).expand() is oo + + +def test_Mul_does_not_let_0_trump_inf(): + assert Mul(*[0, a + zoo]) is S.NaN + assert Mul(*[0, a + oo]) is S.NaN + assert Mul(*[0, a + Integral(1/x**2, (x, 1, oo))]) is S.Zero + # Integral is treated like an unknown like 0*x -> 0 + assert Mul(*[0, a + Integral(x, (x, 1, oo))]) is S.Zero + + +def test_issue_8247_8354(): + from sympy.functions.elementary.trigonometric import tan + z = sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3)) - sqrt(10 + 6*sqrt(3)) + assert z.is_positive is False # it's 0 + z = S('''-2**(1/3)*(3*sqrt(93) + 29)**2 - 4*(3*sqrt(93) + 29)**(4/3) + + 12*sqrt(93)*(3*sqrt(93) + 29)**(1/3) + 116*(3*sqrt(93) + 29)**(1/3) + + 174*2**(1/3)*sqrt(93) + 1678*2**(1/3)''') + assert z.is_positive is False # it's 0 + z = 2*(-3*tan(19*pi/90) + sqrt(3))*cos(11*pi/90)*cos(19*pi/90) - \ + sqrt(3)*(-3 + 4*cos(19*pi/90)**2) + assert z.is_positive is not True # it's zero and it shouldn't hang + z = S('''9*(3*sqrt(93) + 29)**(2/3)*((3*sqrt(93) + + 29)**(1/3)*(-2**(2/3)*(3*sqrt(93) + 29)**(1/3) - 2) - 2*2**(1/3))**3 + + 72*(3*sqrt(93) + 29)**(2/3)*(81*sqrt(93) + 783) + (162*sqrt(93) + + 1566)*((3*sqrt(93) + 29)**(1/3)*(-2**(2/3)*(3*sqrt(93) + 29)**(1/3) - + 2) - 2*2**(1/3))**2''') + assert z.is_positive is False # it's 0 (and a single _mexpand isn't enough) + + +def test_Add_is_zero(): + x, y = symbols('x y', zero=True) + assert (x + y).is_zero + + # Issue 15873 + e = -2*I + (1 + I)**2 + assert e.is_zero is None + + +def test_issue_14392(): + assert (sin(zoo)**2).as_real_imag() == (nan, nan) + + +def test_divmod(): + assert divmod(x, y) == (x//y, x % y) + assert divmod(x, 3) == (x//3, x % 3) + assert divmod(3, x) == (3//x, 3 % x) + + +def test__neg__(): + assert -(x*y) == -x*y + assert -(-x*y) == x*y + assert -(1.*x) == -1.*x + assert -(-1.*x) == 1.*x + assert -(2.*x) == -2.*x + assert -(-2.*x) == 2.*x + with distribute(False): + eq = -(x + y) + assert eq.is_Mul and eq.args == (-1, x + y) + with evaluate(False): + eq = -(x + y) + assert eq.is_Mul and eq.args == (-1, x + y) + + +def test_issue_18507(): + assert Mul(zoo, zoo, 0) is nan + + +def test_issue_17130(): + e = Add(b, -b, I, -I, evaluate=False) + assert e.is_zero is None # ideally this would be True + + +def test_issue_21034(): + e = -I*log((re(asin(5)) + I*im(asin(5)))/sqrt(re(asin(5))**2 + im(asin(5))**2))/pi + assert e.round(2) + + +def test_issue_22021(): + from sympy.calculus.accumulationbounds import AccumBounds + # these objects are special cases in Mul + from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads + L = TensorIndexType("L") + i = tensor_indices("i", L) + A, B = tensor_heads("A B", [L]) + e = A(i) + B(i) + assert -e == -1*e + e = zoo + x + assert -e == -1*e + a = AccumBounds(1, 2) + e = a + x + assert -e == -1*e + for args in permutations((zoo, a, x)): + e = Add(*args, evaluate=False) + assert -e == -1*e + assert 2*Add(1, x, x, evaluate=False) == 4*x + 2 + + +def test_issue_22244(): + assert -(zoo*x) == zoo*x + + +def test_issue_22453(): + from sympy.utilities.iterables import cartes + e = Symbol('e', extended_positive=True) + for a, b in cartes(*[[oo, -oo, 3]]*2): + if a == b == 3: + continue + i = a + I*b + assert i**(1 + e) is S.ComplexInfinity + assert i**-e is S.Zero + assert unchanged(Pow, i, e) + assert 1/(oo + I*oo) is S.Zero + r, i = [Dummy(infinite=True, extended_real=True) for _ in range(2)] + assert 1/(r + I*i) is S.Zero + assert 1/(3 + I*i) is S.Zero + assert 1/(r + I*3) is S.Zero + + +def test_issue_22613(): + assert (0**(x - 2)).as_content_primitive() == (1, 0**(x - 2)) + assert (0**(x + 2)).as_content_primitive() == (1, 0**(x + 2)) + + +def test_issue_25176(): + assert sqrt(-4*3**(S(3)/4)*I/3) == 2*3**(S(7)/8)*sqrt(-I)/3 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_assumptions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_assumptions.py new file mode 100644 index 0000000000000000000000000000000000000000..574e90178fb489fe99c99ea0c72df57ceec4b249 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_assumptions.py @@ -0,0 +1,1335 @@ +from sympy.core.mod import Mod +from sympy.core.numbers import (I, oo, pi) +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (asin, sin) +from sympy.simplify.simplify import simplify +from sympy.core import Symbol, S, Rational, Integer, Dummy, Wild, Pow +from sympy.core.assumptions import (assumptions, check_assumptions, + failing_assumptions, common_assumptions, _generate_assumption_rules, + _load_pre_generated_assumption_rules) +from sympy.core.facts import InconsistentAssumptions +from sympy.core.random import seed +from sympy.combinatorics import Permutation +from sympy.combinatorics.perm_groups import PermutationGroup + +from sympy.testing.pytest import raises, XFAIL + + +def test_symbol_unset(): + 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 is True + assert z.is_integer is True + assert z.is_rational is True + assert z.is_algebraic is True + assert z.is_transcendental is False + 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_finite is True + assert z.is_infinite 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_one(): + z = Integer(1) + assert z.is_commutative is True + assert z.is_integer is True + assert z.is_rational is True + assert z.is_algebraic is True + assert z.is_transcendental is False + 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_finite is True + assert z.is_infinite is False + assert z.is_comparable is True + assert z.is_prime is False + assert z.is_number is True + assert z.is_composite is False # issue 8807 + + +def test_negativeone(): + z = Integer(-1) + assert z.is_commutative is True + assert z.is_integer is True + assert z.is_rational is True + assert z.is_algebraic is True + assert z.is_transcendental is False + 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_finite is True + assert z.is_infinite 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 is True + assert oo.is_integer is False + assert oo.is_rational is False + assert oo.is_algebraic is False + assert oo.is_transcendental is False + assert oo.is_extended_real is True + assert oo.is_real is False + assert oo.is_complex is False + assert oo.is_noninteger is True + assert oo.is_irrational is False + assert oo.is_imaginary is False + assert oo.is_nonzero is False + assert oo.is_positive is False + assert oo.is_negative is False + assert oo.is_nonpositive is False + assert oo.is_nonnegative is False + assert oo.is_extended_nonzero is True + assert oo.is_extended_positive is True + assert oo.is_extended_negative is False + assert oo.is_extended_nonpositive is False + assert oo.is_extended_nonnegative is True + assert oo.is_even is False + assert oo.is_odd is False + assert oo.is_finite is False + assert oo.is_infinite is True + assert oo.is_comparable is True + assert oo.is_prime is False + assert oo.is_composite is False + assert oo.is_number is True + + +def test_neg_infinity(): + mm = S.NegativeInfinity + + assert mm.is_commutative is True + assert mm.is_integer is False + assert mm.is_rational is False + assert mm.is_algebraic is False + assert mm.is_transcendental is False + assert mm.is_extended_real is True + assert mm.is_real is False + assert mm.is_complex is False + assert mm.is_noninteger is True + assert mm.is_irrational is False + assert mm.is_imaginary is False + assert mm.is_nonzero is False + assert mm.is_positive is False + assert mm.is_negative is False + assert mm.is_nonpositive is False + assert mm.is_nonnegative is False + assert mm.is_extended_nonzero is True + assert mm.is_extended_positive is False + assert mm.is_extended_negative is True + assert mm.is_extended_nonpositive is True + assert mm.is_extended_nonnegative is False + assert mm.is_even is False + assert mm.is_odd is False + assert mm.is_finite is False + assert mm.is_infinite is True + 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_zoo(): + zoo = S.ComplexInfinity + assert zoo.is_complex is False + assert zoo.is_real is False + assert zoo.is_prime is False + + +def test_nan(): + nan = S.NaN + + assert nan.is_commutative is True + assert nan.is_integer is None + assert nan.is_rational is None + assert nan.is_algebraic is None + assert nan.is_transcendental 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_finite is None + assert nan.is_infinite 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 is True + assert r.is_integer is False + assert r.is_rational is True + assert r.is_algebraic is True + assert r.is_transcendental is False + 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_finite is True + assert r.is_infinite 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 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 is True + assert z.is_integer is False + assert z.is_rational is False + assert z.is_algebraic is False + assert z.is_transcendental is True + 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_finite is True + assert z.is_infinite 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 is True + assert z.is_integer is False + assert z.is_rational is False + assert z.is_algebraic is False + assert z.is_transcendental is True + 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_finite is True + assert z.is_infinite 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 + assert z.is_commutative is True + assert z.is_integer is False + assert z.is_rational is False + assert z.is_algebraic is True + assert z.is_transcendental is False + assert z.is_real is False + assert z.is_complex is True + assert z.is_noninteger is False + assert z.is_irrational is False + assert z.is_imaginary is True + assert z.is_positive is False + assert z.is_negative is False + assert z.is_nonpositive is False + assert z.is_nonnegative is False + assert z.is_even is False + assert z.is_odd is False + assert z.is_finite is True + assert z.is_infinite is False + assert z.is_comparable is False + assert z.is_prime is False + assert z.is_composite is False + + +def test_symbol_real_false(): + # issue 3848 + a = Symbol('a', real=False) + + assert a.is_real is False + assert a.is_integer is False + assert a.is_zero 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_nonzero is False + + assert a.is_extended_negative is None + assert a.is_extended_positive is None + assert a.is_extended_nonnegative is None + assert a.is_extended_nonpositive is None + assert a.is_extended_nonzero is None + + +def test_symbol_extended_real_false(): + # issue 3848 + a = Symbol('a', extended_real=False) + + assert a.is_real is False + assert a.is_integer is False + assert a.is_zero 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_nonzero is False + + assert a.is_extended_negative is False + assert a.is_extended_positive is False + assert a.is_extended_nonnegative is False + assert a.is_extended_nonpositive is False + assert a.is_extended_nonzero is False + + +def test_symbol_imaginary(): + a = Symbol('a', imaginary=True) + + 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 + assert a.is_nonzero is False # since nonzero -> real + + +def test_symbol_zero(): + x = Symbol('x', zero=True) + assert x.is_positive is False + assert x.is_nonpositive + assert x.is_negative is False + assert x.is_nonnegative + assert x.is_zero is True + # TODO Change to x.is_nonzero is None + # See https://github.com/sympy/sympy/pull/9583 + assert x.is_nonzero is False + assert x.is_finite is True + + +def test_symbol_positive(): + 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 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 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 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 + + +def test_symbol_falsepositive_mul(): + # To test pull request 9379 + # Explicit handling of arg.is_positive=False was added to Mul._eval_is_positive + x = 2*Symbol('x', positive=False) + assert x.is_positive is False # This was None before + 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_symbol_infinitereal_mul(): + ix = Symbol('ix', infinite=True, extended_real=True) + assert (-ix).is_extended_positive is None + + +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 + assert x.is_nonnegative is None + assert x.is_zero is None + assert x.is_nonzero is None + + +def test_neg_symbol_falsenegative(): + # To test pull request 9379 + # Explicit handling of arg.is_negative=False was added to Mul._eval_is_positive + x = -Symbol('x', negative=False) + assert x.is_positive is False # This was None before + 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 + + +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 None + + +@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.NegativeOne.is_prime is False + assert S(-2).is_prime is False + assert S(-4).is_prime is False + assert S.Zero.is_prime is False + assert S.One.is_prime is False + assert S(2).is_prime is True + assert S(17).is_prime is True + assert S(4).is_prime is False + + +def test_composite(): + assert S.NegativeOne.is_composite is False + assert S(-2).is_composite is False + assert S(-4).is_composite is False + assert S.Zero.is_composite is False + assert S(2).is_composite is False + assert S(17).is_composite is False + assert S(4).is_composite is True + x = Dummy(integer=True, positive=True, prime=False) + assert x.is_composite is None # x could be 1 + assert (x + 1).is_composite is None + x = Dummy(positive=True, even=True, prime=False) + assert x.is_integer is True + assert x.is_composite is True + + +def test_prime_symbol(): + x = Symbol('x', prime=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 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) + assert x.is_complex is None + + x = Symbol('x', commutative=False) + assert x.is_integer is False + assert x.is_rational is False + assert x.is_algebraic is False + assert x.is_irrational is False + 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 is True + assert x.is_real is True + assert x.is_finite is True + + x = Symbol('x', integer=True, nonnegative=True) + assert x.is_integer is True + assert x.is_nonnegative is True + assert x.is_negative is False + assert x.is_positive is None + assert x.is_finite is True + + x = Symbol('x', integer=True, nonpositive=True) + assert x.is_integer is True + assert x.is_nonpositive is True + assert x.is_positive is False + assert x.is_negative is None + assert x.is_finite is True + + x = Symbol('x', odd=True) + assert x.is_odd is True + assert x.is_even is False + assert x.is_integer is True + assert x.is_finite is True + + x = Symbol('x', odd=False) + assert x.is_odd is False + assert x.is_even is None + assert x.is_integer is None + assert x.is_finite is None + + x = Symbol('x', even=True) + assert x.is_even is True + assert x.is_odd is False + assert x.is_integer is True + assert x.is_finite is True + + x = Symbol('x', even=False) + assert x.is_even is False + assert x.is_odd is None + assert x.is_integer is None + assert x.is_finite is None + + x = Symbol('x', integer=True, nonnegative=True) + assert x.is_integer is True + assert x.is_nonnegative is True + assert x.is_finite is True + + x = Symbol('x', integer=True, nonpositive=True) + assert x.is_integer is True + assert x.is_nonpositive is True + assert x.is_finite is True + + x = Symbol('x', rational=True) + assert x.is_real is True + assert x.is_finite is True + + x = Symbol('x', rational=False) + assert x.is_real is None + assert x.is_finite is None + + x = Symbol('x', irrational=True) + assert x.is_real is True + assert x.is_finite is True + + x = Symbol('x', irrational=False) + assert x.is_real is None + assert x.is_finite is None + + with raises(AttributeError): + x.is_real = False + + x = Symbol('x', algebraic=True) + assert x.is_transcendental is False + x = Symbol('x', transcendental=True) + assert x.is_algebraic is False + assert x.is_rational is False + assert x.is_integer is False + + +def test_evaluate_false(): + # Previously this failed because the assumptions query would make new + # expressions and some of the evaluation logic would fail under + # evaluate(False). + from sympy.core.parameters import evaluate + from sympy.abc import x, h + f = 2**x**7 + with evaluate(False): + fh = f.xreplace({x: x+h}) + assert fh.exp.is_rational is None + + +def test_issue_3825(): + """catch: hash instability""" + x = Symbol("x") + y = Symbol("y") + a1 = x + y + a2 = y + x + a2.is_comparable + + h1 = hash(a1) + h2 = hash(a2) + assert h1 == h2 + + +def test_issue_4822(): + 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) + + 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) + + assert x != x1 + 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 + + a.is_positive # this uses .evalf() and deduces it is positive + 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) + + assert a == b + assert ha == hb + + +def test_Add_is_pos_neg(): + # these cover lines not covered by the rest of tests in core + n = Symbol('n', extended_negative=True, infinite=True) + nn = Symbol('n', extended_nonnegative=True, infinite=True) + np = Symbol('n', extended_nonpositive=True, infinite=True) + p = Symbol('p', extended_positive=True, infinite=True) + r = Dummy(extended_real=True, finite=False) + x = Symbol('x') + xf = Symbol('xf', finite=True) + assert (n + p).is_extended_positive is None + assert (n + x).is_extended_positive is None + assert (p + x).is_extended_positive is None + assert (n + p).is_extended_negative is None + assert (n + x).is_extended_negative is None + assert (p + x).is_extended_negative is None + + assert (n + xf).is_extended_positive is False + assert (p + xf).is_extended_positive is True + assert (n + xf).is_extended_negative is True + assert (p + xf).is_extended_negative is False + + assert (x - S.Infinity).is_extended_negative is None # issue 7798 + # issue 8046, 16.2 + assert (p + nn).is_extended_positive + assert (n + np).is_extended_negative + assert (p + r).is_extended_positive is None + + +def test_Add_is_imaginary(): + nn = Dummy(nonnegative=True) + assert (I*nn + I).is_imaginary # issue 8046, 17 + + +def test_Add_is_algebraic(): + a = Symbol('a', algebraic=True) + b = Symbol('a', algebraic=True) + na = Symbol('na', algebraic=False) + nb = Symbol('nb', algebraic=False) + x = Symbol('x') + assert (a + b).is_algebraic + assert (na + nb).is_algebraic is None + assert (a + na).is_algebraic is False + assert (a + x).is_algebraic is None + assert (na + x).is_algebraic is None + + +def test_Mul_is_algebraic(): + a = Symbol('a', algebraic=True) + b = Symbol('b', algebraic=True) + na = Symbol('na', algebraic=False) + an = Symbol('an', algebraic=True, nonzero=True) + nb = Symbol('nb', algebraic=False) + x = Symbol('x') + assert (a*b).is_algebraic is True + assert (na*nb).is_algebraic is None + assert (a*na).is_algebraic is None + assert (an*na).is_algebraic is False + assert (a*x).is_algebraic is None + assert (na*x).is_algebraic is None + + +def test_Pow_is_algebraic(): + e = Symbol('e', algebraic=True) + + assert Pow(1, e, evaluate=False).is_algebraic + assert Pow(0, e, evaluate=False).is_algebraic + + a = Symbol('a', algebraic=True) + azf = Symbol('azf', algebraic=True, zero=False) + na = Symbol('na', algebraic=False) + ia = Symbol('ia', algebraic=True, irrational=True) + ib = Symbol('ib', algebraic=True, irrational=True) + r = Symbol('r', rational=True) + x = Symbol('x') + assert (a**2).is_algebraic is True + assert (a**r).is_algebraic is None + assert (azf**r).is_algebraic is True + assert (a**x).is_algebraic is None + assert (na**r).is_algebraic is None + assert (ia**r).is_algebraic is True + assert (ia**ib).is_algebraic is False + + assert (a**e).is_algebraic is None + + # Gelfond-Schneider constant: + assert Pow(2, sqrt(2), evaluate=False).is_algebraic is False + + assert Pow(S.GoldenRatio, sqrt(3), evaluate=False).is_algebraic is False + + # issue 8649 + t = Symbol('t', real=True, transcendental=True) + n = Symbol('n', integer=True) + assert (t**n).is_algebraic is None + assert (t**n).is_integer is None + + assert (pi**3).is_algebraic is False + r = Symbol('r', zero=True) + assert (pi**r).is_algebraic is True + + +def test_Mul_is_prime_composite(): + x = Symbol('x', positive=True, integer=True) + y = Symbol('y', positive=True, integer=True) + assert (x*y).is_prime is None + assert ( (x+1)*(y+1) ).is_prime is False + assert ( (x+1)*(y+1) ).is_composite is True + + x = Symbol('x', positive=True) + assert ( (x+1)*(y+1) ).is_prime is None + assert ( (x+1)*(y+1) ).is_composite is None + + +def test_Pow_is_pos_neg(): + z = Symbol('z', real=True) + w = Symbol('w', nonpositive=True) + + assert (S.NegativeOne**S(2)).is_positive is True + assert (S.One**z).is_positive is True + assert (S.NegativeOne**S(3)).is_positive is False + assert (S.Zero**S.Zero).is_positive is True # 0**0 is 1 + assert (w**S(3)).is_positive is False + assert (w**S(2)).is_positive is None + assert (I**2).is_positive is False + assert (I**4).is_positive is True + + # tests emerging from #16332 issue + p = Symbol('p', zero=True) + q = Symbol('q', zero=False, real=True) + j = Symbol('j', zero=False, even=True) + x = Symbol('x', zero=True) + y = Symbol('y', zero=True) + assert (p**q).is_positive is False + assert (p**q).is_negative is False + assert (p**j).is_positive is False + assert (x**y).is_positive is True # 0**0 + assert (x**y).is_negative is False + + +def test_Pow_is_prime_composite(): + x = Symbol('x', positive=True, integer=True) + y = Symbol('y', positive=True, integer=True) + assert (x**y).is_prime is None + assert ( x**(y+1) ).is_prime is False + assert ( x**(y+1) ).is_composite is None + assert ( (x+1)**(y+1) ).is_composite is True + assert ( (-x-1)**(2*y) ).is_composite is True + + x = Symbol('x', positive=True) + assert (x**y).is_prime is None + + +def test_Mul_is_infinite(): + x = Symbol('x') + f = Symbol('f', finite=True) + i = Symbol('i', infinite=True) + z = Dummy(zero=True) + nzf = Dummy(finite=True, zero=False) + from sympy.core.mul import Mul + assert (x*f).is_finite is None + assert (x*i).is_finite is None + assert (f*i).is_finite is None + assert (x*f*i).is_finite is None + assert (z*i).is_finite is None + assert (nzf*i).is_finite is False + assert (z*f).is_finite is True + assert Mul(0, f, evaluate=False).is_finite is True + assert Mul(0, i, evaluate=False).is_finite is None + + assert (x*f).is_infinite is None + assert (x*i).is_infinite is None + assert (f*i).is_infinite is None + assert (x*f*i).is_infinite is None + assert (z*i).is_infinite is S.NaN.is_infinite + assert (nzf*i).is_infinite is True + assert (z*f).is_infinite is False + assert Mul(0, f, evaluate=False).is_infinite is False + assert Mul(0, i, evaluate=False).is_infinite is S.NaN.is_infinite + + +def test_Add_is_infinite(): + x = Symbol('x') + f = Symbol('f', finite=True) + i = Symbol('i', infinite=True) + i2 = Symbol('i2', infinite=True) + z = Dummy(zero=True) + nzf = Dummy(finite=True, zero=False) + from sympy.core.add import Add + assert (x+f).is_finite is None + assert (x+i).is_finite is None + assert (f+i).is_finite is False + assert (x+f+i).is_finite is None + assert (z+i).is_finite is False + assert (nzf+i).is_finite is False + assert (z+f).is_finite is True + assert (i+i2).is_finite is None + assert Add(0, f, evaluate=False).is_finite is True + assert Add(0, i, evaluate=False).is_finite is False + + assert (x+f).is_infinite is None + assert (x+i).is_infinite is None + assert (f+i).is_infinite is True + assert (x+f+i).is_infinite is None + assert (z+i).is_infinite is True + assert (nzf+i).is_infinite is True + assert (z+f).is_infinite is False + assert (i+i2).is_infinite is None + assert Add(0, f, evaluate=False).is_infinite is False + assert Add(0, i, evaluate=False).is_infinite is True + + +def test_special_is_rational(): + i = Symbol('i', integer=True) + i2 = Symbol('i2', integer=True) + ni = Symbol('ni', integer=True, nonzero=True) + r = Symbol('r', rational=True) + rn = Symbol('r', rational=True, nonzero=True) + nr = Symbol('nr', irrational=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 exp(3).is_rational is False + assert exp(ni).is_rational is False + assert exp(rn).is_rational is False + assert exp(x).is_rational is None + assert exp(log(3), evaluate=False).is_rational is True + assert log(exp(3), evaluate=False).is_rational is True + assert log(3).is_rational is False + assert log(ni + 1).is_rational is False + assert log(rn + 1).is_rational is False + assert log(x).is_rational is None + assert (sqrt(3) + sqrt(5)).is_rational is None + assert (sqrt(3) + S.Pi).is_rational is False + assert (x**i).is_rational is None + assert (i**i).is_rational is True + assert (i**i2).is_rational is None + assert (r**i).is_rational is None + assert (r**r).is_rational is None + assert (r**x).is_rational is None + assert (nr**i).is_rational is None # issue 8598 + assert (nr**Symbol('z', zero=True)).is_rational + assert sin(1).is_rational is False + assert sin(ni).is_rational is False + assert sin(rn).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_6275(): + 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 isinstance(x*0, type(0*S.Infinity)) + if 0*S.Infinity is S.NaN: + b = Symbol('b', finite=None) + assert (b*0).is_zero is None + + +def test_sanitize_assumptions(): + # issue 6666 + for cls in (Symbol, Dummy, Wild): + x = cls('x', real=1, positive=0) + assert x.is_real is True + assert x.is_positive is False + assert cls('', real=True, positive=None).is_positive is None + raises(ValueError, lambda: cls('', commutative=None)) + raises(ValueError, lambda: Symbol._sanitize({"commutative": None})) + + +def test_special_assumptions(): + e = -3 - sqrt(5) + (-sqrt(10)/2 - sqrt(2)/2)**2 + assert simplify(e < 0) is S.false + assert simplify(e > 0) is S.false + assert (e == 0) is False # it's not a literal 0 + assert e.equals(0) is True + + +def test_inconsistent(): + # cf. issues 5795 and 5545 + raises(InconsistentAssumptions, lambda: Symbol('x', real=True, + commutative=False)) + + +def test_issue_6631(): + 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 + + +def test_issue_2730(): + assert (1/(1 + I)).is_real is False + + +def test_issue_4149(): + assert (3 + I).is_complex + assert (3 + I).is_imaginary is False + assert (3*I + S.Pi*I).is_imaginary + # as Zero.is_imaginary is False, see issue 7649 + y = Symbol('y', real=True) + assert (3*I + S.Pi*I + y*I).is_imaginary is None + p = Symbol('p', positive=True) + assert (3*I + S.Pi*I + p*I).is_imaginary + n = Symbol('n', negative=True) + assert (-3*I - S.Pi*I + n*I).is_imaginary + + i = Symbol('i', imaginary=True) + assert ([(i**a).is_imaginary for a in range(4)] == + [False, True, False, True]) + + # tests from the PR #7887: + e = S("-sqrt(3)*I/2 + 0.866025403784439*I") + assert e.is_real is False + assert e.is_imaginary + + +def test_issue_2920(): + n = Symbol('n', negative=True) + assert sqrt(n).is_imaginary + + +def test_issue_7899(): + x = Symbol('x', real=True) + assert (I*x).is_real is None + assert ((x - I)*(x - 1)).is_zero is None + assert ((x - I)*(x - 1)).is_real is None + + +@XFAIL +def test_issue_7993(): + x = Dummy(integer=True) + y = Dummy(noninteger=True) + assert (x - y).is_zero is False + + +def test_issue_8075(): + raises(InconsistentAssumptions, lambda: Dummy(zero=True, finite=False)) + raises(InconsistentAssumptions, lambda: Dummy(zero=True, infinite=True)) + + +def test_issue_8642(): + x = Symbol('x', real=True, integer=False) + assert (x*2).is_integer is None, (x*2).is_integer + + +def test_issues_8632_8633_8638_8675_8992(): + p = Dummy(integer=True, positive=True) + nn = Dummy(integer=True, nonnegative=True) + assert (p - S.Half).is_positive + assert (p - 1).is_nonnegative + assert (nn + 1).is_positive + assert (-p + 1).is_nonpositive + assert (-nn - 1).is_negative + prime = Dummy(prime=True) + assert (prime - 2).is_nonnegative + assert (prime - 3).is_nonnegative is None + even = Dummy(positive=True, even=True) + assert (even - 2).is_nonnegative + + p = Dummy(positive=True) + assert (p/(p + 1) - 1).is_negative + assert ((p + 2)**3 - S.Half).is_positive + n = Dummy(negative=True) + assert (n - 3).is_nonpositive + + +def test_issue_9115_9150(): + n = Dummy('n', integer=True, nonnegative=True) + assert (factorial(n) >= 1) == True + assert (factorial(n) < 1) == False + + assert factorial(n + 1).is_even is None + assert factorial(n + 2).is_even is True + assert factorial(n + 2) >= 2 + + +def test_issue_9165(): + z = Symbol('z', zero=True) + f = Symbol('f', finite=False) + assert 0/z is S.NaN + assert 0*(1/z) is S.NaN + assert 0*f is S.NaN + + +def test_issue_10024(): + x = Dummy('x') + assert Mod(x, 2*pi).is_zero is None + + +def test_issue_10302(): + x = Symbol('x') + r = Symbol('r', real=True) + u = -(3*2**pi)**(1/pi) + 2*3**(1/pi) + i = u + u*I + + assert i.is_real is None # w/o simplification this should fail + assert (u + i).is_zero is None + assert (1 + i).is_zero is False + + a = Dummy('a', zero=True) + assert (a + I).is_zero is False + assert (a + r*I).is_zero is None + assert (a + I).is_imaginary + assert (a + x + I).is_imaginary is None + assert (a + r*I + I).is_imaginary is None + + +def test_complex_reciprocal_imaginary(): + assert (1 / (4 + 3*I)).is_imaginary is False + + +def test_issue_16313(): + x = Symbol('x', extended_real=False) + k = Symbol('k', real=True) + l = Symbol('l', real=True, zero=False) + assert (-x).is_real is False + assert (k*x).is_real is None # k can be zero also + assert (l*x).is_real is False + assert (l*x*x).is_real is None # since x*x can be a real number + assert (-x).is_positive is False + + +def test_issue_16579(): + # extended_real -> finite | infinite + x = Symbol('x', extended_real=True, infinite=False) + y = Symbol('y', extended_real=True, finite=False) + assert x.is_finite is True + assert y.is_infinite is True + + # With PR 16978, complex now implies finite + c = Symbol('c', complex=True) + assert c.is_finite is True + raises(InconsistentAssumptions, lambda: Dummy(complex=True, finite=False)) + + # Now infinite == !finite + nf = Symbol('nf', finite=False) + assert nf.is_infinite is True + + +def test_issue_17556(): + z = I*oo + assert z.is_imaginary is False + assert z.is_finite is False + + +def test_issue_21651(): + k = Symbol('k', positive=True, integer=True) + exp = 2*2**(-k) + assert exp.is_integer is None + + +def test_assumptions_copy(): + assert assumptions(Symbol('x'), {"commutative": True} + ) == {'commutative': True} + assert assumptions(Symbol('x'), ['integer']) == {} + assert assumptions(Symbol('x'), ['commutative'] + ) == {'commutative': True} + assert assumptions(Symbol('x')) == {'commutative': True} + assert assumptions(1)['positive'] + assert assumptions(3 + I) == { + 'algebraic': True, + 'commutative': True, + 'complex': True, + 'composite': False, + 'even': False, + 'extended_negative': False, + 'extended_nonnegative': False, + 'extended_nonpositive': False, + 'extended_nonzero': False, + 'extended_positive': False, + 'extended_real': False, + 'finite': True, + 'imaginary': False, + 'infinite': False, + 'integer': False, + 'irrational': False, + 'negative': False, + 'noninteger': False, + 'nonnegative': False, + 'nonpositive': False, + 'nonzero': False, + 'odd': False, + 'positive': False, + 'prime': False, + 'rational': False, + 'real': False, + 'transcendental': False, + 'zero': False} + + +def test_check_assumptions(): + assert check_assumptions(1, 0) is False + x = Symbol('x', positive=True) + assert check_assumptions(1, x) is True + assert check_assumptions(1, 1) is True + assert check_assumptions(-1, 1) is False + i = Symbol('i', integer=True) + # don't know if i is positive (or prime, etc...) + assert check_assumptions(i, 1) is None + assert check_assumptions(Dummy(integer=None), integer=True) is None + assert check_assumptions(Dummy(integer=None), integer=False) is None + assert check_assumptions(Dummy(integer=False), integer=True) is False + assert check_assumptions(Dummy(integer=True), integer=False) is False + # no T/F assumptions to check + assert check_assumptions(Dummy(integer=False), integer=None) is True + raises(ValueError, lambda: check_assumptions(2*x, x, positive=True)) + + +def test_failing_assumptions(): + x = Symbol('x', positive=True) + y = Symbol('y') + assert failing_assumptions(6*x + y, **x.assumptions0) == \ + {'real': None, 'imaginary': None, 'complex': None, 'hermitian': None, + 'positive': None, 'nonpositive': None, 'nonnegative': None, 'nonzero': None, + 'negative': None, 'zero': None, 'extended_real': None, 'finite': None, + 'infinite': None, 'extended_negative': None, 'extended_nonnegative': None, + 'extended_nonpositive': None, 'extended_nonzero': None, + 'extended_positive': None } + + +def test_common_assumptions(): + assert common_assumptions([0, 1, 2] + ) == {'algebraic': True, 'irrational': False, 'hermitian': + True, 'extended_real': True, 'real': True, 'extended_negative': + False, 'extended_nonnegative': True, 'integer': True, + 'rational': True, 'imaginary': False, 'complex': True, + 'commutative': True,'noninteger': False, 'composite': False, + 'infinite': False, 'nonnegative': True, 'finite': True, + 'transcendental': False,'negative': False} + assert common_assumptions([0, 1, 2], 'positive integer'.split() + ) == {'integer': True} + assert common_assumptions([0, 1, 2], []) == {} + assert common_assumptions([], ['integer']) == {} + assert common_assumptions([0], ['integer']) == {'integer': True} + +def test_pre_generated_assumption_rules_are_valid(): + # check the pre-generated assumptions match freshly generated assumptions + # if this check fails, consider updating the assumptions + # see sympy.core.assumptions._generate_assumption_rules + pre_generated_assumptions =_load_pre_generated_assumption_rules() + generated_assumptions =_generate_assumption_rules() + assert pre_generated_assumptions._to_python() == generated_assumptions._to_python(), "pre-generated assumptions are invalid, see sympy.core.assumptions._generate_assumption_rules" + + +def test_ask_shuffle(): + grp = PermutationGroup(Permutation(1, 0, 2), Permutation(2, 1, 3)) + + seed(123) + first = grp.random() + seed(123) + simplify(I) + second = grp.random() + seed(123) + simplify(-I) + third = grp.random() + + assert first == second == third diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_basic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_basic.py new file mode 100644 index 0000000000000000000000000000000000000000..3a7adbb5dcf0d70089ff79028afa943b24ee0c42 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_basic.py @@ -0,0 +1,343 @@ +"""This tests sympy/core/basic.py with (ideally) no reference to subclasses +of Basic or Atom.""" +import collections +from typing import TypeVar, Generic + +from sympy.assumptions.ask import Q +from sympy.core.basic import (Basic, Atom, as_Basic, + _atomic, _aresame) +from sympy.core.containers import Tuple +from sympy.core.function import Function, Lambda +from sympy.core.numbers import I, pi, Float +from sympy.core.singleton import S +from sympy.core.symbol import symbols, Symbol, Dummy +from sympy.concrete.summations import Sum +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.functions.special.gamma_functions import gamma +from sympy.integrals.integrals import Integral +from sympy.functions.elementary.exponential import exp +from sympy.testing.pytest import raises, warns_deprecated_sympy +from sympy.functions.elementary.complexes import Abs, sign +from sympy.functions.elementary.piecewise import Piecewise +from sympy.core.relational import Eq + +b1 = Basic() +b2 = Basic(b1) +b3 = Basic(b2) +b21 = Basic(b2, b1) +T = TypeVar('T') + + +def test__aresame(): + assert not _aresame(Basic(Tuple()), Basic()) + for i, j in [(S(2), S(2.)), (1., Float(1))]: + for do in range(2): + assert not _aresame(Basic(i), Basic(j)) + assert not _aresame(i, j) + i, j = j, i + + +def test_structure(): + assert b21.args == (b2, b1) + assert b21.func(*b21.args) == b21 + assert bool(b1) + + +def test_immutable(): + assert not hasattr(b1, '__dict__') + with raises(AttributeError): + b1.x = 1 + + +def test_equality(): + 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) + assert (b_i != b_j) == (i != j) + + assert Basic() != [] + assert not(Basic() == []) + assert Basic() != 0 + assert not(Basic() == 0) + + class Foo: + """ + Class that is unaware of Basic, and relies on both classes returning + the NotImplemented singleton for equivalence to evaluate to False. + + """ + + b = Basic() + foo = Foo() + + assert b != foo + assert foo != b + assert not b == foo + assert not foo == b + + class Bar: + """ + Class that considers itself equal to any instance of Basic, and relies + on Basic returning the NotImplemented singleton in order to achieve + a symmetric equivalence relation. + + """ + def __eq__(self, other): + if isinstance(other, Basic): + return True + return NotImplemented + + def __ne__(self, other): + return not self == other + + bar = Bar() + + assert b == bar + assert bar == b + assert not b != bar + assert not bar != b + + +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] + for i, b_i in enumerate(instances): + for j, b_j in enumerate(instances): + 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) + assert b21.has(Basic) + assert not b1.has(b21, b3) + assert not b21.has() + assert not b21.has(str) + assert not Symbol("x").has("x") + + +def test_subs(): + assert b21.subs(b2, b1) == Basic(b1, b1) + assert b21.subs(b2, b21) == Basic(b21, b1) + assert b3.subs(b2, b1) == b2 + + assert b21.subs([(b2, b1), (b1, b2)]) == Basic(b2, b2) + + assert b21.subs({b1: b2, b2: b1}) == Basic(b2, b2) + assert b21.subs(collections.ChainMap({b1: b2}, {b2: b1})) == Basic(b2, b2) + assert b21.subs(collections.OrderedDict([(b2, b1), (b1, b2)])) == Basic(b2, b2) + + raises(ValueError, lambda: b21.subs('bad arg')) + raises(TypeError, lambda: b21.subs(b1, b2, b3)) + # dict(b1=foo) creates a string 'b1' but leaves foo unchanged; subs + # will convert the first to a symbol but will raise an error if foo + # cannot be sympified; sympification is strict if foo is not string + raises(TypeError, lambda: b21.subs(b1='bad arg')) + + assert Symbol("text").subs({"text": b1}) == b1 + assert Symbol("s").subs({"s": 1}) == 1 + + +def test_subs_with_unicode_symbols(): + expr = Symbol('var1') + replaced = expr.subs('var1', 'x') + assert replaced.name == 'x' + + replaced = expr.subs('var1', 'x') + assert replaced.name == 'x' + + +def test_atoms(): + assert b21.atoms() == {Basic()} + + +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) + assert b3.xreplace({b2: b1}) == b2 + assert Basic(b1, b2).xreplace({b1: b2, b2: b1}) == Basic(b2, b1) + 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])) + for f in (exp, Function('f')): + assert f.xreplace({}) == f + assert f.xreplace({}, hack2=True) == f + assert f.xreplace({f: b1}) == b1 + assert f.xreplace({f: b1}, hack2=True) == b1 + + +def test_sorted_args(): + x = symbols('x') + assert b21._sorted_args == b21.args + raises(AttributeError, lambda: x._sorted_args) + +def test_call(): + x, y = symbols('x y') + # See the long history of this in issues 5026 and 5105. + + 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).rcall(1) == sin(x) + assert (1 + sin(x)).rcall(1) == 1 + sin(x) + + # Effect in the presence of callables + l = Lambda(x, 2*x) + 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) + + assert (Q.real & Q.positive).rcall(x) == Q.real(x) & Q.positive(x) + + +def test_rewrite(): + x, y, z = symbols('x y z') + a, b = symbols('a b') + f1 = sin(x) + cos(x) + assert f1.rewrite(cos,exp) == exp(I*x)/2 + sin(x) + exp(-I*x)/2 + assert f1.rewrite([cos],sin) == sin(x) + sin(x + pi/2, evaluate=False) + f2 = sin(x) + cos(y)/gamma(z) + assert f2.rewrite(sin,exp) == -I*(exp(I*x) - exp(-I*x))/2 + cos(y)/gamma(z) + + assert f1.rewrite() == f1 + +def test_literal_evalf_is_number_is_zero_is_comparable(): + x = symbols('x') + f = Function('f') + + # issue 5033 + assert f.is_number is False + # issue 6646 + assert f(1).is_number is False + i = Integral(0, (x, x, x)) + # expressions that are symbolically 0 can be difficult to prove + # so in case there is some easy way to know if something is 0 + # it should appear in the is_zero property for that object; + # if is_zero is true evalf should always be able to compute that + # zero + assert i.n() == 0 + assert i.is_zero + assert i.is_number is False + assert i.evalf(2, strict=False) == 0 + + # issue 10268 + n = sin(1)**2 + cos(1)**2 - 1 + assert n.is_comparable is False + assert n.n(2).is_comparable is False + assert n.n(2).n(2).is_comparable + + +def test_as_Basic(): + assert as_Basic(1) is S.One + assert as_Basic(()) == Tuple() + raises(TypeError, lambda: as_Basic([])) + + +def test_atomic(): + g, h = map(Function, 'gh') + x = symbols('x') + assert _atomic(g(x + h(x))) == {g(x + h(x))} + assert _atomic(g(x + h(x)), recursive=True) == {h(x), x, g(x + h(x))} + assert _atomic(1) == set() + assert _atomic(Basic(S(1), S(2))) == set() + + +def test_as_dummy(): + u, v, x, y, z, _0, _1 = symbols('u v x y z _0 _1') + assert Lambda(x, x + 1).as_dummy() == Lambda(_0, _0 + 1) + assert Lambda(x, x + _0).as_dummy() == Lambda(_1, _0 + _1) + eq = (1 + Sum(x, (x, 1, x))) + ans = 1 + Sum(_0, (_0, 1, x)) + once = eq.as_dummy() + assert once == ans + twice = once.as_dummy() + assert twice == ans + assert Integral(x + _0, (x, x + 1), (_0, 1, 2) + ).as_dummy() == Integral(_0 + _1, (_0, x + 1), (_1, 1, 2)) + for T in (Symbol, Dummy): + d = T('x', real=True) + D = d.as_dummy() + assert D != d and D.func == Dummy and D.is_real is None + assert Dummy().as_dummy().is_commutative + assert Dummy(commutative=False).as_dummy().is_commutative is False + + +def test_canonical_variables(): + x, i0, i1 = symbols('x _:2') + assert Integral(x, (x, x + 1)).canonical_variables == {x: i0} + assert Integral(x, (x, x + 1), (i0, 1, 2)).canonical_variables == { + x: i0, i0: i1} + assert Integral(x, (x, x + i0)).canonical_variables == {x: i1} + + +def test_replace_exceptions(): + from sympy.core.symbol import Wild + x, y = symbols('x y') + e = (x**2 + x*y) + raises(TypeError, lambda: e.replace(sin, 2)) + b = Wild('b') + c = Wild('c') + raises(TypeError, lambda: e.replace(b*c, c.is_real)) + raises(TypeError, lambda: e.replace(b.is_real, 1)) + raises(TypeError, lambda: e.replace(lambda d: d.is_Number, 1)) + + +def test_ManagedProperties(): + # ManagedProperties is now deprecated. Here we do our best to check that if + # someone is using it then it does work in the way that it previously did + # but gives a deprecation warning. + from sympy.core.assumptions import ManagedProperties + + myclasses = [] + + class MyMeta(ManagedProperties): + def __init__(cls, *args, **kwargs): + myclasses.append('executed') + super().__init__(*args, **kwargs) + + code = """ +class MySubclass(Basic, metaclass=MyMeta): + pass +""" + with warns_deprecated_sympy(): + exec(code) + + assert myclasses == ['executed'] + + +def test_generic(): + # https://github.com/sympy/sympy/issues/25399 + class A(Symbol, Generic[T]): + pass + + class B(A[T]): + pass + + +def test_rewrite_abs(): + # https://github.com/sympy/sympy/issues/27323 + x = Symbol('x') + assert sign(x).rewrite(abs) == sign(x).rewrite(Abs) + assert sign(x).rewrite(abs) == Piecewise((0, Eq(x, 0)), (x / Abs(x), True)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_cache.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_cache.py new file mode 100644 index 0000000000000000000000000000000000000000..9124fca70718299252929a9923f335dde25256eb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_cache.py @@ -0,0 +1,91 @@ +import sys +from sympy.core.cache import cacheit, cached_property, lazy_function +from sympy.testing.pytest import raises + +def test_cacheit_doc(): + @cacheit + def testfn(): + "test docstring" + pass + + assert testfn.__doc__ == "test docstring" + assert testfn.__name__ == "testfn" + +def test_cacheit_unhashable(): + @cacheit + def testit(x): + return x + + assert testit(1) == 1 + assert testit(1) == 1 + a = {} + assert testit(a) == {} + a[1] = 2 + assert testit(a) == {1: 2} + +def test_cachit_exception(): + # Make sure the cache doesn't call functions multiple times when they + # raise TypeError + + a = [] + + @cacheit + def testf(x): + a.append(0) + raise TypeError + + raises(TypeError, lambda: testf(1)) + assert len(a) == 1 + + a.clear() + # Unhashable type + raises(TypeError, lambda: testf([])) + assert len(a) == 1 + + @cacheit + def testf2(x): + a.append(0) + raise TypeError("Error") + + a.clear() + raises(TypeError, lambda: testf2(1)) + assert len(a) == 1 + + a.clear() + # Unhashable type + raises(TypeError, lambda: testf2([])) + assert len(a) == 1 + +def test_cached_property(): + class A: + def __init__(self, value): + self.value = value + self.calls = 0 + + @cached_property + def prop(self): + self.calls = self.calls + 1 + return self.value + + a = A(2) + assert a.calls == 0 + assert a.prop == 2 + assert a.calls == 1 + assert a.prop == 2 + assert a.calls == 1 + b = A(None) + assert b.prop == None + + +def test_lazy_function(): + module_name='xmlrpc.client' + function_name = 'gzip_decode' + lazy = lazy_function(module_name, function_name) + assert lazy(b'') == b'' + assert module_name in sys.modules + assert function_name in str(lazy) + repr_lazy = repr(lazy) + assert 'LazyFunction' in repr_lazy + assert function_name in repr_lazy + + lazy = lazy_function('sympy.core.cache', 'cheap') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_compatibility.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_compatibility.py new file mode 100644 index 0000000000000000000000000000000000000000..31d2bed07b21aa2fa489273dca9edfc9993cfd86 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_compatibility.py @@ -0,0 +1,6 @@ +from sympy.testing.pytest import warns_deprecated_sympy + +def test_compatibility_submodule(): + # Test the sympy.core.compatibility deprecation warning + with warns_deprecated_sympy(): + import sympy.core.compatibility # noqa:F401 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_complex.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_complex.py new file mode 100644 index 0000000000000000000000000000000000000000..a607e0bdb4db859336aa30aa61f43bfb57d5df88 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_complex.py @@ -0,0 +1,226 @@ +from sympy.core.function import expand_complex +from sympy.core.numbers import (I, Integer, Rational, pi) +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.complexes import (Abs, conjugate, im, re, sign) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.hyperbolic import (cosh, coth, sinh, tanh) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, cot, sin, tan) + +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) == Pow(I, S.Half) + + +def test_conjugate(): + a = Symbol("a", real=True) + b = Symbol("b", real=True) + c = Symbol("c", imaginary=True) + d = Symbol("d", imaginary=True) + x = Symbol('x') + z = a + I*b + c + I*d + zc = a - I*b - c + I*d + assert conjugate(z) == zc + assert conjugate(exp(z)) == exp(zc) + assert conjugate(exp(I*x)) == exp(-I*conjugate(x)) + assert conjugate(z**5) == zc**5 + assert conjugate(abs(x)) == abs(x) + assert conjugate(sign(z)) == sign(zc) + assert conjugate(sin(z)) == sin(zc) + assert conjugate(cos(z)) == cos(zc) + assert conjugate(tan(z)) == tan(zc) + assert conjugate(cot(z)) == cot(zc) + assert conjugate(sinh(z)) == sinh(zc) + assert conjugate(cosh(z)) == cosh(zc) + 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) + assert abs(a) == Abs(a) + assert abs(-a) == abs(a) + assert abs(a + I*b) == sqrt(a**2 + b**2) + + +def test_abs2(): + 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) + + +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 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 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 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 tan(I*x).expand(complex=True) == tanh(x) * I + assert tan(x + I*y).expand(complex=True) == ( + sin(2*x)/(cos(2*x) + cosh(2*y)) + + I*sinh(2*y)/(cos(2*x) + cosh(2*y))) + + 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 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 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() + + +def test_pythoncomplex(): + x = Symbol("x") + assert 4j*x != 4*x*I + 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 (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) + + +def test_expand_complex(): + 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) == \ + -81079464736246615951519029367296227340216902563389546989376269312984127074385455204551402940331021387412262494620336565547972162814110386834027871072723273110439771695255662375718498785908345629702081336606863762777939617745464755635193139022811989314881997210583159045854968310911252660312523907616129080027594310008539817935736331124833163907518549408018652090650537035647520296539436440394920287688149200763245475036722326561143851304795139005599209239350981457301460233967137708519975586996623552182807311159141501424576682074392689622074945519232029999 + \ + 46938745946789557590804551905243206242164799136976022474337918748798900569942573265747576032611189047943842446167719177749107138603040963603119861476016947257034472364028585381714774667326478071264878108114128915685688115488744955550920239128462489496563930809677159214598114273887061533057125164518549173898349061972857446844052995037423459472376202251620778517659247970283904820245958198842631651569984310559418135975795868314764489884749573052997832686979294085577689571149679540256349988338406458116270429842222666345146926395233040564229555893248370000*I + assert ((2 + 3*I/4)**1000).expand(complex=True) == \ + Integer(1)*37079892761199059751745775382463070250205990218394308874593455293485167797989691280095867197640410033222367257278387021789651672598831503296531725827158233077451476545928116965316544607115843772405184272449644892857783761260737279675075819921259597776770965829089907990486964515784097181964312256560561065607846661496055417619388874421218472707497847700629822858068783288579581649321248495739224020822198695759609598745114438265083593711851665996586461937988748911532242908776883696631067311443171682974330675406616373422505939887984366289623091300746049101284856530270685577940283077888955692921951247230006346681086274961362500646889925803654263491848309446197554307105991537357310209426736453173441104334496173618419659521888945605315751089087820455852582920963561495787655250624781448951403353654348109893478206364632640344111022531861683064175862889459084900614967785405977231549003280842218501570429860550379522498497412180001/114813069527425452423283320117768198402231770208869520047764273682576626139237031385665948631650626991844596463898746277344711896086305533142593135616665318539129989145312280000688779148240044871428926990063486244781615463646388363947317026040466353970904996558162398808944629605623311649536164221970332681344168908984458505602379484807914058900934776500429002716706625830522008132236281291761267883317206598995396418127021779858404042159853183251540889433902091920554957783589672039160081957216630582755380425583726015528348786419432054508915275783882625175435528800822842770817965453762184851149029376 + \ + I*421638390580169706973991429333213477486930178424989246669892530737775352519112934278994501272111385966211392610029433824534634841747911783746811994443436271013377059560245191441549885048056920190833693041257216263519792201852046825443439142932464031501882145407459174948712992271510309541474392303461939389368955986650538525895866713074543004916049550090364398070215427272240155060576252568700906004691224321432509053286859100920489253598392100207663785243368195857086816912514025693453058403158416856847185079684216151337200057494966741268925263085619240941610301610538225414050394612058339070756009433535451561664522479191267503989904464718368605684297071150902631208673621618217106272361061676184840810762902463998065947687814692402219182668782278472952758690939877465065070481351343206840649517150634973307937551168752642148704904383991876969408056379195860410677814566225456558230131911142229028179902418223009651437985670625/1793954211366022694113801876840128100034871409513586250746316776290259783425578615401030447369541046747571819748417910583511123376348523955353017744010395602173906080395504375010762174191250701116076984219741972574712741619474818186676828531882286780795390571221287481389759837587864244524002565968286448146002639202882164150037179450123657170327105882819203167448541028601906377066191895183769810676831353109303069033234715310287563158747705988305326397404720186258671215368588625611876280581509852855552819149745718992630449787803625851701801184123166018366180137512856918294030710215034138299203584 + 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) == \ + 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) + + +def test_expand(): + f = (16 - 2*sqrt(29))**2 + assert f.expand() == 372 - 64*sqrt(29) + f = (Integer(1)/2 + I/2)**10 + assert f.expand() == I/32 + 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_5084(): + x = Symbol('x') + assert ((x + x*I)/(1 + I)).as_real_imag() == (re((x + I*x)/(1 + I) + ), im((x + I*x)/(1 + I))) + + +def test_issue_5236(): + 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, 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 5395: + 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 6573: + assert (x**2).as_real_imag() == (re(x)**2 - im(x)**2, 2*re(x)*im(x)) + + # issue 6428: + 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)) + assert (i*r*x*(y + 2)).as_real_imag() == ( + I*i*r*(re(y) + 2)*im(x) + I*i*r*re(x)*im(y), + -I*i*r*(re(y) + 2)*re(x) + I*i*r*im(x)*im(y)) + + # issue 7106: + assert ((1 + I)/(1 - I)).as_real_imag() == (0, 1) + assert ((1 + 2*I)*(1 + 3*I)).as_real_imag() == (-5, 5) + + +def test_pow_issue_1724(): + e = ((S.NegativeOne)**(S.One/3)) + assert e.conjugate().n() == e.n().conjugate() + e = S('-2/3 - (-29/54 + sqrt(93)/18)**(1/3) - 1/(9*(-29/54 + sqrt(93)/18)**(1/3))') + assert e.conjugate().n() == e.n().conjugate() + e = 2**I + assert e.conjugate().n() == e.n().conjugate() + + +def test_issue_5429(): + assert sqrt(I).conjugate() != sqrt(I) + +def test_issue_4124(): + from sympy.core.numbers import oo + assert expand_complex(I*oo) == oo*I + +def test_issue_11518(): + x = Symbol("x", real=True) + y = Symbol("y", real=True) + r = sqrt(x**2 + y**2) + assert conjugate(r) == r + s = abs(x + I * y) + assert conjugate(s) == r diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_constructor_postprocessor.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_constructor_postprocessor.py new file mode 100644 index 0000000000000000000000000000000000000000..c199e24eddf8ef7c2a14e38d1ad2dc95e4acc0cc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_constructor_postprocessor.py @@ -0,0 +1,87 @@ +from sympy.core.basic import Basic +from sympy.core.mul import Mul +from sympy.core.symbol import (Symbol, symbols) + +from sympy.testing.pytest import XFAIL + +class SymbolInMulOnce(Symbol): + # Test class for a symbol that can only appear once in a `Mul` expression. + pass + + +Basic._constructor_postprocessor_mapping[SymbolInMulOnce] = { + "Mul": [lambda x: x], + "Pow": [lambda x: x.base if isinstance(x.base, SymbolInMulOnce) else x], + "Add": [lambda x: x], +} + + +def _postprocess_SymbolRemovesOtherSymbols(expr): + args = tuple(i for i in expr.args if not isinstance(i, Symbol) or isinstance(i, SymbolRemovesOtherSymbols)) + if args == expr.args: + return expr + return Mul.fromiter(args) + + +class SymbolRemovesOtherSymbols(Symbol): + # Test class for a symbol that removes other symbols in `Mul`. + pass + +Basic._constructor_postprocessor_mapping[SymbolRemovesOtherSymbols] = { + "Mul": [_postprocess_SymbolRemovesOtherSymbols], +} + +class SubclassSymbolInMulOnce(SymbolInMulOnce): + pass + +class SubclassSymbolRemovesOtherSymbols(SymbolRemovesOtherSymbols): + pass + + +def test_constructor_postprocessors1(): + x = SymbolInMulOnce("x") + y = SymbolInMulOnce("y") + assert isinstance(3*x, Mul) + assert (3*x).args == (3, x) + assert x*x == x + assert 3*x*x == 3*x + assert 2*x*x + x == 3*x + assert x**3*y*y == x*y + assert x**5 + y*x**3 == x + x*y + + w = SymbolRemovesOtherSymbols("w") + assert x*w == w + assert (3*w).args == (3, w) + assert set((w + x).args) == {x, w} + +def test_constructor_postprocessors2(): + x = SubclassSymbolInMulOnce("x") + y = SubclassSymbolInMulOnce("y") + assert isinstance(3*x, Mul) + assert (3*x).args == (3, x) + assert x*x == x + assert 3*x*x == 3*x + assert 2*x*x + x == 3*x + assert x**3*y*y == x*y + assert x**5 + y*x**3 == x + x*y + + w = SubclassSymbolRemovesOtherSymbols("w") + assert x*w == w + assert (3*w).args == (3, w) + assert set((w + x).args) == {x, w} + + +@XFAIL +def test_subexpression_postprocessors(): + # The postprocessors used to work with subexpressions, but the + # functionality was removed. See #15948. + a = symbols("a") + x = SymbolInMulOnce("x") + w = SymbolRemovesOtherSymbols("w") + assert 3*a*w**2 == 3*w**2 + assert 3*a*x**3*w**2 == 3*w**2 + + x = SubclassSymbolInMulOnce("x") + w = SubclassSymbolRemovesOtherSymbols("w") + assert 3*a*w**2 == 3*w**2 + assert 3*a*x**3*w**2 == 3*w**2 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_containers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_containers.py new file mode 100644 index 0000000000000000000000000000000000000000..23357b9f667fffc82d93b2b1adb42b495114c67e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_containers.py @@ -0,0 +1,217 @@ +from collections import defaultdict + +from sympy.core.basic import Basic +from sympy.core.containers import (Dict, Tuple) +from sympy.core.numbers import Integer +from sympy.core.kind import NumberKind +from sympy.matrices.kind import MatrixKind +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.core.sympify import sympify +from sympy.matrices.dense import Matrix +from sympy.sets.sets import FiniteSet +from sympy.core.containers import tuple_wrapper, TupleKind +from sympy.core.expr import unchanged +from sympy.core.function import Function, Lambda +from sympy.core.relational import Eq +from sympy.testing.pytest import raises +from sympy.utilities.iterables import is_sequence, iterable + +from sympy.abc import x, y + + +def test_Tuple(): + t = (1, 2, 3, 4) + st = Tuple(*t) + assert set(sympify(t)) == set(st) + assert len(t) == len(st) + assert set(sympify(t[:2])) == set(st[:2]) + assert isinstance(st[:], Tuple) + assert st == Tuple(1, 2, 3, 4) + assert st.func(*st.args) == st + p, q, r, s = symbols('p q r s') + 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}) + # issue 5505 + assert all(isinstance(arg, Basic) for arg in st.args) + assert Tuple(p, 1).subs(p, 0) == Tuple(0, 1) + assert Tuple(p, Tuple(p, 1)).subs(p, 0) == Tuple(0, Tuple(0, 1)) + + assert Tuple(t2) == Tuple(Tuple(*t2)) + assert Tuple.fromiter(t2) == Tuple(*t2) + 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) + assert Tuple(1, 2) + (3, 4) == Tuple(1, 2, 3, 4) + raises(TypeError, lambda: Tuple(1, 2) + 3) + raises(TypeError, lambda: 1 + Tuple(2, 3)) + + #the Tuple case in __radd__ is only reached when a subclass is involved + class Tuple2(Tuple): + def __radd__(self, other): + return Tuple.__radd__(self, other + other) + 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 not isinstance(Tuple(1, 2), tuple) + assert (Tuple(1, 2) == (1, 2)) is True + assert (Tuple(1, 2) != (1, 2)) is False + assert (Tuple(1, 2) == (1, 3)) is False + assert (Tuple(1, 2) != (1, 3)) is True + assert (Tuple(1, 2) == Tuple(1, 2)) is True + assert (Tuple(1, 2) != Tuple(1, 2)) is False + assert (Tuple(1, 2) == Tuple(1, 3)) is False + assert (Tuple(1, 2) != Tuple(1, 3)) is True + + +def test_Tuple_Eq(): + assert Eq(Tuple(), Tuple()) is S.true + assert Eq(Tuple(1), 1) is S.false + assert Eq(Tuple(1, 2), Tuple(1)) is S.false + assert Eq(Tuple(1), Tuple(1)) is S.true + assert Eq(Tuple(1, 2), Tuple(1, 3)) is S.false + assert Eq(Tuple(1, 2), Tuple(1, 2)) is S.true + assert unchanged(Eq, Tuple(1, x), Tuple(1, 2)) + assert Eq(Tuple(1, x), Tuple(1, 2)).subs(x, 2) is S.true + assert unchanged(Eq, Tuple(1, 2), x) + f = Function('f') + assert unchanged(Eq, Tuple(1), f(x)) + assert Eq(Tuple(1), f(x)).subs(x, 1).subs(f, Lambda(y, (y,))) is S.true + + +def test_Tuple_comparision(): + assert (Tuple(1, 3) >= Tuple(-10, 30)) is S.true + assert (Tuple(1, 3) <= Tuple(-10, 30)) is S.false + assert (Tuple(1, 3) >= Tuple(1, 3)) is S.true + assert (Tuple(1, 3) <= Tuple(1, 3)) is S.true + + +def test_Tuple_tuple_count(): + assert Tuple(0, 1, 2, 3).tuple_count(4) == 0 + assert Tuple(0, 4, 1, 2, 3).tuple_count(4) == 1 + assert Tuple(0, 4, 1, 4, 2, 3).tuple_count(4) == 2 + assert Tuple(0, 4, 1, 4, 2, 4, 3).tuple_count(4) == 3 + + +def test_Tuple_index(): + assert Tuple(4, 0, 1, 2, 3).index(4) == 0 + assert Tuple(0, 4, 1, 2, 3).index(4) == 1 + assert Tuple(0, 1, 4, 2, 3).index(4) == 2 + assert Tuple(0, 1, 2, 4, 3).index(4) == 3 + assert Tuple(0, 1, 2, 3, 4).index(4) == 4 + + raises(ValueError, lambda: Tuple(0, 1, 2, 3).index(4)) + raises(ValueError, lambda: Tuple(4, 0, 1, 2, 3).index(4, 1)) + raises(ValueError, lambda: Tuple(0, 1, 2, 3, 4).index(4, 1, 4)) + + +def test_Tuple_mul(): + assert Tuple(1, 2, 3)*2 == Tuple(1, 2, 3, 1, 2, 3) + assert 2*Tuple(1, 2, 3) == Tuple(1, 2, 3, 1, 2, 3) + assert Tuple(1, 2, 3)*Integer(2) == Tuple(1, 2, 3, 1, 2, 3) + assert Integer(2)*Tuple(1, 2, 3) == Tuple(1, 2, 3, 1, 2, 3) + + raises(TypeError, lambda: Tuple(1, 2, 3)*S.Half) + raises(TypeError, lambda: S.Half*Tuple(1, 2, 3)) + + +def test_tuple_wrapper(): + + @tuple_wrapper + def wrap_tuples_and_return(*t): + return t + + p = symbols('p') + assert wrap_tuples_and_return(p, 1) == (p, 1) + 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 = [[], (), Tuple(), Matrix([[]])] + unordered = [set()] + not_sympy_iterable = [{}, '', ''] + assert all(is_sequence(i) for i in ordered) + assert all(not is_sequence(i) for i in unordered) + assert all(iterable(i) for i in ordered + unordered) + 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_TupleKind(): + kind = TupleKind(NumberKind, MatrixKind(NumberKind)) + assert Tuple(1, Matrix([1, 2])).kind is kind + assert Tuple(1, 2).kind is TupleKind(NumberKind, NumberKind) + assert Tuple(1, 2).kind.element_kind == (NumberKind, NumberKind) + + +def test_Dict(): + 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]) + raises(KeyError, lambda: d['2']) + assert len(d) == 3 + assert set(d.keys()) == {x, y, z} + assert set(d.values()) == {S.One, S(2), S(3)} + assert d.get(5, 'default') == 'default' + assert d.get('5', 'default') == 'default' + assert x in d and z in d and 5 not in d and '5' not in d + 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))) + + raises(TypeError, lambda: Dict(((x, 1), (y, 2), (z, 3)))) + with raises(NotImplementedError): + d[5] = 6 # assert immutability + + assert set( + d.items()) == {Tuple(x, S.One), Tuple(y, S(2)), Tuple(z, S(3))} + assert set(d) == {x, y, z} + assert str(d) == '{x: 1, y: 2, z: 3}' + assert d.__repr__() == '{x: 1, y: 2, z: 3}' + + # Test creating a Dict from a Dict. + d = Dict({x: 1, y: 2, z: 3}) + assert d == Dict(d) + + # Test for supporting defaultdict + d = defaultdict(int) + assert d[x] == 0 + assert d[y] == 0 + assert d[z] == 0 + assert Dict(d) + d = Dict(d) + assert len(d) == 3 + assert set(d.keys()) == {x, y, z} + assert set(d.values()) == {S.Zero, S.Zero, S.Zero} + + +def test_issue_5788(): + args = [(1, 2), (2, 1)] + for o in [Dict, Tuple, FiniteSet]: + # __eq__ and arg handling + if o != Tuple: + assert o(*args) == o(*reversed(args)) + pair = [o(*args), o(*reversed(args))] + assert sorted(pair) == sorted(pair) + assert set(o(*args)) # doesn't fail diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_count_ops.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_count_ops.py new file mode 100644 index 0000000000000000000000000000000000000000..bc95004ef5ba4421927289a049a9197d208c30d0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_count_ops.py @@ -0,0 +1,155 @@ +from sympy.concrete.summations import Sum +from sympy.core.basic import Basic +from sympy.core.function import (Derivative, Function, count_ops) +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.relational import (Eq, Rel) +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.integrals.integrals import Integral +from sympy.logic.boolalg import (And, Equivalent, ITE, Implies, Nand, + Nor, Not, Or, Xor) +from sympy.matrices.expressions.matexpr import MatrixSymbol +from sympy.core.containers import Tuple + +x, y, z = symbols('x,y,z') +a, b, c = symbols('a,b,c') + +def test_count_ops_non_visual(): + def count(val): + return count_ops(val, visual=False) + assert count(x) == 0 + assert count(x) is not S.Zero + assert count(x + y) == 1 + assert count(x + y) is not S.One + assert count(x + y*x + 2*y) == 4 + assert count({x + y: x}) == 1 + assert count({x + y: S(2) + x}) is not S.One + assert count(x < y) == 1 + assert count(Or(x,y)) == 1 + assert count(And(x,y)) == 1 + assert count(Not(x)) == 1 + assert count(Nor(x,y)) == 2 + assert count(Nand(x,y)) == 2 + assert count(Xor(x,y)) == 1 + assert count(Implies(x,y)) == 1 + assert count(Equivalent(x,y)) == 1 + assert count(ITE(x,y,z)) == 1 + assert count(ITE(True,x,y)) == 0 + + +def test_count_ops_visual(): + ADD, MUL, POW, SIN, COS, EXP, AND, D, G, M = symbols( + 'Add Mul Pow sin cos exp And Derivative Integral Sum'.upper()) + DIV, SUB, NEG = symbols('DIV SUB NEG') + LT, LE, GT, GE, EQ, NE = symbols('LT LE GT GE EQ NE') + NOT, OR, AND, XOR, IMPLIES, EQUIVALENT, _ITE, BASIC, TUPLE = symbols( + 'Not Or And Xor Implies Equivalent ITE Basic Tuple'.upper()) + + def count(val): + return count_ops(val, visual=True) + + assert count(7) is S.Zero + assert count(S(7)) is S.Zero + assert count(-1) == NEG + assert count(-2) == NEG + assert count(S(2)/3) == DIV + assert count(Rational(2, 3)) == DIV + assert count(pi/3) == DIV + assert count(-pi/3) == DIV + NEG + assert count(I - 1) == SUB + assert count(1 - I) == SUB + assert count(1 - 2*I) == SUB + MUL + + assert count(x) is S.Zero + assert count(-x) == NEG + assert count(-2*x/3) == NEG + DIV + MUL + assert count(Rational(-2, 3)*x) == NEG + DIV + MUL + assert count(1/x) == DIV + assert count(1/(x*y)) == DIV + MUL + assert count(-1/x) == NEG + DIV + assert count(-2/x) == NEG + DIV + assert count(x/y) == DIV + assert count(-x/y) == NEG + DIV + + assert count(x**2) == POW + assert count(-x**2) == POW + NEG + assert count(-2*x**2) == POW + MUL + NEG + + assert count(x + pi/3) == ADD + DIV + assert count(x + S.One/3) == ADD + DIV + assert count(x + Rational(1, 3)) == ADD + DIV + assert count(x + y) == ADD + assert count(x - y) == SUB + assert count(y - x) == SUB + assert count(-1/(x - y)) == DIV + NEG + SUB + assert count(-1/(y - x)) == DIV + NEG + SUB + assert count(1 + x**y) == ADD + POW + assert count(1 + x + y) == 2*ADD + assert count(1 + x + y + z) == 3*ADD + assert count(1 + x**y + 2*x*y + y**2) == 3*ADD + 2*POW + 2*MUL + assert count(2*z + y + x + 1) == 3*ADD + MUL + 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(Derivative(x, x)) == D + assert count(Integral(x, x) + 2*x/(1 + x)) == G + DIV + MUL + 2*ADD + assert count(Sum(x, (x, 1, x + 1)) + 2*x/(1 + x)) == M + DIV + MUL + 3*ADD + assert count(Basic()) is S.Zero + + assert count({x + 1: sin(x)}) == ADD + SIN + assert count([x + 1, sin(x) + y, None]) == ADD + SIN + ADD + assert count({x + 1: sin(x), y: cos(x) + 1}) == SIN + COS + 2*ADD + assert count({}) is S.Zero + assert count([x + 1, sin(x)*y, None]) == SIN + ADD + MUL + assert count([]) is S.Zero + + assert count(Basic()) == 0 + assert count(Basic(Basic(),Basic(x,x+y))) == ADD + 2*BASIC + assert count(Basic(x, x + y)) == ADD + BASIC + assert [count(Rel(x, y, op)) for op in '< <= > >= == <> !='.split() + ] == [LT, LE, GT, GE, EQ, NE, NE] + assert count(Or(x, y)) == OR + assert count(And(x, y)) == AND + assert count(Or(x, Or(y, And(z, a)))) == AND + OR + assert count(Nor(x, y)) == NOT + OR + assert count(Nand(x, y)) == NOT + AND + assert count(Xor(x, y)) == XOR + assert count(Implies(x, y)) == IMPLIES + assert count(Equivalent(x, y)) == EQUIVALENT + assert count(ITE(x, y, z)) == _ITE + assert count([Or(x, y), And(x, y), Basic(x + y)] + ) == ADD + AND + BASIC + OR + + assert count(Basic(Tuple(x))) == BASIC + TUPLE + #It checks that TUPLE is counted as an operation. + + assert count(Eq(x + y, S(2))) == ADD + EQ + + +def test_issue_9324(): + def count(val): + return count_ops(val, visual=False) + + M = MatrixSymbol('M', 10, 10) + assert count(M[0, 0]) == 0 + assert count(2 * M[0, 0] + M[5, 7]) == 2 + P = MatrixSymbol('P', 3, 3) + Q = MatrixSymbol('Q', 3, 3) + assert count(P + Q) == 1 + m = Symbol('m', integer=True) + n = Symbol('n', integer=True) + M = MatrixSymbol('M', m + n, m * m) + assert count(M[0, 1]) == 2 + + +def test_issue_21532(): + f = Function('f') + g = Function('g') + FUNC_F, FUNC_G = symbols('FUNC_F, FUNC_G') + assert f(x).count_ops(visual=True) == FUNC_F + assert g(x).count_ops(visual=True) == FUNC_G diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_diff.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_diff.py new file mode 100644 index 0000000000000000000000000000000000000000..effc9cd91d2e7b6f8f8e5fd04bb667ed71c0ffaf --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_diff.py @@ -0,0 +1,160 @@ +from sympy.concrete.summations import Sum +from sympy.core.expr import Expr +from sympy.core.function import (Derivative, Function, diff, Subs) +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.complexes import (im, re) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import Max +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (cos, cot, sin, tan) +from sympy.tensor.array.ndim_array import NDimArray +from sympy.testing.pytest import raises +from sympy.abc import a, b, c, x, y, z + +def test_diff(): + assert Rational(1, 3).diff(x) is S.Zero + assert I.diff(x) is S.Zero + assert pi.diff(x) is S.Zero + assert x.diff(x, 0) == x + assert (x**2).diff(x, 2, x) == 0 + assert (x**2).diff((x, 2), x) == 0 + assert (x**2).diff((x, 1), x) == 2 + assert (x**2).diff((x, 1), (x, 1)) == 2 + assert (x**2).diff((x, 2)) == 2 + assert (x**2).diff(x, y, 0) == 2*x + assert (x**2).diff(x, (y, 0)) == 2*x + assert (x**2).diff(x, y) == 0 + raises(ValueError, lambda: x.diff(1, x)) + + p = Rational(5) + e = a*b + b**p + assert e.diff(a) == b + assert e.diff(b) == a + 5*b**4 + assert e.diff(b).diff(a) == Rational(1) + e = a*(b + c) + assert e.diff(a) == b + c + assert e.diff(b) == a + assert e.diff(b).diff(a) == Rational(1) + e = c**p + assert e.diff(c, 6) == Rational(0) + assert e.diff(c, 5) == Rational(120) + e = c**Rational(2) + assert e.diff(c) == 2*c + e = a*b*c + assert e.diff(c) == a*b + + +def test_diff2(): + n3 = Rational(3) + n2 = Rational(2) + n6 = Rational(6) + + 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) + assert e.diff(x).expand() == x**3*cos(x) + + e = (x + 1)**3 + assert e.diff(x) == 3*(x + 1)**2 + e = x*(x + 1)**3 + assert e.diff(x) == (x + 1)**3 + 3*x*(x + 1)**2 + e = 2*exp(x*x)*x + assert e.diff(x) == 2*exp(x**2) + 4*x**2*exp(x**2) + + +def test_diff3(): + 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) + 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) + assert e.diff(c) == log(c) + e = log(sin(c)) + assert e == log(sin(c)) + assert e.diff(c) in [sin(c)**(-1)*cos(c), cot(c)] + e = (Rational(2)**a/log(Rational(2))) + 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): + return Expr.__new__(cls, x) + + # My doesn't have its own _eval_derivative method + assert My(x).diff(x).func is Derivative + assert My(x).diff(x, 3).func is Derivative + assert re(x).diff(x, 2) == Derivative(re(x), (x, 2)) # issue 15518 + assert diff(NDimArray([re(x), im(x)]), (x, 2)) == NDimArray( + [Derivative(re(x), (x, 2)), Derivative(im(x), (x, 2))]) + # 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. + assert x.diff(x, 10**8) == 0 + + +def test_deriv_noncommutative(): + A = Symbol("A", commutative=False) + f = Function("f") + assert A*f(x)*A == f(x)*A**2 + assert A*f(x).diff(x)*A == f(x).diff(x) * A**2 + + +def test_diff_nth_derivative(): + f = Function("f") + n = Symbol("n", integer=True) + + expr = diff(sin(x), (x, n)) + expr2 = diff(f(x), (x, 2)) + expr3 = diff(f(x), (x, n)) + + assert expr.subs(sin(x), cos(-x)) == Derivative(cos(-x), (x, n)) + assert expr.subs(n, 1).doit() == cos(x) + assert expr.subs(n, 2).doit() == -sin(x) + + assert expr2.subs(Derivative(f(x), x), y) == Derivative(y, x) + # Currently not supported (cannot determine if `n > 1`): + #assert expr3.subs(Derivative(f(x), x), y) == Derivative(y, (x, n-1)) + assert expr3 == Derivative(f(x), (x, n)) + + assert diff(x, (x, n)) == Piecewise((x, Eq(n, 0)), (1, Eq(n, 1)), (0, True)) + assert diff(2*x, (x, n)).dummy_eq( + Sum(Piecewise((2*x*factorial(n)/(factorial(y)*factorial(-y + n)), + Eq(y, 0) & Eq(Max(0, -y + n), 0)), + (2*factorial(n)/(factorial(y)*factorial(-y + n)), Eq(y, 0) & Eq(Max(0, + -y + n), 1)), (0, True)), (y, 0, n))) + # TODO: assert diff(x**2, (x, n)) == x**(2-n)*ff(2, n) + exprm = x*sin(x) + mul_diff = diff(exprm, (x, n)) + assert isinstance(mul_diff, Sum) + for i in range(5): + assert mul_diff.subs(n, i).doit() == exprm.diff((x, i)).expand() + + exprm2 = 2*y*x*sin(x)*cos(x)*log(x)*exp(x) + dex = exprm2.diff((x, n)) + assert isinstance(dex, Sum) + for i in range(7): + assert dex.subs(n, i).doit().expand() == \ + exprm2.diff((x, i)).expand() + + assert (cos(x)*sin(y)).diff([[x, y, z]]) == NDimArray([ + -sin(x)*sin(y), cos(x)*cos(y), 0]) + + +def test_issue_16160(): + assert Derivative(x**3, (x, x)).subs(x, 2) == Subs( + Derivative(x**3, (x, 2)), x, 2) + assert Derivative(1 + x**3, (x, x)).subs(x, 0 + ) == Derivative(1 + y**3, (y, 0)).subs(y, 0) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_equal.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_equal.py new file mode 100644 index 0000000000000000000000000000000000000000..82213b757cda5fbd80310e387bdf00cc1c9c25fe --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_equal.py @@ -0,0 +1,89 @@ +from sympy.core.numbers import Rational +from sympy.core.symbol import (Dummy, Symbol) +from sympy.functions.elementary.exponential import exp + + +def test_equal(): + b = Symbol("b") + a = Symbol("a") + e1 = a + b + e2 = 2*a*b + e3 = a**3*b**2 + e4 = a*b + b*a + assert not e1 == e2 + assert not e1 == e2 + assert e1 != e2 + assert e2 == e4 + assert e2 != e3 + assert not e2 == e3 + + x = Symbol("x") + e1 = exp(x + 1/x) + y = Symbol("x") + e2 = exp(y + 1/y) + assert e1 == e2 + assert not e1 != e2 + y = Symbol("y") + e2 = exp(y + 1/y) + assert not e1 == e2 + assert e1 != e2 + + 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 + + +def test_expevalbug(): + x = Symbol("x") + e1 = exp(1*x) + e3 = exp(x) + assert e1 == e3 + + +def test_cmp_bug1(): + class T: + pass + + t = T() + x = Symbol("x") + + assert not (x == t) + assert (x != t) + + +def test_cmp_bug2(): + class T: + pass + + t = T() + + assert not (Symbol == t) + assert (Symbol != t) + + +def test_cmp_issue_4357(): + """ Check that Basic subclasses can be compared with sympifiable objects. + + https://github.com/sympy/sympy/issues/4357 + """ + assert not (Symbol == 1) + assert (Symbol != 1) + 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) is True + assert ((u**2 + 1) == (x**2 + 1)) is 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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_eval.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_eval.py new file mode 100644 index 0000000000000000000000000000000000000000..9c1633f77b50483afee21c6d9fca232b1279d2b9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_eval.py @@ -0,0 +1,95 @@ +from sympy.core.function import Function +from sympy.core.numbers import (I, Rational) +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, tan) +from sympy.testing.pytest import XFAIL + + +def test_add_eval(): + a = Symbol("a") + 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 + + +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 + + +def test_pow_eval(): + # XXX Pow does not fully support conversion of negative numbers + # to their complex equivalent + + assert sqrt(-1) == I + + 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 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 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 (cos(2) / tan(2))**2 == (cos(2) / tan(2))**2 + + +@XFAIL +def test_pow_eval_X1(): + assert (-1)**Rational(1, 3) == S.Half + S.Half*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') + + f = x**4*y**4 + assert f == x**4*y**4 + assert f == f.expand() + + g = (x*y)**4 + assert g == f + assert g.expand() == f + assert g.expand() == g.expand().expand() + + +def test_function(): + f, l = map(Function, 'fl') + x = Symbol('x') + assert exp(l(x))*l(x)/exp(l(x)) == l(x) + assert exp(f(x))*f(x)/exp(f(x)) == f(x) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_evalf.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_evalf.py new file mode 100644 index 0000000000000000000000000000000000000000..2c3c26a2d265da9ea2daa73a9eea3091b2af1999 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_evalf.py @@ -0,0 +1,738 @@ +import math + +from sympy.concrete.products import (Product, product) +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.evalf import N +from sympy.core.function import (Function, nfloat) +from sympy.core.mul import Mul +from sympy.core import (GoldenRatio) +from sympy.core.numbers import (AlgebraicNumber, E, Float, I, Rational, + oo, zoo, nan, pi) +from sympy.core.power import Pow +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.combinatorial.numbers import fibonacci +from sympy.functions.elementary.complexes import (Abs, re, im) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.hyperbolic import (acosh, cosh) +from sympy.functions.elementary.integers import (ceiling, floor) +from sympy.functions.elementary.miscellaneous import (Max, sqrt) +from sympy.functions.elementary.trigonometric import (acos, atan, cos, sin, tan) +from sympy.integrals.integrals import (Integral, integrate) +from sympy.polys.polytools import factor +from sympy.polys.rootoftools import CRootOf +from sympy.polys.specialpolys import cyclotomic_poly +from sympy.printing import srepr +from sympy.printing.str import sstr +from sympy.simplify.simplify import simplify +from sympy.core.numbers import comp +from sympy.core.evalf import (complex_accuracy, PrecisionExhausted, + scaled_zero, get_integer_part, as_mpmath, evalf, _evalf_with_bounded_error) +from mpmath import inf, ninf, make_mpc +from mpmath.libmp.libmpf import from_float, fzero +from sympy.core.expr import unchanged +from sympy.testing.pytest import raises, XFAIL +from sympy.abc import n, x, y + + +def NS(e, n=15, **options): + return sstr(sympify(e).evalf(n, **options), full_prec=True) + + +def test_evalf_helpers(): + from mpmath.libmp import finf + 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(finf) == math.inf + assert complex_accuracy(zoo) == math.inf + raises(ValueError, lambda: get_integer_part(zoo, 1, {})) + + +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('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' + + +def test_evalf_powers(): + 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' + +# 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' + + +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' + + +@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') + + +def test_evalf_complex_powers(): + assert NS('(E+pi*I)**100000000000000000') == \ + '-3.58896782867793e+61850354284995199 + 4.58581754997159e+61850354284995199*I' + # 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**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**12 + pi*I)**4') == '-389.636364136258 + 2.481e-10*I' + 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(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(exp(pi)) == '23.1406926327793' + 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') + C = Rational('69301/100000') + D = Rational('83542/100000') + F = Rational('2231321613/2500000000') + # XXX: the number of returned mantissa digits in the real part could + # change with the implementation. What matters is that the returned digits are + # correct; those that are showing now are correct. + # >>> ((A+B*I)*(C+D*I)).expand() + # 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') + + +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' + assert NS('log(-1 + 0.00001)', 2) == '-1.0e-5 + 3.1*I' + assert NS('log(100, 10, evaluate=False)', 15) == '2.00000000000000' + assert NS('-2*I*log(-(-1)**(S(1)/9))', 15) == '-5.58505360638185' + + +def test_evalf_trig(): + assert NS('sin(1)', 15) == '0.841470984807897' + assert NS('cos(1)', 15) == '0.540302305868140' + assert NS('tan(1)', 15) == '1.55740772465490' + assert NS('sin(10**-6)', 15) == '9.99999999999833e-7' + assert NS('cos(10**-6)', 15) == '0.999999999999500' + assert NS('tan(10**-6)', 15) == '1.00000000000033e-6' + assert NS('sin(E*10**100)', 15) == '0.409160531722613' + assert NS('tan(I)',15) =='0.761594155955765*I' + assert NS('tan(1000*I)',15)== '1.00000000000000*I' + # 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) == \ + '6.99999999428333e-5' + 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)) + 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('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' + +# 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('expand_log(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' + # issue 4758 (1/2): + assert NS(pi.evalf(69) - pi) == '-4.43863937855894e-71' + # issue 4758 (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() + ) == '(1.00000000000000 - x)**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() + # issue 6660. 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*E**(oo)).n() is S.NaN + assert (0/E**(oo)).n() is S.Zero + + assert (0+E**(oo)).n() is S.Infinity + assert (0-E**(oo)).n() is S.NegativeInfinity + + assert (5*E**(oo)).n() is S.Infinity + assert (5/E**(oo)).n() is S.Zero + + assert (5+E**(oo)).n() is S.Infinity + assert (5-E**(oo)).n() is S.NegativeInfinity + + #issue 7416 + assert as_mpmath(0.0, 10, {'chop': True}) == 0 + + #issue 5412 + assert ((oo*I).n() == S.Infinity*I) + assert ((oo+oo*I).n() == S.Infinity + S.Infinity*I) + + #issue 11518 + assert NS(2*x**2.5, 5) == '2.0000*x**2.5000' + + #issue 13076 + assert NS(Mul(Max(0, y), x, evaluate=False).evalf()) == 'x*Max(0, y)' + + #issue 18516 + assert NS(log(S(3273390607896141870013189696827599152216642046043064789483291368096133796404674554883270092325904157150886684127560071009217256545885393053328527589376)/36360291795869936842385267079543319118023385026001623040346035832580600191583895484198508262979388783308179702534403855752855931517013066142992430916562025780021771247847643450125342836565813209972590371590152578728008385990139795377610001).evalf(15, chop=True)) == '-oo' + + +def test_evalf_integer_parts(): + a = floor(log(8)/log(2) - exp(-1000), evaluate=False) + b = floor(log(8)/log(2), evaluate=False) + assert a.evalf() == 3.0 + assert b.evalf() == 3.0 + # 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(70)) == \ + int(11188719610782480504630258070757734324011354208865721592720336800) + assert int(ceiling(factorial(50)/E, evaluate=False).evalf(70)) == \ + int(11188719610782480504630258070757734324011354208865721592720336801) + assert int(floor(GoldenRatio**999 / sqrt(5) + S.Half) + .evalf(1000)) == fibonacci(999) + assert int(floor(GoldenRatio**1000 / sqrt(5) + S.Half) + .evalf(1000)) == fibonacci(1000) + + assert ceiling(x).evalf(subs={x: 3}) == 3.0 + assert ceiling(x).evalf(subs={x: 3*I}) == 3.0*I + assert ceiling(x).evalf(subs={x: 2 + 3*I}) == 2.0 + 3.0*I + assert ceiling(x).evalf(subs={x: 3.}) == 3.0 + assert ceiling(x).evalf(subs={x: 3.*I}) == 3.0*I + assert ceiling(x).evalf(subs={x: 2. + 3*I}) == 2.0 + 3.0*I + + assert float((floor(1.5, evaluate=False)+1/9).evalf()) == 1 + 1/9 + assert float((floor(0.5, evaluate=False)+20).evalf()) == 20 + + # issue 19991 + n = 1169809367327212570704813632106852886389036911 + r = 744723773141314414542111064094745678855643068 + + assert floor(n / (pi / 2)) == r + assert floor(80782 * sqrt(2)) == 114242 + + # issue 20076 + assert 260515 - floor(260515/pi + 1/2) * pi == atan(tan(260515)) + + assert floor(x).evalf(subs={x: sqrt(2)}) == 1.0 + + +def test_evalf_trig_zero_detection(): + a = sin(160*pi, evaluate=False) + t = a.evalf(maxn=100) + assert abs(t) < 1e-100 + assert t._prec < 2 + assert a.evalf(chop=True) == 0 + raises(PrecisionExhausted, lambda: a.evalf(strict=True)) + + +def test_evalf_sum(): + assert Sum(n,(n,1,2)).evalf() == 3. + assert Sum(n,(n,1,2)).doit().evalf() == 3. + # the next test should return instantly + assert Sum(1/n,(n,1,2)).evalf() == 1.5 + + # issue 8219 + assert Sum(E/factorial(n), (n, 0, oo)).evalf() == (E*E).evalf() + # issue 8254 + assert Sum(2**n*n/factorial(n), (n, 0, oo)).evalf() == (2*E*E).evalf() + # issue 8411 + s = Sum(1/x**2, (x, 100, oo)) + assert s.n() == s.doit().n() + + +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((-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()) + + +def test_evalf_product(): + assert Product(n, (n, 1, 10)).evalf() == 3628800. + assert comp(Product(1 - S.Half**2/n**2, (n, 1, oo)).n(5), 0.63662) + assert Product(n, (n, -1, 3)).evalf() == 0 + + +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)) + + +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.0 + assert (3**x).evalf(subs={x: 0}) == 1.0 + assert exp(x).evalf(subs={x: 0}) == 1.0 + assert ((2 + I)**x).evalf(subs={x: 0}) == 1.0 + assert (0**x).evalf(subs={x: 0}) == 1.0 + + +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') + f = implemented_function(f, lambda x: x + 1) + assert str(f(x)) == "f(x)" + assert str(f(2)) == "f(2)" + assert f(2).evalf() == 3.0 + assert f(x).evalf() == f(x) + f = implemented_function(Function('sin'), lambda x: x + 1) + assert f(2).evalf() != sin(2) + del f._imp_ # XXX: due to caching _imp_ would influence all other tests + + +def test_evaluate_false(): + for no in [0, False]: + assert Add(3, 2, evaluate=no).is_Add + assert Mul(3, 2, evaluate=no).is_Mul + 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) + # if this first assertion fails it should be replaced with + # one that doesn't + assert unchanged(Eq, (3 - I)**2/2 + I, 0) + assert Eq((3 - I)**2/2 + I, 0).n() is S.false + assert nfloat(Eq((3 - I)**2 + I, 0)) == S.false + + +def test_issue_5486(): + assert not cos(sqrt(0.5 + I)).n().is_Function + + +def test_issue_5486_bug(): + from sympy.core.expr import Expr + from sympy.core.numbers import I + assert abs(Expr._from_mpmath(I._to_mpmath(15), 15) - I) < 1.0e-15 + + +def test_bugs(): + from sympy.functions.elementary.complexes import (polar_lift, re) + + 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(): + 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' + raises(TypeError, lambda: x.evalf(subs=(x, 1))) + + +def test_issue_4956_5204(): + # issue 4956 + v = S('''(-27*12**(1/3)*sqrt(31)*I + + 27*2**(2/3)*3**(1/3)*sqrt(31)*I)/(-2511*2**(2/3)*3**(1/3) + + (29*18**(1/3) + 9*2**(1/3)*3**(2/3)*sqrt(31)*I + + 87*2**(1/3)*3**(1/6)*I)**2)''') + assert NS(v, 1) == '0.e-118 - 0.e-118*I' + + # issue 5204 + v = S('''-(357587765856 + 18873261792*249**(1/2) + 56619785376*I*83**(1/2) + + 108755765856*I*3**(1/2) + 41281887168*6**(1/3)*(1422 + + 54*249**(1/2))**(1/3) - 1239810624*6**(1/3)*249**(1/2)*(1422 + + 54*249**(1/2))**(1/3) - 3110400000*I*6**(1/3)*83**(1/2)*(1422 + + 54*249**(1/2))**(1/3) + 13478400000*I*3**(1/2)*6**(1/3)*(1422 + + 54*249**(1/2))**(1/3) + 1274950152*6**(2/3)*(1422 + + 54*249**(1/2))**(2/3) + 32347944*6**(2/3)*249**(1/2)*(1422 + + 54*249**(1/2))**(2/3) - 1758790152*I*3**(1/2)*6**(2/3)*(1422 + + 54*249**(1/2))**(2/3) - 304403832*I*6**(2/3)*83**(1/2)*(1422 + + 4*249**(1/2))**(2/3))/(175732658352 + (1106028 + 25596*249**(1/2) + + 76788*I*83**(1/2))**2)''') + 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_4806(): + assert integrate(atan(x)**2, (x, -1, 1)).evalf().round(1) == Float(0.5, 1) + 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) + assert scaled_zero(a) == (0, 1, 100, 1) + a, b = (([1], 1, 100, 1), -1) + assert scaled_zero(100, -1) == (a, b) + assert scaled_zero(a) == (1, 1, 100, 1) + raises(ValueError, lambda: scaled_zero(scaled_zero(100))) + raises(ValueError, lambda: scaled_zero(100, 2)) + 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 + + +def test_to_mpmath(): + assert sqrt(3)._to_mpmath(20)._mpf_ == (0, int(908093), -19, 20) + assert S(3.2)._to_mpmath(20)._mpf_ == (0, int(838861), -18, 20) + + +def test_issue_6632_evalf(): + add = (-100000*sqrt(2500000001) + 5000000001) + assert add.n() == 9.999999998e-11 + assert (add*add).n() == 9.999999996e-21 + + +def test_issue_4945(): + from sympy.abc import H + assert (H/0).evalf(subs={H:1}) == zoo + + +def test_evalf_integral(): + # test that workprec has to increase in order to get a result other than 0 + eps = Rational(1, 1000000) + assert Integral(sin(x), (x, -pi, pi + eps)).n(2)._prec == 10 + + +def test_issue_8821_highprec_from_str(): + s = str(pi.evalf(128)) + p = N(s) + assert Abs(sin(p)) < 1e-15 + p = N(s, 64) + assert Abs(sin(p)) < 1e-64 + + +def test_issue_8853(): + p = Symbol('x', even=True, positive=True) + assert floor(-p - S.Half).is_even == False + assert floor(-p + S.Half).is_even == True + assert ceiling(p - S.Half).is_even == True + assert ceiling(p + S.Half).is_even == False + + assert get_integer_part(S.Half, -1, {}, True) == (0, 0) + assert get_integer_part(S.Half, 1, {}, True) == (1, 0) + assert get_integer_part(Rational(-1, 2), -1, {}, True) == (-1, 0) + assert get_integer_part(Rational(-1, 2), 1, {}, True) == (0, 0) + + +def test_issue_17681(): + class identity_func(Function): + + def _eval_evalf(self, *args, **kwargs): + return self.args[0].evalf(*args, **kwargs) + + assert floor(identity_func(S(0))) == 0 + assert get_integer_part(S(0), 1, {}, True) == (0, 0) + + +def test_issue_9326(): + from sympy.core.symbol import Dummy + d1 = Dummy('d') + d2 = Dummy('d') + e = d1 + d2 + assert e.evalf(subs = {d1: 1, d2: 2}) == 3.0 + + +def test_issue_10323(): + assert ceiling(sqrt(2**30 + 1)) == 2**15 + 1 + + +def test_AssocOp_Function(): + # the first arg of Min is not comparable in the imaginary part + raises(ValueError, lambda: S(''' + Min(-sqrt(3)*cos(pi/18)/6 + re(1/((-1/2 - sqrt(3)*I/2)*(1/6 + + sqrt(3)*I/18)**(1/3)))/3 + sin(pi/18)/2 + 2 + I*(-cos(pi/18)/2 - + sqrt(3)*sin(pi/18)/6 + im(1/((-1/2 - sqrt(3)*I/2)*(1/6 + + sqrt(3)*I/18)**(1/3)))/3), re(1/((-1/2 + sqrt(3)*I/2)*(1/6 + + sqrt(3)*I/18)**(1/3)))/3 - sqrt(3)*cos(pi/18)/6 - sin(pi/18)/2 + 2 + + I*(im(1/((-1/2 + sqrt(3)*I/2)*(1/6 + sqrt(3)*I/18)**(1/3)))/3 - + sqrt(3)*sin(pi/18)/6 + cos(pi/18)/2))''')) + # if that is changed so a non-comparable number remains as + # an arg, then the Min/Max instantiation needs to be changed + # to watch out for non-comparable args when making simplifications + # and the following test should be added instead (with e being + # the sympified expression above): + # raises(ValueError, lambda: e._eval_evalf(2)) + + +def test_issue_10395(): + eq = x*Max(0, y) + assert nfloat(eq) == eq + eq = x*Max(y, -1.1) + assert nfloat(eq) == eq + assert Max(y, 4).n() == Max(4.0, y) + + +def test_issue_13098(): + assert floor(log(S('9.'+'9'*20), 10)) == 0 + assert ceiling(log(S('9.'+'9'*20), 10)) == 1 + assert floor(log(20 - S('9.'+'9'*20), 10)) == 1 + assert ceiling(log(20 - S('9.'+'9'*20), 10)) == 2 + + +def test_issue_14601(): + e = 5*x*y/2 - y*(35*(x**3)/2 - 15*x/2) + subst = {x:0.0, y:0.0} + e2 = e.evalf(subs=subst) + assert float(e2) == 0.0 + assert float((x + x*(x**2 + x)).evalf(subs={x: 0.0})) == 0.0 + + +def test_issue_11151(): + z = S.Zero + e = Sum(z, (x, 1, 2)) + assert e != z # it shouldn't evaluate + # when it does evaluate, this is what it should give + assert evalf(e, 15, {}) == \ + evalf(z, 15, {}) == (None, None, 15, None) + # so this shouldn't fail + assert (e/2).n() == 0 + # this was where the issue appeared + expr0 = Sum(x**2 + x, (x, 1, 2)) + expr1 = Sum(0, (x, 1, 2)) + expr2 = expr1/expr0 + assert simplify(factor(expr2) - expr2) == 0 + + +def test_issue_13425(): + assert N('2**.5', 30) == N('sqrt(2)', 30) + assert N('x - x', 30) == 0 + assert abs((N('pi*.1', 22)*10 - pi).n()) < 1e-22 + + +def test_issue_17421(): + assert N(acos(-I + acosh(cosh(cosh(1) + I)))) == 1.0*I + + +def test_issue_20291(): + from sympy.sets import EmptySet, Reals + from sympy.sets.sets import (Complement, FiniteSet, Intersection) + a = Symbol('a') + b = Symbol('b') + A = FiniteSet(a, b) + assert A.evalf(subs={a: 1, b: 2}) == FiniteSet(1.0, 2.0) + B = FiniteSet(a-b, 1) + assert B.evalf(subs={a: 1, b: 2}) == FiniteSet(-1.0, 1.0) + + sol = Complement(Intersection(FiniteSet(-b/2 - sqrt(b**2-4*pi)/2), Reals), FiniteSet(0)) + assert sol.evalf(subs={b: 1}) == EmptySet + + +def test_evalf_with_zoo(): + assert (1/x).evalf(subs={x: 0}) == zoo # issue 8242 + assert (-1/x).evalf(subs={x: 0}) == zoo # PR 16150 + assert (0 ** x).evalf(subs={x: -1}) == zoo # PR 16150 + assert (0 ** x).evalf(subs={x: -1 + I}) == nan + assert Mul(2, Pow(0, -1, evaluate=False), evaluate=False).evalf() == zoo # issue 21147 + assert Mul(x, 1/x, evaluate=False).evalf(subs={x: 0}) == Mul(x, 1/x, evaluate=False).subs(x, 0) == nan + assert Mul(1/x, 1/x, evaluate=False).evalf(subs={x: 0}) == zoo + assert Mul(1/x, Abs(1/x), evaluate=False).evalf(subs={x: 0}) == zoo + assert Abs(zoo, evaluate=False).evalf() == oo + assert re(zoo, evaluate=False).evalf() == nan + assert im(zoo, evaluate=False).evalf() == nan + assert Add(zoo, zoo, evaluate=False).evalf() == nan + assert Add(oo, zoo, evaluate=False).evalf() == nan + assert Pow(zoo, -1, evaluate=False).evalf() == 0 + assert Pow(zoo, Rational(-1, 3), evaluate=False).evalf() == 0 + assert Pow(zoo, Rational(1, 3), evaluate=False).evalf() == zoo + assert Pow(zoo, S.Half, evaluate=False).evalf() == zoo + assert Pow(zoo, 2, evaluate=False).evalf() == zoo + assert Pow(0, zoo, evaluate=False).evalf() == nan + assert log(zoo, evaluate=False).evalf() == zoo + assert zoo.evalf(chop=True) == zoo + assert x.evalf(subs={x: zoo}) == zoo + + +def test_evalf_with_bounded_error(): + cases = [ + # zero + (Rational(0), None, 1), + # zero im part + (pi, None, 10), + # zero real part + (pi*I, None, 10), + # re and im nonzero + (2-3*I, None, 5), + # similar tests again, but using eps instead of m + (Rational(0), Rational(1, 2), None), + (pi, Rational(1, 1000), None), + (pi * I, Rational(1, 1000), None), + (2 - 3 * I, Rational(1, 1000), None), + # very large eps + (2 - 3 * I, Rational(1000), None), + # case where x already small, hence some cancellation in p = m + n - 1 + (Rational(1234, 10**8), Rational(1, 10**12), None), + ] + for x0, eps, m in cases: + a, b, _, _ = evalf(x0, 53, {}) + c, d, _, _ = _evalf_with_bounded_error(x0, eps, m) + if eps is None: + eps = 2**(-m) + z = make_mpc((a or fzero, b or fzero)) + w = make_mpc((c or fzero, d or fzero)) + assert abs(w - z) < eps + + # eps must be positive + raises(ValueError, lambda: _evalf_with_bounded_error(pi, Rational(0))) + raises(ValueError, lambda: _evalf_with_bounded_error(pi, -pi)) + raises(ValueError, lambda: _evalf_with_bounded_error(pi, I)) + + +def test_issue_22849(): + a = -8 + 3 * sqrt(3) + x = AlgebraicNumber(a) + assert evalf(a, 1, {}) == evalf(x, 1, {}) + + +def test_evalf_real_alg_num(): + # This test demonstrates why the entry for `AlgebraicNumber` in + # `sympy.core.evalf._create_evalf_table()` has to use `x.to_root()`, + # instead of `x.as_expr()`. If the latter is used, then `z` will be + # a complex number with `0.e-20` for imaginary part, even though `a5` + # is a real number. + zeta = Symbol('zeta') + a5 = AlgebraicNumber(CRootOf(cyclotomic_poly(5), -1), [-1, -1, 0, 0], alias=zeta) + z = a5.evalf() + assert isinstance(z, Float) + assert not hasattr(z, '_mpc_') + assert hasattr(z, '_mpf_') + + +def test_issue_20733(): + expr = 1/((x - 9)*(x - 8)*(x - 7)*(x - 4)**2*(x - 3)**3*(x - 2)) + assert str(expr.evalf(1, subs={x:1})) == '-4.e-5' + assert str(expr.evalf(2, subs={x:1})) == '-4.1e-5' + assert str(expr.evalf(11, subs={x:1})) == '-4.1335978836e-5' + assert str(expr.evalf(20, subs={x:1})) == '-0.000041335978835978835979' + + expr = Mul(*((x - i) for i in range(2, 1000))) + assert srepr(expr.evalf(2, subs={x: 1})) == "Float('4.0271e+2561', precision=10)" + assert srepr(expr.evalf(10, subs={x: 1})) == "Float('4.02790050126e+2561', precision=37)" + assert srepr(expr.evalf(53, subs={x: 1})) == "Float('4.0279005012722099453824067459760158730668154575647110393e+2561', precision=179)" diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_expand.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_expand.py new file mode 100644 index 0000000000000000000000000000000000000000..e7abb5daacebbe81664b3de3a7ac35a490ab31bc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_expand.py @@ -0,0 +1,364 @@ +from sympy.core.expr import unchanged +from sympy.core.mul import Mul +from sympy.core.numbers import (I, Rational as R, pi) +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.series.order import O +from sympy.simplify.radsimp import expand_numer +from sympy.core.function import (expand, expand_multinomial, + expand_power_base, expand_log) + +from sympy.testing.pytest import raises +from sympy.core.random import verify_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) + + +def test_expand_no_multinomial(): + 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) + 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() == 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() == 1 / (2*x*y + x**2 + y**2) + assert expr.expand(multinomial=False) == (x + y)**(-2) + + +def test_expand_non_commutative(): + 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) + 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) + # issue 6219 + 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 + # issue 6558 + assert (A*B*(A*B)**-1).expand() == 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)**-2).expand() == \ + A*B**-1*A**-1*B**-2*A**-1*B**-1*A**-1/a**2 + 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) + + assert (a**1).expand() == a + assert (a**3).expand() == x*a + y*a + assert (a**5).expand() == x**2*a + 2*x*y*a + y**2*a + + assert (1/a**1).expand() == 1/a + 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) + + assert (a**1).expand() == a + assert (a**2).expand() == a**2 + assert (a**4).expand() == x*a + y*a + 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 + assert (x + y/2).expand(modulus=1) == y/2 + + raises(ValueError, lambda: ((x + y)**11).expand(modulus=0)) + raises(ValueError, lambda: ((x + y)**11).expand(modulus=x)) + + +def test_issue_5743(): + 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) == \ + (x*y + y**2)/(x**2 + x) + assert expand((x + y)*y/x/(x + 1), numer=True) == \ + (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 + assert expand_numer(eq, multinomial=False) == eq + # issue 26329 + eq = (exp(x*z) - exp(y*z))/exp(z*(x + y)) + ans = exp(-y*z) - exp(-x*z) + assert eq.expand(numer=True) != ans + assert eq.expand(numer=True, exact=True) == ans + assert expand_numer(eq) != ans + assert expand_numer(eq, exact=True) == ans + + +def test_issue_6121(): + eq = -I*exp(-3*I*pi/4)/(4*pi**(S(3)/2)*sqrt(x)) + assert eq.expand(complex=True) # does not give oo recursion + eq = -I*exp(-3*I*pi/4)/(4*pi**(R(3, 2))*sqrt(x)) + assert eq.expand(complex=True) # does not give oo recursion + + +def test_expand_power_base(): + assert expand_power_base((x*y*z)**4) == x**4*y**4*z**4 + assert expand_power_base((x*y*z)**x).is_Pow + assert expand_power_base((x*y*z)**x, force=True) == x**x*y**x*z**x + 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(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)*exp(y))**z).is_Pow + 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, 6)/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 * (x + (y + 1)**2) + assert e.expand(deep=False) == x**2 + x*(y + 1)**2 + 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 5482 + assert sqrt(-2*x*n) == sqrt(2)*sqrt(-n)*sqrt(x) + # issue 5605 (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_expand_mul(): + # part of issue 20597 + e = Mul(2, 3, evaluate=False) + assert e.expand() == 6 + + e = Mul(2, 3, 1/x, evaluate=False) + assert e.expand() == 6/x + e = Mul(2, R(1, 3), evaluate=False) + assert e.expand() == R(2, 3) + +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_5919_6830(): + # issue 5919 + 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) + + # issue 6830 + 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 verify_numerically(e, expand_multinomial(e)) + + for a in [2, S.Half]: + for b in [3, R(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 + assert expand_log(log(7*6)/log(6)) == 1 + log(7)/log(6) + b = factorial(10) + assert expand_log(log(7*b**4)/log(b) + ) == 4 + log(7)/log(b) + + +def test_issue_23952(): + assert (x**(y + z)).expand(force=True) == x**y*x**z + one = Symbol('1', integer=True, prime=True, odd=True, positive=True) + two = Symbol('2', integer=True, prime=True, even=True) + e = two - one + for b in (0, x): + # 0**e = 0, 0**-e = zoo; but if expanded then nan + assert unchanged(Pow, b, e) # power_exp + assert unchanged(Pow, b, -e) # power_exp + assert unchanged(Pow, b, y - x) # power_exp + assert unchanged(Pow, b, 3 - x) # multinomial + assert (b**e).expand().is_Pow # power_exp + assert (b**-e).expand().is_Pow # power_exp + assert (b**(y - x)).expand().is_Pow # power_exp + assert (b**(3 - x)).expand().is_Pow # multinomial + nn1 = Symbol('nn1', nonnegative=True) + nn2 = Symbol('nn2', nonnegative=True) + nn3 = Symbol('nn3', nonnegative=True) + assert (x**(nn1 + nn2)).expand() == x**nn1*x**nn2 + assert (x**(-nn1 - nn2)).expand() == x**-nn1*x**-nn2 + assert unchanged(Pow, x, nn1 + nn2 - nn3) + assert unchanged(Pow, x, 1 + nn2 - nn3) + assert unchanged(Pow, x, nn1 - nn2) + assert unchanged(Pow, x, 1 - nn2) + assert unchanged(Pow, x, -1 + nn2) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_expr.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_expr.py new file mode 100644 index 0000000000000000000000000000000000000000..af63823345e2b0564ebb7e9015bfe1b423c9bafa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_expr.py @@ -0,0 +1,2313 @@ +from sympy.assumptions.refine import refine +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.expr import (ExprBuilder, unchanged, Expr, + UnevaluatedExpr) +from sympy.core.function import (Function, expand, WildFunction, + AppliedUndef, Derivative, diff, Subs) +from sympy.core.mul import Mul, _unevaluated_Mul +from sympy.core.numbers import (NumberSymbol, E, zoo, oo, Float, I, + Rational, nan, Integer, Number, pi, _illegal) +from sympy.core.power import Pow +from sympy.core.relational import Ge, Lt, Gt, Le +from sympy.core.singleton import S +from sympy.core.sorting import default_sort_key +from sympy.core.symbol import Symbol, symbols, Dummy, Wild +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.exponential import exp_polar, exp, log +from sympy.functions.elementary.hyperbolic import sinh, tanh +from sympy.functions.elementary.miscellaneous import sqrt, Max +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import tan, sin, cos +from sympy.functions.special.delta_functions import (Heaviside, + DiracDelta) +from sympy.functions.special.error_functions import Si +from sympy.functions.special.gamma_functions import gamma +from sympy.integrals.integrals import integrate, Integral +from sympy.physics.secondquant import FockState +from sympy.polys.partfrac import apart +from sympy.polys.polytools import factor, cancel, Poly +from sympy.polys.rationaltools import together +from sympy.series.order import O +from sympy.sets.sets import FiniteSet +from sympy.simplify.combsimp import combsimp +from sympy.simplify.gammasimp import gammasimp +from sympy.simplify.powsimp import powsimp +from sympy.simplify.radsimp import collect, radsimp +from sympy.simplify.ratsimp import ratsimp +from sympy.simplify.simplify import simplify, nsimplify +from sympy.simplify.trigsimp import trigsimp +from sympy.tensor.indexed import Indexed +from sympy.physics.units import meter + +from sympy.testing.pytest import raises, XFAIL + +from sympy.abc import a, b, c, n, t, u, x, y, z + + +f, g, h = symbols('f,g,h', cls=Function) + + +class DummyNumber: + """ + Minimal implementation of a number that works with SymPy. + + If one has a Number class (e.g. Sage Integer, or some other custom class) + that one wants to work well with SymPy, one has to implement at least the + methods of this class DummyNumber, resp. its subclasses I5 and F1_1. + + Basically, one just needs to implement either __int__() or __float__() and + then one needs to make sure that the class works with Python integers and + with itself. + """ + + def __radd__(self, a): + if isinstance(a, (int, float)): + return a + self.number + return NotImplemented + + def __add__(self, a): + if isinstance(a, (int, float, DummyNumber)): + return self.number + a + return NotImplemented + + def __rsub__(self, a): + if isinstance(a, (int, float)): + return a - self.number + return NotImplemented + + def __sub__(self, a): + if isinstance(a, (int, float, DummyNumber)): + return self.number - a + return NotImplemented + + def __rmul__(self, a): + if isinstance(a, (int, float)): + return a * self.number + return NotImplemented + + def __mul__(self, a): + if isinstance(a, (int, float, DummyNumber)): + return self.number * a + return NotImplemented + + def __rtruediv__(self, a): + if isinstance(a, (int, float)): + return a / self.number + return NotImplemented + + def __truediv__(self, a): + if isinstance(a, (int, float, DummyNumber)): + return self.number / a + return NotImplemented + + def __rpow__(self, a): + if isinstance(a, (int, float)): + return a ** self.number + return NotImplemented + + def __pow__(self, a): + if isinstance(a, (int, float, DummyNumber)): + return self.number ** a + return NotImplemented + + def __pos__(self): + return self.number + + 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 + +i5 = I5() +f1_1 = F1_1() + +# basic SymPy objects +basic_objs = [ + Rational(2), + Float("1.3"), + x, + y, + pow(x, y)*y, +] + +# all supported objects +all_objs = basic_objs + [ + 5, + 5.5, + i5, + f1_1 +] + + +def dotest(s): + for xo in all_objs: + for yo in all_objs: + s(xo, yo) + return True + + +def test_basic(): + 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 + del x + assert dotest(j) + + +def test_ibasic(): + def s(a, b): + x = a + x += b + x = a + x -= b + x = a + x *= b + x = a + x /= b + assert dotest(s) + + +class NonBasic: + '''This class represents an object that knows how to implement binary + operations like +, -, etc with Expr but is not a subclass of Basic itself. + The NonExpr subclass below does subclass Basic but not Expr. + + For both NonBasic and NonExpr it should be possible for them to override + Expr.__add__ etc because Expr.__add__ should be returning NotImplemented + for non Expr classes. Otherwise Expr.__add__ would create meaningless + objects like Add(Integer(1), FiniteSet(2)) and it wouldn't be possible for + other classes to override these operations when interacting with Expr. + ''' + def __add__(self, other): + return SpecialOp('+', self, other) + + def __radd__(self, other): + return SpecialOp('+', other, self) + + def __sub__(self, other): + return SpecialOp('-', self, other) + + def __rsub__(self, other): + return SpecialOp('-', other, self) + + def __mul__(self, other): + return SpecialOp('*', self, other) + + def __rmul__(self, other): + return SpecialOp('*', other, self) + + def __truediv__(self, other): + return SpecialOp('/', self, other) + + def __rtruediv__(self, other): + return SpecialOp('/', other, self) + + def __floordiv__(self, other): + return SpecialOp('//', self, other) + + def __rfloordiv__(self, other): + return SpecialOp('//', other, self) + + def __mod__(self, other): + return SpecialOp('%', self, other) + + def __rmod__(self, other): + return SpecialOp('%', other, self) + + def __divmod__(self, other): + return SpecialOp('divmod', self, other) + + def __rdivmod__(self, other): + return SpecialOp('divmod', other, self) + + def __pow__(self, other): + return SpecialOp('**', self, other) + + def __rpow__(self, other): + return SpecialOp('**', other, self) + + def __lt__(self, other): + return SpecialOp('<', self, other) + + def __gt__(self, other): + return SpecialOp('>', self, other) + + def __le__(self, other): + return SpecialOp('<=', self, other) + + def __ge__(self, other): + return SpecialOp('>=', self, other) + + +class NonExpr(Basic, NonBasic): + '''Like NonBasic above except this is a subclass of Basic but not Expr''' + pass + + +class SpecialOp(): + '''Represents the results of operations with NonBasic and NonExpr''' + def __new__(cls, op, arg1, arg2): + obj = object.__new__(cls) + obj.args = (op, arg1, arg2) + return obj + + +class NonArithmetic(Basic): + '''Represents a Basic subclass that does not support arithmetic operations''' + pass + + +def test_cooperative_operations(): + '''Tests that Expr uses binary operations cooperatively. + + In particular it should be possible for non-Expr classes to override + binary operators like +, - etc when used with Expr instances. This should + work for non-Expr classes whether they are Basic subclasses or not. Also + non-Expr classes that do not define binary operators with Expr should give + TypeError. + ''' + # A bunch of instances of Expr subclasses + exprs = [ + Expr(), + S.Zero, + S.One, + S.Infinity, + S.NegativeInfinity, + S.ComplexInfinity, + S.Half, + Float(0.5), + Integer(2), + Symbol('x'), + Mul(2, Symbol('x')), + Add(2, Symbol('x')), + Pow(2, Symbol('x')), + ] + + for e in exprs: + # Test that these classes can override arithmetic operations in + # combination with various Expr types. + for ne in [NonBasic(), NonExpr()]: + + results = [ + (ne + e, ('+', ne, e)), + (e + ne, ('+', e, ne)), + (ne - e, ('-', ne, e)), + (e - ne, ('-', e, ne)), + (ne * e, ('*', ne, e)), + (e * ne, ('*', e, ne)), + (ne / e, ('/', ne, e)), + (e / ne, ('/', e, ne)), + (ne // e, ('//', ne, e)), + (e // ne, ('//', e, ne)), + (ne % e, ('%', ne, e)), + (e % ne, ('%', e, ne)), + (divmod(ne, e), ('divmod', ne, e)), + (divmod(e, ne), ('divmod', e, ne)), + (ne ** e, ('**', ne, e)), + (e ** ne, ('**', e, ne)), + (e < ne, ('>', ne, e)), + (ne < e, ('<', ne, e)), + (e > ne, ('<', ne, e)), + (ne > e, ('>', ne, e)), + (e <= ne, ('>=', ne, e)), + (ne <= e, ('<=', ne, e)), + (e >= ne, ('<=', ne, e)), + (ne >= e, ('>=', ne, e)), + ] + + for res, args in results: + assert type(res) is SpecialOp and res.args == args + + # These classes do not support binary operators with Expr. Every + # operation should raise in combination with any of the Expr types. + for na in [NonArithmetic(), object()]: + + raises(TypeError, lambda : e + na) + raises(TypeError, lambda : na + e) + raises(TypeError, lambda : e - na) + raises(TypeError, lambda : na - e) + raises(TypeError, lambda : e * na) + raises(TypeError, lambda : na * e) + raises(TypeError, lambda : e / na) + raises(TypeError, lambda : na / e) + raises(TypeError, lambda : e // na) + raises(TypeError, lambda : na // e) + raises(TypeError, lambda : e % na) + raises(TypeError, lambda : na % e) + raises(TypeError, lambda : divmod(e, na)) + raises(TypeError, lambda : divmod(na, e)) + raises(TypeError, lambda : e ** na) + raises(TypeError, lambda : na ** e) + raises(TypeError, lambda : e > na) + raises(TypeError, lambda : na > e) + raises(TypeError, lambda : e < na) + raises(TypeError, lambda : na < e) + raises(TypeError, lambda : e >= na) + raises(TypeError, lambda : na >= e) + raises(TypeError, lambda : e <= na) + raises(TypeError, lambda : na <= e) + + +def test_relational(): + from sympy.core.relational import Lt + assert (pi < 3) is S.false + assert (pi <= 3) is S.false + assert (pi > 3) is S.true + assert (pi >= 3) is S.true + assert (-pi < 3) is S.true + assert (-pi <= 3) is S.true + assert (-pi > 3) is S.false + assert (-pi >= 3) is S.false + r = Symbol('r', real=True) + assert (r - 2 < r - 3) is S.false + assert Lt(x + I, x + I + 2).func == Lt # issue 8288 + + +def test_relational_assumptions(): + 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 S.true + assert (m2 <= 0) is S.true + assert (m3 > 0) is S.true + assert (m4 >= 0) is S.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 S.true + assert (m2 <= 0) is S.true + assert (m3 > 0) is S.true + assert (m4 >= 0) is S.true + m1 = Symbol("m1", negative=False, real=True) + m2 = Symbol("m2", nonpositive=False, real=True) + m3 = Symbol("m3", positive=False, real=True) + m4 = Symbol("m4", nonnegative=False, real=True) + assert (m1 < 0) is S.false + assert (m2 <= 0) is S.false + assert (m3 > 0) is S.false + assert (m4 >= 0) is S.false + + +# See https://github.com/sympy/sympy/issues/17708 +#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) == Le(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: + assert obj * '1' == '11' + else: + raises(TypeError, lambda: obj * '1') + raises(TypeError, lambda: obj / '1') + raises(TypeError, lambda: obj ** '1') + + +def test_series_expansion_for_uniform_order(): + assert (1/x + y + x).series(x, 0, 0) == 1/x + O(1, x) + assert (1/x + y + x).series(x, 0, 1) == 1/x + y + O(x) + assert (1/x + 1 + x).series(x, 0, 0) == 1/x + O(1, x) + assert (1/x + 1 + x).series(x, 0, 1) == 1/x + 1 + O(x) + assert (1/x + x).series(x, 0, 0) == 1/x + O(1, x) + assert (1/x + y + y*x + x).series(x, 0, 0) == 1/x + O(1, x) + assert (1/x + y + y*x + x).series(x, 0, 1) == 1/x + y + O(x) + + +def test_leadterm(): + 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 (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 (x**2).as_leading_term(x) == x**2 + assert (x + oo).as_leading_term(x) is oo + + raises(ValueError, lambda: (x + 1).as_leading_term(1)) + + # https://github.com/sympy/sympy/issues/21177 + e = -3*x + (x + Rational(3, 2) - sqrt(3)*S.ImaginaryUnit/2)**2\ + - Rational(3, 2) + 3*sqrt(3)*S.ImaginaryUnit/2 + assert e.as_leading_term(x) == -sqrt(3)*I*x + + # https://github.com/sympy/sympy/issues/21245 + e = 1 - x - x**2 + d = (1 + sqrt(5))/2 + assert e.subs(x, y + 1/d).as_leading_term(y) == \ + (-40*y - 16*sqrt(5)*y)/(16 + 8*sqrt(5)) + + # https://github.com/sympy/sympy/issues/26991 + assert sinh(tanh(3/(100*x))).as_leading_term(x, cdir = 1) == sinh(1) + + +def test_leadterm2(): + assert (x*cos(1)*cos(1 + sin(1)) + sin(1 + sin(1))).leadterm(x) == \ + (sin(1 + sin(1)), 0) + + +def test_leadterm3(): + 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)) + + +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*x + pi*x + + +def test_as_leading_term4(): + # see issue 6843 + n = Symbol('n', integer=True, positive=True) + r = -n**3/(2*n**2 + 4*n + 2) - n**2/(n**2 + 2*n + 1) + \ + n**2/(n + 1) - n/(2*n**2 + 4*n + 2) + n/(n*x + x) + 2*n/(n + 1) - \ + 1 + 1/(n*x + x) + 1/(n + 1) - 1/x + assert r.as_leading_term(x).cancel() == n/2 + + +def test_as_leading_term_stub(): + class foo(Function): + pass + assert foo(1/x).as_leading_term(x) == foo(1/x) + assert foo(1).as_leading_term(x) == foo(1) + raises(NotImplementedError, lambda: foo(x).as_leading_term(x)) + + +def test_as_leading_term_deriv_integral(): + # related to issue 11313 + assert Derivative(x ** 3, x).as_leading_term(x) == 3*x**2 + assert Derivative(x ** 3, y).as_leading_term(x) == 0 + + assert Integral(x ** 3, x).as_leading_term(x) == x**4/4 + assert Integral(x ** 3, y).as_leading_term(x) == y*x**3 + + assert Derivative(exp(x), x).as_leading_term(x) == 1 + assert Derivative(log(x), x).as_leading_term(x) == (1/x).as_leading_term(x) + + +def test_atoms(): + assert x.atoms() == {x} + assert (1 + x).atoms() == {x, S.One} + + assert (1 + 2*cos(x)).atoms(Symbol) == {x} + assert (1 + 2*cos(x)).atoms(Symbol, Number) == {S.One, S(2), x} + + assert (2*(x**(y**x))).atoms() == {S(2), x, y} + + assert S.Half.atoms() == {S.Half} + assert S.Half.atoms(Symbol) == set() + + assert sin(oo).atoms(oo) == set() + + assert Poly(0, x).atoms() == {S.Zero, x} + assert Poly(1, x).atoms() == {S.One, x} + + assert Poly(x, x).atoms() == {x} + assert Poly(x, x, y).atoms() == {x, y} + assert Poly(x + y, x, y).atoms() == {x, y} + assert Poly(x + y, x, y, z).atoms() == {x, y, z} + assert Poly(x + y*t, x, y, z).atoms() == {t, x, y, z} + + assert (I*pi).atoms(NumberSymbol) == {pi} + assert (I*pi).atoms(NumberSymbol, I) == \ + (I*pi).atoms(I, NumberSymbol) == {pi, I} + + assert exp(exp(x)).atoms(exp) == {exp(exp(x)), exp(x)} + assert (1 + x*(2 + y) + exp(3 + z)).atoms(Add) == \ + {1 + x*(2 + y) + exp(3 + z), 2 + y, 3 + z} + + # issue 6132 + e = (f(x) + sin(x) + 2) + assert e.atoms(AppliedUndef) == \ + {f(x)} + assert e.atoms(AppliedUndef, Function) == \ + {f(x), sin(x)} + assert e.atoms(Function) == \ + {f(x), sin(x)} + assert e.atoms(AppliedUndef, Number) == \ + {f(x), S(2)} + assert e.atoms(Function, Number) == \ + {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) 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**2).is_polynomial(x) is True + assert (x**2).is_polynomial(y) is True + + assert (x**(-2)).is_polynomial(x) is False + assert (x**(-2)).is_polynomial(y) is True + + assert (2**x).is_polynomial(x) is False + assert (2**x).is_polynomial(y) is 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) is False + assert ((2*x)**k).is_polynomial(x) is 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() is True + + assert sqrt(x).is_polynomial(x) is False + assert (sqrt(x)**3).is_polynomial(x) is 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)*(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(x, y) is True + assert ( + (x**2)*(y**2) + x*(y**2) + y*x + exp(x)).is_polynomial(x, y) is False + + assert (1/f(x) + 1).is_polynomial(f(x)) is False + + +def test_is_rational_function(): + assert Integer(1).is_rational_function() is True + assert Integer(1).is_rational_function(x) is 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() is True + assert (12/x).is_rational_function(x) is True + + 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 + + for i in _illegal: + assert not i.is_rational_function() + for d in (1, x): + assert not (i/d).is_rational_function() + + +def test_is_meromorphic(): + f = a/x**2 + b + x + c*x**2 + assert f.is_meromorphic(x, 0) is True + assert f.is_meromorphic(x, 1) is True + assert f.is_meromorphic(x, zoo) is True + + g = 3 + 2*x**(log(3)/log(2) - 1) + assert g.is_meromorphic(x, 0) is False + assert g.is_meromorphic(x, 1) is True + assert g.is_meromorphic(x, zoo) is False + + n = Symbol('n', integer=True) + e = sin(1/x)**n*x + assert e.is_meromorphic(x, 0) is False + assert e.is_meromorphic(x, 1) is True + assert e.is_meromorphic(x, zoo) is False + + e = log(x)**pi + assert e.is_meromorphic(x, 0) is False + assert e.is_meromorphic(x, 1) is False + assert e.is_meromorphic(x, 2) is True + assert e.is_meromorphic(x, zoo) is False + + assert (log(x)**a).is_meromorphic(x, 0) is False + assert (log(x)**a).is_meromorphic(x, 1) is False + assert (a**log(x)).is_meromorphic(x, 0) is None + assert (3**log(x)).is_meromorphic(x, 0) is False + assert (3**log(x)).is_meromorphic(x, 1) is True + +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.One/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 https://github.com/sympy/sympy/issues/3346 + class MyInt: + def _sympy_(self): + return Integer(5) + m = MyInt() + e = Rational(2)*m + assert e == 10 + + raises(TypeError, lambda: Rational(2)*MyInt) + + +def test_SAGE2(): + class MyInt: + def __int__(self): + return 5 + assert sympify(MyInt()) == 5 + e = Rational(2)*MyInt() + assert e == 10 + + raises(TypeError, lambda: Rational(2)*MyInt) + + +def test_SAGE3(): + class MySymbol: + def __rmul__(self, other): + return ('mys', other, self) + + o = MySymbol() + e = x*o + + assert e == ('mys', x, o) + + +def test_len(): + e = x*y + assert len(e.args) == 2 + e = x + y + z + assert len(e.args) == 3 + + +def test_doit(): + a = Integral(x**2, x) + + assert isinstance(a.doit(), Integral) is False + + 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 sin(x*y).args == (x*y,) + assert sin(x*y).args[0] == x*y + assert (x**y).args == (x, y) + assert (x**y).args[0] == x + assert (x**y).args[1] == y + + +def test_noncommutative_expand_issue_3757(): + 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 + + +def test_as_numer_denom(): + a, b, c = symbols('a, b, c') + + assert nan.as_numer_denom() == (nan, 1) + assert oo.as_numer_denom() == (oo, 1) + assert (-oo).as_numer_denom() == (-oo, 1) + assert zoo.as_numer_denom() == (zoo, 1) + assert (-zoo).as_numer_denom() == (zoo, 1) + + assert x.as_numer_denom() == (x, 1) + assert (1/x).as_numer_denom() == (1, x) + assert (x/y).as_numer_denom() == (x, y) + assert (x/2).as_numer_denom() == (x, 2) + assert (x*y/z).as_numer_denom() == (x*y, z) + assert (x/(y*z)).as_numer_denom() == (x, y*z) + assert S.Half.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).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) + assert (a/x + b/2/x + c/3/y).as_numer_denom() == \ + (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) + # 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 + for i in [S.Infinity, S.NegativeInfinity, S.ComplexInfinity]: + assert (i + x/3).as_numer_denom() == \ + (x + i, 3) + assert (S.Infinity + x/3 + y/4).as_numer_denom() == \ + (4*x + 3*y + S.Infinity, 12) + assert (oo*x + zoo*y).as_numer_denom() == \ + (zoo*y + oo*x, 1) + + A, B, C = symbols('A,B,C', commutative=False) + + 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) + assert (C**-1*A*B).as_numer_denom() == (C**-1*A*B, 1) + assert (C**-1*A*B/x).as_numer_denom() == (C**-1*A*B, x) + 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) + + # the following morphs from Add to Mul during processing + assert Add(0, (x + y)/z/-2, evaluate=False).as_numer_denom( + ) == (-x - y, 2*z) + + +def test_trunc(): + import math + x, y = symbols('x y') + assert math.trunc(2) == 2 + assert math.trunc(4.57) == 4 + assert math.trunc(-5.79) == -5 + assert math.trunc(pi) == 3 + assert math.trunc(log(7)) == 1 + assert math.trunc(exp(5)) == 148 + assert math.trunc(cos(pi)) == -1 + assert math.trunc(sin(5)) == 0 + + raises(TypeError, lambda: math.trunc(x)) + raises(TypeError, lambda: math.trunc(x + y**2)) + raises(TypeError, lambda: math.trunc(oo)) + + +def test_as_independent(): + assert S.Zero.as_independent(x, as_Add=True) == (0, 0) + assert S.Zero.as_independent(x, as_Add=False) == (0, 0) + 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 (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)) + + assert (x*sin(x)*cos(y)).as_independent(x, y) == (1, x*sin(x)*cos(y)) + + assert (sin(x)).as_independent(x) == (1, sin(x)) + assert (sin(x)).as_independent(y) == (sin(x), 1) + + assert (2*sin(x)).as_independent(x) == (2, sin(x)) + assert (2*sin(x)).as_independent(y) == (2*sin(x), 1) + + # issue 4903 = 1766b + n1, n2, n3 = symbols('n1 n2 n3', commutative=False) + assert (n1 + n1*n2).as_independent(n2) == (n1, n1*n2) + assert (n2*n1 + n1*n2).as_independent(n2) == (0, n1*n2 + n2*n1) + assert (n1*n2*n1).as_independent(n2) == (n1, n2*n1) + assert (n1*n2*n1).as_independent(n1) == (1, n1*n2*n1) + + 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) + + # issue 5479 + assert (3*x).as_independent(Symbol) == (3, x) + + # issue 5648 + 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 (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(x - n2), DiracDelta(y - n1)) + + # issue 5784 + assert (x + Integral(x, (x, 1, 2))).as_independent(x, strict=True) == \ + (Integral(x, (x, 1, 2)), x) + + eq = Add(x, -x, 2, -3, evaluate=False) + assert eq.as_independent(x) == (-1, Add(x, -x, evaluate=False)) + eq = Mul(x, 1/x, 2, -3, evaluate=False) + assert eq.as_independent(x) == (-6, Mul(x, 1/x, evaluate=False)) + + assert (x*y).as_independent(z, as_Add=True) == (x*y, 0) + +@XFAIL +def test_call_2(): + # TODO UndefinedFunction does not subclass Expr + assert (2*f)(x) == 2*f(x) + + +def test_replace(): + e = log(sin(x)) + tan(sin(x**2)) + + assert e.replace(sin, cos) == log(cos(x)) + tan(cos(x**2)) + assert e.replace( + sin, lambda a: sin(2*a)) == log(sin(2*x)) + tan(sin(2*x**2)) + + a = Wild('a') + b = Wild('b') + + assert e.replace(sin(a), cos(a)) == log(cos(x)) + tan(cos(x**2)) + assert e.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, b - a, exact=False) == 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 + assert (2*x).replace(a*x + b, lambda a, b: b - a, exact=False) == 2/x + + g = 2*sin(x**3) + + 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) + + 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 + ) == x**2/2 + O(x**3) + 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 + + # https://groups.google.com/forum/#!topic/sympy/8wCgeC95tz0 + n1, n2, n3 = symbols('n1:4', commutative=False) + assert (n1*f(n2)).replace(f, lambda x: x) == n1*n2 + assert (n3*f(n2)).replace(f, lambda x: x) == n3*n2 + + # issue 16725 + assert S.Zero.replace(Wild('x'), 1) == 1 + # let the user override the default decision of False + assert S.Zero.replace(Wild('x'), 1, exact=True) == 0 + + +def test_replace_integral(): + # https://github.com/sympy/sympy/issues/27142 + q, p, s, t = symbols('q p s t', cls=Wild) + a, b, c, d = symbols('a b c d') + i = Integral(a + b, (b, c, d)) + pattern = Integral(q, (p, s, t)) + assert i.replace(pattern, q) == a + b + + +def test_find(): + expr = (x + y + 2 + sin(3*x)) + + assert expr.find(lambda u: u.is_Integer) == {S(2), S(3)} + assert expr.find(lambda u: u.is_Symbol) == {x, y} + + assert expr.find(lambda u: u.is_Integer, group=True) == {S(2): 1, S(3): 1} + assert expr.find(lambda u: u.is_Symbol, group=True) == {x: 2, y: 1} + + assert expr.find(Integer) == {S(2), S(3)} + assert expr.find(Symbol) == {x, y} + + assert expr.find(Integer, group=True) == {S(2): 1, S(3): 1} + assert expr.find(Symbol, group=True) == {x: 2, y: 1} + + a = Wild('a') + + expr = sin(sin(x)) + sin(x) + cos(x) + x + + assert expr.find(lambda u: type(u) is sin) == {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(sin(a)) == {sin(x), sin(sin(x))} + assert expr.find(sin(a), group=True) == {sin(x): 2, sin(sin(x)): 1} + + assert expr.find(sin) == {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)) + + assert expr.count(lambda u: u.is_Integer) == 2 + assert expr.count(lambda u: u.is_Symbol) == 3 + + assert expr.count(Integer) == 2 + assert expr.count(Symbol) == 3 + assert expr.count(2) == 1 + + a = Wild('a') + + assert expr.count(sin) == 1 + assert expr.count(sin(a)) == 1 + assert expr.count(lambda u: type(u) is sin) == 1 + + assert f(x).count(f(x)) == 1 + assert f(x).diff(x).count(f(x)) == 1 + assert f(x).diff(x).count(x) == 2 + + +def test_has_basics(): + p = Wild('p') + + assert sin(x).has(x) + assert sin(x).has(sin) + assert not sin(x).has(y) + assert not sin(x).has(cos) + assert f(x).has(x) + assert f(x).has(f) + assert not f(x).has(y) + assert not f(x).has(g) + + assert f(x).diff(x).has(x) + assert f(x).diff(x).has(f) + assert f(x).diff(x).has(Derivative) + assert not f(x).diff(x).has(y) + assert not f(x).diff(x).has(g) + assert not f(x).diff(x).has(sin) + + assert (x**2).has(Symbol) + assert not (x**2).has(Wild) + assert (2*p).has(Wild) + + assert not x.has() + + # see issue at https://github.com/sympy/sympy/issues/5190 + assert not S(1).has(Wild) + assert not x.has(Wild) + + +def test_has_multiple(): + f = x**2*y + sin(2**t + log(z)) + + assert f.has(x) + assert f.has(y) + assert f.has(z) + assert f.has(t) + + assert not f.has(u) + + assert f.has(x, y, z, t) + assert f.has(x, y, z, t, u) + + i = Integer(4400) + + assert not i.has(x) + + assert (i*x**i).has(x) + assert not (i*y**i).has(x) + 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) + p = Piecewise((g(x), x < -1), (1, x <= 1), (f, True)) + + assert p.has(x) + assert p.has(y) + assert not p.has(z) + assert p.has(1) + assert p.has(3) + assert not p.has(4) + assert p.has(f) + 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) + + assert f.has(x) + assert f.has(x*y) + assert f.has(x*sin(x)) + assert not f.has(x*sin(y)) + assert f.has(x*A) + assert f.has(x*A*B) + assert not f.has(x*A*C) + assert f.has(x*A*B*C) + assert not f.has(x*A*C*B) + assert f.has(x*sin(x)*A*B*C) + assert not f.has(x*sin(x)*A*C*B) + assert not f.has(x*sin(y)*A*B*C) + assert f.has(x*gamma(x)) + assert not f.has(x + sin(x)) + + assert (x & y & z).has(x & z) + + +def test_has_integrals(): + f = Integral(x**2 + sin(x*y*z), (x, 0, x + y + z)) + + assert f.has(x + y) + assert f.has(x + z) + assert f.has(y + z) + + assert f.has(x*y) + assert f.has(x*z) + assert f.has(y*z) + + assert not f.has(2*x + y) + assert not f.has(2*x*y) + + +def test_has_tuple(): + assert Tuple(x, y).has(x) + assert not Tuple(x, y).has(z) + assert Tuple(f(x), g(x)).has(x) + assert not Tuple(f(x), g(x)).has(y) + assert Tuple(f(x), g(x)).has(f) + assert Tuple(f(x), g(x)).has(f(x)) + # XXX to be deprecated + #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) + assert Tuple(True).has(S.true) + assert not Tuple(True).has(1) + + +def test_has_units(): + from sympy.physics.units import m, s + + 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) + + assert poly.has(x) + 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 + + assert f.as_poly().as_expr() == f + assert f.as_poly(x, y).as_expr() == f + + assert (f + sin(x)).as_poly(x, y) is None + + p = Poly(f, x, y) + + assert p.as_poly() == p + + # https://github.com/sympy/sympy/issues/20610 + assert S(2).as_poly() is None + assert sqrt(2).as_poly(extension=True) is None + + raises(AttributeError, lambda: Tuple(x, x).as_poly(x)) + raises(AttributeError, lambda: Tuple(x ** 2, x, y).as_poly(x)) + + +def test_nonzero(): + 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 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 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 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 (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 S(-3.0).as_coeff_mul(rational=False) == (-S(3.0), ()) + 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,)) + assert (3 + x).as_coeff_mul() == (1, (3 + x,)) + assert (3 + x).as_coeff_mul(y) == (3 + x, ()) + # don't do expansion + e = exp(x + y) + assert e.as_coeff_mul(y) == (1, (e,)) + e = 2**(x + y) + assert e.as_coeff_mul(y) == (1, (e,)) + assert (1.1*x).as_coeff_mul(rational=False) == (1.1, (x,)) + assert (1.1*x).as_coeff_mul() == (1, (1.1, x)) + assert (-oo*x).as_coeff_mul(rational=True) == (-1, (oo, x)) + + +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) + assert (4*x**2).as_coeff_exponent(x) == (4, 2) + assert (6*x**1).as_coeff_exponent(x) == (6, 1) + assert (3*x**0).as_coeff_exponent(x) == (3, 0) + assert (2*x**0).as_coeff_exponent(x) == (2, 0) + assert (1*x**0).as_coeff_exponent(x) == (1, 0) + 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 (x*log(2)/(2*x + pi*x)).as_coeff_exponent(x) == \ + (log(2)/(2 + pi), 0) + # issue 4784 + D = Derivative + fx = D(f(x), x) + assert fx.as_coeff_exponent(f(x)) == (fx, 0) + + +def test_extractions(): + for base in (2, S.Exp1): + assert Pow(base**x, 3, evaluate=False + ).extract_multiplicatively(base**x) == base**(2*x) + assert (base**(5*x)).extract_multiplicatively( + base**(3*x)) == base**(2*x) + assert ((x*y)**3).extract_multiplicatively(x**2 * y) == x*y**2 + assert ((x*y)**3).extract_multiplicatively(x**4 * y) is None + assert (2*x).extract_multiplicatively(2) == x + assert (2*x).extract_multiplicatively(3) is None + assert (2*x).extract_multiplicatively(-1) is None + assert (S.Half*x).extract_multiplicatively(3) == x/6 + assert (sqrt(x)).extract_multiplicatively(x) is None + assert (sqrt(x)).extract_multiplicatively(1/x) is None + assert x.extract_multiplicatively(-x) is None + assert (-2 - 4*I).extract_multiplicatively(-2) == 1 + 2*I + assert (-2 - 4*I).extract_multiplicatively(3) is None + assert (-2*x - 4*y - 8).extract_multiplicatively(-2) == x + 2*y + 4 + assert (-2*x*y - 4*x**2*y).extract_multiplicatively(-2*y) == 2*x**2 + x + assert (2*x*y + 4*x**2*y).extract_multiplicatively(2*y) == 2*x**2 + x + assert (-4*y**2*x).extract_multiplicatively(-3*y) is None + assert (2*x).extract_multiplicatively(1) == 2*x + assert (-oo).extract_multiplicatively(5) is -oo + assert (oo).extract_multiplicatively(5) is oo + + assert ((x*y)**3).extract_additively(1) is None + assert (x + 1).extract_additively(x) == 1 + 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) 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 + assert S(2.).extract_additively(2.) is S.Zero + assert S(2.).extract_additively(2) is S.Zero + assert S(2*x + 3).extract_additively(x + 1) == x + 2 + assert S(2*x + 3).extract_additively(y + 1) is None + assert S(2*x - 3).extract_additively(x + 1) is None + assert S(2*x - 3).extract_additively(y + z) is None + assert ((a + 1)*x*4 + y).extract_additively(x).expand() == \ + 4*a*x + 3*x + y + assert ((a + 1)*x*4 + 3*y).extract_additively(x + 2*y).expand() == \ + 4*a*x + 3*x + y + assert (y*(x + 1)).extract_additively(x + 1) is None + assert ((y + 1)*(x + 1) + 3).extract_additively(x + 1) == \ + y*(x + 1) + 3 + assert ((x + y)*(x + 1) + x + y + 3).extract_additively(x + y) == \ + x*(x + y) + 3 + assert (x + y + 2*((x + y)*(x + 1)) + 3).extract_additively((x + y)*(x + 1)) == \ + x + y + (x + 1)*(x + y) + 3 + assert ((y + 1)*(x + 2*y + 1) + 3).extract_additively(y + 1) == \ + (x + 2*y)*(y + 1) + 3 + assert (-x - x*I).extract_additively(-x) == -I*x + # extraction does not leave artificats, now + assert (4*x*(y + 1) + y).extract_additively(x) == x*(4*y + 3) + y + + n = Symbol("n", integer=True) + 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 False + assert ((x + x*y)/(-y)).could_extract_minus_sign() is True + assert ((x + x*y)/y).could_extract_minus_sign() is False + assert ((-x - y)/(x + y)).could_extract_minus_sign() is False + + class sign_invariant(Function, Expr): + nargs = 1 + def __neg__(self): + return self + foo = sign_invariant(x) + assert foo == -foo + assert foo.could_extract_minus_sign() is False + assert (x - y).could_extract_minus_sign() is False + assert (-x + y).could_extract_minus_sign() is True + assert (x - 1).could_extract_minus_sign() is False + assert (1 - x).could_extract_minus_sign() is True + assert (sqrt(2) - 1).could_extract_minus_sign() is True + assert (1 - sqrt(2)).could_extract_minus_sign() is False + # check that result is canonical + eq = (3*x + 15*y).extract_multiplicatively(3) + assert eq.args == eq.func(*eq.args).args + + +def test_nan_extractions(): + for r in (1, 0, I, nan): + assert nan.extract_additively(r) is None + assert nan.extract_multiplicatively(r) is None + + +def test_coeff(): + 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 (-x/8 + x*y).coeff(x) == Rational(-1, 8) + y + assert (-x/8 + x*y).coeff(-x) == S.One/8 + assert (4*x).coeff(2*x) == 0 + assert (2*x).coeff(2*x) == 1 + assert (-oo*x).coeff(x*oo) == -1 + assert (10*x).coeff(x, 0) == 0 + assert (10*x).coeff(10*x, 0) == 0 + + 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 (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*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 + + assert (x + y + 3*z).coeff(1) == x + y + assert (-x + 2*y).coeff(-1) == x + assert (x - 2*y).coeff(-1) == 2*y + 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) == 4 + assert (3 + 2*x + 4*x**2).coeff(x**3) == 0 + assert (z*(x + y)**2).coeff((x + y)**2) == z + assert (z*(x + y)**2).coeff(x + y) == 0 + assert (2 + 2*x + (x + 1)*y).coeff(x + 1) == y + + assert (x + 2*y + 3).coeff(1) == x + assert (x + 2*y + 3).coeff(x, 0) == 2*y + 3 + assert (x**2 + 2*y + 3*x).coeff(x**2, 0) == 2*y + 3*x + assert x.coeff(0, 0) == 0 + assert x.coeff(x, 0) == 0 + + n, m, o, l = symbols('n m o l', commutative=False) + assert n.coeff(n) == 1 + assert y.coeff(n) == 0 + assert (3*n).coeff(n) == 3 + assert (2 + n).coeff(x*m) == 0 + assert (2*x*n*m).coeff(x) == 2*n*m + 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).coeff(n) == 0 + assert (n*m + o*m*n).coeff(m*n) == o + assert (n*m + o*m*n).coeff(m*n, right=True) == 1 + assert (n*m + n*m*n).coeff(n*m, right=True) == 1 + n # = n*m*(n + 1) + + assert (x*y).coeff(z, 0) == x*y + + assert (x*n + y*n + z*m).coeff(n) == x + y + assert (n*m + n*o + o*l).coeff(n, right=True) == m + o + assert (x*n*m*n + y*n*m*o + z*l).coeff(m, right=True) == x*n + y*o + assert (x*n*m*n + x*n*m*o + z*l).coeff(m, right=True) == n + o + assert (x*n*m*n + x*n*m*o + z*l).coeff(m) == x*n + + +def test_coeff2(): + r, kappa = symbols('r, kappa') + psi = Function("psi") + g = 1/r**2 * (2*r*psi(r).diff(r, 1) + r**2 * psi(r).diff(r, 2)) + g = g.expand() + assert g.coeff(psi(r).diff(r)) == 2/r + + +def test_coeff2_0(): + r, kappa = symbols('r, kappa') + psi = Function("psi") + g = 1/r**2 * (2*r*psi(r).diff(r, 1) + r**2 * psi(r).diff(r, 2)) + g = g.expand() + + 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 + + +def test_integrate(): + assert x.integrate(x) == x**2/2 + assert x.integrate((x, 0, 1)) == S.Half + + +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**2*y**2).as_base_exp() == (x*y, 2) + assert (x**z*y**z).as_base_exp() == (x**z*y**z, S.One) + + +def test_issue_4963(): + assert hasattr(Mul(x, y), "is_commutative") + assert hasattr(Mul(x, y, evaluate=False), "is_commutative") + assert hasattr(Pow(x, y), "is_commutative") + assert hasattr(Pow(x, y, evaluate=False), "is_commutative") + 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 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 radsimp(1/(a + b*sqrt(c)), symbolic=False) == \ + (1/(a + b*sqrt(c))).radsimp(symbolic=False) + assert powsimp(x**y*x**z*y**z, combine='all') == \ + (x**y*x**z*y**z).powsimp(combine='all') + assert (x**t*y**t).powsimp(force=True) == (x*y)**t + 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() + 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 gammasimp(gamma(x)/gamma(x-5)) == (gamma(x)/gamma(x-5)).gammasimp() + 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() + + +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, 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.One, 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, 3] + assert [Add(3*x, 2*x, y, 3, evaluate=False).as_coefficients_dict()[i] + for i in check] == [3, 5, 1, 0, 3] + assert [(3*x*y).as_coefficients_dict()[i] for i in check] == \ + [0, 0, 0, 3, 0] + assert [(3.0*x*y).as_coefficients_dict()[i] for i in check] == \ + [0, 0, 0, 3.0, 0] + assert (3.0*x*y).as_coefficients_dict()[3.0*x*y] == 0 + eq = x*(x + 1)*a + x*b + c/x + assert eq.as_coefficients_dict(x) == {x: b, 1/x: c, + x*(x + 1): a} + assert eq.expand().as_coefficients_dict(x) == {x**2: a, x: a + b, 1/x: c} + assert x.as_coefficients_dict() == {x: S.One} + + +def test_args_cnc(): + A = symbols('A', commutative=False) + assert (x + A).args_cnc() == \ + [[], [x + A]] + assert (x + a).args_cnc() == \ + [[a + x], []] + assert (x*a).args_cnc() == \ + [[a, x], []] + assert (x*y*A*(A + 1)).args_cnc(cset=True) == \ + [{x, y}, [A, 1 + A]] + assert Mul(x, x, evaluate=False).args_cnc(cset=True, warn=False) == \ + [{x}, []] + assert Mul(x, x**2, evaluate=False).args_cnc(cset=True, warn=False) == \ + [{x, x**2}, []] + 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) + a = x + n + assert a.is_commutative is False + assert a._new_rawargs(x).is_commutative + assert a._new_rawargs(x, y).is_commutative + assert a._new_rawargs(x, n).is_commutative is False + assert a._new_rawargs(x, y, n).is_commutative is False + m = x*n + assert m.is_commutative is False + assert m._new_rawargs(x).is_commutative + assert m._new_rawargs(n).is_commutative is False + assert m._new_rawargs(x, y).is_commutative + assert m._new_rawargs(x, n).is_commutative is False + assert m._new_rawargs(x, y, n).is_commutative is False + + assert m._new_rawargs(x, n, reeval=False).is_commutative is False + assert m._new_rawargs(S.One) is S.One + + +def test_issue_5226(): + assert Add(evaluate=False) == 0 + assert Mul(evaluate=False) == 1 + assert Mul(x + y, evaluate=False).is_Add + + +def test_free_symbols(): + # free_symbols should return the free symbols of an object + assert S.One.free_symbols == set() + assert x.free_symbols == {x} + assert Integral(x, (x, 1, y)).free_symbols == {y} + assert (-Integral(x, (x, 1, y))).free_symbols == {y} + assert meter.free_symbols == set() + assert (meter**x).free_symbols == {x} + + +def test_has_free(): + assert x.has_free(x) + assert not x.has_free(y) + assert (x + y).has_free(x) + assert (x + y).has_free(*(x, z)) + assert f(x).has_free(x) + assert f(x).has_free(f(x)) + assert Integral(f(x), (f(x), 1, y)).has_free(y) + assert not Integral(f(x), (f(x), 1, y)).has_free(x) + assert not Integral(f(x), (f(x), 1, y)).has_free(f(x)) + # simple extraction + assert (x + 1 + y).has_free(x + 1) + assert not (x + 2 + y).has_free(x + 1) + assert (2 + 3*x*y).has_free(3*x) + raises(TypeError, lambda: x.has_free({x, y})) + s = FiniteSet(1, 2) + assert Piecewise((s, x > 3), (4, True)).has_free(s) + assert not Piecewise((1, x > 3), (4, True)).has_free(s) + # can't make set of these, but fallback will handle + raises(TypeError, lambda: x.has_free(y, [])) + + +def test_has_xfree(): + assert (x + 1).has_xfree({x}) + assert ((x + 1)**2).has_xfree({x + 1}) + assert not (x + y + 1).has_xfree({x + 1}) + raises(TypeError, lambda: x.has_xfree(x)) + raises(TypeError, lambda: x.has_xfree([x])) + + +def test_issue_5300(): + x = Symbol('x', commutative=False) + assert x*sqrt(2)/sqrt(6) == x*sqrt(3)/3 + + +def test_floordiv(): + from sympy.functions.elementary.integers import floor + assert x // y == floor(x / y) + + +def test_as_coeff_Mul(): + assert Integer(3).as_coeff_Mul() == (Integer(3), Integer(1)) + assert Rational(3, 4).as_coeff_Mul() == (Rational(3, 4), Integer(1)) + assert Float(5.0).as_coeff_Mul() == (Float(5.0), Integer(1)) + assert Float(0.0).as_coeff_Mul() == (Float(0.0), Integer(1)) + + assert (Integer(3)*x).as_coeff_Mul() == (Integer(3), x) + assert (Rational(3, 4)*x).as_coeff_Mul() == (Rational(3, 4), x) + assert (Float(5.0)*x).as_coeff_Mul() == (Float(5.0), x) + + assert (Integer(3)*x*y).as_coeff_Mul() == (Integer(3), x*y) + assert (Rational(3, 4)*x*y).as_coeff_Mul() == (Rational(3, 4), x*y) + assert (Float(5.0)*x*y).as_coeff_Mul() == (Float(5.0), x*y) + + assert (x).as_coeff_Mul() == (S.One, x) + assert (x*y).as_coeff_Mul() == (S.One, x*y) + assert (-oo*x).as_coeff_Mul(rational=True) == (-1, oo*x) + + +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)) + assert Float(5.0).as_coeff_Add() == (Float(5.0), Integer(0)) + + assert (Integer(3) + x).as_coeff_Add() == (Integer(3), x) + assert (Rational(3, 4) + x).as_coeff_Add() == (Rational(3, 4), x) + assert (Float(5.0) + x).as_coeff_Add() == (Float(5.0), x) + assert (Float(5.0) + x).as_coeff_Add(rational=True) == (0, Float(5.0) + x) + + assert (Integer(3) + x + y).as_coeff_Add() == (Integer(3), x + y) + assert (Rational(3, 4) + x + y).as_coeff_Add() == (Rational(3, 4), x + y) + assert (Float(5.0) + x + y).as_coeff_Add() == (Float(5.0), x + y) + + assert (x).as_coeff_Add() == (S.Zero, x) + assert (x*y).as_coeff_Add() == (S.Zero, x*y) + + +def test_expr_sorting(): + + 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)] + assert sorted(exprs, key=default_sort_key) == exprs + + exprs = [x + 1, x**2 + x + 1, x**3 + x**2 + x + 1] + assert sorted(exprs, key=default_sort_key) == exprs + + exprs = [S(4), x - 3*I/2, x + 3*I/2, x - 4*I + 1, x + 4*I + 1] + assert sorted(exprs, key=default_sort_key) == exprs + + exprs = [f(1), f(2), f(3), f(1, 2, 3), g(1), g(2), g(3), g(1, 2, 3)] + assert sorted(exprs, key=default_sort_key) == exprs + + exprs = [f(x), g(x), exp(x), sin(x), cos(x), factorial(x)] + assert sorted(exprs, key=default_sort_key) == exprs + + exprs = [Tuple(x, y), Tuple(x, z), Tuple(x, y, z)] + assert sorted(exprs, key=default_sort_key) == exprs + + exprs = [[3], [1, 2]] + assert sorted(exprs, key=default_sort_key) == exprs + + exprs = [[1, 2], [2, 3]] + assert sorted(exprs, key=default_sort_key) == exprs + + exprs = [[1, 2], [1, 2, 3]] + assert sorted(exprs, key=default_sort_key) == exprs + + exprs = [{x: -y}, {x: y}] + assert sorted(exprs, key=default_sort_key) == exprs + + exprs = [{1}, {1, 2}] + assert sorted(exprs, key=default_sort_key) == exprs + + a, b = exprs = [Dummy('x'), Dummy('x')] + assert sorted([b, a], key=default_sort_key) == exprs + + +def test_as_ordered_factors(): + + 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)] + + args = [f(1), f(2), f(3), f(1, 2, 3), g(1), g(2), g(3), g(1, 2, 3)] + expr = Mul(*args) + + assert expr.as_ordered_factors() == args + + A, B = symbols('A,B', commutative=False) + + assert (A*B).as_ordered_factors() == [A, B] + assert (B*A).as_ordered_factors() == [B, A] + + +def test_as_ordered_terms(): + + 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] + + args = [f(1), f(2), f(3), f(1, 2, 3), g(1), g(2), g(3), g(1, 2, 3)] + expr = Add(*args) + + assert expr.as_ordered_terms() == args + + 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 ( 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] + + e = x**2*y**2 + x*y**4 + y + 2 + + assert e.as_ordered_terms(order="lex") == [x**2*y**2, x*y**4, y, 2] + assert e.as_ordered_terms(order="grlex") == [x*y**4, x**2*y**2, y, 2] + assert e.as_ordered_terms(order="rev-lex") == [2, y, x*y**4, x**2*y**2] + assert e.as_ordered_terms(order="rev-grlex") == [2, y, x**2*y**2, x*y**4] + + k = symbols('k') + assert k.as_ordered_terms(data=True) == ([(k, ((1.0, 0.0), (1,), ()))], [k]) + + +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_eval_interval(): + assert exp(x)._eval_interval(*Tuple(x, 0, 1)) == exp(1) - exp(0) + + # issue 4199 + a = x/y + raises(NotImplementedError, lambda: a._eval_interval(x, S.Zero, oo)._eval_interval(y, oo, S.Zero)) + raises(NotImplementedError, lambda: a._eval_interval(x, S.Zero, oo)._eval_interval(y, S.Zero, oo)) + a = x - y + raises(NotImplementedError, lambda: a._eval_interval(x, S.One, oo)._eval_interval(y, oo, S.One)) + raises(ValueError, lambda: x._eval_interval(x, None, None)) + a = -y*Heaviside(x - y) + assert a._eval_interval(x, -oo, oo) == -y + assert a._eval_interval(x, oo, -oo) == y + + +def test_eval_interval_zoo(): + # Test that limit is used when zoo is returned + assert Si(1/x)._eval_interval(x, S.Zero, S.One) == -pi/2 + Si(1) + + +def test_primitive(): + assert (3*(x + 1)**2).primitive() == (3, (x + 1)**2) + assert (6*x + 2).primitive() == (2, 3*x + 1) + assert (x/2 + 3).primitive() == (S.Half, x + 6) + eq = (6*x + 2)*(x/2 + 3) + assert eq.primitive()[0] == 1 + eq = (2 + 2*x)**2 + assert eq.primitive()[0] == 1 + assert (4.0*x).primitive() == (1, 4.0*x) + assert (4.0*x + y/2).primitive() == (S.Half, 8.0*x + y) + assert (-2*x).primitive() == (2, -x) + assert Add(5*z/7, 0.5*x, 3*y/2, evaluate=False).primitive() == \ + (S.One/14, 7.0*x + 21*y + 10*z) + for i in [S.Infinity, S.NegativeInfinity, S.ComplexInfinity]: + assert (i + x/3).primitive() == \ + (S.One/3, i + x) + assert (S.Infinity + 2*x/3 + 4*y/7).primitive() == \ + (S.One/21, 14*x + 12*y + oo) + assert S.Zero.primitive() == (S.One, S.Zero) + + +def test_issue_5843(): + 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 + assert Sum(x, (x, 1, 10)).is_constant() is True + assert Sum(x, (x, 1, n)).is_constant() is False + assert Sum(x, (x, 1, n)).is_constant(y) is True + assert Sum(x, (x, 1, n)).is_constant(n) is False + assert Sum(x, (x, 1, n)).is_constant(x) is True + eq = a*cos(x)**2 + a*sin(x)**2 - a + assert 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 log(x/y).is_constant() is False + + assert checksol(x, x, Sum(x, (x, 1, n))) is False + assert checksol(x, x, Sum(x, (x, 1, n))) is False + assert f(1).is_constant + assert checksol(x, x, f(x)) is False + + assert Pow(x, S.Zero, evaluate=False).is_constant() is True # == 1 + assert Pow(S.Zero, x, evaluate=False).is_constant() is False # == 0 or 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 + + assert meter.is_constant() is True + 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)) + assert (cos(x)**2 + sin(x)**2).equals(1) + assert (a*cos(x)**2 + a*sin(x)**2).equals(a) + r = sqrt(2) + assert (-1/(r + r*x) + 1/r/(1 + x)).equals(0) + assert factorial(x + 1).equals((x + 1)*factorial(x)) + assert sqrt(3).equals(2*sqrt(3)) is False + assert (sqrt(5)*sqrt(3)).equals(sqrt(3)) is False + assert (sqrt(5) + sqrt(3)).equals(0) is False + 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.One/4) + (-6)**(S.One/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 + i = 2*sqrt(2)*x**(S(5)/2)*(1 + 1/(2*x))**(S(5)/2)/5 + \ + 2*sqrt(2)*x**(S(3)/2)*(1 + 1/(2*x))**(S(5)/2)/(-6 - 3/x) + ans = sqrt(2*x + 1)*(6*x**2 + x - 1)/15 + diff = i - ans + assert diff.equals(0) is None # should be False, but previously this was False due to wrong intermediate result + assert diff.subs(x, Rational(-1, 2)/2) == 7*sqrt(2)/120 + # there are regions for x for which the expression is True, for + # example, when x < -1/2 or x > 0 the expression is zero + p = Symbol('p', positive=True) + 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 6829 + # eq = q*x + q/4 + x**4 + x**3 + 2*x**2 - S.One/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.One/3) - + S(13)/12)/2 - sqrt((2*q - S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - + S(2197)/13824)**(S.One/3) - S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - + S(2197)/13824)**(S.One/3) - S(13)/6)/2 - S.One/4) + q/4 + (-sqrt(-2*(-(q + - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/12)/2 - sqrt((2*q + - S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - + S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - + S(13)/6)/2 - S.One/4)**4 + (-sqrt(-2*(-(q - S(7)/8)**S(2)/8 - + S(2197)/13824)**(S.One/3) - S(13)/12)/2 - sqrt((2*q - + S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - + S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - + S(13)/6)/2 - S.One/4)**3 + 2*(-sqrt(-2*(-(q - S(7)/8)**S(2)/8 - + S(2197)/13824)**(S.One/3) - S(13)/12)/2 - sqrt((2*q - + S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - + S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - + S(13)/6)/2 - S.One/4)**2 - Rational(1, 3)) + assert z.equals(0) + + +def test_random(): + from sympy.functions.combinatorial.numbers import lucas + from sympy.simplify.simplify import posify + assert posify(x)[0]._random() is not None + assert lucas(n)._random(2, -2, 0, -1, 1) is None + + # issue 8662 + assert Piecewise((Max(x, y), z))._random() is None + + +def test_round(): + assert str(Float('0.1249999').round(2)) == '0.12' + d20 = 12345678901234567890 + ans = S(d20).round(2) + assert ans.is_Integer and ans == d20 + ans = S(d20).round(-2) + assert ans.is_Integer and ans == 12345678901234567900 + assert str(S('1/7').round(4)) == '0.1429' + assert str(S('.[12345]').round(4)) == '0.1235' + assert str(S('.1349').round(2)) == '0.13' + n = S(12345) + ans = n.round() + assert ans.is_Integer + assert ans == n + ans = n.round(1) + assert ans.is_Integer + assert ans == n + ans = n.round(4) + assert ans.is_Integer + assert ans == n + assert n.round(-1) == 12340 + + r = Float(str(n)).round(-4) + assert r == 10000.0 + + assert n.round(-5) == 0 + + assert str((pi + sqrt(2)).round(2)) == '4.56' + assert (10*(pi + sqrt(2))).round(-1) == 50.0 + raises(TypeError, lambda: round(x + 2, 2)) + assert str(S(2.3).round(1)) == '2.3' + # rounding in SymPy (as in Decimal) should be + # exact for the given precision; we check here + # that when a 5 follows the last digit that + # the rounded digit will be even. + for i in range(-99, 100): + # construct a decimal that ends in 5, e.g. 123 -> 0.1235 + s = str(abs(i)) + p = len(s) # we are going to round to the last digit of i + n = '0.%s5' % s # put a 5 after i's digits + j = p + 2 # 2 for '0.' + if i < 0: # 1 for '-' + j += 1 + n = '-' + n + v = str(Float(n).round(p))[:j] # pertinent digits + if v.endswith('.'): + continue # it ends with 0 which is even + L = int(v[-1]) # last digit + assert L % 2 == 0, (n, '->', v) + + assert (Float(.3, 3) + 2*pi).round() == 7 + assert (Float(.3, 3) + 2*pi*100).round() == 629 + assert (pi + 2*E*I).round() == 3 + 5*I + # don't let request for extra precision give more than + # what is known (in this case, only 3 digits) + assert str((Float(.03, 3) + 2*pi/100).round(5)) == '0.0928' + assert str((Float(.03, 3) + 2*pi/100).round(4)) == '0.0928' + + assert S.Zero.round() == 0 + + a = (Add(1, Float('1.' + '9'*27, ''), evaluate=False)) + assert a.round(10) == Float('3.000000000000000000000000000', '') + assert a.round(25) == Float('3.000000000000000000000000000', '') + assert a.round(26) == Float('3.000000000000000000000000000', '') + assert a.round(27) == Float('2.999999999999999999999999999', '') + assert a.round(30) == Float('2.999999999999999999999999999', '') + #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', '') + + # XXX: Should round set the precision of the result? + # The previous version of the tests above is this but they only pass + # because Floats with unequal precision compare equal: + # + # 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()) + raises(TypeError, lambda: f(1).round()) + + # exact magnitude of 10 + assert str(S.One.round()) == '1' + assert str(S(100).round()) == '100' + + # applied to real and imaginary portions + assert (2*pi + E*I).round() == 6 + 3*I + assert (2*pi + I/10).round() == 6 + assert (pi/10 + 2*I).round() == 2*I + # the lhs re and im parts are Float with dps of 2 + # and those on the right have dps of 15 so they won't compare + # equal unless we use string or compare components (which will + # then coerce the floats to the same precision) or re-create + # the floats + assert str((pi/10 + E*I).round(2)) == '0.31 + 2.72*I' + assert str((pi/10 + E*I).round(2).as_real_imag()) == '(0.31, 2.72)' + assert str((pi/10 + E*I).round(2)) == '0.31 + 2.72*I' + + # issue 6914 + assert (I**(I + 3)).round(3) == Float('-0.208', '')*I + + # issue 8720 + assert S(-123.6).round() == -124 + assert S(-1.5).round() == -2 + assert S(-100.5).round() == -100 + assert S(-1.5 - 10.5*I).round() == -2 - 10*I + + # issue 7961 + assert str(S(0.006).round(2)) == '0.01' + assert str(S(0.00106).round(4)) == '0.0011' + + # issue 8147 + assert S.NaN.round() is S.NaN + assert S.Infinity.round() is S.Infinity + assert S.NegativeInfinity.round() is S.NegativeInfinity + assert S.ComplexInfinity.round() is S.ComplexInfinity + + # check that types match + for i in range(2): + fi = float(i) + # 2 args + assert all(type(round(i, p)) is int for p in (-1, 0, 1)) + assert all(S(i).round(p).is_Integer for p in (-1, 0, 1)) + assert all(type(round(fi, p)) is float for p in (-1, 0, 1)) + assert all(S(fi).round(p).is_Float for p in (-1, 0, 1)) + # 1 arg (p is None) + assert type(round(i)) is int + assert S(i).round().is_Integer + assert type(round(fi)) is int + assert S(fi).round().is_Integer + + # issue 25698 + n = 6000002 + assert int(n*(log(n) + log(log(n)))) == 110130079 + one = cos(2)**2 + sin(2)**2 + eq = exp(one*I*pi) + qr, qi = eq.as_real_imag() + assert qi.round(2) == 0.0 + assert eq.round(2) == -1.0 + eq = one - 1/S(10**120) + assert S.true not in (eq > 1, eq < 1) + assert int(eq) == int(.9) == 0 + assert int(-eq) == int(-.9) == 0 + + +def test_held_expression_UnevaluatedExpr(): + x = symbols("x") + he = UnevaluatedExpr(1/x) + e1 = x*he + + assert isinstance(e1, Mul) + assert e1.args == (x, he) + assert e1.doit() == 1 + assert UnevaluatedExpr(Derivative(x, x)).doit(deep=False + ) == Derivative(x, x) + assert UnevaluatedExpr(Derivative(x, x)).doit() == 1 + + xx = Mul(x, x, evaluate=False) + assert xx != x**2 + + ue2 = UnevaluatedExpr(xx) + assert isinstance(ue2, UnevaluatedExpr) + assert ue2.args == (xx,) + assert ue2.doit() == x**2 + assert ue2.doit(deep=False) == xx + + x2 = UnevaluatedExpr(2)*2 + assert type(x2) is Mul + assert x2.args == (2, UnevaluatedExpr(2)) + +def test_round_exception_nostr(): + # Don't use the string form of the expression in the round exception, as + # it's too slow + s = Symbol('bad') + try: + s.round() + except TypeError as e: + assert 'bad' not in str(e) + else: + # Did not raise + raise AssertionError("Did not raise") + + +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_6325(): + 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 + assert e.diff(t, 2) == ans + assert diff(e, t, 2, simplify=False) != ans + + +def test_issue_7426(): + f1 = a % c + f2 = x % z + assert f1.equals(f2) is None + + +def test_issue_11122(): + x = Symbol('x', extended_positive=False) + assert unchanged(Gt, x, 0) # (x > 0) + # (x > 0) should remain unevaluated after PR #16956 + + x = Symbol('x', positive=False, real=True) + assert (x > 0) is S.false + + +def test_issue_10651(): + x = Symbol('x', real=True) + e1 = (-1 + x)/(1 - x) + e3 = (4*x**2 - 4)/((1 - x)*(1 + x)) + e4 = 1/(cos(x)**2) - (tan(x))**2 + x = Symbol('x', positive=True) + e5 = (1 + x)/x + assert e1.is_constant() is None + assert e3.is_constant() is None + assert e4.is_constant() is None + assert e5.is_constant() is False + + +def test_issue_10161(): + x = symbols('x', real=True) + assert x*abs(x)*abs(x) == x**3 + + +def test_issue_10755(): + x = symbols('x') + raises(TypeError, lambda: int(log(x))) + raises(TypeError, lambda: log(x).round(2)) + + +def test_issue_11877(): + x = symbols('x') + assert integrate(log(S.Half - x), (x, 0, S.Half)) == Rational(-1, 2) -log(2)/2 + + +def test_normal(): + x = symbols('x') + e = Mul(S.Half, 1 + x, evaluate=False) + assert e.normal() == e + + +def test_expr(): + x = symbols('x') + raises(TypeError, lambda: tan(x).series(x, 2, oo, "+")) + + +def test_ExprBuilder(): + eb = ExprBuilder(Mul) + eb.args.extend([x, x]) + assert eb.build() == x**2 + + +def test_issue_22020(): + from sympy.parsing.sympy_parser import parse_expr + x = parse_expr("log((2*V/3-V)/C)/-(R+r)*C") + y = parse_expr("log((2*V/3-V)/C)/-(R+r)*2") + assert x.equals(y) is False + + +def test_non_string_equality(): + # Expressions should not compare equal to strings + x = symbols('x') + one = sympify(1) + assert (x == 'x') is False + assert (x != 'x') is True + assert (one == '1') is False + assert (one != '1') is True + assert (x + 1 == 'x + 1') is False + assert (x + 1 != 'x + 1') is True + + # Make sure == doesn't try to convert the resulting expression to a string + # (e.g., by calling sympify() instead of _sympify()) + + class BadRepr: + def __repr__(self): + raise RuntimeError + + assert (x == BadRepr()) is False + assert (x != BadRepr()) is True + + +def test_21494(): + from sympy.testing.pytest import warns_deprecated_sympy + + with warns_deprecated_sympy(): + assert x.expr_free_symbols == {x} + + with warns_deprecated_sympy(): + assert Basic().expr_free_symbols == set() + + with warns_deprecated_sympy(): + assert S(2).expr_free_symbols == {S(2)} + + with warns_deprecated_sympy(): + assert Indexed("A", x).expr_free_symbols == {Indexed("A", x)} + + with warns_deprecated_sympy(): + assert Subs(x, x, 0).expr_free_symbols == set() + + +def test_Expr__eq__iterable_handling(): + assert x != range(3) + + +def test_format(): + assert '{:1.2f}'.format(S.Zero) == '0.00' + assert '{:+3.0f}'.format(S(3)) == ' +3' + assert '{:23.20f}'.format(pi) == ' 3.14159265358979323846' + assert '{:50.48f}'.format(exp(sin(1))) == '2.319776824715853173956590377503266813254904772376' + + +def test_issue_24045(): + assert powsimp(exp(a)/((c*a - c*b)*(Float(1.0)*c*a - Float(1.0)*c*b))) # doesn't raise + + +def test__unevaluated_Mul(): + A, B = symbols('A B', commutative=False) + assert _unevaluated_Mul(x, A, B, S(2), A).args == (2, x, A, B, A) + assert _unevaluated_Mul(-x*A*B, S(2), A).args == (-2, x, A, B, A) + + +def test_Float_zero_division_error(): + # issue 27165 + assert Float('1.7567e-1417').round(15) == Float(0) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_exprtools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_exprtools.py new file mode 100644 index 0000000000000000000000000000000000000000..b550db1606866fb76442980ea2139aaf61219525 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_exprtools.py @@ -0,0 +1,493 @@ +"""Tests for tools for manipulating of large commutative expressions. """ + +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.containers import (Dict, Tuple) +from sympy.core.function import Function +from sympy.core.mul import Mul +from sympy.core.numbers import (I, Rational, oo) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol, symbols) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import (root, sqrt) +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.integrals.integrals import Integral +from sympy.series.order import O +from sympy.sets.sets import Interval +from sympy.simplify.radsimp import collect +from sympy.simplify.simplify import simplify +from sympy.core.exprtools import (decompose_power, Factors, Term, _gcd_terms, + gcd_terms, factor_terms, factor_nc, _mask_nc, + _monotonic_sign) +from sympy.core.mul import _keep_coeff as _keep_coeff +from sympy.simplify.cse_opts import sub_pre +from sympy.testing.pytest import raises + +from sympy.abc import a, b, t, x, y, z + + +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) + assert decompose_power(x**(y*Rational(2, 3))) == (x**(y/3), 2) + + +def test_Factors(): + assert Factors() == Factors({}) == Factors(S.One) + assert Factors().as_expr() is 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}) + # issue #18059: + assert Factors((x**2)**S.Half).as_expr() == (x**2)**S.Half + + a = Factors({x: 5, y: 3, z: 7}) + 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.quo(b) == a/b == Factors({x: 5, z: 4}) + 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}) + + assert a.gcd(b) == Factors({y: 3, z: 3}) + assert a.lcm(b) == Factors({x: 5, y: 4, z: 7, t: 10}) + + a = Factors({x: 4, y: 7, t: 7}) + b = Factors({z: 1, t: 3}) + + 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.NegativeOne: S(3)})*Factors({S.NegativeOne: S.One, I: S(5)}) == \ + Factors(I) + assert Factors(sqrt(I)*I) == Factors(I**(S(3)/2)) == Factors({I: S(3)/2}) + assert Factors({I: S(3)/2}).as_expr() == I**(S(3)/2) + + 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.One})) + + # coverage + # /!\ things break if this is not True + assert Factors({S.NegativeOne: Rational(3, 2)}) == Factors({I: S.One, S.NegativeOne: S.One}) + assert Factors({I: S.One, S.NegativeOne: Rational(1, 3)}).as_expr() == I*(-1)**Rational(1, 3) + + assert Factors(-1.) == Factors({S.NegativeOne: S.One, S(1.): 1}) + assert Factors(-2.) == Factors({S.NegativeOne: S.One, S(2.): 1}) + assert Factors((-2.)**x) == Factors({S(-2.): x}) + assert Factors(S(-2)) == Factors({S.NegativeOne: S.One, S(2): 1}) + assert Factors(S.Half) == Factors({S(2): -S.One}) + assert Factors(Rational(3, 2)) == Factors({S(3): S.One, S(2): S.NegativeOne}) + assert Factors({I: S.One}) == Factors(I) + assert Factors({-1.0: 2, I: 1}) == Factors({S(1.0): 1, I: 1}) + assert Factors({S.NegativeOne: Rational(-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.Zero) == (Factors(), Factors(S.Zero)) + raises(ZeroDivisionError, lambda: Factors(x).div(S.Zero)) + assert Factors(x).mul(S(2)) == Factors(2*x) + assert Factors(x).mul(S.Zero).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.Zero) == Factors(x) + assert Factors(x).lcm(S.Zero).is_zero + assert Factors(S.Zero).div(x) == (Factors(S.Zero), Factors()) + assert Factors(x).div(x) == (Factors(), Factors()) + assert Factors({x: .2})/Factors({x: .2}) == Factors() + assert Factors(x) != Factors() + assert Factors(S.Zero).normal(x) == (Factors(S.Zero), Factors()) + n, d = x**(2 + y), x**2 + f = Factors(n) + assert f.div(d) == f.normal(d) == (Factors(x**y), Factors()) + assert f.gcd(d) == Factors() + d = x**y + assert f.div(d) == f.normal(d) == (Factors(x**2), Factors()) + assert f.gcd(d) == Factors(d) + n = d = 2**x + f = Factors(n) + assert f.div(d) == f.normal(d) == (Factors(), Factors()) + assert f.gcd(d) == Factors(d) + n, d = 2**x, 2**y + f = Factors(n) + assert f.div(d) == f.normal(d) == (Factors({S(2): x}), Factors({S(2): y})) + assert f.gcd(d) == Factors() + + # 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})) + + assert Factors(3 * x / 2) == Factors({3: 1, 2: -1, x: 1}) + assert Factors(x * x / y) == Factors({x: 2, y: -1}) + assert Factors(27 * x / y**9) == Factors({27: 1, x: 1, y: -9}) + + +def test_Term(): + a = Term(4*x*y**2/z/t**3) + b = Term(2*x**3*y**5/t**3) + + assert a == Term(4, Factors({x: 1, y: 2}), Factors({z: 1, t: 3})) + assert b == Term(2, Factors({x: 3, y: 5}), Factors({t: 3})) + + 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.One/4, Factors({z: 1, t: 3}), Factors({x: 1, y: 2})) + assert b.inv() == Term(S.Half, 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.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 b.pow(3) == b**3 == Term(8, Factors({x: 9, y: 15}), Factors({t: 9})) + + assert a.pow(-3) == a**(-3) == \ + Term(S.One/64, Factors({z: 3, t: 9}), Factors({x: 3, y: 6})) + assert b.pow(-3) == b**(-3) == \ + Term(S.One/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})) + + a = Term(4*x*y**2/z/t**3) + b = Term(2*x**3*y**5*t**7) + + 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({})) + + +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) + + assert _gcd_terms(f) == ((Rational(6, 5))*((1 + x)/(1 + x**2)), 5 + x, 1) + assert _gcd_terms(Add.make_args(f)) == \ + ((Rational(6, 5))*((1 + x)/(1 + x**2)), 5 + x, 1) + + newf = (Rational(6, 5))*((1 + x)*(5 + x)/(1 + x**2)) + assert gcd_terms(f) == newf + args = Add.make_args(f) + # non-Basic sequences of terms treated as terms of Add + assert gcd_terms(list(args)) == newf + assert gcd_terms(tuple(args)) == newf + 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(S(1), 3*y + 3*x*y), Tuple(S(1), S(3)))) == \ + Basic(Tuple(S(1), 3*y*(x + 1)), Tuple(S(1), S(3))) + # but we shouldn't change keys of a dictionary or some may be lost + assert gcd_terms(Dict((x*(1 + y), S(2)), (x + x*y, y + x*y))) == \ + Dict({x*(y + 1): S(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) + + assert gcd_terms(0) == 0 + assert gcd_terms(1) == 1 + assert gcd_terms(x) == x + assert gcd_terms(2 + 2*x) == Mul(2, 1 + x, evaluate=False) + arg = x*(2*x + 4*y) + garg = 2*x*(x + 2*y) + assert gcd_terms(arg) == garg + assert gcd_terms(sin(arg)) == sin(garg) + + # issue 6139-like + alpha, alpha1, alpha2, alpha3 = symbols('alpha:4') + a = alpha**2 - alpha*x**2 + alpha + x**3 - x*(alpha + 1) + rep = (alpha, (1 + sqrt(5))/2 + alpha1*x + alpha2*x**2 + alpha3*x**3) + s = (a/(x - alpha)).subs(*rep).series(x, 0, 1) + assert simplify(collect(s, x)) == -sqrt(5)/2 - Rational(3, 2) + O(x) + + # issue 5917 + assert _gcd_terms([S.Zero, S.Zero]) == (0, 0, 1) + assert _gcd_terms([2*x + 4]) == (2, x + 2, 1) + + eq = x/(x + 1/x) + assert gcd_terms(eq, fraction=False) == eq + eq = x/2/y + 1/x/y + assert gcd_terms(eq, fraction=True, clear=True) == \ + (x**2 + 2)/(2*x*y) + assert gcd_terms(eq, fraction=True, clear=False) == \ + (x**2/2 + 1)/(x*y) + assert gcd_terms(eq, fraction=False, clear=True) == \ + (x + 2/x)/(2*y) + assert gcd_terms(eq, fraction=False, clear=False) == \ + (x/2 + 1/x)/y + + +def test_factor_terms(): + A = Symbol('A', commutative=False) + assert factor_terms(9*(x + x*y + 1) + (3*x + 3)**(2 + 2*x)) == \ + 9*x*y + 9*x + _keep_coeff(S(3), x + 1)**_keep_coeff(S(2), x + 1) + 9 + assert factor_terms(9*(x + x*y + 1) + (3)**(2 + 2*x)) == \ + _keep_coeff(S(9), 3**(2*x) + x*y + x + 1) + assert factor_terms(3**(2 + 2*x) + a*3**(2 + 2*x)) == \ + 9*3**(2*x)*(a + 1) + assert factor_terms(x + x*A) == \ + x*(1 + A) + assert factor_terms(sin(x + x*A)) == \ + sin(x*(1 + A)) + assert factor_terms((3*x + 3)**((2 + 2*x)/3)) == \ + _keep_coeff(S(3), x + 1)**_keep_coeff(Rational(2, 3), x + 1) + assert factor_terms(x + (x*y + x)**(3*x + 3)) == \ + x + (x*(y + 1))**_keep_coeff(S(3), x + 1) + assert factor_terms(a*(x + x*y) + b*(x*2 + y*x*2)) == \ + x*(a + 2*b)*(y + 1) + i = Integral(x, (x, 0, oo)) + assert factor_terms(i) == i + + assert factor_terms(x/2 + y) == x/2 + y + # fraction doesn't apply to integer denominators + assert factor_terms(x/2 + y, fraction=True) == x/2 + y + # clear *does* apply to the integer denominators + assert factor_terms(x/2 + y, clear=True) == Mul(S.Half, x + 2*y, evaluate=False) + + # 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.One/3)*(1 + (-1)**(S.One/3)) + + eq = [x + x*y] + ans = [x*(y + 1)] + for c in [list, tuple, set]: + assert factor_terms(c(eq)) == c(ans) + assert factor_terms(Tuple(x + x*y)) == Tuple(x*(y + 1)) + assert factor_terms(Interval(0, 1)) == Interval(0, 1) + e = 1/sqrt(a/2 + 1) + assert factor_terms(e, clear=False) == 1/sqrt(a/2 + 1) + assert factor_terms(e, clear=True) == sqrt(2)/sqrt(a + 2) + + eq = x/(x + 1/x) + 1/(x**2 + 1) + assert factor_terms(eq, fraction=False) == eq + assert factor_terms(eq, fraction=True) == 1 + + 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)) + + # sum/integral tests + for F in (Sum, Integral): + assert factor_terms(F(x, (y, 1, 10))) == x * F(1, (y, 1, 10)) + assert factor_terms(F(x, (y, 1, 10)) + x) == x * (1 + F(1, (y, 1, 10))) + assert factor_terms(F(x*y + x*y**2, (y, 1, 10))) == x*F(y*(y + 1), (y, 1, 10)) + + # expressions involving Pow terms with base 0 + assert factor_terms(0**(x - 2) - 1) == 0**(x - 2) - 1 + assert factor_terms(0**(x + 2) - 1) == 0**(x + 2) - 1 + assert factor_terms((0**(x + 2) - 1).subs(x,-2)) == 0 + + +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 + from sympy.core.function import _mexpand + e = x*(1 + y)**2 + assert _mexpand(e) == x + x*2*y + x*y**2 + + def factor_nc_test(e): + ex = _mexpand(e) + assert ex.is_Add + f = factor_nc(ex) + assert not f.is_Add and _mexpand(f) == ex + + factor_nc_test(x*(1 + y)) + factor_nc_test(n*(x + 1)) + factor_nc_test(n*(x + m)) + factor_nc_test((x + m)*n) + factor_nc_test(n*m*(x*o + n*o*m)*n) + s = Sum(x, (x, 1, 2)) + factor_nc_test(x*(1 + s)) + factor_nc_test(x*(1 + s)*s) + 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*m + 1)) + factor_nc_test(x*(n*m + x)) + factor_nc_test(x*(x*n*m + 1)) + factor_nc_test(n*(m/x + o)) + factor_nc_test(m*(n + o/2)) + factor_nc_test(x*n*(x*m + 1)) + factor_nc_test(x*(m*n + x*n*m)) + factor_nc_test(n*(1 - m)*n**2) + + factor_nc_test((n + m)**2) + factor_nc_test((n - m)*(n + m)**2) + factor_nc_test((n + m)**2*(n - m)) + factor_nc_test((m - n)*(n + m)**2*(n - m)) + + assert factor_nc(n*(n + n*m)) == n**2*(1 + m) + assert factor_nc(m*(m*n + n*m*n**2)) == m*(m + n*m*n)*n + eq = m*sin(n) - sin(n)*m + assert factor_nc(eq) == eq + + # for coverage: + from sympy.physics.secondquant import Commutator + from sympy.polys.polytools import factor + eq = 1 + x*Commutator(m, n) + assert factor_nc(eq) == eq + eq = x*Commutator(m, n) + x*Commutator(m, o)*Commutator(m, n) + assert factor(eq) == x*(1 + Commutator(m, o))*Commutator(m, n) + + # issue 6534 + assert (2*n + 2*m).factor() == 2*(n + m) + + # issue 6701 + _n = symbols('nz', zero=False, commutative=False) + 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 6918 + assert factor_nc(-n*(2*x**2 + 2*x)) == -2*n*x*(x + 1) + + +def test_issue_6360(): + a, b = symbols("a b") + apb = a + b + eq = apb + apb**2*(-2*a - 2*b) + assert factor_terms(sub_pre(eq)) == a + b - 2*(a + b)**3 + + +def test_issue_7903(): + a = symbols(r'a', real=True) + t = exp(I*cos(a)) + exp(-I*sin(a)) + assert t.simplify() + +def test_issue_8263(): + F, G = symbols('F, G', commutative=False, cls=Function) + x, y = symbols('x, y') + expr, dummies, _ = _mask_nc(F(x)*G(y) - G(y)*F(x)) + for v in dummies.values(): + assert not v.is_commutative + assert not expr.is_zero + +def test_monotonic_sign(): + F = _monotonic_sign + x = symbols('x') + assert F(x) is None + assert F(-x) is None + assert F(Dummy(prime=True)) == 2 + assert F(Dummy(prime=True, odd=True)) == 3 + assert F(Dummy(composite=True)) == 4 + assert F(Dummy(composite=True, odd=True)) == 9 + assert F(Dummy(positive=True, integer=True)) == 1 + assert F(Dummy(positive=True, even=True)) == 2 + assert F(Dummy(positive=True, even=True, prime=False)) == 4 + assert F(Dummy(negative=True, integer=True)) == -1 + assert F(Dummy(negative=True, even=True)) == -2 + assert F(Dummy(zero=True)) == 0 + assert F(Dummy(nonnegative=True)) == 0 + assert F(Dummy(nonpositive=True)) == 0 + + assert F(Dummy(positive=True) + 1).is_positive + assert F(Dummy(positive=True, integer=True) - 1).is_nonnegative + assert F(Dummy(positive=True) - 1) is None + assert F(Dummy(negative=True) + 1) is None + assert F(Dummy(negative=True, integer=True) - 1).is_nonpositive + assert F(Dummy(negative=True) - 1).is_negative + assert F(-Dummy(positive=True) + 1) is None + assert F(-Dummy(positive=True, integer=True) - 1).is_negative + assert F(-Dummy(positive=True) - 1).is_negative + assert F(-Dummy(negative=True) + 1).is_positive + assert F(-Dummy(negative=True, integer=True) - 1).is_nonnegative + assert F(-Dummy(negative=True) - 1) is None + x = Dummy(negative=True) + assert F(x**3).is_nonpositive + assert F(x**3 + log(2)*x - 1).is_negative + x = Dummy(positive=True) + assert F(-x**3).is_nonpositive + + p = Dummy(positive=True) + assert F(1/p).is_positive + assert F(p/(p + 1)).is_positive + p = Dummy(nonnegative=True) + assert F(p/(p + 1)).is_nonnegative + p = Dummy(positive=True) + assert F(-1/p).is_negative + p = Dummy(nonpositive=True) + assert F(p/(-p + 1)).is_nonpositive + + p = Dummy(positive=True, integer=True) + q = Dummy(positive=True, integer=True) + assert F(-2/p/q).is_negative + assert F(-2/(p - 1)/q) is None + + assert F((p - 1)*q + 1).is_positive + assert F(-(p - 1)*q - 1).is_negative + +def test_issue_17256(): + from sympy.sets.fancysets import Range + x = Symbol('x') + s1 = Sum(x + 1, (x, 1, 9)) + s2 = Sum(x + 1, (x, Range(1, 10))) + a = Symbol('a') + r1 = s1.xreplace({x:a}) + r2 = s2.xreplace({x:a}) + + assert r1.doit() == r2.doit() + s1 = Sum(x + 1, (x, 0, 9)) + s2 = Sum(x + 1, (x, Range(10))) + a = Symbol('a') + r1 = s1.xreplace({x:a}) + r2 = s2.xreplace({x:a}) + assert r1 == r2 + +def test_issue_21623(): + from sympy.matrices.expressions.matexpr import MatrixSymbol + M = MatrixSymbol('X', 2, 2) + assert gcd_terms(M[0,0], 1) == M[0,0] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_facts.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_facts.py new file mode 100644 index 0000000000000000000000000000000000000000..7ca04877d0bdaf8124258ea1d25a10bcfa0f5f3a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_facts.py @@ -0,0 +1,312 @@ +from sympy.core.facts import (deduce_alpha_implications, + apply_beta_to_alpha_route, rules_2prereq, FactRules, FactKB) +from sympy.core.logic import And, Not +from sympy.testing.pytest import raises + +T = True +F = False +U = None + + +def test_deduce_alpha_implications(): + def D(i): + I = deduce_alpha_implications(i) + P = rules_2prereq({ + (k, True): {(v, True) for v in S} for k, S in I.items()}) + return I, P + + # transitivity + I, P = D([('a', 'b'), ('b', 'c')]) + assert I == {'a': {'b', 'c'}, 'b': {'c'}, Not('b'): + {Not('a')}, Not('c'): {Not('a'), Not('b')}} + assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}} + + # Duplicate entry + I, P = D([('a', 'b'), ('b', 'c'), ('b', 'c')]) + assert I == {'a': {'b', 'c'}, 'b': {'c'}, Not('b'): {Not('a')}, Not('c'): {Not('a'), Not('b')}} + assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}} + + # see if it is tolerant to cycles + assert D([('a', 'a'), ('a', 'a')]) == ({}, {}) + assert D([('a', 'b'), ('b', 'a')]) == ( + {'a': {'b'}, 'b': {'a'}, Not('a'): {Not('b')}, Not('b'): {Not('a')}}, + {'a': {'b'}, 'b': {'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'))])) + + # see if it handles implications with negations + I, P = D([('a', Not('b')), ('c', 'b')]) + assert I == {'a': {Not('b'), Not('c')}, 'b': {Not('a')}, 'c': {'b', Not('a')}, Not('b'): {Not('c')}} + assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}} + I, P = D([(Not('a'), 'b'), ('a', 'c')]) + assert I == {'a': {'c'}, Not('a'): {'b'}, Not('b'): {'a', + 'c'}, Not('c'): {Not('a'), 'b'},} + assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}} + + + # Long deductions + I, P = D([('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e')]) + assert I == {'a': {'b', 'c', 'd', 'e'}, 'b': {'c', 'd', 'e'}, + 'c': {'d', 'e'}, 'd': {'e'}, Not('b'): {Not('a')}, + Not('c'): {Not('a'), Not('b')}, Not('d'): {Not('a'), Not('b'), + Not('c')}, Not('e'): {Not('a'), Not('b'), Not('c'), Not('d')}} + assert P == {'a': {'b', 'c', 'd', 'e'}, 'b': {'a', 'c', 'd', + 'e'}, 'c': {'a', 'b', 'd', 'e'}, 'd': {'a', 'b', 'c', 'e'}, + 'e': {'a', 'b', 'c', 'd'}} + + # something related to real-world + I, P = D([('rat', 'real'), ('int', 'rat')]) + + assert I == {'int': {'rat', 'real'}, 'rat': {'real'}, + Not('real'): {Not('rat'), Not('int')}, Not('rat'): {Not('int')}} + assert P == {'rat': {'int', 'real'}, 'real': {'int', 'rat'}, + 'int': {'rat', 'real'}} + + +# TODO move me to appropriate place +def test_apply_beta_to_alpha_route(): + APPLY = apply_beta_to_alpha_route + + # indicates empty alpha-chain with attached beta-rule #bidx + def Q(bidx): + return (set(), [bidx]) + + # x -> a &(a,b) -> x -- x -> a + A = {'x': {'a'}} + B = [(And('a', 'b'), 'x')] + assert APPLY(A, B) == {'x': ({'a'}, []), 'a': Q(0), 'b': Q(0)} + + # x -> a &(a,!x) -> b -- x -> a + A = {'x': {'a'}} + B = [(And('a', Not('x')), 'b')] + assert APPLY(A, B) == {'x': ({'a'}, []), Not('x'): Q(0), 'a': Q(0)} + + # x -> a b &(a,b) -> c -- x -> a b c + A = {'x': {'a', 'b'}} + B = [(And('a', 'b'), 'c')] + assert APPLY(A, B) == \ + {'x': ({'a', 'b', 'c'}, []), 'a': Q(0), 'b': Q(0)} + + # x -> a &(a,b) -> y -- x -> a [#0] + A = {'x': {'a'}} + B = [(And('a', 'b'), 'y')] + assert APPLY(A, B) == {'x': ({'a'}, [0]), 'a': Q(0), 'b': Q(0)} + + # x -> a b c &(a,b) -> c -- x -> a b c + A = {'x': {'a', 'b', 'c'}} + B = [(And('a', 'b'), 'c')] + assert APPLY(A, B) == \ + {'x': ({'a', 'b', 'c'}, []), 'a': Q(0), 'b': Q(0)} + + # x -> a b &(a,b,c) -> y -- x -> a b [#0] + A = {'x': {'a', 'b'}} + B = [(And('a', 'b', 'c'), 'y')] + assert APPLY(A, B) == \ + {'x': ({'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': {'a', 'b'}, 'c': {'d'}} + B = [(And('a', 'b'), 'c')] + assert APPLY(A, B) == {'x': ({'a', 'b', 'c', 'd'}, []), + 'c': ({'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': {'a', 'b'}, 'c': {'d'}} + B = [(And('a', 'b'), 'c'), (And('c', 'd'), 'e')] + assert APPLY(A, B) == {'x': ({'a', 'b', 'c', 'd', 'e'}, []), + 'c': ({'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': {'a', 'b'}} + B = [(And('a', 'y'), 'z'), (And('a', 'b'), 'y')] + assert APPLY(A, B) == {'x': ({'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': {'a', 'b'}} + B = [(And('a', Not('b')), 'c')] + assert APPLY(A, B) == \ + {'x': ({'a', 'b'}, []), 'a': Q(0), Not('b'): Q(0)} + + # !x -> !a !b &(!a,b) -> c -- !x -> !a !b + A = {Not('x'): {Not('a'), Not('b')}} + B = [(And(Not('a'), 'b'), 'c')] + assert APPLY(A, B) == \ + {Not('x'): ({Not('a'), Not('b')}, []), Not('a'): Q(0), 'b': Q(0)} + + # x -> a b &(b,c) -> !a -- x -> a b + A = {'x': {'a', 'b'}} + B = [(And('b', 'c'), Not('a'))] + assert APPLY(A, B) == {'x': ({'a', 'b'}, []), 'b': Q(0), 'c': Q(0)} + + # x -> a b &(a, b) -> c -- x -> a b c p + # c -> p a + A = {'x': {'a', 'b'}, 'c': {'p', 'a'}} + B = [(And('a', 'b'), 'c')] + assert APPLY(A, B) == {'x': ({'a', 'b', 'c', 'p'}, []), + 'c': ({'p', 'a'}, []), 'a': Q(0), 'b': Q(0)} + + +def test_FactRules_parse(): + f = FactRules('a -> b') + assert f.prereq == {'b': {'a'}, 'a': {'b'}} + + f = FactRules('a -> !b') + assert f.prereq == {'b': {'a'}, 'a': {'b'}} + + f = FactRules('!a -> b') + assert f.prereq == {'b': {'a'}, 'a': {'b'}} + + f = FactRules('!a -> !b') + assert f.prereq == {'b': {'a'}, 'a': {'b'}} + + f = FactRules('!z == nz') + assert f.prereq == {'z': {'nz'}, 'nz': {'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': 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} + + # 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} + + +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} + + # --- 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({'pos': T, 'npos': F}) == {'real': T, 'pos': T, 'npos': F} + assert D({'pos': F, 'npos': T}) == {'real': T, 'pos': F, 'npos': T} + + +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} + + # --- 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} + + +def test_FactRules_deduce_base(): + # deduction that starts from base + + f = FactRules(['real == neg | zero | pos', + 'neg -> real & !zero & !pos', + 'pos -> real & !zero & !neg']) + base = FactKB(f) + + base.deduce_all_facts({'real': T, 'neg': F}) + assert base == {'real': T, 'neg': F} + + base.deduce_all_facts({'zero': F}) + assert base == {'real': T, 'neg': F, 'zero': F, 'pos': T} + + +def test_FactRules_deduce_staticext(): + # verify that static beta-extensions deduction takes place + f = FactRules(['real == neg | zero | pos', + 'neg -> real & !zero & !pos', + 'pos -> real & !zero & !neg', + 'nneg == real & !neg', + 'npos == real & !pos']) + + assert ('npos', True) in f.full_implications[('neg', True)] + assert ('nneg', True) in f.full_implications[('pos', True)] + assert ('nneg', True) in f.full_implications[('zero', True)] + assert ('npos', True) in f.full_implications[('zero', True)] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_function.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_function.py new file mode 100644 index 0000000000000000000000000000000000000000..a69c6b81b786ab0f0592367eaf402c2165a615dc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_function.py @@ -0,0 +1,1459 @@ +from sympy.concrete.summations import Sum +from sympy.core.basic import Basic, _aresame +from sympy.core.cache import clear_cache +from sympy.core.containers import Dict, Tuple +from sympy.core.expr import Expr, unchanged +from sympy.core.function import (Subs, Function, diff, Lambda, expand, + nfloat, Derivative) +from sympy.core.numbers import E, Float, zoo, Rational, pi, I, oo, nan +from sympy.core.power import Pow +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import symbols, Dummy, Symbol +from sympy.functions.elementary.complexes import im, re +from sympy.functions.elementary.exponential import log, exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import sin, cos, acos +from sympy.functions.special.error_functions import expint +from sympy.functions.special.gamma_functions import loggamma, polygamma +from sympy.matrices.dense import Matrix +from sympy.printing.str import sstr +from sympy.series.order import O +from sympy.tensor.indexed import Indexed +from sympy.core.function import (PoleError, _mexpand, arity, + BadSignatureError, BadArgumentsError) +from sympy.core.parameters import _exp_is_pow +from sympy.core.sympify import sympify, SympifyError +from sympy.matrices import MutableMatrix, ImmutableMatrix +from sympy.sets.sets import FiniteSet +from sympy.solvers.solveset import solveset +from sympy.tensor.array import NDimArray +from sympy.utilities.iterables import subsets, variations +from sympy.testing.pytest import XFAIL, raises, warns_deprecated_sympy, _both_exp_pow + +from sympy.abc import t, w, x, y, z +f, g, h = symbols('f g h', cls=Function) +_xi_1, _xi_2, _xi_3 = [Dummy() for i in range(3)] + +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)) + + +def test_bug1(): + e = sqrt(-log(w)) + assert e.subs(log(w), -x) == sqrt(x) + + e = sqrt(-5*log(w)) + assert e.subs(log(w), -x) == sqrt(5*x) + + +def test_general_function(): + nu = Function('nu') + + e = nu(x) + edx = e.diff(x) + edy = e.diff(y) + edxdx = e.diff(x).diff(x) + edxdy = e.diff(x).diff(y) + assert e == nu(x) + assert edx != nu(x) + assert edx == diff(nu(x), x) + assert edy == 0 + assert edxdx == diff(diff(nu(x), x), x) + assert edxdy == 0 + +def test_general_function_nullary(): + nu = Function('nu') + + e = nu() + edx = e.diff(x) + edxdx = e.diff(x).diff(x) + assert e == nu() + assert edx != nu() + assert edx == 0 + assert edxdx == 0 + + +def test_derivative_subs_bug(): + e = diff(g(x), x) + assert e.subs(g(x), f(x)) != e + assert e.subs(g(x), f(x)) == Derivative(f(x), x) + assert e.subs(g(x), -f(x)) == Derivative(-f(x), x) + + assert e.subs(x, y) == Derivative(g(y), y) + + +def test_derivative_subs_self_bug(): + d = diff(f(x), x) + + assert d.subs(d, y) == y + + +def test_derivative_linearity(): + assert diff(-f(x), x) == -diff(f(x), x) + assert diff(8*f(x), x) == 8*diff(f(x), x) + assert diff(8*f(x), x) != 7*diff(f(x), x) + assert diff(8*f(x)*x, x) == 8*f(x) + 8*x*diff(f(x), x) + assert diff(8*f(x)*y*x, x).expand() == 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) + + assert Derivative(Derivative(f(x), x), x) == diff(f(x), x, x) + assert Derivative(sin(x), x, 0) == sin(x) + assert Derivative(sin(x), (x, y), (x, -y)) == 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) == Derivative(f(x, y, z), (x, 3)) + assert diff(f(x, y, z), x, 3) == Derivative(f(x, y, z), x, 3) + + # issue 5028 + assert [diff(-z + x/y, sym) for sym in (z, x, y)] == [-1, 1/y, -x/y**2] + assert diff(f(x, y, z), x, y, z, 2) == Derivative(f(x, y, z), x, y, z, z) + assert diff(f(x, y, z), x, y, z, 2, evaluate=False) == \ + Derivative(f(x, y, z), x, y, z, z) + assert Derivative(f(x, y, z), x, y, z)._eval_derivative(z) == \ + Derivative(f(x, y, z), x, y, z, z) + assert Derivative(Derivative(f(x, y, z), x), y)._eval_derivative(z) == \ + Derivative(f(x, y, z), x, y, z) + + raises(TypeError, lambda: cos(x).diff((x, y)).variables) + assert cos(x).diff((x, y))._wrt_variables == [x] + + # issue 23222 + assert sympify("a*x+b").diff("x") == sympify("a") + +def test_Function(): + class myfunc(Function): + @classmethod + def eval(cls): # zero args + return + + assert myfunc.nargs == FiniteSet(0) + assert myfunc().nargs == FiniteSet(0) + raises(TypeError, lambda: myfunc(x).nargs) + + class myfunc(Function): + @classmethod + def eval(cls, x): # one arg + return + + assert myfunc.nargs == FiniteSet(1) + assert myfunc(x).nargs == FiniteSet(1) + raises(TypeError, lambda: myfunc(x, y).nargs) + + class myfunc(Function): + @classmethod + def eval(cls, *x): # star args + return + + assert myfunc.nargs == S.Naturals0 + assert myfunc(x).nargs == S.Naturals0 + + +def test_nargs(): + f = Function('f') + assert f.nargs == S.Naturals0 + assert f(1).nargs == S.Naturals0 + assert Function('f', nargs=2)(1, 2).nargs == FiniteSet(2) + assert sin.nargs == FiniteSet(1) + assert sin(2).nargs == FiniteSet(1) + assert log.nargs == FiniteSet(1, 2) + assert log(2).nargs == FiniteSet(1, 2) + assert Function('f', nargs=2).nargs == FiniteSet(2) + assert Function('f', nargs=0).nargs == FiniteSet(0) + assert Function('f', nargs=(0, 1)).nargs == FiniteSet(0, 1) + assert Function('f', nargs=None).nargs == S.Naturals0 + raises(ValueError, lambda: Function('f', nargs=())) + +def test_nargs_inheritance(): + class f1(Function): + nargs = 2 + class f2(f1): + pass + class f3(f2): + pass + class f4(f3): + nargs = 1,2 + class f5(f4): + pass + class f6(f5): + pass + class f7(f6): + nargs=None + class f8(f7): + pass + class f9(f8): + pass + class f10(f9): + nargs = 1 + class f11(f10): + pass + assert f1.nargs == FiniteSet(2) + assert f2.nargs == FiniteSet(2) + assert f3.nargs == FiniteSet(2) + assert f4.nargs == FiniteSet(1, 2) + assert f5.nargs == FiniteSet(1, 2) + assert f6.nargs == FiniteSet(1, 2) + assert f7.nargs == S.Naturals0 + assert f8.nargs == S.Naturals0 + assert f9.nargs == S.Naturals0 + assert f10.nargs == FiniteSet(1) + assert f11.nargs == FiniteSet(1) + +def test_arity(): + f = lambda x, y: 1 + assert arity(f) == 2 + def f(x, y, z=None): + pass + assert arity(f) == (2, 3) + assert arity(lambda *x: x) is None + assert arity(log) == (1, 2) + + +def test_Lambda(): + e = Lambda(x, x**2) + assert e(4) == 16 + assert e(x) == x**2 + assert e(y) == y**2 + + assert Lambda((), 42)() == 42 + assert unchanged(Lambda, (), 42) + assert Lambda((), 42) != Lambda((), 43) + assert Lambda((), f(x))() == f(x) + assert Lambda((), 42).nargs == FiniteSet(0) + + assert unchanged(Lambda, (x,), x**2) + assert Lambda(x, x**2) == Lambda((x,), x**2) + assert Lambda(x, x**2) != Lambda(x, x**2 + 1) + assert Lambda((x, y), x**y) != Lambda((y, x), y**x) + assert Lambda((x, y), x**y) != Lambda((x, y), y**x) + + assert Lambda((x, y), x**y)(x, y) == x**y + assert Lambda((x, y), x**y)(3, 3) == 3**3 + assert Lambda((x, y), x**y)(x, 3) == x**3 + assert Lambda((x, y), x**y)(3, y) == 3**y + assert Lambda(x, f(x))(x) == f(x) + assert Lambda(x, x**2)(e(x)) == x**4 + assert e(e(x)) == x**4 + + x1, x2 = (Indexed('x', i) for i in (1, 2)) + assert Lambda((x1, x2), x1 + x2)(x, y) == x + y + + assert Lambda((x, y), x + y).nargs == FiniteSet(2) + + p = x, y, z, t + assert Lambda(p, t*(x + y + z))(*p) == t * (x + y + z) + + eq = Lambda(x, 2*x) + Lambda(y, 2*y) + assert eq != 2*Lambda(x, 2*x) + assert eq.as_dummy() == 2*Lambda(x, 2*x).as_dummy() + assert Lambda(x, 2*x) not in [ Lambda(x, x) ] + raises(BadSignatureError, lambda: Lambda(1, x)) + assert Lambda(x, 1)(1) is S.One + + raises(BadSignatureError, lambda: Lambda((x, x), x + 2)) + raises(BadSignatureError, lambda: Lambda(((x, x), y), x)) + raises(BadSignatureError, lambda: Lambda(((y, x), x), x)) + raises(BadSignatureError, lambda: Lambda(((y, 1), 2), x)) + + with warns_deprecated_sympy(): + assert Lambda([x, y], x+y) == Lambda((x, y), x+y) + + flam = Lambda(((x, y),), x + y) + assert flam((2, 3)) == 5 + flam = Lambda(((x, y), z), x + y + z) + assert flam((2, 3), 1) == 6 + flam = Lambda((((x, y), z),), x + y + z) + assert flam(((2, 3), 1)) == 6 + raises(BadArgumentsError, lambda: flam(1, 2, 3)) + flam = Lambda( (x,), (x, x)) + assert flam(1,) == (1, 1) + assert flam((1,)) == ((1,), (1,)) + flam = Lambda( ((x,),), (x, x)) + raises(BadArgumentsError, lambda: flam(1)) + assert flam((1,)) == (1, 1) + + # Previously TypeError was raised so this is potentially needed for + # backwards compatibility. + assert issubclass(BadSignatureError, TypeError) + assert issubclass(BadArgumentsError, TypeError) + + # These are tested to see they don't raise: + hash(Lambda(x, 2*x)) + hash(Lambda(x, x)) # IdentityFunction subclass + + +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 == {y} + assert Lambda((), 42).free_symbols == set() + assert Lambda((), x*y).free_symbols == {x,y} + + +def test_functionclas_symbols(): + assert f.free_symbols == set() + + +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((), 42)(x)) + + +def test_Lambda_equality(): + assert Lambda((x, y), 2*x) == Lambda((x, y), 2*x) + # these, of course, should never be equal + assert Lambda(x, 2*x) != Lambda((x, y), 2*x) + assert Lambda(x, 2*x) != 2*x + # But it is tempting to want expressions that differ only + # in bound symbols to compare the same. But this is not what + # Python's `==` is intended to do; two objects that compare + # as equal means that they are indistibguishable and cache to the + # same value. We wouldn't want to expression that are + # mathematically the same but written in different variables to be + # interchanged else what is the point of allowing for different + # variable names? + assert Lambda(x, 2*x) != Lambda(y, 2*y) + + +def test_Subs(): + assert Subs(1, (), ()) is S.One + # check null subs influence on hashing + assert Subs(x, y, z) != Subs(x, y, 1) + # neutral subs works + assert Subs(x, x, 1).subs(x, y).has(y) + # self mapping var/point + assert Subs(Derivative(f(x), (x, 2)), x, x).doit() == f(x).diff(x, x) + assert Subs(x, x, 0).has(x) # it's a structural answer + assert not Subs(x, x, 0).free_symbols + assert Subs(Subs(x + y, x, 2), y, 1) == Subs(x + y, (x, y), (2, 1)) + assert Subs(x, (x,), (0,)) == Subs(x, x, 0) + assert Subs(x, x, 0) == Subs(y, y, 0) + assert Subs(x, x, 0).subs(x, 1) == Subs(x, x, 0) + 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)) + assert Subs(x, y, 2).subs(x, y).doit() == 2 + assert Subs(f(x, y), (x, y, z), (0, 1, 1)) != \ + 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))) + raises(ValueError, lambda: Subs(f(x, y), (x, x, y), (0, 0, 1))) + + assert len(Subs(f(x, y), (x, y), (0, 1)).variables) == 2 + assert Subs(f(x, y), (x, y), (0, 1)).point == Tuple(0, 1) + + assert Subs(f(x), x, 0) == Subs(f(y), y, 0) + assert Subs(f(x, y), (x, y), (0, 1)) == Subs(f(x, y), (y, x), (1, 0)) + assert Subs(f(x)*y, (x, y), (0, 1)) == Subs(f(y)*x, (y, x), (0, 1)) + assert Subs(f(x)*y, (x, y), (1, 1)) == Subs(f(y)*x, (x, y), (1, 1)) + + assert Subs(f(x), x, 0).subs(x, 1).doit() == f(0) + assert Subs(f(x), x, y).subs(y, 0) == Subs(f(x), x, 0) + assert Subs(y*f(x), x, y).subs(y, 2) == Subs(2*f(x), x, 2) + assert (2 * Subs(f(x), x, 0)).subs(Subs(f(x), x, 0), y) == 2*y + + assert Subs(f(x), x, 0).free_symbols == set() + assert Subs(f(x, y), x, z).free_symbols == {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(y*f(x, y).diff(x), (x, y), (0, 2)).doit() == \ + 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) + assert e.diff(y) == e.doit().diff(y) == y**2*Derivative(f(y), y) + 2*y*f(y) + + assert Subs(f(x), x, 0) + Subs(f(x), x, 0) == 2*Subs(f(x), x, 0) + e1 = Subs(z*f(x), x, 1) + 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)) == Derivative(f(g(x)), g(x)) + assert Derivative(f(x), x).subs(x, x + y) == Subs(Derivative(f(x), x), + x, x + y) + 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) + + assert f(x).diff(x).subs(x, 0).subs(x, y) == f(x).diff(x).subs(x, 0) + assert (x*f(x).diff(x).subs(x, 0)).subs(x, y) == y*f(x).diff(x).subs(x, 0) + assert Subs(Derivative(g(x)**2, g(x), x), g(x), exp(x) + ).doit() == 2*exp(x) + assert Subs(Derivative(g(x)**2, g(x), x), g(x), exp(x) + ).doit(deep=False) == 2*Derivative(exp(x), x) + assert Derivative(f(x, g(x)), x).doit() == Derivative( + f(x, g(x)), g(x))*Derivative(g(x), x) + Subs(Derivative( + f(y, g(x)), y), y, x) + +def test_doitdoit(): + done = Derivative(f(x, g(x)), x, g(x)).doit() + assert done == done.doit() + + +@XFAIL +def test_Subs2(): + # this reflects a limitation of subs(), probably won't fix + assert Subs(f(x), x**2, x).doit() == f(sqrt(x)) + + +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)**11, modulus=11) == x**11 + y**11 + + +def test_function_comparable(): + assert sin(x).is_comparable is False + assert cos(x).is_comparable is False + + assert sin(Float('0.1')).is_comparable is True + assert cos(Float('0.1')).is_comparable is 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 + + +def test_function_comparable_infinities(): + 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 require derivatives evaluated at a point (issue 4719) to work. + # See issue 4624 + assert f(2*x).diff(x) == 2*Subs(Derivative(f(x), x), x, 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), x, 2*x) + + assert f(2 + x).diff(x) == Subs(Derivative(f(x), x), x, x + 2) + assert f(2 + 3*x).diff(x) == 3*Subs( + Derivative(f(x), x), x, 3*x + 2) + assert f(3*sin(x)).diff(x) == 3*cos(x)*Subs( + Derivative(f(x), x), x, 3*sin(x)) + + # See issue 8510 + assert f(x, x + z).diff(x) == ( + Subs(Derivative(f(y, x + z), y), y, x) + + Subs(Derivative(f(x, y), y), y, x + z)) + assert f(x, x**2).diff(x) == ( + 2*x*Subs(Derivative(f(x, y), y), y, x**2) + + Subs(Derivative(f(y, x**2), y), y, x)) + # but Subs is not always necessary + assert f(x, g(y)).diff(g(y)) == Derivative(f(x, g(y)), g(y)) + + +def test_deriv2(): + assert (x**3).diff(x) == 3*x**2 + assert (x**3).diff(x, evaluate=False) != 3*x**2 + assert (x**3).diff(x, evaluate=False) == Derivative(x**3, x) + + assert diff(x**3, x) == 3*x**2 + 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 4534 + assert f(x, y).diff(x, y) - f(x, y).diff(y, x) == 0 + assert Derivative(f(x, y), x, y).args[1:] == ((x, 1), (y, 1)) + assert Derivative(f(x, y), y, x).args[1:] == ((y, 1), (x, 1)) + 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 + 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(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) + + +@_both_exp_pow +def test_function_non_commutative(): + x = Symbol('x', 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 + assert f(x).is_complex is False + assert sin(x).is_complex is False + assert exp(x).is_complex is False + assert log(x).is_complex is False + + +def test_function_complex(): + x = Symbol('x', complex=True) + xzf = Symbol('x', complex=True, zero=False) + assert f(x).is_commutative is True + assert sin(x).is_commutative is True + assert exp(x).is_commutative is True + assert log(x).is_commutative is True + assert f(x).is_complex is None + assert sin(x).is_complex is True + assert exp(x).is_complex is True + assert log(x).is_complex is None + assert log(xzf).is_complex is True + + +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)*sqrt(x**2) + 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)) + assert acos(1 - x)._eval_nseries(x, 2, None) == sqrt(2)*sqrt(x) + sqrt(2)*x**(S(3)/2)/12 + O(x**2) + assert acos(1 + x)._eval_nseries(x, 2, None) == sqrt(2)*sqrt(-x) + sqrt(2)*(-x)**(S(3)/2)/12 + O(x**2) + 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 6725: + assert expint(Rational(3, 2), -x)._eval_nseries(x, 5, None) == \ + 2 - 2*x - x**2/3 - x**3/15 - x**4/84 - 2*I*sqrt(pi)*sqrt(x) + O(x**5) + assert sin(sqrt(x))._eval_nseries(x, 3, None) == \ + sqrt(x) - x**Rational(3, 2)/6 + x**Rational(5, 2)/120 + O(x**3) + + # issue 19065: + s1 = f(x,y).series(y, n=2) + assert {i.name for i in s1.atoms(Symbol)} == {'x', 'xi', 'y'} + xi = Symbol('xi') + s2 = f(xi, y).series(y, n=2) + assert {i.name for i in s2.atoms(Symbol)} == {'xi', 'xi0', 'y'} + +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)) + + +def test_evalf_default(): + from sympy.functions.special.gamma_functions import polygamma + assert type(sin(4.0)) == Float + 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 + + +def test_issue_5399(): + 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 + 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 < len(a)) and + all(a[i + 1].is_Symbol + for i in n_at if i + 1 < len(a))) + eq = x**10*y**8 + for a in subsets(args): + for v in variations(a, len(a)): + if ok(v): + eq.diff(*v) # does not raise + else: + raises(ValueError, lambda: eq.diff(*v)) + + +def test_derivative_numerically(): + z0 = x._random() + assert abs(Derivative(sin(x), x).doit_numerically(z0) - cos(z0)) < 1e-15 + + +def test_fdiff_argument_index_error(): + from sympy.core.function import ArgumentIndexError + + class myfunc(Function): + nargs = 1 # define since there is no eval routine + + def fdiff(self, idx): + raise ArgumentIndexError + mf = myfunc(x) + assert mf.diff(x) == Derivative(mf, x) + raises(TypeError, lambda: myfunc(x, x)) + + +def test_deriv_wrt_function(): + x = f(t) + xd = diff(x, t) + xdd = diff(xd, t) + y = g(t) + yd = diff(y, t) + + assert diff(x, t) == xd + assert diff(2 * x + 4, t) == 2 * xd + assert diff(2 * x + 4 + y, t) == 2 * xd + yd + assert diff(2 * x + 4 + y * x, t) == 2 * xd + x * yd + xd * y + assert diff(2 * x + 4 + y * x, x) == 2 + y + assert (diff(4 * x**2 + 3 * x + x * y, t) == 3 * xd + x * yd + xd * y + + 8 * x * xd) + assert (diff(4 * x**2 + 3 * xd + x * y, t) == 3 * xdd + x * yd + xd * y + + 8 * x * xd) + assert diff(4 * x**2 + 3 * xd + x * y, xd) == 3 + assert diff(4 * x**2 + 3 * xd + x * y, xdd) == 0 + assert diff(sin(x), t) == xd * cos(x) + assert diff(exp(x), t) == xd * exp(x) + assert diff(sqrt(x), t) == xd / (2 * sqrt(x)) + + +def test_diff_wrt_value(): + assert Expr()._diff_wrt is False + assert x._diff_wrt is True + assert f(x)._diff_wrt is True + assert Derivative(f(x), x)._diff_wrt is True + assert Derivative(x**2, x)._diff_wrt is False + + +def test_diff_wrt(): + fx = f(x) + dfx = diff(f(x), x) + ddfx = diff(f(x), x, x) + + assert diff(sin(fx) + fx**2, fx) == cos(fx) + 2*fx + assert diff(sin(dfx) + dfx**2, dfx) == cos(dfx) + 2*dfx + assert diff(sin(ddfx) + ddfx**2, ddfx) == cos(ddfx) + 2*ddfx + assert diff(fx**2, dfx) == 0 + assert diff(fx**2, ddfx) == 0 + assert diff(dfx**2, fx) == 0 + assert diff(dfx**2, ddfx) == 0 + assert diff(ddfx**2, dfx) == 0 + + assert diff(fx*dfx*ddfx, fx) == dfx*ddfx + assert diff(fx*dfx*ddfx, dfx) == fx*ddfx + assert diff(fx*dfx*ddfx, ddfx) == fx*dfx + + assert diff(f(x), x).diff(f(x)) == 0 + assert (sin(f(x)) - cos(diff(f(x), x))).diff(f(x)) == cos(f(x)) + + assert diff(sin(fx), fx, x) == diff(sin(fx), x, fx) + + # Chain rule cases + assert f(g(x)).diff(x) == \ + Derivative(g(x), x)*Derivative(f(g(x)), g(x)) + assert diff(f(g(x), h(y)), x) == \ + Derivative(g(x), x)*Derivative(f(g(x), h(y)), g(x)) + assert diff(f(g(x), h(x)), x) == ( + Derivative(f(g(x), h(x)), g(x))*Derivative(g(x), x) + + Derivative(f(g(x), h(x)), h(x))*Derivative(h(x), x)) + assert f( + sin(x)).diff(x) == cos(x)*Subs(Derivative(f(x), x), x, sin(x)) + + assert diff(f(g(x)), g(x)) == Derivative(f(g(x)), g(x)) + + +def test_diff_wrt_func_subs(): + assert f(g(x)).diff(x).subs(g, Lambda(x, 2*x)).doit() == f(2*x).diff(x) + + +def test_subs_in_derivative(): + expr = sin(x*exp(y)) + u = Function('u') + v = Function('v') + assert Derivative(expr, y).subs(expr, y) == Derivative(y, y) + assert Derivative(expr, y).subs(y, x).doit() == \ + Derivative(expr, y).doit().subs(y, x) + assert Derivative(f(x, y), y).subs(y, x) == Subs(Derivative(f(x, y), y), y, x) + assert Derivative(f(x, y), y).subs(x, y) == Subs(Derivative(f(x, y), y), x, y) + assert Derivative(f(x, y), y).subs(y, g(x, y)) == Subs(Derivative(f(x, y), y), y, g(x, y)).doit() + assert Derivative(f(x, y), y).subs(x, g(x, y)) == Subs(Derivative(f(x, y), y), x, g(x, y)) + assert Derivative(f(x, y), g(y)).subs(x, g(x, y)) == Derivative(f(g(x, y), y), g(y)) + assert Derivative(f(u(x), h(y)), h(y)).subs(h(y), g(x, y)) == \ + Subs(Derivative(f(u(x), h(y)), h(y)), h(y), g(x, y)).doit() + assert Derivative(f(x, y), y).subs(y, z) == Derivative(f(x, z), z) + assert Derivative(f(x, y), y).subs(y, g(y)) == Derivative(f(x, g(y)), g(y)) + assert Derivative(f(g(x), h(y)), h(y)).subs(h(y), u(y)) == \ + Derivative(f(g(x), u(y)), u(y)) + assert Derivative(f(x, f(x, x)), f(x, x)).subs( + f, Lambda((x, y), x + y)) == Subs( + Derivative(z + x, z), z, 2*x) + assert Subs(Derivative(f(f(x)), x), f, cos).doit() == sin(x)*sin(cos(x)) + assert Subs(Derivative(f(f(x)), f(x)), f, cos).doit() == -sin(cos(x)) + # Issue 13791. No comparison (it's a long formula) but this used to raise an exception. + assert isinstance(v(x, y, u(x, y)).diff(y).diff(x).diff(y), Expr) + # This is also related to issues 13791 and 13795; issue 15190 + F = Lambda((x, y), exp(2*x + 3*y)) + abstract = f(x, f(x, x)).diff(x, 2) + concrete = F(x, F(x, x)).diff(x, 2) + assert (abstract.subs(f, F).doit() - concrete).simplify() == 0 + # don't introduce a new symbol if not necessary + assert x in f(x).diff(x).subs(x, 0).atoms() + # case (4) + assert Derivative(f(x,f(x,y)), x, y).subs(x, g(y) + ) == Subs(Derivative(f(x, f(x, y)), x, y), x, g(y)) + + assert Derivative(f(x, x), x).subs(x, 0 + ) == Subs(Derivative(f(x, x), x), x, 0) + # issue 15194 + assert Derivative(f(y, g(x)), (x, z)).subs(z, x + ) == Derivative(f(y, g(x)), (x, x)) + + df = f(x).diff(x) + assert df.subs(df, 1) is S.One + assert df.diff(df) is S.One + dxy = Derivative(f(x, y), x, y) + dyx = Derivative(f(x, y), y, x) + assert dxy.subs(Derivative(f(x, y), y, x), 1) is S.One + assert dxy.diff(dyx) is S.One + assert Derivative(f(x, y), x, 2, y, 3).subs( + dyx, g(x, y)) == Derivative(g(x, y), x, 1, y, 2) + assert Derivative(f(x, x - y), y).subs(x, x + y) == Subs( + Derivative(f(x, x - y), y), x, x + y) + + +def test_diff_wrt_not_allowed(): + # issue 7027 included + for wrt in ( + cos(x), re(x), x**2, x*y, 1 + x, + Derivative(cos(x), x), Derivative(f(f(x)), x)): + raises(ValueError, lambda: diff(f(x), wrt)) + # if we don't differentiate wrt then don't raise error + assert diff(exp(x*y), x*y, 0) == exp(x*y) + + +def test_diff_wrt_intlike(): + class Two: + def __int__(self): + return 2 + + assert cos(x).diff(x, Two()) == -cos(x) + + +def test_klein_gordon_lagrangian(): + m = Symbol('m') + phi = f(x, t) + + L = -(diff(phi, t)**2 - diff(phi, x)**2 - m**2*phi**2)/2 + eqna = Eq( + diff(L, phi) - diff(L, diff(phi, x), x) - diff(L, diff(phi, t), t), 0) + eqnb = Eq(diff(phi, t, t) - diff(phi, x, x) + m**2*phi, 0) + assert eqna == eqnb + + +def test_sho_lagrangian(): + m = Symbol('m') + k = Symbol('k') + x = f(t) + + L = m*diff(x, t)**2/2 - k*x**2/2 + eqna = Eq(diff(L, x), diff(L, diff(x, t), t)) + eqnb = Eq(-k*x, m*diff(x, t, t)) + assert eqna == eqnb + + assert diff(L, x, t) == diff(L, t, x) + assert diff(L, diff(x, t), t) == m*diff(x, t, 2) + assert diff(L, t, diff(x, t)) == -k*x + m*diff(x, t, 2) + + +def test_straight_line(): + F = f(x) + Fd = F.diff(x) + L = sqrt(1 + Fd**2) + assert diff(L, F) == 0 + assert diff(L, Fd) == Fd/sqrt(1 + Fd**2) + + +def test_sort_variable(): + vsort = Derivative._sort_variable_count + def vsort0(*v, reverse=False): + return [i[0] for i in vsort([(i, 0) for i in ( + reversed(v) if reverse else v)])] + + for R in range(2): + assert vsort0(y, x, reverse=R) == [x, y] + assert vsort0(f(x), x, reverse=R) == [x, f(x)] + assert vsort0(f(y), f(x), reverse=R) == [f(x), f(y)] + assert vsort0(g(x), f(y), reverse=R) == [f(y), g(x)] + assert vsort0(f(x, y), f(x), reverse=R) == [f(x), f(x, y)] + fx = f(x).diff(x) + assert vsort0(fx, y, reverse=R) == [y, fx] + fy = f(y).diff(y) + assert vsort0(fy, fx, reverse=R) == [fx, fy] + fxx = fx.diff(x) + assert vsort0(fxx, fx, reverse=R) == [fx, fxx] + assert vsort0(Basic(x), f(x), reverse=R) == [f(x), Basic(x)] + assert vsort0(Basic(y), Basic(x), reverse=R) == [Basic(x), Basic(y)] + assert vsort0(Basic(y, z), Basic(x), reverse=R) == [ + Basic(x), Basic(y, z)] + assert vsort0(fx, x, reverse=R) == [ + x, fx] if R else [fx, x] + assert vsort0(Basic(x), x, reverse=R) == [ + x, Basic(x)] if R else [Basic(x), x] + assert vsort0(Basic(f(x)), f(x), reverse=R) == [ + f(x), Basic(f(x))] if R else [Basic(f(x)), f(x)] + assert vsort0(Basic(x, z), Basic(x), reverse=R) == [ + Basic(x), Basic(x, z)] if R else [Basic(x, z), Basic(x)] + assert vsort([]) == [] + assert _aresame(vsort([(x, 1)]), [Tuple(x, 1)]) + assert vsort([(x, y), (x, z)]) == [(x, y + z)] + assert vsort([(y, 1), (x, 1 + y)]) == [(x, 1 + y), (y, 1)] + # coverage complete; legacy tests below + assert vsort([(x, 3), (y, 2), (z, 1)]) == [(x, 3), (y, 2), (z, 1)] + assert vsort([(h(x), 1), (g(x), 1), (f(x), 1)]) == [ + (f(x), 1), (g(x), 1), (h(x), 1)] + assert vsort([(z, 1), (y, 2), (x, 3), (h(x), 1), (g(x), 1), + (f(x), 1)]) == [(x, 3), (y, 2), (z, 1), (f(x), 1), (g(x), 1), + (h(x), 1)] + assert vsort([(x, 1), (f(x), 1), (y, 1), (f(y), 1)]) == [(x, 1), + (y, 1), (f(x), 1), (f(y), 1)] + assert vsort([(y, 1), (x, 2), (g(x), 1), (f(x), 1), (z, 1), + (h(x), 1), (y, 2), (x, 1)]) == [(x, 3), (y, 3), (z, 1), + (f(x), 1), (g(x), 1), (h(x), 1)] + assert vsort([(z, 1), (y, 1), (f(x), 1), (x, 1), (f(x), 1), + (g(x), 1)]) == [(x, 1), (y, 1), (z, 1), (f(x), 2), (g(x), 1)] + assert vsort([(z, 1), (y, 2), (f(x), 1), (x, 2), (f(x), 2), + (g(x), 1), (z, 2), (z, 1), (y, 1), (x, 1)]) == [(x, 3), (y, 3), + (z, 4), (f(x), 3), (g(x), 1)] + assert vsort(((y, 2), (x, 1), (y, 1), (x, 1))) == [(x, 2), (y, 3)] + assert isinstance(vsort([(x, 3), (y, 2), (z, 1)])[0], Tuple) + assert vsort([(x, 1), (f(x), 1), (x, 1)]) == [(x, 2), (f(x), 1)] + assert vsort([(y, 2), (x, 3), (z, 1)]) == [(x, 3), (y, 2), (z, 1)] + assert vsort([(h(y), 1), (g(x), 1), (f(x), 1)]) == [ + (f(x), 1), (g(x), 1), (h(y), 1)] + assert vsort([(x, 1), (y, 1), (x, 1)]) == [(x, 2), (y, 1)] + assert vsort([(f(x), 1), (f(y), 1), (f(x), 1)]) == [ + (f(x), 2), (f(y), 1)] + dfx = f(x).diff(x) + self = [(dfx, 1), (x, 1)] + assert vsort(self) == self + assert vsort([ + (dfx, 1), (y, 1), (f(x), 1), (x, 1), (f(y), 1), (x, 1)]) == [ + (y, 1), (f(x), 1), (f(y), 1), (dfx, 1), (x, 2)] + dfy = f(y).diff(y) + assert vsort([(dfy, 1), (dfx, 1)]) == [(dfx, 1), (dfy, 1)] + d2fx = dfx.diff(x) + assert vsort([(d2fx, 1), (dfx, 1)]) == [(dfx, 1), (d2fx, 1)] + + +def test_multiple_derivative(): + # Issue #15007 + assert f(x, y).diff(y, y, x, y, x + ) == Derivative(f(x, y), (x, 2), (y, 3)) + + +def test_unhandled(): + class MyExpr(Expr): + def _eval_derivative(self, s): + if not s.name.startswith('xi'): + return self + else: + return None + + eq = MyExpr(f(x), y, z) + assert diff(eq, x, y, f(x), z) == Derivative(eq, f(x)) + assert diff(eq, f(x), x) == Derivative(eq, f(x)) + assert f(x, y).diff(x,(y, z)) == Derivative(f(x, y), x, (y, z)) + assert f(x, y).diff(x,(y, 0)) == Derivative(f(x, y), x) + + +def test_nfloat(): + from sympy.core.basic import _aresame + from sympy.polys.rootoftools import rootof + + x = Symbol("x") + eq = x**Rational(4, 3) + 4*x**(S.One/3)/3 + assert _aresame(nfloat(eq), x**Rational(4, 3) + (4.0/3)*x**(S.One/3)) + assert _aresame(nfloat(eq, exponent=True), x**(4.0/3) + (4.0/3)*x**(1.0/3)) + eq = x**Rational(4, 3) + 4*x**(x/3)/3 + assert _aresame(nfloat(eq), x**Rational(4, 3) + (4.0/3)*x**(x/3)) + big = 12345678901234567890 + # specify precision to match value used in nfloat + Float_big = Float(big, 15) + assert _aresame(nfloat(big), Float_big) + assert _aresame(nfloat(big*x), Float_big*x) + assert _aresame(nfloat(x**big, exponent=True), x**Float_big) + assert nfloat(cos(x + sqrt(2))) == cos(x + nfloat(sqrt(2))) + + # issue 6342 + f = S('x*lamda + lamda**3*(x/2 + 1/2) + lamda**2 + 1/4') + assert not any(a.free_symbols for a in solveset(f.subs(x, -0.139))) + + # issue 6632 + assert nfloat(-100000*sqrt(2500000001) + 5000000001) == \ + 9.99999999800000e-11 + + # issue 7122 + eq = cos(3*x**4 + y)*rootof(x**5 + 3*x**3 + 1, 0) + assert str(nfloat(eq, exponent=False, n=1)) == '-0.7*cos(3.0*x**4 + y)' + + # issue 10933 + for ti in (dict, Dict): + d = ti({S.Half: S.Half}) + n = nfloat(d) + assert isinstance(n, ti) + assert _aresame(list(n.items()).pop(), (S.Half, Float(.5))) + for ti in (dict, Dict): + d = ti({S.Half: S.Half}) + n = nfloat(d, dkeys=True) + assert isinstance(n, ti) + assert _aresame(list(n.items()).pop(), (Float(.5), Float(.5))) + d = [S.Half] + n = nfloat(d) + assert type(n) is list + assert _aresame(n[0], Float(.5)) + assert _aresame(nfloat(Eq(x, S.Half)).rhs, Float(.5)) + assert _aresame(nfloat(S(True)), S(True)) + assert _aresame(nfloat(Tuple(S.Half))[0], Float(.5)) + assert nfloat(Eq((3 - I)**2/2 + I, 0)) == S.false + # pass along kwargs + assert nfloat([{S.Half: x}], dkeys=True) == [{Float(0.5): x}] + + # Issue 17706 + A = MutableMatrix([[1, 2], [3, 4]]) + B = MutableMatrix( + [[Float('1.0', precision=53), Float('2.0', precision=53)], + [Float('3.0', precision=53), Float('4.0', precision=53)]]) + assert _aresame(nfloat(A), B) + A = ImmutableMatrix([[1, 2], [3, 4]]) + B = ImmutableMatrix( + [[Float('1.0', precision=53), Float('2.0', precision=53)], + [Float('3.0', precision=53), Float('4.0', precision=53)]]) + assert _aresame(nfloat(A), B) + + # issue 22524 + f = Function('f') + assert not nfloat(f(2)).atoms(Float) + + +def test_issue_7068(): + from sympy.abc import a, b + f = Function('f') + y1 = Dummy('y') + y2 = Dummy('y') + func1 = f(a + y1 * b) + func2 = f(a + y2 * b) + func1_y = func1.diff(y1) + func2_y = func2.diff(y2) + assert func1_y != func2_y + z1 = Subs(f(a), a, y1) + z2 = Subs(f(a), a, y2) + assert z1 != z2 + + +def test_issue_7231(): + from sympy.abc import a + ans1 = f(x).series(x, a) + res = (f(a) + (-a + x)*Subs(Derivative(f(y), y), y, a) + + (-a + x)**2*Subs(Derivative(f(y), y, y), y, a)/2 + + (-a + x)**3*Subs(Derivative(f(y), y, y, y), + y, a)/6 + + (-a + x)**4*Subs(Derivative(f(y), y, y, y, y), + y, a)/24 + + (-a + x)**5*Subs(Derivative(f(y), y, y, y, y, y), + y, a)/120 + O((-a + x)**6, (x, a))) + assert res == ans1 + ans2 = f(x).series(x, a) + assert res == ans2 + + +def test_issue_7687(): + from sympy.core.function import Function + from sympy.abc import x + f = Function('f')(x) + ff = Function('f')(x) + match_with_cache = ff.matches(f) + assert isinstance(f, type(ff)) + clear_cache() + ff = Function('f')(x) + assert isinstance(f, type(ff)) + assert match_with_cache == ff.matches(f) + + +def test_issue_7688(): + from sympy.core.function import Function, UndefinedFunction + + f = Function('f') # actually an UndefinedFunction + clear_cache() + class A(UndefinedFunction): + pass + a = A('f') + assert isinstance(a, type(f)) + + +def test_mexpand(): + from sympy.abc import x + assert _mexpand(None) is None + assert _mexpand(1) is S.One + assert _mexpand(x*(x + 1)**2) == (x*(x + 1)**2).expand() + + +def test_issue_8469(): + # This should not take forever to run + N = 40 + def g(w, theta): + return 1/(1+exp(w-theta)) + + ws = symbols(['w%i'%i for i in range(N)]) + import functools + expr = functools.reduce(g, ws) + assert isinstance(expr, Pow) + + +def test_issue_12996(): + # foo=True imitates the sort of arguments that Derivative can get + # from Integral when it passes doit to the expression + assert Derivative(im(x), x).doit(foo=True) == Derivative(im(x), x) + + +def test_should_evalf(): + # This should not take forever to run (see #8506) + assert isinstance(sin((1.0 + 1.0*I)**10000 + 1), sin) + + +def test_Derivative_as_finite_difference(): + # Central 1st derivative at gridpoint + x, h = symbols('x h', real=True) + dfdx = f(x).diff(x) + assert (dfdx.as_finite_difference([x-2, x-1, x, x+1, x+2]) - + (S.One/12*(f(x-2)-f(x+2)) + Rational(2, 3)*(f(x+1)-f(x-1)))).simplify() == 0 + + # Central 1st derivative "half-way" + assert (dfdx.as_finite_difference() - + (f(x + S.Half)-f(x - S.Half))).simplify() == 0 + assert (dfdx.as_finite_difference(h) - + (f(x + h/S(2))-f(x - h/S(2)))/h).simplify() == 0 + assert (dfdx.as_finite_difference([x - 3*h, x-h, x+h, x + 3*h]) - + (S(9)/(8*2*h)*(f(x+h) - f(x-h)) + + S.One/(24*2*h)*(f(x - 3*h) - f(x + 3*h)))).simplify() == 0 + + # One sided 1st derivative at gridpoint + assert (dfdx.as_finite_difference([0, 1, 2], 0) - + (Rational(-3, 2)*f(0) + 2*f(1) - f(2)/2)).simplify() == 0 + assert (dfdx.as_finite_difference([x, x+h], x) - + (f(x+h) - f(x))/h).simplify() == 0 + assert (dfdx.as_finite_difference([x-h, x, x+h], x-h) - + (-S(3)/(2*h)*f(x-h) + 2/h*f(x) - + S.One/(2*h)*f(x+h))).simplify() == 0 + + # One sided 1st derivative "half-way" + assert (dfdx.as_finite_difference([x-h, x+h, x + 3*h, x + 5*h, x + 7*h]) + - 1/(2*h)*(-S(11)/(12)*f(x-h) + S(17)/(24)*f(x+h) + + Rational(3, 8)*f(x + 3*h) - Rational(5, 24)*f(x + 5*h) + + S.One/24*f(x + 7*h))).simplify() == 0 + + d2fdx2 = f(x).diff(x, 2) + # Central 2nd derivative at gridpoint + assert (d2fdx2.as_finite_difference([x-h, x, x+h]) - + h**-2 * (f(x-h) + f(x+h) - 2*f(x))).simplify() == 0 + + assert (d2fdx2.as_finite_difference([x - 2*h, x-h, x, x+h, x + 2*h]) - + h**-2 * (Rational(-1, 12)*(f(x - 2*h) + f(x + 2*h)) + + Rational(4, 3)*(f(x+h) + f(x-h)) - Rational(5, 2)*f(x))).simplify() == 0 + + # Central 2nd derivative "half-way" + assert (d2fdx2.as_finite_difference([x - 3*h, x-h, x+h, x + 3*h]) - + (2*h)**-2 * (S.Half*(f(x - 3*h) + f(x + 3*h)) - + S.Half*(f(x+h) + f(x-h)))).simplify() == 0 + + # One sided 2nd derivative at gridpoint + assert (d2fdx2.as_finite_difference([x, x+h, x + 2*h, x + 3*h]) - + h**-2 * (2*f(x) - 5*f(x+h) + + 4*f(x+2*h) - f(x+3*h))).simplify() == 0 + + # One sided 2nd derivative at "half-way" + assert (d2fdx2.as_finite_difference([x-h, x+h, x + 3*h, x + 5*h]) - + (2*h)**-2 * (Rational(3, 2)*f(x-h) - Rational(7, 2)*f(x+h) + Rational(5, 2)*f(x + 3*h) - + S.Half*f(x + 5*h))).simplify() == 0 + + d3fdx3 = f(x).diff(x, 3) + # Central 3rd derivative at gridpoint + assert (d3fdx3.as_finite_difference() - + (-f(x - Rational(3, 2)) + 3*f(x - S.Half) - + 3*f(x + S.Half) + f(x + Rational(3, 2)))).simplify() == 0 + + assert (d3fdx3.as_finite_difference( + [x - 3*h, x - 2*h, x-h, x, x+h, x + 2*h, x + 3*h]) - + h**-3 * (S.One/8*(f(x - 3*h) - f(x + 3*h)) - f(x - 2*h) + + f(x + 2*h) + Rational(13, 8)*(f(x-h) - f(x+h)))).simplify() == 0 + + # Central 3rd derivative at "half-way" + assert (d3fdx3.as_finite_difference([x - 3*h, x-h, x+h, x + 3*h]) - + (2*h)**-3 * (f(x + 3*h)-f(x - 3*h) + + 3*(f(x-h)-f(x+h)))).simplify() == 0 + + # One sided 3rd derivative at gridpoint + assert (d3fdx3.as_finite_difference([x, x+h, x + 2*h, x + 3*h]) - + h**-3 * (f(x + 3*h)-f(x) + 3*(f(x+h)-f(x + 2*h)))).simplify() == 0 + + # One sided 3rd derivative at "half-way" + assert (d3fdx3.as_finite_difference([x-h, x+h, x + 3*h, x + 5*h]) - + (2*h)**-3 * (f(x + 5*h)-f(x-h) + + 3*(f(x+h)-f(x + 3*h)))).simplify() == 0 + + # issue 11007 + y = Symbol('y', real=True) + d2fdxdy = f(x, y).diff(x, y) + + ref0 = Derivative(f(x + S.Half, y), y) - Derivative(f(x - S.Half, y), y) + assert (d2fdxdy.as_finite_difference(wrt=x) - ref0).simplify() == 0 + + half = S.Half + xm, xp, ym, yp = x-half, x+half, y-half, y+half + ref2 = f(xm, ym) + f(xp, yp) - f(xp, ym) - f(xm, yp) + assert (d2fdxdy.as_finite_difference() - ref2).simplify() == 0 + + +def test_issue_11159(): + # Tests Application._eval_subs + with _exp_is_pow(False): + expr1 = E + expr0 = expr1 * expr1 + expr1 = expr0.subs(expr1,expr0) + assert expr0 == expr1 + with _exp_is_pow(True): + expr1 = E + expr0 = expr1 * expr1 + expr2 = expr0.subs(expr1, expr0) + assert expr2 == E ** 4 + + +def test_issue_12005(): + e1 = Subs(Derivative(f(x), x), x, x) + assert e1.diff(x) == Derivative(f(x), x, x) + e2 = Subs(Derivative(f(x), x), x, x**2 + 1) + assert e2.diff(x) == 2*x*Subs(Derivative(f(x), x, x), x, x**2 + 1) + e3 = Subs(Derivative(f(x) + y**2 - y, y), y, y**2) + assert e3.diff(y) == 4*y + e4 = Subs(Derivative(f(x + y), y), y, (x**2)) + assert e4.diff(y) is S.Zero + e5 = Subs(Derivative(f(x), x), (y, z), (y, z)) + assert e5.diff(x) == Derivative(f(x), x, x) + assert f(g(x)).diff(g(x), g(x)) == Derivative(f(g(x)), g(x), g(x)) + + +def test_issue_13843(): + x = symbols('x') + f = Function('f') + m, n = symbols('m n', integer=True) + assert Derivative(Derivative(f(x), (x, m)), (x, n)) == Derivative(f(x), (x, m + n)) + assert Derivative(Derivative(f(x), (x, m+5)), (x, n+3)) == Derivative(f(x), (x, m + n + 8)) + + assert Derivative(f(x), (x, n)).doit() == Derivative(f(x), (x, n)) + + +def test_order_could_be_zero(): + x, y = symbols('x, y') + n = symbols('n', integer=True, nonnegative=True) + m = symbols('m', integer=True, positive=True) + assert diff(y, (x, n)) == Piecewise((y, Eq(n, 0)), (0, True)) + assert diff(y, (x, n + 1)) is S.Zero + assert diff(y, (x, m)) is S.Zero + + +def test_undefined_function_eq(): + f = Function('f') + f2 = Function('f') + g = Function('g') + f_real = Function('f', is_real=True) + + # This test may only be meaningful if the cache is turned off + assert f == f2 + assert hash(f) == hash(f2) + assert f == f + + assert f != g + + assert f != f_real + + +def test_function_assumptions(): + x = Symbol('x') + f = Function('f') + f_real = Function('f', real=True) + f_real1 = Function('f', real=1) + f_real_inherit = Function(Symbol('f', real=True)) + + assert f_real == f_real1 # assumptions are sanitized + assert f != f_real + assert f(x) != f_real(x) + + assert f(x).is_real is None + assert f_real(x).is_real is True + assert f_real_inherit(x).is_real is True and f_real_inherit.name == 'f' + + # Can also do it this way, but it won't be equal to f_real because of the + # way UndefinedFunction.__new__ works. Any non-recognized assumptions + # are just added literally as something which is used in the hash + f_real2 = Function('f', is_real=True) + assert f_real2(x).is_real is True + + +def test_undef_fcn_float_issue_6938(): + f = Function('ceil') + assert not f(0.3).is_number + f = Function('sin') + assert not f(0.3).is_number + assert not f(pi).evalf().is_number + x = Symbol('x') + assert not f(x).evalf(subs={x:1.2}).is_number + + +def test_undefined_function_eval(): + # Issue 15170. Make sure UndefinedFunction with eval defined works + # properly. + + fdiff = lambda self, argindex=1: cos(self.args[argindex - 1]) + eval = classmethod(lambda cls, t: None) + _imp_ = classmethod(lambda cls, t: sin(t)) + + temp = Function('temp', fdiff=fdiff, eval=eval, _imp_=_imp_) + + expr = temp(t) + assert sympify(expr) == expr + assert type(sympify(expr)).fdiff.__name__ == "" + assert expr.diff(t) == cos(t) + + +def test_issue_15241(): + F = f(x) + Fx = F.diff(x) + assert (F + x*Fx).diff(x, Fx) == 2 + assert (F + x*Fx).diff(Fx, x) == 1 + assert (x*F + x*Fx*F).diff(F, x) == x*Fx.diff(x) + Fx + 1 + assert (x*F + x*Fx*F).diff(x, F) == x*Fx.diff(x) + Fx + 1 + y = f(x) + G = f(y) + Gy = G.diff(y) + assert (G + y*Gy).diff(y, Gy) == 2 + assert (G + y*Gy).diff(Gy, y) == 1 + assert (y*G + y*Gy*G).diff(G, y) == y*Gy.diff(y) + Gy + 1 + assert (y*G + y*Gy*G).diff(y, G) == y*Gy.diff(y) + Gy + 1 + + +def test_issue_15226(): + assert Subs(Derivative(f(y), x, y), y, g(x)).doit() != 0 + + +def test_issue_7027(): + for wrt in (cos(x), re(x), Derivative(cos(x), x)): + raises(ValueError, lambda: diff(f(x), wrt)) + + +def test_derivative_quick_exit(): + assert f(x).diff(y) == 0 + assert f(x).diff(y, f(x)) == 0 + assert f(x).diff(x, f(y)) == 0 + assert f(f(x)).diff(x, f(x), f(y)) == 0 + assert f(f(x)).diff(x, f(x), y) == 0 + assert f(x).diff(g(x)) == 0 + assert f(x).diff(x, f(x).diff(x)) == 1 + df = f(x).diff(x) + assert f(x).diff(df) == 0 + dg = g(x).diff(x) + assert dg.diff(df).doit() == 0 + + +def test_issue_15084_13166(): + eq = f(x, g(x)) + assert eq.diff((g(x), y)) == Derivative(f(x, g(x)), (g(x), y)) + # issue 13166 + assert eq.diff(x, 2).doit() == ( + (Derivative(f(x, g(x)), (g(x), 2))*Derivative(g(x), x) + + Subs(Derivative(f(x, _xi_2), _xi_2, x), _xi_2, g(x)))*Derivative(g(x), + x) + Derivative(f(x, g(x)), g(x))*Derivative(g(x), (x, 2)) + + Derivative(g(x), x)*Subs(Derivative(f(_xi_1, g(x)), _xi_1, g(x)), + _xi_1, x) + Subs(Derivative(f(_xi_1, g(x)), (_xi_1, 2)), _xi_1, x)) + # issue 6681 + assert diff(f(x, t, g(x, t)), x).doit() == ( + Derivative(f(x, t, g(x, t)), g(x, t))*Derivative(g(x, t), x) + + Subs(Derivative(f(_xi_1, t, g(x, t)), _xi_1), _xi_1, x)) + # make sure the order doesn't matter when using diff + assert eq.diff(x, g(x)) == eq.diff(g(x), x) + + +def test_negative_counts(): + # issue 13873 + raises(ValueError, lambda: sin(x).diff(x, -1)) + + +def test_Derivative__new__(): + raises(TypeError, lambda: f(x).diff((x, 2), 0)) + assert f(x, y).diff([(x, y), 0]) == f(x, y) + assert f(x, y).diff([(x, y), 1]) == NDimArray([ + Derivative(f(x, y), x), Derivative(f(x, y), y)]) + assert f(x,y).diff(y, (x, z), y, x) == Derivative( + f(x, y), (x, z + 1), (y, 2)) + assert Matrix([x]).diff(x, 2) == Matrix([0]) # is_zero exit + + +def test_issue_14719_10150(): + class V(Expr): + _diff_wrt = True + is_scalar = False + assert V().diff(V()) == Derivative(V(), V()) + assert (2*V()).diff(V()) == 2*Derivative(V(), V()) + class X(Expr): + _diff_wrt = True + assert X().diff(X()) == 1 + assert (2*X()).diff(X()) == 2 + + +def test_noncommutative_issue_15131(): + x = Symbol('x', commutative=False) + t = Symbol('t', commutative=False) + fx = Function('Fx', commutative=False)(x) + ft = Function('Ft', commutative=False)(t) + A = Symbol('A', commutative=False) + eq = fx * A * ft + eqdt = eq.diff(t) + assert eqdt.args[-1] == ft.diff(t) + + +def test_Subs_Derivative(): + a = Derivative(f(g(x), h(x)), g(x), h(x),x) + b = Derivative(Derivative(f(g(x), h(x)), g(x), h(x)),x) + c = f(g(x), h(x)).diff(g(x), h(x), x) + d = f(g(x), h(x)).diff(g(x), h(x)).diff(x) + e = Derivative(f(g(x), h(x)), x) + eqs = (a, b, c, d, e) + subs = lambda arg: arg.subs(f, Lambda((x, y), exp(x + y)) + ).subs(g(x), 1/x).subs(h(x), x**3) + ans = 3*x**2*exp(1/x)*exp(x**3) - exp(1/x)*exp(x**3)/x**2 + assert all(subs(i).doit().expand() == ans for i in eqs) + assert all(subs(i.doit()).doit().expand() == ans for i in eqs) + +def test_issue_15360(): + f = Function('f') + assert f.name == 'f' + + +def test_issue_15947(): + assert f._diff_wrt is False + raises(TypeError, lambda: f(f)) + raises(TypeError, lambda: f(x).diff(f)) + + +def test_Derivative_free_symbols(): + f = Function('f') + n = Symbol('n', integer=True, positive=True) + assert diff(f(x), (x, n)).free_symbols == {n, x} + + +def test_issue_20683(): + x = Symbol('x') + y = Symbol('y') + z = Symbol('z') + y = Derivative(z, x).subs(x,0) + assert y.doit() == 0 + y = Derivative(8, x).subs(x,0) + assert y.doit() == 0 + + +def test_issue_10503(): + f = exp(x**3)*cos(x**6) + assert f.series(x, 0, 14) == 1 + x**3 + x**6/2 + x**9/6 - 11*x**12/24 + O(x**14) + + +def test_issue_17382(): + # copied from sympy/core/tests/test_evalf.py + def NS(e, n=15, **options): + return sstr(sympify(e).evalf(n, **options), full_prec=True) + + x = Symbol('x') + expr = solveset(2 * cos(x) * cos(2 * x) - 1, x, S.Reals) + expected = "Union(" \ + "ImageSet(Lambda(_n, 6.28318530717959*_n + 5.79812359592087), Integers), " \ + "ImageSet(Lambda(_n, 6.28318530717959*_n + 0.485061711258717), Integers))" + assert NS(expr) == expected + +def test_eval_sympified(): + # Check both arguments and return types from eval are sympified + + class F(Function): + @classmethod + def eval(cls, x): + assert x is S.One + return 1 + + assert F(1) is S.One + + # String arguments are not allowed + class F2(Function): + @classmethod + def eval(cls, x): + if x == 0: + return '1' + + raises(SympifyError, lambda: F2(0)) + F2(1) # Doesn't raise + + # TODO: Disable string inputs (https://github.com/sympy/sympy/issues/11003) + # raises(SympifyError, lambda: F2('2')) + +def test_eval_classmethod_check(): + with raises(TypeError): + class F(Function): + def eval(self, x): + pass + + +def test_issue_27163(): + # https://github.com/sympy/sympy/issues/27163 + raises(TypeError, lambda: Derivative(f, t)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_kind.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_kind.py new file mode 100644 index 0000000000000000000000000000000000000000..cbfdffb9304b49488756752ca198fd4067087437 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_kind.py @@ -0,0 +1,57 @@ +from sympy.core.add import Add +from sympy.core.kind import NumberKind, UndefinedKind +from sympy.core.mul import Mul +from sympy.core.numbers import pi, zoo, I, AlgebraicNumber +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.integrals.integrals import Integral +from sympy.core.function import Derivative +from sympy.matrices import (Matrix, SparseMatrix, ImmutableMatrix, + ImmutableSparseMatrix, MatrixSymbol, MatrixKind, MatMul) + +comm_x = Symbol('x') +noncomm_x = Symbol('x', commutative=False) + +def test_NumberKind(): + assert S.One.kind is NumberKind + assert pi.kind is NumberKind + assert S.NaN.kind is NumberKind + assert zoo.kind is NumberKind + assert I.kind is NumberKind + assert AlgebraicNumber(1).kind is NumberKind + +def test_Add_kind(): + assert Add(2, 3, evaluate=False).kind is NumberKind + assert Add(2,comm_x).kind is NumberKind + assert Add(2,noncomm_x).kind is UndefinedKind + +def test_mul_kind(): + assert Mul(2,comm_x, evaluate=False).kind is NumberKind + assert Mul(2,3, evaluate=False).kind is NumberKind + assert Mul(noncomm_x,2, evaluate=False).kind is UndefinedKind + assert Mul(2,noncomm_x, evaluate=False).kind is UndefinedKind + +def test_Symbol_kind(): + assert comm_x.kind is NumberKind + assert noncomm_x.kind is UndefinedKind + +def test_Integral_kind(): + A = MatrixSymbol('A', 2,2) + assert Integral(comm_x, comm_x).kind is NumberKind + assert Integral(A, comm_x).kind is MatrixKind(NumberKind) + +def test_Derivative_kind(): + A = MatrixSymbol('A', 2,2) + assert Derivative(comm_x, comm_x).kind is NumberKind + assert Derivative(A, comm_x).kind is MatrixKind(NumberKind) + +def test_Matrix_kind(): + classes = (Matrix, SparseMatrix, ImmutableMatrix, ImmutableSparseMatrix) + for cls in classes: + m = cls.zeros(3, 2) + assert m.kind is MatrixKind(NumberKind) + +def test_MatMul_kind(): + M = Matrix([[1,2],[3,4]]) + assert MatMul(2, M).kind is MatrixKind(NumberKind) + assert MatMul(comm_x, M).kind is MatrixKind(NumberKind) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_logic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_logic.py new file mode 100644 index 0000000000000000000000000000000000000000..df5647f32ea7c4e326eb4e3aec6a7b2987f32aee --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_logic.py @@ -0,0 +1,198 @@ +from sympy.core.logic import (fuzzy_not, Logic, And, Or, Not, fuzzy_and, + fuzzy_or, _fuzzy_group, _torf, fuzzy_nand, fuzzy_xor) +from sympy.testing.pytest import raises + +from itertools import product + +T = True +F = False +U = None + + + +def test_torf(): + v = [T, F, U] + for i in product(*[v]*3): + assert _torf(i) is (True if all(j for j in i) else + (False if all(j is False for j in i) else None)) + + +def test_fuzzy_group(): + v = [T, F, U] + for i in product(*[v]*3): + assert _fuzzy_group(i) is (None if None in i else + (True if all(j for j in i) else False)) + assert _fuzzy_group(i, quick_exit=True) is \ + (None if (i.count(False) > 1) else + (None if None in i else (True if all(j for j in i) else False))) + it = (True if (i == 0) else None for i in range(2)) + assert _torf(it) is None + it = (True if (i == 1) else None for i in range(2)) + assert _torf(it) is None + + +def test_fuzzy_not(): + assert fuzzy_not(T) == F + assert fuzzy_not(F) == T + assert fuzzy_not(U) == U + + +def test_fuzzy_and(): + assert fuzzy_and([T, T]) == T + assert fuzzy_and([T, F]) == F + assert fuzzy_and([T, U]) == U + assert fuzzy_and([F, F]) == F + assert fuzzy_and([F, U]) == F + assert fuzzy_and([U, U]) == U + assert [fuzzy_and([w]) for w in [U, T, F]] == [U, T, F] + assert fuzzy_and([T, F, U]) == F + assert fuzzy_and([]) == T + raises(TypeError, lambda: fuzzy_and()) + + +def test_fuzzy_or(): + assert fuzzy_or([T, T]) == T + assert fuzzy_or([T, F]) == T + assert fuzzy_or([T, U]) == T + assert fuzzy_or([F, F]) == F + assert fuzzy_or([F, U]) == U + assert fuzzy_or([U, U]) == U + assert [fuzzy_or([w]) for w in [U, T, F]] == [U, T, F] + assert fuzzy_or([T, F, U]) == T + assert fuzzy_or([]) == F + raises(TypeError, lambda: fuzzy_or()) + + +def test_logic_cmp(): + l1 = And('a', Not('b')) + l2 = And('a', Not('b')) + + assert hash(l1) == hash(l2) + assert (l1 == l2) == T + assert (l1 != l2) == F + + assert And('a', 'b', 'c') == And('b', 'a', 'c') + assert And('a', 'b', 'c') == And('c', 'b', 'a') + assert And('a', 'b', 'c') == And('c', 'a', 'b') + + assert Not('a') < Not('b') + assert (Not('b') < Not('a')) is False + assert (Not('a') < 2) is False + + +def test_logic_onearg(): + assert And() is True + assert Or() is False + + assert And(T) == T + assert And(F) == F + assert Or(T) == T + assert Or(F) == F + + assert And('a') == 'a' + assert Or('a') == 'a' + + +def test_logic_xnotx(): + assert And('a', Not('a')) == F + assert Or('a', Not('a')) == T + + +def test_logic_eval_TF(): + assert And(F, F) == F + assert And(F, T) == F + assert And(T, F) == F + assert And(T, T) == T + + assert Or(F, F) == F + assert Or(F, T) == T + assert Or(T, F) == T + assert Or(T, T) == T + + assert And('a', T) == 'a' + assert And('a', F) == F + assert Or('a', T) == T + assert Or('a', F) == 'a' + + +def test_logic_combine_args(): + assert And('a', 'b', 'a') == And('a', 'b') + assert Or('a', 'b', 'a') == Or('a', 'b') + + assert And(And('a', 'b'), And('c', 'd')) == And('a', 'b', 'c', 'd') + assert Or(Or('a', 'b'), Or('c', 'd')) == Or('a', 'b', 'c', 'd') + + assert Or('t', And('n', 'p', 'r'), And('n', 'r'), And('n', 'p', 'r'), 't', + And('n', 'r')) == Or('t', And('n', 'p', 'r'), And('n', 'r')) + + +def test_logic_expand(): + t = And(Or('a', 'b'), 'c') + assert t.expand() == Or(And('a', 'c'), And('b', 'c')) + + t = And(Or('a', Not('b')), 'b') + assert t.expand() == And('a', 'b') + + t = And(Or('a', 'b'), Or('c', 'd')) + assert t.expand() == \ + Or(And('a', 'c'), And('a', 'd'), And('b', 'c'), And('b', 'd')) + + +def test_logic_fromstring(): + S = Logic.fromstring + + assert S('a') == 'a' + assert S('!a') == Not('a') + assert S('a & b') == And('a', 'b') + assert S('a | b') == Or('a', 'b') + assert S('a | b & c') == And(Or('a', 'b'), 'c') + assert S('a & b | c') == Or(And('a', 'b'), 'c') + assert S('a & b & c') == And('a', 'b', 'c') + assert S('a | b | c') == Or('a', 'b', 'c') + + raises(ValueError, lambda: S('| a')) + raises(ValueError, lambda: S('& a')) + raises(ValueError, lambda: S('a | | b')) + raises(ValueError, lambda: S('a | & b')) + raises(ValueError, lambda: S('a & & b')) + raises(ValueError, lambda: S('a |')) + raises(ValueError, lambda: S('a|b')) + raises(ValueError, lambda: S('!')) + raises(ValueError, lambda: S('! a')) + raises(ValueError, lambda: S('!(a + 1)')) + raises(ValueError, lambda: S('')) + + +def test_logic_not(): + assert Not('a') != '!a' + assert Not('!a') != 'a' + assert Not(True) == False + assert Not(False) == True + + # NOTE: we may want to change default Not behaviour and put this + # functionality into some method. + assert Not(And('a', 'b')) == Or(Not('a'), Not('b')) + assert Not(Or('a', 'b')) == And(Not('a'), Not('b')) + + raises(ValueError, lambda: Not(1)) + + +def test_formatting(): + S = Logic.fromstring + raises(ValueError, lambda: S('a&b')) + raises(ValueError, lambda: S('a|b')) + raises(ValueError, lambda: S('! a')) + + +def test_fuzzy_xor(): + assert fuzzy_xor((None,)) is None + assert fuzzy_xor((None, True)) is None + assert fuzzy_xor((None, False)) is None + assert fuzzy_xor((True, False)) is True + assert fuzzy_xor((True, True)) is False + assert fuzzy_xor((True, True, False)) is False + assert fuzzy_xor((True, True, False, True)) is True + +def test_fuzzy_nand(): + for args in [(1, 0), (1, 1), (0, 0)]: + assert fuzzy_nand(args) == fuzzy_not(fuzzy_and(args)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_match.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_match.py new file mode 100644 index 0000000000000000000000000000000000000000..b44012bebc4a5f3ec413c236dca1dec71da78cf5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_match.py @@ -0,0 +1,766 @@ +from sympy import abc +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.function import (Derivative, Function, diff) +from sympy.core.mul import Mul +from sympy.core.numbers import (Float, I, Integer, Rational, oo, pi) +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, Wild, symbols) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.functions.special.hyper import meijerg +from sympy.polys.polytools import Poly +from sympy.simplify.radsimp import collect +from sympy.simplify.simplify import signsimp + +from sympy.testing.pytest import XFAIL + + +def test_symbol(): + x = Symbol('x') + a, b, c, p, q = map(Wild, 'abcpq') + + e = x + assert e.match(x) == {} + assert e.matches(x) == {} + assert e.match(a) == {a: x} + + e = Rational(5) + assert e.match(c) == {c: 5} + assert e.match(e) == {} + assert e.match(e + 1) is None + + +def test_add(): + x, y, a, b, c = map(Symbol, 'xyabc') + p, q, r = map(Wild, 'pqr') + + e = a + b + assert e.match(p + b) == {p: a} + assert e.match(p + a) == {p: b} + + e = 1 + b + assert e.match(p + b) == {p: 1} + + e = a + b + c + assert e.match(a + p + c) == {p: b} + assert e.match(b + p + c) == {p: a} + + e = a + b + c + x + assert e.match(a + p + x + c) == {p: b} + assert e.match(b + p + c + x) == {p: a} + assert e.match(b) is None + assert e.match(b + p) == {p: a + c + x} + assert e.match(a + p + c) == {p: b + x} + assert e.match(b + p + c) == {p: a + x} + + e = 4*x + 5 + assert e.match(4*x + p) == {p: 5} + assert e.match(3*x + p) == {p: x + 5} + assert e.match(p*x + 5) == {p: 4} + + +def test_power(): + x, y, a, b, c = map(Symbol, 'xyabc') + p, q, r = map(Wild, 'pqr') + + e = (x + y)**a + assert e.match(p**q) == {p: x + y, q: a} + assert e.match(p**p) is None + + e = (x + y)**(x + y) + assert e.match(p**p) == {p: x + y} + assert e.match(p**q) == {p: x + y, q: x + y} + + e = (2*x)**2 + assert e.match(p*q**r) == {p: 4, q: x, r: 2} + + e = Integer(1) + assert e.match(x**p) == {p: 0} + + +def test_match_exclude(): + x = Symbol('x') + y = Symbol('y') + p = Wild("p") + q = Wild("q") + r = Wild("r") + + e = Rational(6) + assert e.match(2*p) == {p: 3} + + e = 3/(4*x + 5) + assert e.match(3/(p*x + q)) == {p: 4, q: 5} + + e = 3/(4*x + 5) + assert e.match(p/(q*x + r)) == {p: 3, q: 4, r: 5} + + e = 2/(x + 1) + assert e.match(p/(q*x + r)) == {p: 2, q: 1, r: 1} + + e = 1/(x + 1) + assert e.match(p/(q*x + r)) == {p: 1, q: 1, r: 1} + + e = 4*x + 5 + assert e.match(p*x + q) == {p: 4, q: 5} + + e = 4*x + 5*y + 6 + assert e.match(p*x + q*y + r) == {p: 4, q: 5, r: 6} + + a = Wild('a', exclude=[x]) + + e = 3*x + assert e.match(p*x) == {p: 3} + assert e.match(a*x) == {a: 3} + + e = 3*x**2 + assert e.match(p*x) == {p: 3*x} + assert e.match(a*x) is None + + e = 3*x + 3 + 6/x + assert e.match(p*x**2 + p*x + 2*p) == {p: 3/x} + assert e.match(a*x**2 + a*x + 2*a) is None + + +def test_mul(): + x, y, a, b, c = map(Symbol, 'xyabc') + p, q = map(Wild, 'pq') + + e = 4*x + assert e.match(p*x) == {p: 4} + assert e.match(p*y) is None + assert e.match(e + p*y) == {p: 0} + + e = a*x*b*c + assert e.match(p*x) == {p: a*b*c} + assert e.match(c*p*x) == {p: a*b} + + e = (a + b)*(a + c) + assert e.match((p + b)*(p + c)) == {p: a} + + e = x + assert e.match(p*x) == {p: 1} + + e = exp(x) + assert e.match(x**p*exp(x*q)) == {p: 0, q: 1} + + e = I*Poly(x, x) + assert e.match(I*p) == {p: x} + + +def test_mul_noncommutative(): + x, y = symbols('x y') + A, B, C = symbols('A B C', commutative=False) + u, v = symbols('u v', cls=Wild) + w, z = symbols('w z', cls=Wild, commutative=False) + + assert (u*v).matches(x) in ({v: x, u: 1}, {u: x, v: 1}) + assert (u*v).matches(x*y) in ({v: y, u: x}, {u: y, v: x}) + assert (u*v).matches(A) is None + assert (u*v).matches(A*B) is None + assert (u*v).matches(x*A) is None + assert (u*v).matches(x*y*A) is None + assert (u*v).matches(x*A*B) is None + assert (u*v).matches(x*y*A*B) is None + + assert (v*w).matches(x) is None + assert (v*w).matches(x*y) is None + assert (v*w).matches(A) == {w: A, v: 1} + assert (v*w).matches(A*B) == {w: A*B, v: 1} + assert (v*w).matches(x*A) == {w: A, v: x} + assert (v*w).matches(x*y*A) == {w: A, v: x*y} + assert (v*w).matches(x*A*B) == {w: A*B, v: x} + assert (v*w).matches(x*y*A*B) == {w: A*B, v: x*y} + + assert (v*w).matches(-x) is None + assert (v*w).matches(-x*y) is None + assert (v*w).matches(-A) == {w: A, v: -1} + assert (v*w).matches(-A*B) == {w: A*B, v: -1} + assert (v*w).matches(-x*A) == {w: A, v: -x} + assert (v*w).matches(-x*y*A) == {w: A, v: -x*y} + assert (v*w).matches(-x*A*B) == {w: A*B, v: -x} + assert (v*w).matches(-x*y*A*B) == {w: A*B, v: -x*y} + + assert (w*z).matches(x) is None + assert (w*z).matches(x*y) is None + assert (w*z).matches(A) is None + assert (w*z).matches(A*B) == {w: A, z: B} + assert (w*z).matches(B*A) == {w: B, z: A} + assert (w*z).matches(A*B*C) in [{w: A, z: B*C}, {w: A*B, z: C}] + assert (w*z).matches(x*A) is None + assert (w*z).matches(x*y*A) is None + assert (w*z).matches(x*A*B) is None + assert (w*z).matches(x*y*A*B) is None + + assert (w*A).matches(A) is None + assert (A*w*B).matches(A*B) is None + + assert (u*w*z).matches(x) is None + assert (u*w*z).matches(x*y) is None + assert (u*w*z).matches(A) is None + assert (u*w*z).matches(A*B) == {u: 1, w: A, z: B} + assert (u*w*z).matches(B*A) == {u: 1, w: B, z: A} + assert (u*w*z).matches(x*A) is None + assert (u*w*z).matches(x*y*A) is None + assert (u*w*z).matches(x*A*B) == {u: x, w: A, z: B} + assert (u*w*z).matches(x*B*A) == {u: x, w: B, z: A} + assert (u*w*z).matches(x*y*A*B) == {u: x*y, w: A, z: B} + assert (u*w*z).matches(x*y*B*A) == {u: x*y, w: B, z: A} + + assert (u*A).matches(x*A) == {u: x} + assert (u*A).matches(x*A*B) is None + assert (u*B).matches(x*A) is None + assert (u*A*B).matches(x*A*B) == {u: x} + assert (u*A*B).matches(x*B*A) is None + assert (u*A*B).matches(x*A) is None + + assert (u*w*A).matches(x*A*B) is None + assert (u*w*B).matches(x*A*B) == {u: x, w: A} + + assert (u*v*A*B).matches(x*A*B) in [{u: x, v: 1}, {v: x, u: 1}] + assert (u*v*A*B).matches(x*B*A) is None + assert (u*v*A*B).matches(u*v*A*C) is None + + +def test_mul_noncommutative_mismatch(): + A, B, C = symbols('A B C', commutative=False) + w = symbols('w', cls=Wild, commutative=False) + + assert (w*B*w).matches(A*B*A) == {w: A} + assert (w*B*w).matches(A*C*B*A*C) == {w: A*C} + assert (w*B*w).matches(A*C*B*A*B) is None + assert (w*B*w).matches(A*B*C) is None + assert (w*w*C).matches(A*B*C) is None + + +def test_mul_noncommutative_pow(): + A, B, C = symbols('A B C', commutative=False) + w = symbols('w', cls=Wild, commutative=False) + + assert (A*B*w).matches(A*B**2) == {w: B} + assert (A*(B**2)*w*(B**3)).matches(A*B**8) == {w: B**3} + assert (A*B*w*C).matches(A*(B**4)*C) == {w: B**3} + + assert (A*B*(w**(-1))).matches(A*B*(C**(-1))) == {w: C} + assert (A*(B*w)**(-1)*C).matches(A*(B*C)**(-1)*C) == {w: C} + + assert ((w**2)*B*C).matches((A**2)*B*C) == {w: A} + assert ((w**2)*B*(w**3)).matches((A**2)*B*(A**3)) == {w: A} + assert ((w**2)*B*(w**4)).matches((A**2)*B*(A**2)) is None + +def test_complex(): + a, b, c = map(Symbol, 'abc') + x, y = map(Wild, 'xy') + + assert (1 + I).match(x + I) == {x: 1} + assert (a + I).match(x + I) == {x: a} + assert (2*I).match(x*I) == {x: 2} + assert (a*I).match(x*I) == {x: a} + assert (a*I).match(x*y) == {x: I, y: a} + assert (2*I).match(x*y) == {x: 2, y: I} + assert (a + b*I).match(x + y*I) == {x: a, y: b} + + +def test_functions(): + from sympy.core.function import WildFunction + x = Symbol('x') + g = WildFunction('g') + p = Wild('p') + q = Wild('q') + + f = cos(5*x) + notf = x + assert f.match(p*cos(q*x)) == {p: 1, q: 5} + assert f.match(p*g) == {p: 1, g: cos(5*x)} + assert notf.match(g) is None + + +@XFAIL +def test_functions_X1(): + from sympy.core.function import WildFunction + x = Symbol('x') + g = WildFunction('g') + p = Wild('p') + q = Wild('q') + + f = cos(5*x) + assert f.match(p*g(q*x)) == {p: 1, g: cos, q: 5} + + +def test_interface(): + x, y = map(Symbol, 'xy') + p, q = map(Wild, 'pq') + + assert (x + 1).match(p + 1) == {p: x} + assert (x*3).match(p*3) == {p: x} + assert (x**3).match(p**3) == {p: x} + assert (x*cos(y)).match(p*cos(q)) == {p: x, q: y} + + assert (x*y).match(p*q) in [{p:x, q:y}, {p:y, q:x}] + assert (x + y).match(p + q) in [{p:x, q:y}, {p:y, q:x}] + assert (x*y + 1).match(p*q) in [{p:1, q:1 + x*y}, {p:1 + x*y, q:1}] + + +def test_derivative1(): + x, y = map(Symbol, 'xy') + p, q = map(Wild, 'pq') + + f = Function('f', nargs=1) + fd = Derivative(f(x), x) + + assert fd.match(p) == {p: fd} + assert (fd + 1).match(p + 1) == {p: fd} + assert (fd).match(fd) == {} + assert (3*fd).match(p*fd) is not None + assert (3*fd - 1).match(p*fd + q) == {p: 3, q: -1} + + +def test_derivative_bug1(): + f = Function("f") + x = Symbol("x") + a = Wild("a", exclude=[f, x]) + b = Wild("b", exclude=[f]) + pattern = a * Derivative(f(x), x, x) + b + expr = Derivative(f(x), x) + x**2 + d1 = {b: x**2} + d2 = pattern.xreplace(d1).matches(expr, d1) + assert d2 is None + + +def test_derivative2(): + f = Function("f") + x = Symbol("x") + a = Wild("a", exclude=[f, x]) + b = Wild("b", exclude=[f]) + e = Derivative(f(x), x) + assert e.match(Derivative(f(x), x)) == {} + assert e.match(Derivative(f(x), x, x)) is None + e = Derivative(f(x), x, x) + assert e.match(Derivative(f(x), x)) is None + assert e.match(Derivative(f(x), x, x)) == {} + e = Derivative(f(x), x) + x**2 + assert e.match(a*Derivative(f(x), x) + b) == {a: 1, b: x**2} + assert e.match(a*Derivative(f(x), x, x) + b) is None + e = Derivative(f(x), x, x) + x**2 + assert e.match(a*Derivative(f(x), x) + b) is None + assert e.match(a*Derivative(f(x), x, x) + b) == {a: 1, b: x**2} + + +def test_match_deriv_bug1(): + n = Function('n') + l = Function('l') + + x = Symbol('x') + p = Wild('p') + + e = diff(l(x), x)/x - diff(diff(n(x), x), x)/2 - \ + diff(n(x), x)**2/4 + diff(n(x), x)*diff(l(x), x)/4 + e = e.subs(n(x), -l(x)).doit() + t = x*exp(-l(x)) + t2 = t.diff(x, x)/t + assert e.match( (p*t2).expand() ) == {p: Rational(-1, 2)} + + +def test_match_bug2(): + x, y = map(Symbol, 'xy') + p, q, r = map(Wild, 'pqr') + res = (x + y).match(p + q + r) + assert (p + q + r).subs(res) == x + y + + +def test_match_bug3(): + x, a, b = map(Symbol, 'xab') + p = Wild('p') + assert (b*x*exp(a*x)).match(x*exp(p*x)) is None + + +def test_match_bug4(): + x = Symbol('x') + p = Wild('p') + e = x + assert e.match(-p*x) == {p: -1} + + +def test_match_bug5(): + x = Symbol('x') + p = Wild('p') + e = -x + assert e.match(-p*x) == {p: 1} + + +def test_match_bug6(): + x = Symbol('x') + p = Wild('p') + e = x + assert e.match(3*p*x) == {p: Rational(1)/3} + + +def test_match_polynomial(): + x = Symbol('x') + a = Wild('a', exclude=[x]) + b = Wild('b', exclude=[x]) + c = Wild('c', exclude=[x]) + d = Wild('d', exclude=[x]) + + eq = 4*x**3 + 3*x**2 + 2*x + 1 + pattern = a*x**3 + b*x**2 + c*x + d + assert eq.match(pattern) == {a: 4, b: 3, c: 2, d: 1} + assert (eq - 3*x**2).match(pattern) == {a: 4, b: 0, c: 2, d: 1} + assert (x + sqrt(2) + 3).match(a + b*x + c*x**2) == \ + {b: 1, a: sqrt(2) + 3, c: 0} + + +def test_exclude(): + x, y, a = map(Symbol, 'xya') + p = Wild('p', exclude=[1, x]) + q = Wild('q') + r = Wild('r', exclude=[sin, y]) + + assert sin(x).match(r) is None + assert cos(y).match(r) is None + + e = 3*x**2 + y*x + a + assert e.match(p*x**2 + q*x + r) == {p: 3, q: y, r: a} + + e = x + 1 + assert e.match(x + p) is None + assert e.match(p + 1) is None + assert e.match(x + 1 + p) == {p: 0} + + e = cos(x) + 5*sin(y) + assert e.match(r) is None + assert e.match(cos(y) + r) is None + assert e.match(r + p*sin(q)) == {r: cos(x), p: 5, q: y} + + +def test_floats(): + a, b = map(Wild, 'ab') + + e = cos(0.12345, evaluate=False)**2 + r = e.match(a*cos(b)**2) + assert r == {a: 1, b: Float(0.12345)} + + +def test_Derivative_bug1(): + f = Function("f") + x = abc.x + a = Wild("a", exclude=[f(x)]) + b = Wild("b", exclude=[f(x)]) + eq = f(x).diff(x) + assert eq.match(a*Derivative(f(x), x) + b) == {a: 1, b: 0} + + +def test_match_wild_wild(): + p = Wild('p') + q = Wild('q') + r = Wild('r') + + assert p.match(q + r) in [ {q: p, r: 0}, {q: 0, r: p} ] + assert p.match(q*r) in [ {q: p, r: 1}, {q: 1, r: p} ] + + p = Wild('p') + q = Wild('q', exclude=[p]) + r = Wild('r') + + assert p.match(q + r) == {q: 0, r: p} + assert p.match(q*r) == {q: 1, r: p} + + p = Wild('p') + q = Wild('q', exclude=[p]) + r = Wild('r', exclude=[p]) + + assert p.match(q + r) is None + assert p.match(q*r) is None + + +def test__combine_inverse(): + x, y = symbols("x y") + assert Mul._combine_inverse(x*I*y, x*I) == y + assert Mul._combine_inverse(x*x**(1 + y), x**(1 + y)) == x + assert Mul._combine_inverse(x*I*y, y*I) == x + assert Mul._combine_inverse(oo*I*y, y*I) is oo + assert Mul._combine_inverse(oo*I*y, oo*I) == y + assert Mul._combine_inverse(oo*I*y, oo*I) == y + assert Mul._combine_inverse(oo*y, -oo) == -y + assert Mul._combine_inverse(-oo*y, oo) == -y + assert Mul._combine_inverse((1-exp(x/y)),(exp(x/y)-1)) == -1 + assert Add._combine_inverse(oo, oo) is S.Zero + assert Add._combine_inverse(oo*I, oo*I) is S.Zero + assert Add._combine_inverse(x*oo, x*oo) is S.Zero + assert Add._combine_inverse(-x*oo, -x*oo) is S.Zero + assert Add._combine_inverse((x - oo)*(x + oo), -oo) + + +def test_issue_3773(): + x = symbols('x') + z, phi, r = symbols('z phi r') + c, A, B, N = symbols('c A B N', cls=Wild) + l = Wild('l', exclude=(0,)) + + eq = z * sin(2*phi) * r**7 + matcher = c * sin(phi*N)**l * r**A * log(r)**B + + assert eq.match(matcher) == {c: z, l: 1, N: 2, A: 7, B: 0} + assert (-eq).match(matcher) == {c: -z, l: 1, N: 2, A: 7, B: 0} + assert (x*eq).match(matcher) == {c: x*z, l: 1, N: 2, A: 7, B: 0} + assert (-7*x*eq).match(matcher) == {c: -7*x*z, l: 1, N: 2, A: 7, B: 0} + + matcher = c*sin(phi*N)**l * r**A + + assert eq.match(matcher) == {c: z, l: 1, N: 2, A: 7} + assert (-eq).match(matcher) == {c: -z, l: 1, N: 2, A: 7} + assert (x*eq).match(matcher) == {c: x*z, l: 1, N: 2, A: 7} + assert (-7*x*eq).match(matcher) == {c: -7*x*z, l: 1, N: 2, A: 7} + + +def test_issue_3883(): + from sympy.abc import gamma, mu, x + f = (-gamma * (x - mu)**2 - log(gamma) + log(2*pi))/2 + a, b, c = symbols('a b c', cls=Wild, exclude=(gamma,)) + + assert f.match(a * log(gamma) + b * gamma + c) == \ + {a: Rational(-1, 2), b: -(-mu + x)**2/2, c: log(2*pi)/2} + assert f.expand().collect(gamma).match(a * log(gamma) + b * gamma + c) == \ + {a: Rational(-1, 2), b: (-(x - mu)**2/2).expand(), c: (log(2*pi)/2).expand()} + 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: Rational(-1, 2), g2: -mu**2/2 + mu*x - x**2/2} + + +def test_issue_4418(): + x = Symbol('x') + a, b, c = symbols('a b c', cls=Wild, exclude=(x,)) + f, g = symbols('f g', cls=Function) + + eq = diff(g(x)*f(x).diff(x), x) + + assert eq.match( + g(x).diff(x)*f(x).diff(x) + g(x)*f(x).diff(x, x) + c) == {c: 0} + assert eq.match(a*g(x).diff( + x)*f(x).diff(x) + b*g(x)*f(x).diff(x, x) + c) == {a: 1, b: 1, c: 0} + + +def test_issue_4700(): + f = Function('f') + x = Symbol('x') + a, b = symbols('a b', cls=Wild, exclude=(f(x),)) + + p = a*f(x) + b + eq1 = sin(x) + eq2 = f(x) + sin(x) + eq3 = f(x) + x + sin(x) + eq4 = x + sin(x) + + assert eq1.match(p) == {a: 0, b: sin(x)} + assert eq2.match(p) == {a: 1, b: sin(x)} + assert eq3.match(p) == {a: 1, b: x + sin(x)} + assert eq4.match(p) == {a: 0, b: x + sin(x)} + + +def test_issue_5168(): + a, b, c = symbols('a b c', cls=Wild) + x = Symbol('x') + f = Function('f') + + assert x.match(a) == {a: x} + assert x.match(a*f(x)**c) == {a: x, c: 0} + assert x.match(a*b) == {a: 1, b: x} + assert x.match(a*b*f(x)**c) == {a: 1, b: x, c: 0} + + assert (-x).match(a) == {a: -x} + assert (-x).match(a*f(x)**c) == {a: -x, c: 0} + assert (-x).match(a*b) == {a: -1, b: x} + assert (-x).match(a*b*f(x)**c) == {a: -1, b: x, c: 0} + + assert (2*x).match(a) == {a: 2*x} + assert (2*x).match(a*f(x)**c) == {a: 2*x, c: 0} + assert (2*x).match(a*b) == {a: 2, b: x} + assert (2*x).match(a*b*f(x)**c) == {a: 2, b: x, c: 0} + + assert (-2*x).match(a) == {a: -2*x} + assert (-2*x).match(a*f(x)**c) == {a: -2*x, c: 0} + assert (-2*x).match(a*b) == {a: -2, b: x} + assert (-2*x).match(a*b*f(x)**c) == {a: -2, b: x, c: 0} + + +def test_issue_4559(): + x = Symbol('x') + e = Symbol('e') + w = Wild('w', exclude=[x]) + y = Wild('y') + + # this is as it should be + + assert (3/x).match(w/y) == {w: 3, y: x} + assert (3*x).match(w*y) == {w: 3, y: x} + assert (x/3).match(y/w) == {w: 3, y: x} + assert (3*x).match(y/w) == {w: S.One/3, y: x} + assert (3*x).match(y/w) == {w: Rational(1, 3), y: x} + + # these could be allowed to fail + + assert (x/3).match(w/y) == {w: S.One/3, y: 1/x} + assert (3*x).match(w/y) == {w: 3, y: 1/x} + assert (3/x).match(w*y) == {w: 3, y: 1/x} + + # Note that solve will give + # multiple roots but match only gives one: + # + # >>> 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.Zero + 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)} + +# The pattern matcher doesn't know how to handle (x - a)**2 == (a - x)**2. To +# avoid ambiguity in actual applications, don't put a coefficient (including a +# minus sign) in front of a wild. +@XFAIL +def test_issue_4883(): + 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_4319(): + x, y = symbols('x y') + + p = -x*(S.One/8 - y) + ans = {S.Zero, y - S.One/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_3778(): + 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_6103(): + 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} + +def test_gh_issue_2711(): + x = Symbol('x') + f = meijerg(((), ()), ((0,), ()), x) + a = Wild('a') + b = Wild('b') + + assert f.find(a) == {(S.Zero,), ((), ()), ((S.Zero,), ()), x, S.Zero, + (), meijerg(((), ()), ((S.Zero,), ()), x)} + assert f.find(a + b) == \ + {meijerg(((), ()), ((S.Zero,), ()), x), x, S.Zero} + assert f.find(a**2) == {meijerg(((), ()), ((S.Zero,), ()), x), x} + + +def test_issue_17354(): + from sympy.core.symbol import (Wild, symbols) + x, y = symbols("x y", real=True) + a, b = symbols("a b", cls=Wild) + assert ((0 <= x).reversed | (y <= x)).match((1/a <= b) | (a <= b)) is None + + +def test_match_issue_17397(): + f = Function("f") + x = Symbol("x") + a3 = Wild('a3', exclude=[f(x), f(x).diff(x), f(x).diff(x, 2)]) + b3 = Wild('b3', exclude=[f(x), f(x).diff(x), f(x).diff(x, 2)]) + c3 = Wild('c3', exclude=[f(x), f(x).diff(x), f(x).diff(x, 2)]) + deq = a3*(f(x).diff(x, 2)) + b3*f(x).diff(x) + c3*f(x) + + eq = (x-2)**2*(f(x).diff(x, 2)) + (x-2)*(f(x).diff(x)) + ((x-2)**2 - 4)*f(x) + r = collect(eq, [f(x).diff(x, 2), f(x).diff(x), f(x)]).match(deq) + assert r == {a3: (x - 2)**2, c3: (x - 2)**2 - 4, b3: x - 2} + + eq =x*f(x) + x*Derivative(f(x), (x, 2)) - 4*f(x) + Derivative(f(x), x) \ + - 4*Derivative(f(x), (x, 2)) - 2*Derivative(f(x), x)/x + 4*Derivative(f(x), (x, 2))/x + r = collect(eq, [f(x).diff(x, 2), f(x).diff(x), f(x)]).match(deq) + assert r == {a3: x - 4 + 4/x, b3: 1 - 2/x, c3: x - 4} + + +def test_match_issue_21942(): + a, r, w = symbols('a, r, w', nonnegative=True) + p = symbols('p', positive=True) + g_ = Wild('g') + pattern = g_ ** (1 / (1 - p)) + eq = (a * r ** (1 - p) + w ** (1 - p) * (1 - a)) ** (1 / (1 - p)) + m = {g_: a * r ** (1 - p) + w ** (1 - p) * (1 - a)} + assert pattern.matches(eq) == m + assert (-pattern).matches(-eq) == m + assert pattern.matches(signsimp(eq)) is None + + +def test_match_terms(): + X, Y = map(Wild, "XY") + x, y, z = symbols('x y z') + assert (5*y - x).match(5*X - Y) == {X: y, Y: x} + # 15907 + assert (x + (y - 1)*z).match(x + X*z) == {X: y - 1} + # 20747 + assert (x - log(x/y)*(1-exp(x/y))).match(x - log(X/y)*(1-exp(x/y))) == {X: x} + + +def test_match_bound(): + V, W = map(Wild, "VW") + x, y = symbols('x y') + assert Sum(x, (x, 1, 2)).match(Sum(y, (y, 1, W))) is None + assert Sum(x, (x, 1, 2)).match(Sum(V, (V, 1, W))) == {W: 2, V:x} + assert Sum(x, (x, 1, 2)).match(Sum(V, (V, 1, 2))) == {V:x} + + +def test_issue_22462(): + x, f = symbols('x'), Function('f') + n, Q = symbols('n Q', cls=Wild) + pattern = -Q*f(x)**n + eq = 5*f(x)**2 + assert pattern.matches(eq) == {n: 2, Q: -5} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_multidimensional.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_multidimensional.py new file mode 100644 index 0000000000000000000000000000000000000000..765c78adf8dbed2ead43721ca4ab9510dbeeb282 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_multidimensional.py @@ -0,0 +1,24 @@ +from sympy.core.function import (Derivative, Function, diff) +from sympy.core.symbol import symbols +from sympy.functions.elementary.trigonometric import sin +from sympy.core.multidimensional import vectorize +x, y, z = symbols('x y z') +f, g, h = list(map(Function, 'fgh')) + + +def test_vectorize(): + @vectorize(0) + def vsin(x): + return sin(x) + + assert vsin([1, x, y]) == [sin(1), sin(x), sin(y)] + + @vectorize(0, 1) + def vdiff(f, y): + return diff(f, y) + + assert 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)]] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_noncommutative.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_noncommutative.py new file mode 100644 index 0000000000000000000000000000000000000000..b3d3a3cec2ef64aa500aad08b438c90cc8987581 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_noncommutative.py @@ -0,0 +1,140 @@ +"""Tests for noncommutative symbols and expressions.""" + +from sympy.core.function import expand +from sympy.core.numbers import I +from sympy.core.symbol import symbols +from sympy.functions.elementary.complexes import (adjoint, conjugate, transpose) +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.polys.polytools import (cancel, factor) +from sympy.simplify.combsimp import combsimp +from sympy.simplify.gammasimp import gammasimp +from sympy.simplify.radsimp import (collect, radsimp, rcollect) +from sympy.simplify.ratsimp import ratsimp +from sympy.simplify.simplify import (posify, simplify) +from sympy.simplify.trigsimp import trigsimp +from sympy.abc import x, y, z +from sympy.testing.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)) + + +def test_cancel(): + assert cancel(A*B - B*A) == A*B - B*A + assert cancel(A*B*(x - 1)) == A*B*(x - 1) + assert cancel(A*B*(x**2 - 1)/(x + 1)) == A*B*(x - 1) + assert cancel(A*B*(x**2 - 1)/(x + 1) - B*A*(x - 1)) == A*B*(x - 1) + (1 - x)*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_gammasimp(): + assert gammasimp(A*B - B*A) == A*B - B*A + + +def test_conjugate(): + 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 + 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 + assert expand((A*B/A)**2) == A*B*B/A + 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 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 + assert (x*A*x*x).subs(x**2*A, C) == x*C + assert (x*A*x*B).subs(x**2*A, C) == C*B + 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 + + +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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_numbers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_numbers.py new file mode 100644 index 0000000000000000000000000000000000000000..10d14b6ac09fb0ab102c37cb99405440bd0bbffb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_numbers.py @@ -0,0 +1,2335 @@ +import numbers as nums +import decimal +from sympy.concrete.summations import Sum +from sympy.core import (EulerGamma, Catalan, TribonacciConstant, + GoldenRatio) +from sympy.core.containers import Tuple +from sympy.core.expr import unchanged +from sympy.core.logic import fuzzy_not +from sympy.core.mul import Mul +from sympy.core.numbers import (mpf_norm, seterr, + Integer, I, pi, comp, Rational, E, nan, + oo, AlgebraicNumber, Number, Float, zoo, equal_valued, + int_valued, all_close) +from sympy.core.intfunc import (igcd, igcdex, igcd2, igcd_lehmer, + ilcm, integer_nthroot, isqrt, integer_log, mod_inverse) +from sympy.core.power import Pow +from sympy.core.relational import Ge, Gt, Le, Lt +from sympy.core.singleton import S +from sympy.core.symbol import Dummy, Symbol +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.integers import floor +from sympy.functions.combinatorial.numbers import fibonacci +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.miscellaneous import sqrt, cbrt +from sympy.functions.elementary.trigonometric import cos, sin +from sympy.polys.domains.realfield import RealField +from sympy.printing.latex import latex +from sympy.printing.repr import srepr +from sympy.simplify import simplify +from sympy.polys.domains.groundtypes import PythonRational +from sympy.utilities.decorator import conserve_mpmath_dps +from sympy.utilities.iterables import permutations +from sympy.testing.pytest import (XFAIL, raises, _both_exp_pow, + warns_deprecated_sympy) +from sympy import Add + +from mpmath import mpf +import mpmath +from sympy.core import numbers +t = Symbol('t', real=False) + +_ninf = float(-oo) +_inf = float(oo) + + +def same_and_same_prec(a, b): + # stricter matching for Floats + return a == b and a._prec == b._prec + + +def test_seterr(): + seterr(divide=True) + raises(ValueError, lambda: S.Zero/S.Zero) + seterr(divide=False) + assert S.Zero / S.Zero is S.NaN + + +def test_mod(): + x = S.Half + y = Rational(3, 4) + z = Rational(5, 18043) + + assert x % x == 0 + assert x % y == S.Half + assert x % z == Rational(3, 36086) + assert y % x == Rational(1, 4) + assert y % y == 0 + assert y % z == Rational(9, 72172) + assert z % x == Rational(5, 18043) + assert z % y == Rational(5, 18043) + assert z % z == 0 + + a = Float(2.6) + + assert (a % .2) == 0.0 + assert (a % 2).round(15) == 0.6 + assert (a % 0.5).round(15) == 0.1 + + p = Symbol('p', infinite=True) + + assert oo % oo is nan + assert zoo % oo is nan + assert 5 % oo is nan + assert p % 5 is nan + + # 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) == 0.0 + + # No rounding required since these numbers can be represented + # exactly. + 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 Float('1.5').__rmod__(Float('2.75')) == Float('1.25') + assert 2.75 % Float('1.5') == Float('1.25') + + a = Integer(7) + b = Integer(4) + + 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 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(): + x = Symbol("x") + assert divmod(S(12), S(8)) == Tuple(1, 4) + assert divmod(-S(12), S(8)) == Tuple(-2, 4) + assert divmod(S.Zero, S.One) == Tuple(0, 0) + raises(ZeroDivisionError, lambda: divmod(S.Zero, S.Zero)) + raises(ZeroDivisionError, lambda: divmod(S.One, S.Zero)) + assert divmod(S(12), 8) == Tuple(1, 4) + assert divmod(12, S(8)) == Tuple(1, 4) + assert S(1024)//x == 1024//x == floor(1024/x) + + assert divmod(S("2"), S("3/2")) == Tuple(S("1"), S("1/2")) + assert divmod(S("3/2"), S("2")) == Tuple(S("0"), S("3/2")) + assert divmod(S("2"), S("3.5")) == Tuple(S("0"), S("2.")) + assert divmod(S("3.5"), S("2")) == Tuple(S("1"), S("1.5")) + assert divmod(S("2"), S("1/3")) == Tuple(S("6"), S("0")) + assert divmod(S("1/3"), S("2")) == Tuple(S("0"), S("1/3")) + assert divmod(S("2"), S("1/10")) == Tuple(S("20"), S("0")) + assert divmod(S("2"), S(".1"))[0] == 19 + assert divmod(S("0.1"), S("2")) == Tuple(S("0"), S("0.1")) + assert divmod(S("2"), 2) == Tuple(S("1"), S("0")) + assert divmod(2, S("2")) == Tuple(S("1"), S("0")) + assert divmod(S("2"), 1.5) == Tuple(S("1"), S("0.5")) + assert divmod(1.5, S("2")) == Tuple(S("0"), S("1.5")) + assert divmod(0.3, S("2")) == Tuple(S("0"), S("0.3")) + assert divmod(S("3/2"), S("3.5")) == Tuple(S("0"), S(3/2)) + assert divmod(S("3.5"), S("3/2")) == Tuple(S("2"), S("0.5")) + assert divmod(S("3/2"), S("1/3")) == Tuple(S("4"), S("1/6")) + assert divmod(S("1/3"), S("3/2")) == Tuple(S("0"), S("1/3")) + assert divmod(S("3/2"), S("0.1"))[0] == 14 + assert divmod(S("0.1"), S("3/2")) == Tuple(S("0"), S("0.1")) + assert divmod(S("3/2"), 2) == Tuple(S("0"), S("3/2")) + assert divmod(2, S("3/2")) == Tuple(S("1"), S("1/2")) + assert divmod(S("3/2"), 1.5) == Tuple(S("1"), S("0.")) + assert divmod(1.5, S("3/2")) == Tuple(S("1"), S("0.")) + assert divmod(S("3/2"), 0.3) == Tuple(S("5"), S("0.")) + assert divmod(0.3, S("3/2")) == Tuple(S("0"), S("0.3")) + assert divmod(S("1/3"), S("3.5")) == (0, 1/3) + assert divmod(S("3.5"), S("0.1")) == Tuple(S("35"), S("0.")) + assert divmod(S("0.1"), S("3.5")) == Tuple(S("0"), S("0.1")) + assert divmod(S("3.5"), 2) == Tuple(S("1"), S("1.5")) + assert divmod(2, S("3.5")) == Tuple(S("0"), S("2.")) + assert divmod(S("3.5"), 1.5) == Tuple(S("2"), S("0.5")) + assert divmod(1.5, S("3.5")) == Tuple(S("0"), S("1.5")) + assert divmod(0.3, S("3.5")) == Tuple(S("0"), S("0.3")) + assert divmod(S("0.1"), S("1/3")) == Tuple(S("0"), S("0.1")) + assert divmod(S("1/3"), 2) == Tuple(S("0"), S("1/3")) + assert divmod(2, S("1/3")) == Tuple(S("6"), S("0")) + assert divmod(S("1/3"), 1.5) == (0, 1/3) + assert divmod(0.3, S("1/3")) == (0, 0.3) + assert divmod(S("0.1"), 2) == (0, 0.1) + assert divmod(2, S("0.1"))[0] == 19 + assert divmod(S("0.1"), 1.5) == (0, 0.1) + assert divmod(1.5, S("0.1")) == Tuple(S("15"), S("0.")) + assert divmod(S("0.1"), 0.3) == Tuple(S("0"), S("0.1")) + + assert str(divmod(S("2"), 0.3)) == '(6, 0.2)' + assert str(divmod(S("3.5"), S("1/3"))) == '(10, 0.166666666666667)' + assert str(divmod(S("3.5"), 0.3)) == '(11, 0.2)' + assert str(divmod(S("1/3"), S("0.1"))) == '(3, 0.0333333333333333)' + assert str(divmod(1.5, S("1/3"))) == '(4, 0.166666666666667)' + assert str(divmod(S("1/3"), 0.3)) == '(1, 0.0333333333333333)' + assert str(divmod(0.3, S("0.1"))) == '(2, 0.1)' + + assert divmod(-3, S(2)) == (-2, 1) + assert divmod(S(-3), S(2)) == (-2, 1) + assert divmod(S(-3), 2) == (-2, 1) + + assert divmod(oo, 1) == (S.NaN, S.NaN) + assert divmod(S.NaN, 1) == (S.NaN, S.NaN) + assert divmod(1, S.NaN) == (S.NaN, S.NaN) + ans = [(-1, oo), (-1, oo), (0, 0), (0, 1), (0, 2)] + OO = float('inf') + ANS = [tuple(map(float, i)) for i in ans] + assert [divmod(i, oo) for i in range(-2, 3)] == ans + ans = [(0, -2), (0, -1), (0, 0), (-1, -oo), (-1, -oo)] + ANS = [tuple(map(float, i)) for i in ans] + assert [divmod(i, -oo) for i in range(-2, 3)] == ans + assert [divmod(i, -OO) for i in range(-2, 3)] == ANS + + # sympy's divmod gives an Integer for the quotient rather than a float + dmod = lambda a, b: tuple([j if i else int(j) for i, j in enumerate(divmod(a, b))]) + for a in (4, 4., 4.25, 0, 0., -4, -4. -4.25): + for b in (2, 2., 2.5, -2, -2., -2.5): + assert divmod(S(a), S(b)) == dmod(a, b) + + +def test_igcd(): + assert igcd(0, 0) == 0 + assert igcd(0, 1) == 1 + assert igcd(1, 0) == 1 + assert igcd(0, 7) == 7 + assert igcd(7, 0) == 7 + assert igcd(7, 1) == 1 + assert igcd(1, 7) == 1 + assert igcd(-1, 0) == 1 + assert igcd(0, -1) == 1 + assert igcd(-1, -1) == 1 + assert igcd(-1, 7) == 1 + assert igcd(7, -1) == 1 + assert igcd(8, 2) == 2 + assert igcd(4, 8) == 4 + assert igcd(8, 16) == 8 + assert igcd(7, -3) == 1 + assert igcd(-7, 3) == 1 + assert igcd(-7, -3) == 1 + assert igcd(*[10, 20, 30]) == 10 + raises(TypeError, lambda: igcd()) + raises(TypeError, lambda: igcd(2)) + raises(ValueError, lambda: igcd(0, None)) + raises(ValueError, lambda: igcd(1, 2.2)) + for args in permutations((45.1, 1, 30)): + raises(ValueError, lambda: igcd(*args)) + for args in permutations((1, 2, None)): + raises(ValueError, lambda: igcd(*args)) + + +def test_igcd_lehmer(): + a, b = fibonacci(10001), fibonacci(10000) + # len(str(a)) == 2090 + # small divisors, long Euclidean sequence + assert igcd_lehmer(a, b) == 1 + c = fibonacci(100) + assert igcd_lehmer(a*c, b*c) == c + # big divisor + assert igcd_lehmer(a, 10**1000) == 1 + # swapping argument + assert igcd_lehmer(1, 2) == igcd_lehmer(2, 1) + + +def test_igcd2(): + # short loop + assert igcd2(2**100 - 1, 2**99 - 1) == 1 + # Lehmer's algorithm + a, b = int(fibonacci(10001)), int(fibonacci(10000)) + assert igcd2(a, b) == 1 + + +def test_ilcm(): + assert ilcm(0, 0) == 0 + assert ilcm(1, 0) == 0 + assert ilcm(0, 1) == 0 + assert ilcm(1, 1) == 1 + assert ilcm(2, 1) == 2 + assert ilcm(8, 2) == 8 + assert ilcm(8, 6) == 24 + assert ilcm(8, 7) == 56 + assert ilcm(*[10, 20, 30]) == 60 + raises(ValueError, lambda: ilcm(8.1, 7)) + raises(ValueError, lambda: ilcm(8, 7.1)) + raises(TypeError, lambda: ilcm(8)) + + +def test_igcdex(): + assert igcdex(2, 3) == (-1, 1, 1) + assert igcdex(10, 12) == (-1, 1, 2) + assert igcdex(100, 2004) == (-20, 1, 4) + assert igcdex(0, 0) == (0, 0, 0) + assert igcdex(1, 0) == (1, 0, 1) + + +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. + """ + assert cls(0) is S.Zero + assert cls(1) is S.One + assert cls(-1) is S.NegativeOne + # These look odd, but are similar to int(): + assert cls('1') is S.One + assert cls('-1') is S.NegativeOne + + i = Integer(10) + assert _strictly_equal(i, cls('10')) + assert _strictly_equal(i, cls('10')) + assert _strictly_equal(i, cls(int(10))) + 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 + + +def test_Rational_new(): + """" + Test for Rational constructor + """ + _test_rational_new(Rational) + + n1 = S.Half + assert n1 == Rational(Integer(1), 2) + assert n1 == Rational(Integer(1), Integer(2)) + assert n1 == Rational(1, Integer(2)) + assert n1 == Rational(S.Half) + assert 1 == Rational(n1, n1) + assert Rational(3, 2) == Rational(S.Half, 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 + assert Rational(1.0, 3) == Rational(1, 3) + assert Rational(1, 3.0) == Rational(1, 3) + assert Rational(Float(0.5)) == S.Half + assert Rational('1e2/1e-2') == Rational(10000) + assert Rational('1 234') == Rational(1234) + assert Rational('1/1 234') == Rational(1, 1234) + assert Rational(-1, 0) is S.ComplexInfinity + assert Rational(1, 0) is S.ComplexInfinity + # Make sure Rational doesn't lose precision on Floats + assert Rational(pi.evalf(100)).evalf(100) == pi.evalf(100) + raises(TypeError, lambda: Rational('3**3')) + raises(TypeError, lambda: Rational('1/2 + 2/3')) + + # handle fractions.Fraction instances + try: + import fractions + assert Rational(fractions.Fraction(1, 2)) == S.Half + except ImportError: + pass + + assert Rational(PythonRational(2, 6)) == Rational(1, 3) + + with warns_deprecated_sympy(): + assert Rational(2, 4, gcd=1).q == 4 + with warns_deprecated_sympy(): + n = Rational(2, -4, gcd=1) + assert n.q == 4 + assert n.p == -2 + + assert Rational.from_coprime_ints(3, 5) == Rational(3, 5) + + +def test_issue_24543(): + for p in ('1.5', 1.5, 2): + for q in ('1.5', 1.5, 2): + assert Rational(p, q).as_numer_denom() == Rational('%s/%s'%(p,q)).as_numer_denom() + + assert Rational('0.5', '100') == Rational(1, 200) + + +def test_Number_new(): + """" + Test for Number constructor + """ + # Expected behavior on numbers and strings + 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 Float + 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 Float + raises(ValueError, lambda: Number('cos')) + raises(TypeError, lambda: Number(cos)) + a = Rational(3, 5) + assert Number(a) is a # Check idempotence on Numbers + u = ['inf', '-inf', 'nan', 'iNF', '+inf'] + v = [oo, -oo, nan, oo, oo] + for i, a in zip(u, v): + assert Number(i) is a, (i, Number(i), a) + + +def test_Number_cmp(): + n1 = Number(1) + n2 = Number(2) + n3 = Number(-3) + + assert n1 < n2 + assert n1 <= n2 + assert n3 < n1 + assert n2 > n3 + assert n2 >= n3 + + raises(TypeError, lambda: n1 < S.NaN) + raises(TypeError, lambda: n1 <= S.NaN) + raises(TypeError, lambda: n1 > S.NaN) + raises(TypeError, lambda: n1 >= S.NaN) + + +def test_Rational_cmp(): + 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 n8 < n5 + assert n5 < n6 + assert n6 < n7 + assert n8 < n7 + assert n7 > 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 + + raises(TypeError, lambda: n1 < S.NaN) + raises(TypeError, lambda: n1 <= S.NaN) + raises(TypeError, lambda: n1 > S.NaN) + raises(TypeError, lambda: n1 >= S.NaN) + + +def test_Float(): + def eq(a, b): + t = Float("1.0E-15") + return (-t < a - b < t) + + equal_pairs = [ + (0, 0.0), # This is just how Python works... + (0, S.Zero), + (0.0, Float(0)), + ] + unequal_pairs = [ + (0.0, S.Zero), + (0, Float(0)), + (S.Zero, Float(0)), + ] + for p1, p2 in equal_pairs: + assert (p1 == p2) is True + assert (p1 != p2) is False + assert (p2 == p1) is True + assert (p2 != p1) is False + for p1, p2 in unequal_pairs: + assert (p1 == p2) is False + assert (p1 != p2) is True + assert (p2 == p1) is False + assert (p2 != p1) is True + + assert S.Zero.is_zero + + a = Float(2) ** Float(3) + assert eq(a.evalf(), Float(8)) + assert eq((pi ** -1).evalf(), Float("0.31830988618379067")) + a = Float(2) ** Float(4) + assert eq(a.evalf(), Float(16)) + assert (S(.3) == S(.5)) is False + + mpf = (0, 5404319552844595, -52, 53) + x_str = Float((0, '13333333333333', -52, 53)) + x_0xstr = Float((0, '0x13333333333333', -52, 53)) + x2_str = Float((0, '26666666666666', -53, 54)) + x_hex = Float((0, int(0x13333333333333), -52, 53)) + x_dec = Float(mpf) + assert x_str == x_0xstr == x_hex == x_dec == Float(1.2) + # x2_str was entered slightly malformed in that the mantissa + # was even -- it should be odd and the even part should be + # included with the exponent, but this is resolved by normalization + # ONLY IF REQUIREMENTS of mpf_norm are met: the bitcount must + # be exact: double the mantissa ==> increase bc by 1 + assert Float(1.2)._mpf_ == mpf + assert x2_str._mpf_ == mpf + + assert Float((0, int(0), -123, -1)) is S.NaN + assert Float((0, int(0), -456, -2)) is S.Infinity + assert Float((1, int(0), -789, -3)) is S.NegativeInfinity + # if you don't give the full signature, it's not special + assert Float((0, int(0), -123)) == Float(0) + assert Float((0, int(0), -456)) == Float(0) + assert Float((1, int(0), -789)) == Float(0) + + raises(ValueError, lambda: Float((0, 7, 1, 3), '')) + + assert Float('0.0').is_finite is True + assert Float('0.0').is_negative is False + assert Float('0.0').is_positive is False + assert Float('0.0').is_infinite is False + assert Float('0.0').is_zero is True + + # rationality properties + # if the integer test fails then the use of intlike + # should be removed from gamma_functions.py + assert Float(1).is_integer is None + assert Float(1).is_rational is None + assert Float(1).is_irrational is None + assert sqrt(2).n(15).is_rational is None + assert sqrt(2).n(15).is_irrational is None + + # do not automatically evalf + def teq(a): + assert (a.evalf() == a) is False + assert (a.evalf() != a) is True + assert (a == a.evalf()) is False + assert (a != a.evalf()) is True + + teq(pi) + teq(2*pi) + teq(cos(0.1, evaluate=False)) + + # long integer + i = 12345678901234567890 + assert same_and_same_prec(Float(12, ''), Float('12', '')) + assert same_and_same_prec(Float(Integer(i), ''), Float(i, '')) + assert same_and_same_prec(Float(i, ''), Float(str(i), 20)) + assert same_and_same_prec(Float(str(i)), Float(i, '')) + assert same_and_same_prec(Float(i), Float(i, '')) + + # inexact floats (repeating binary = denom not multiple of 2) + # cannot have precision greater than 15 + assert Float(.125, 22)._prec == 76 + assert Float(2.0, 22)._prec == 76 + # only default prec is equal, even for exactly representable float + assert Float(.125, 22) != .125 + #assert Float(2.0, 22) == 2 + assert float(Float('.12500000000000001', '')) == .125 + raises(ValueError, lambda: Float(.12500000000000001, '')) + + # allow spaces + assert Float('123 456.123 456') == Float('123456.123456') + assert Integer('123 456') == Integer('123456') + assert Rational('123 456.123 456') == Rational('123456.123456') + assert Float(' .3e2') == Float('0.3e2') + # but treat them as strictly ass underscore between digits: only 1 + raises(ValueError, lambda: Float('1 2')) + + # allow underscore between digits + assert Float('1_23.4_56') == Float('123.456') + # assert Float('1_23.4_5_6', 12) == Float('123.456', 12) + # ...but not in all cases (per Py 3.6) + raises(ValueError, lambda: Float('1_')) + raises(ValueError, lambda: Float('1__2')) + raises(ValueError, lambda: Float('_1')) + raises(ValueError, lambda: Float('_inf')) + + # allow auto precision detection + assert Float('.1', '') == Float(.1, 1) + assert Float('.125', '') == Float(.125, 3) + assert Float('.100', '') == Float(.1, 3) + 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('-.')) + + 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) + assert Float(decimal.Decimal('nan')) is S.NaN + assert Float(decimal.Decimal('Infinity')) is S.Infinity + assert Float(decimal.Decimal('-Infinity')) is S.NegativeInfinity + + assert '{:.3f}'.format(Float(4.236622)) == '4.237' + assert '{:.35f}'.format(Float(pi.n(40), 40)) == \ + '3.14159265358979323846264338327950288' + + # unicode + assert Float('0.73908513321516064100000000') == \ + Float('0.73908513321516064100000000') + assert Float('0.73908513321516064100000000', 28) == \ + Float('0.73908513321516064100000000', 28) + + # binary precision + # Decimal value 0.1 cannot be expressed precisely as a base 2 fraction + a = Float(S.One/10, dps=15) + b = Float(S.One/10, dps=16) + p = Float(S.One/10, precision=53) + q = Float(S.One/10, precision=54) + assert a._mpf_ == p._mpf_ + assert not a._mpf_ == q._mpf_ + assert not b._mpf_ == q._mpf_ + + # Precision specifying errors + raises(ValueError, lambda: Float("1.23", dps=3, precision=10)) + raises(ValueError, lambda: Float("1.23", dps="", precision=10)) + raises(ValueError, lambda: Float("1.23", dps=3, precision="")) + raises(ValueError, lambda: Float("1.23", dps="", precision="")) + + # from NumberSymbol + assert same_and_same_prec(Float(pi, 32), pi.evalf(32)) + assert same_and_same_prec(Float(Catalan), Catalan.evalf()) + + # oo and nan + u = ['inf', '-inf', 'nan', 'iNF', '+inf'] + v = [oo, -oo, nan, oo, oo] + for i, a in zip(u, v): + assert Float(i) is a + + +def test_zero_not_false(): + # https://github.com/sympy/sympy/issues/20796 + assert (S(0.0) == S.false) is False + assert (S.false == S(0.0)) is False + assert (S(0) == S.false) is False + assert (S.false == S(0)) is False + + +@conserve_mpmath_dps +def test_float_mpf(): + import mpmath + mpmath.mp.dps = 100 + mp_pi = mpmath.pi() + + assert Float(mp_pi, 100) == Float(mp_pi._mpf_, 100) == pi.evalf(100) + + mpmath.mp.dps = 15 + + assert Float(mp_pi, 100) == Float(mp_pi._mpf_, 100) == pi.evalf(100) + + +def test_Float_RealElement(): + repi = RealField(dps=100)(pi.evalf(100)) + # We still have to pass the precision because Float doesn't know what + # RealElement is, but make sure it keeps full precision from the result. + assert Float(repi, 100) == pi.evalf(100) + + +def test_Float_default_to_highprec_from_str(): + s = str(pi.evalf(128)) + assert same_and_same_prec(Float(s), Float(s, '')) + + +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) + + assert a - a == 0 + assert a + (-a) == 0 + assert S.Zero + a - a == 0 + assert S.Zero + a + (-a) == 0 + + assert b - b == 0 + assert b + (-b) == 0 + assert S.Zero + b - b == 0 + assert S.Zero + b + (-b) == 0 + + +def test_issue_14289(): + from sympy.polys.numberfields import to_number_field + + a = 1 - sqrt(2) + b = to_number_field(a) + assert b.as_expr() == a + assert b.minpoly(a).expand() == 0 + + +def test_Float_from_tuple(): + a = Float((0, '1L', 0, 1)) + b = Float((0, '1', 0, 1)) + assert a == b + + +def test_Infinity(): + assert oo != 1 + assert 1*oo is oo + assert 1 != oo + assert oo != -oo + assert oo != Symbol("x")**3 + assert oo + 1 is oo + assert 2 + oo is oo + assert 3*oo + 2 is oo + assert S.Half**oo == 0 + assert S.Half**(-oo) is oo + assert -oo*3 is -oo + assert oo + oo is oo + assert -oo + oo*(-5) is -oo + assert 1/oo == 0 + assert 1/(-oo) == 0 + assert 8/oo == 0 + assert oo % 2 is nan + assert 2 % oo is nan + assert oo/oo is nan + assert oo/-oo is nan + assert -oo/oo is nan + assert -oo/-oo is nan + assert oo - oo is nan + assert oo - -oo is oo + assert -oo - oo is -oo + assert -oo - -oo is nan + assert oo + -oo is nan + assert -oo + oo is nan + assert oo + oo is oo + assert -oo + oo is nan + assert oo + -oo is nan + assert -oo + -oo is -oo + assert oo*oo is oo + assert -oo*oo is -oo + assert oo*-oo is -oo + assert -oo*-oo is oo + assert oo/0 is oo + assert -oo/0 is -oo + assert 0/oo == 0 + assert 0/-oo == 0 + assert oo*0 is nan + assert -oo*0 is nan + assert 0*oo is nan + assert 0*-oo is nan + assert oo + 0 is oo + assert -oo + 0 is -oo + assert 0 + oo is oo + assert 0 + -oo is -oo + assert oo - 0 is oo + assert -oo - 0 is -oo + assert 0 - oo is -oo + assert 0 - -oo is oo + assert oo/2 is oo + assert -oo/2 is -oo + assert oo/-2 is -oo + assert -oo/-2 is oo + assert oo*2 is oo + assert -oo*2 is -oo + assert oo*-2 is -oo + assert 2/oo == 0 + assert 2/-oo == 0 + assert -2/oo == 0 + assert -2/-oo == 0 + assert 2*oo is oo + assert 2*-oo is -oo + assert -2*oo is -oo + assert -2*-oo is oo + assert 2 + oo is oo + assert 2 - oo is -oo + assert -2 + oo is oo + assert -2 - oo is -oo + assert 2 + -oo is -oo + assert 2 - -oo is oo + assert -2 + -oo is -oo + assert -2 - -oo is oo + assert S(2) + oo is oo + assert S(2) - oo is -oo + assert oo/I == -oo*I + assert -oo/I == oo*I + assert oo*float(1) == _inf and (oo*float(1)) is oo + assert -oo*float(1) == _ninf and (-oo*float(1)) is -oo + assert oo/float(1) == _inf and (oo/float(1)) is oo + assert -oo/float(1) == _ninf and (-oo/float(1)) is -oo + assert oo*float(-1) == _ninf and (oo*float(-1)) is -oo + assert -oo*float(-1) == _inf and (-oo*float(-1)) is oo + assert oo/float(-1) == _ninf and (oo/float(-1)) is -oo + assert -oo/float(-1) == _inf and (-oo/float(-1)) is oo + assert oo + float(1) == _inf and (oo + float(1)) is oo + assert -oo + float(1) == _ninf and (-oo + float(1)) is -oo + assert oo - float(1) == _inf and (oo - float(1)) is oo + assert -oo - float(1) == _ninf and (-oo - float(1)) is -oo + assert float(1)*oo == _inf and (float(1)*oo) is oo + assert float(1)*-oo == _ninf and (float(1)*-oo) is -oo + assert float(1)/oo == 0 + assert float(1)/-oo == 0 + assert float(-1)*oo == _ninf and (float(-1)*oo) is -oo + assert float(-1)*-oo == _inf and (float(-1)*-oo) is oo + assert float(-1)/oo == 0 + assert float(-1)/-oo == 0 + assert float(1) + oo is oo + assert float(1) + -oo is -oo + assert float(1) - oo is -oo + assert float(1) - -oo is oo + assert oo == float(oo) + assert (oo != float(oo)) is False + assert type(float(oo)) is float + assert -oo == float(-oo) + assert (-oo != float(-oo)) is False + assert type(float(-oo)) is float + + assert Float('nan') is nan + assert nan*1.0 is nan + assert -1.0*nan is nan + assert nan*oo is nan + assert nan*-oo is nan + assert nan/oo is nan + assert nan/-oo is nan + assert nan + oo is nan + assert nan + -oo is nan + assert nan - oo is nan + assert nan - -oo is nan + assert -oo * S.Zero is nan + + assert oo*nan is nan + assert -oo*nan is nan + assert oo/nan is nan + assert -oo/nan is nan + assert oo + nan is nan + assert -oo + nan is nan + assert oo - nan is nan + assert -oo - nan is nan + assert S.Zero * oo is nan + assert oo.is_Rational is False + assert isinstance(oo, Rational) is False + + assert S.One/oo == 0 + assert -S.One/oo == 0 + assert S.One/-oo == 0 + assert -S.One/-oo == 0 + assert S.One*oo is oo + assert -S.One*oo is -oo + assert S.One*-oo is -oo + assert -S.One*-oo is oo + assert S.One/nan is nan + assert S.One - -oo is oo + assert S.One + nan is nan + assert S.One - nan is nan + assert nan - S.One is nan + assert nan/S.One is nan + assert -oo - S.One is -oo + + +def test_Infinity_2(): + x = Symbol('x') + assert oo*x != oo + assert oo*(pi - 1) is oo + assert oo*(1 - pi) is -oo + + assert (-oo)*x != -oo + assert (-oo)*(pi - 1) is -oo + assert (-oo)*(1 - pi) is oo + + assert (-1)**S.NaN is S.NaN + assert oo - _inf is S.NaN + assert oo + _ninf is S.NaN + assert oo*0 is S.NaN + assert oo/_inf is S.NaN + assert oo/_ninf is S.NaN + assert oo**S.NaN is S.NaN + assert -oo + _inf is S.NaN + assert -oo - _ninf is S.NaN + assert -oo*S.NaN is S.NaN + assert -oo*0 is S.NaN + assert -oo/_inf is S.NaN + assert -oo/_ninf is S.NaN + assert -oo/S.NaN is S.NaN + assert abs(-oo) is oo + assert all((-oo)**i is S.NaN for i in (oo, -oo, S.NaN)) + assert (-oo)**3 is -oo + assert (-oo)**2 is oo + assert abs(S.ComplexInfinity) is oo + + +def test_Mul_Infinity_Zero(): + assert Float(0)*_inf is nan + assert Float(0)*_ninf is nan + assert Float(0)*_inf is nan + assert Float(0)*_ninf is nan + assert _inf*Float(0) is nan + assert _ninf*Float(0) is nan + assert _inf*Float(0) is nan + assert _ninf*Float(0) is nan + + +def test_Div_By_Zero(): + assert 1/S.Zero is zoo + assert 1/Float(0) is zoo + assert 0/S.Zero is nan + assert 0/Float(0) is nan + assert S.Zero/0 is nan + assert Float(0)/0 is nan + assert -1/S.Zero is zoo + assert -1/Float(0) is zoo + + +@_both_exp_pow +def test_Infinity_inequations(): + assert oo > pi + assert not (oo < pi) + assert exp(-3) < oo + + assert _inf > pi + assert not (_inf < pi) + assert exp(-3) < _inf + + raises(TypeError, lambda: oo < I) + raises(TypeError, lambda: oo <= I) + raises(TypeError, lambda: oo > I) + raises(TypeError, lambda: oo >= I) + raises(TypeError, lambda: -oo < I) + raises(TypeError, lambda: -oo <= I) + raises(TypeError, lambda: -oo > I) + raises(TypeError, lambda: -oo >= I) + + raises(TypeError, lambda: I < oo) + raises(TypeError, lambda: I <= oo) + raises(TypeError, lambda: I > oo) + raises(TypeError, lambda: I >= oo) + raises(TypeError, lambda: I < -oo) + raises(TypeError, lambda: I <= -oo) + raises(TypeError, lambda: I > -oo) + raises(TypeError, lambda: I >= -oo) + + assert oo > -oo and oo >= -oo + assert (oo < -oo) == False and (oo <= -oo) == False + assert -oo < oo and -oo <= oo + assert (-oo > oo) == False and (-oo >= oo) == False + + assert (oo < oo) == False # issue 7775 + assert (oo > oo) == False + assert (-oo > -oo) == False and (-oo < -oo) == False + assert oo >= oo and oo <= oo and -oo >= -oo and -oo <= -oo + assert (-oo < -_inf) == False + assert (oo > _inf) == False + assert -oo >= -_inf + assert oo <= _inf + + x = Symbol('x') + b = Symbol('b', finite=True, real=True) + assert (x < oo) == Lt(x, oo) # issue 7775 + assert b < oo and b > -oo and b <= oo and b >= -oo + assert oo > b and oo >= b and (oo < b) == False and (oo <= b) == False + assert (-oo > b) == False and (-oo >= b) == False and -oo < b and -oo <= b + assert (oo < x) == Lt(oo, x) and (oo > x) == Gt(oo, x) + assert (oo <= x) == Le(oo, x) and (oo >= x) == Ge(oo, x) + assert (-oo < x) == Lt(-oo, x) and (-oo > x) == Gt(-oo, x) + assert (-oo <= x) == Le(-oo, x) and (-oo >= x) == Ge(-oo, x) + + +def test_NaN(): + assert nan is nan + assert nan != 1 + assert 1*nan is nan + assert 1 != nan + assert -nan is nan + assert oo != Symbol("x")**3 + assert 2 + nan is nan + assert 3*nan + 2 is nan + assert -nan*3 is nan + assert nan + nan is nan + assert -nan + nan*(-5) is nan + assert 8/nan is nan + raises(TypeError, lambda: nan > 0) + raises(TypeError, lambda: nan < 0) + raises(TypeError, lambda: nan >= 0) + raises(TypeError, lambda: nan <= 0) + raises(TypeError, lambda: 0 < nan) + raises(TypeError, lambda: 0 > nan) + raises(TypeError, lambda: 0 <= nan) + raises(TypeError, lambda: 0 >= nan) + assert nan**0 == 1 # as per IEEE 754 + assert 1**nan is nan # IEEE 754 is not the best choice for symbolic work + # test Pow._eval_power's handling of NaN + assert Pow(nan, 0, evaluate=False)**2 == 1 + for n in (1, 1., S.One, S.NegativeOne, Float(1)): + assert n + nan is nan + assert n - nan is nan + assert nan + n is nan + assert nan - n is nan + assert n/nan is nan + assert nan/n is nan + + +def test_special_numbers(): + 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 S.ComplexInfinity.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) + assert integer_nthroot(1, 5) == (1, True) + assert integer_nthroot(2, 1) == (2, True) + assert integer_nthroot(2, 2) == (1, False) + 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(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(1234567**7, 7) == (1234567, True) + 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) + 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) + + 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) + + # output should be int if possible + assert type(integer_nthroot(2**61, 2)[0]) is int + + +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_integer_log(): + raises(ValueError, lambda: integer_log(2, 1)) + raises(ValueError, lambda: integer_log(0, 2)) + raises(ValueError, lambda: integer_log(1.1, 2)) + raises(ValueError, lambda: integer_log(1, 2.2)) + + assert integer_log(1, 2) == (0, True) + assert integer_log(1, 3) == (0, True) + assert integer_log(2, 3) == (0, False) + assert integer_log(3, 3) == (1, True) + assert integer_log(3*2, 3) == (1, False) + assert integer_log(3**2, 3) == (2, True) + assert integer_log(3*4, 3) == (2, False) + assert integer_log(3**3, 3) == (3, True) + assert integer_log(27, 5) == (2, False) + assert integer_log(2, 3) == (0, False) + assert integer_log(-4, 2) == (2, False) + assert integer_log(-16, 4) == (0, False) + assert integer_log(-4, -2) == (2, False) + assert integer_log(4, -2) == (2, True) + assert integer_log(-8, -2) == (3, True) + assert integer_log(8, -2) == (3, False) + assert integer_log(-9, 3) == (0, False) + assert integer_log(-9, -3) == (2, False) + assert integer_log(9, -3) == (2, True) + assert integer_log(-27, -3) == (3, True) + assert integer_log(27, -3) == (3, False) + + +def test_isqrt(): + from math import sqrt as _sqrt + limit = 4503599761588223 + assert int(_sqrt(limit)) == integer_nthroot(limit, 2)[0] + assert int(_sqrt(limit + 1)) != integer_nthroot(limit + 1, 2)[0] + assert isqrt(limit + 1) == integer_nthroot(limit + 1, 2)[0] + assert isqrt(limit + S.Half) == integer_nthroot(limit, 2)[0] + assert isqrt(limit + 1 + S.Half) == integer_nthroot(limit + 1, 2)[0] + assert isqrt(limit + 2 + S.Half) == integer_nthroot(limit + 2, 2)[0] + + # Regression tests for https://github.com/sympy/sympy/issues/17034 + assert isqrt(4503599761588224) == 67108864 + assert isqrt(9999999999999999) == 99999999 + + # Other corner cases, especially involving non-integers. + raises(ValueError, lambda: isqrt(-1)) + raises(ValueError, lambda: isqrt(-10**1000)) + raises(ValueError, lambda: isqrt(Rational(-1, 2))) + + tiny = Rational(1, 10**1000) + raises(ValueError, lambda: isqrt(-tiny)) + assert isqrt(1-tiny) == 0 + assert isqrt(4503599761588224-tiny) == 67108864 + assert isqrt(10**100 - tiny) == 10**50 - 1 + + +def test_powers_Integer(): + """Test Integer._eval_power""" + # check infinity + assert S.One ** S.Infinity is S.NaN + assert S.NegativeOne** S.Infinity is S.NaN + assert S(2) ** S.Infinity is S.Infinity + assert S(-2)** S.Infinity == zoo + assert S(0) ** S.Infinity is S.Zero + + # check Nan + assert S.One ** S.NaN is S.NaN + assert S.NegativeOne ** S.NaN is S.NaN + + # check for exact roots + assert S.NegativeOne ** Rational(6, 5) == - (-1)**(S.One/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(-27) ** Rational(2, 3) == 9 * (S.NegativeOne ** Rational(2, 3)) + assert (-2) ** Rational(-2, 1) == Rational(1, 4) + + # not exact roots + assert sqrt(-3) == I*sqrt(3) + assert (3) ** (Rational(3, 2)) == 3 * sqrt(3) + assert (-3) ** (Rational(3, 2)) == - 3 * sqrt(-3) + assert (-3) ** (Rational(5, 2)) == 9 * I * sqrt(3) + assert (-3) ** (Rational(7, 2)) == - I * 27 * sqrt(3) + assert (2) ** (Rational(3, 2)) == 2 * sqrt(2) + assert (2) ** (Rational(-3, 2)) == sqrt(2) / 4 + assert (81) ** (Rational(2, 3)) == 9 * (S(3) ** (Rational(2, 3))) + assert (-81) ** (Rational(2, 3)) == 9 * (S(-3) ** (Rational(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) + + # separate symbols & constansts + x = Symbol("x") + assert sqrt(49 * x) == 7 * sqrt(x) + 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) + + # 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 (-2) ** Rational(-10, 3) == \ + (-1)**Rational(2, 3)*2**Rational(2, 3)/16 + assert abs(Pow(-2, Rational(-10, 3)).n() - + Pow(-2, Rational(-10, 3), evaluate=False).n()) < 1e-16 + + # negative base and rational power with some simplification + assert (-8) ** Rational(2, 5) == \ + 2*(-1)**Rational(2, 5)*2**Rational(1, 5) + assert (-4) ** Rational(9, 5) == \ + -8*(-1)**Rational(4, 5)*2**Rational(3, 5) + + 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 + # the current limit in factor_trial_division (2**15) + from sympy.ntheory.generate import nextprime + n = nextprime(2**15) + assert sqrt(n**2) == n + assert sqrt(n**3) == n*sqrt(n) + assert sqrt(4*n) == 2*sqrt(n) + + # check that factors of base with powers sharing gcd with power are removed + assert (2**4*3)**Rational(1, 6) == 2**Rational(2, 3)*3**Rational(1, 6) + assert (2**4*3)**Rational(5, 6) == 8*2**Rational(1, 3)*3**Rational(5, 6) + + # 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) + assert sqrt(8)*24**Rational(1, 3)*6**Rational(1, 5) == \ + 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) + 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, 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, Rational(-1, 3), evaluate=False) == 3**Rational(2, 3) + assert (-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 (-1)**Float(.5) == 1.0*I + + +def test_powers_Rational(): + """Test Rational._eval_power""" + # check infinity + assert S.Half ** S.Infinity == 0 + assert Rational(3, 2) ** S.Infinity is S.Infinity + assert Rational(-1, 2) ** S.Infinity == 0 + assert Rational(-3, 2) ** S.Infinity == zoo + + # check Nan + assert Rational(3, 4) ** S.NaN is S.NaN + assert Rational(-2, 3) ** S.NaN is 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) + + # exact root on denominator + assert sqrt(Rational(1, 4)) == S.Half + assert sqrt(Rational(1, -4)) == I * S.Half + 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(S.Half) == 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 + assert Rational(-3, 2)**Rational(-2, 3) == \ + -(-1)**Rational(1, 3)*2**Rational(2, 3)*3**Rational(1, 3)/3 + assert Rational(-3, 2)**Rational(-10, 3) == \ + 8*(-1)**Rational(2, 3)*2**Rational(1, 3)*3**Rational(2, 3)/81 + assert abs(Pow(Rational(-2, 3), Rational(-7, 4)).n() - + Pow(Rational(-2, 3), Rational(-7, 4), evaluate=False).n()) < 1e-16 + + # 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) + + +def test_powers_Float(): + assert str((S('-1/10')**S('3/10')).n()) == str(Float(-.1)**(.3)) + + +def test_lshift_Integer(): + assert Integer(0) << Integer(2) == Integer(0) + assert Integer(0) << 2 == Integer(0) + assert 0 << Integer(2) == Integer(0) + + assert Integer(0b11) << Integer(0) == Integer(0b11) + assert Integer(0b11) << 0 == Integer(0b11) + assert 0b11 << Integer(0) == Integer(0b11) + + assert Integer(0b11) << Integer(2) == Integer(0b11 << 2) + assert Integer(0b11) << 2 == Integer(0b11 << 2) + assert 0b11 << Integer(2) == Integer(0b11 << 2) + + assert Integer(-0b11) << Integer(2) == Integer(-0b11 << 2) + assert Integer(-0b11) << 2 == Integer(-0b11 << 2) + assert -0b11 << Integer(2) == Integer(-0b11 << 2) + + raises(TypeError, lambda: Integer(2) << 0.0) + raises(TypeError, lambda: 0.0 << Integer(2)) + raises(ValueError, lambda: Integer(1) << Integer(-1)) + + +def test_rshift_Integer(): + assert Integer(0) >> Integer(2) == Integer(0) + assert Integer(0) >> 2 == Integer(0) + assert 0 >> Integer(2) == Integer(0) + + assert Integer(0b11) >> Integer(0) == Integer(0b11) + assert Integer(0b11) >> 0 == Integer(0b11) + assert 0b11 >> Integer(0) == Integer(0b11) + + assert Integer(0b11) >> Integer(2) == Integer(0) + assert Integer(0b11) >> 2 == Integer(0) + assert 0b11 >> Integer(2) == Integer(0) + + assert Integer(-0b11) >> Integer(2) == Integer(-1) + assert Integer(-0b11) >> 2 == Integer(-1) + assert -0b11 >> Integer(2) == Integer(-1) + + assert Integer(0b1100) >> Integer(2) == Integer(0b1100 >> 2) + assert Integer(0b1100) >> 2 == Integer(0b1100 >> 2) + assert 0b1100 >> Integer(2) == Integer(0b1100 >> 2) + + assert Integer(-0b1100) >> Integer(2) == Integer(-0b1100 >> 2) + assert Integer(-0b1100) >> 2 == Integer(-0b1100 >> 2) + assert -0b1100 >> Integer(2) == Integer(-0b1100 >> 2) + + raises(TypeError, lambda: Integer(0b10) >> 0.0) + raises(TypeError, lambda: 0.0 >> Integer(2)) + raises(ValueError, lambda: Integer(1) >> Integer(-1)) + + +def test_and_Integer(): + assert Integer(0b01010101) & Integer(0b10101010) == Integer(0) + assert Integer(0b01010101) & 0b10101010 == Integer(0) + assert 0b01010101 & Integer(0b10101010) == Integer(0) + + assert Integer(0b01010101) & Integer(0b11011011) == Integer(0b01010001) + assert Integer(0b01010101) & 0b11011011 == Integer(0b01010001) + assert 0b01010101 & Integer(0b11011011) == Integer(0b01010001) + + assert -Integer(0b01010101) & Integer(0b11011011) == Integer(-0b01010101 & 0b11011011) + assert Integer(-0b01010101) & 0b11011011 == Integer(-0b01010101 & 0b11011011) + assert -0b01010101 & Integer(0b11011011) == Integer(-0b01010101 & 0b11011011) + + assert Integer(0b01010101) & -Integer(0b11011011) == Integer(0b01010101 & -0b11011011) + assert Integer(0b01010101) & -0b11011011 == Integer(0b01010101 & -0b11011011) + assert 0b01010101 & Integer(-0b11011011) == Integer(0b01010101 & -0b11011011) + + raises(TypeError, lambda: Integer(2) & 0.0) + raises(TypeError, lambda: 0.0 & Integer(2)) + + +def test_xor_Integer(): + assert Integer(0b01010101) ^ Integer(0b11111111) == Integer(0b10101010) + assert Integer(0b01010101) ^ 0b11111111 == Integer(0b10101010) + assert 0b01010101 ^ Integer(0b11111111) == Integer(0b10101010) + + assert Integer(0b01010101) ^ Integer(0b11011011) == Integer(0b10001110) + assert Integer(0b01010101) ^ 0b11011011 == Integer(0b10001110) + assert 0b01010101 ^ Integer(0b11011011) == Integer(0b10001110) + + assert -Integer(0b01010101) ^ Integer(0b11011011) == Integer(-0b01010101 ^ 0b11011011) + assert Integer(-0b01010101) ^ 0b11011011 == Integer(-0b01010101 ^ 0b11011011) + assert -0b01010101 ^ Integer(0b11011011) == Integer(-0b01010101 ^ 0b11011011) + + assert Integer(0b01010101) ^ -Integer(0b11011011) == Integer(0b01010101 ^ -0b11011011) + assert Integer(0b01010101) ^ -0b11011011 == Integer(0b01010101 ^ -0b11011011) + assert 0b01010101 ^ Integer(-0b11011011) == Integer(0b01010101 ^ -0b11011011) + + raises(TypeError, lambda: Integer(2) ^ 0.0) + raises(TypeError, lambda: 0.0 ^ Integer(2)) + + +def test_or_Integer(): + assert Integer(0b01010101) | Integer(0b10101010) == Integer(0b11111111) + assert Integer(0b01010101) | 0b10101010 == Integer(0b11111111) + assert 0b01010101 | Integer(0b10101010) == Integer(0b11111111) + + assert Integer(0b01010101) | Integer(0b11011011) == Integer(0b11011111) + assert Integer(0b01010101) | 0b11011011 == Integer(0b11011111) + assert 0b01010101 | Integer(0b11011011) == Integer(0b11011111) + + assert -Integer(0b01010101) | Integer(0b11011011) == Integer(-0b01010101 | 0b11011011) + assert Integer(-0b01010101) | 0b11011011 == Integer(-0b01010101 | 0b11011011) + assert -0b01010101 | Integer(0b11011011) == Integer(-0b01010101 | 0b11011011) + + assert Integer(0b01010101) | -Integer(0b11011011) == Integer(0b01010101 | -0b11011011) + assert Integer(0b01010101) | -0b11011011 == Integer(0b01010101 | -0b11011011) + assert 0b01010101 | Integer(-0b11011011) == Integer(0b01010101 | -0b11011011) + + raises(TypeError, lambda: Integer(2) | 0.0) + raises(TypeError, lambda: 0.0 | Integer(2)) + + +def test_invert_Integer(): + assert ~Integer(0b01010101) == Integer(-0b01010110) + assert ~Integer(0b01010101) == Integer(~0b01010101) + assert ~(~Integer(0b01010101)) == Integer(0b01010101) + + +def test_abs1(): + assert Rational(1, 6) != Rational(-1, 6) + assert abs(Rational(1, 6)) == abs(Rational(-1, 6)) + + +def test_accept_int(): + assert not Float(4) == 4 + assert Float(4) != 4 + assert Float(4) == 4.0 + + +def test_dont_accept_str(): + assert Float("0.2") != "0.2" + assert not (Float("0.2") == "0.2") + + +def test_int(): + a = Rational(5) + assert int(a) == 5 + a = Rational(9, 10) + assert int(a) == int(-a) == 0 + assert 1/(-1)**Rational(2, 3) == -(-1)**Rational(1, 3) + # issue 10368 + a = Rational(32442016954, 78058255275) + assert type(int(a)) is type(int(-a)) is int + + +def test_int_NumberSymbols(): + assert int(Catalan) == 0 + assert int(EulerGamma) == 0 + assert int(pi) == 3 + assert int(E) == 2 + assert int(GoldenRatio) == 1 + assert int(TribonacciConstant) == 1 + for i in [Catalan, E, EulerGamma, GoldenRatio, TribonacciConstant, pi]: + a, b = i.approximation_interval(Integer) + ia = int(i) + assert ia == a + assert isinstance(ia, int) + assert b == a + 1 + assert a.is_Integer and b.is_Integer + + +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" + + +def test_bug_sqrt(): + 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" + from sympy import pi # noqa + with raises(ImportError): + from sympy import Pi # noqa + + +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(Integer(2))) + + +def test_issue_3321(): + assert sqrt(Rational(1, 5)) == Rational(1, 5)**S.Half + assert 5 * sqrt(Rational(1, 5)) == sqrt(5) + + +def test_issue_3692(): + 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_issue_3423(): + x = Symbol("x") + assert sqrt(x - 1).as_base_exp() == (x - 1, S.Half) + assert sqrt(x - 1) != I*sqrt(1 - x) + + +def test_issue_3449(): + x = Symbol("x") + assert sqrt(x - 1).subs(x, 5) == 2 + + +def test_issue_13890(): + x = Symbol("x") + e = (-x/4 - S.One/12)**x - 1 + f = simplify(e) + a = Rational(9, 5) + assert abs(e.subs(x,a).evalf() - f.subs(x,a).evalf()) < 1e-15 + + +def test_Integer_factors(): + def F(i): + return Integer(i).factors() + + assert F(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) + + 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} + + +def test_issue_4107(): + 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**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_Rational_gcd_lcm_cofactors(): + assert Integer(4).gcd(2) == Integer(2) + assert Integer(4).lcm(2) == Integer(4) + assert Integer(4).gcd(Integer(2)) == Integer(2) + assert Integer(4).lcm(Integer(2)) == Integer(4) + a, b = 720**99911, 480**12342 + assert Integer(a).lcm(b) == a*b/Integer(a).gcd(b) + + assert Integer(4).gcd(3) == Integer(1) + assert Integer(4).lcm(3) == Integer(12) + 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(5, 9).lcm(Rational(3, 7)) == Rational(Integer(5).lcm(3),Integer(9).gcd(7)) + + 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).gcd(Float(2.0)) == Float(1.0) + assert Integer(4).lcm(Float(2.0)) == Float(8.0) + assert Integer(4).cofactors(Float(2.0)) == (Float(1.0), Float(4.0), Float(2.0)) + + assert S.Half.gcd(Float(2.0)) == Float(1.0) + assert S.Half.lcm(Float(2.0)) == Float(1.0) + assert S.Half.cofactors(Float(2.0)) == \ + (Float(1.0), Float(0.5), Float(2.0)) + + +def test_Float_gcd_lcm_cofactors(): + assert Float(2.0).gcd(Integer(4)) == Float(1.0) + assert Float(2.0).lcm(Integer(4)) == Float(8.0) + assert Float(2.0).cofactors(Integer(4)) == (Float(1.0), Float(2.0), Float(4.0)) + + assert Float(2.0).gcd(S.Half) == Float(1.0) + assert Float(2.0).lcm(S.Half) == Float(1.0) + assert Float(2.0).cofactors(S.Half) == \ + (Float(1.0), Float(2.0), Float(0.5)) + + +def test_issue_4611(): + assert abs(pi._evalf(50) - 3.14159265358979) < 1e-10 + assert abs(E._evalf(50) - 2.71828182845905) < 1e-10 + assert abs(Catalan._evalf(50) - 0.915965594177219) < 1e-10 + assert abs(EulerGamma._evalf(50) - 0.577215664901533) < 1e-10 + assert abs(GoldenRatio._evalf(50) - 1.61803398874989) < 1e-10 + assert abs(TribonacciConstant._evalf(50) - 1.83928675521416) < 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 (TribonacciConstant + x).evalf() == TribonacciConstant.evalf() + x + + +@conserve_mpmath_dps +def test_conversion_to_mpmath(): + assert mpmath.mpmathify(Integer(1)) == mpmath.mpf(1) + assert mpmath.mpmathify(S.Half) == mpmath.mpf(0.5) + assert mpmath.mpmathify(Float('1.23', 15)) == mpmath.mpf('1.23') + + assert mpmath.mpmathify(I) == mpmath.mpc(1j) + + assert mpmath.mpmathify(1 + 2*I) == mpmath.mpc(1 + 2j) + assert mpmath.mpmathify(1.0 + 2*I) == mpmath.mpc(1 + 2j) + assert mpmath.mpmathify(1 + 2.0*I) == mpmath.mpc(1 + 2j) + assert mpmath.mpmathify(1.0 + 2.0*I) == mpmath.mpc(1 + 2j) + assert mpmath.mpmathify(S.Half + S.Half*I) == mpmath.mpc(0.5 + 0.5j) + + assert mpmath.mpmathify(2*I) == mpmath.mpc(2j) + assert mpmath.mpmathify(2.0*I) == mpmath.mpc(2j) + assert mpmath.mpmathify(S.Half*I) == mpmath.mpc(0.5j) + + mpmath.mp.dps = 100 + assert mpmath.mpmathify(pi.evalf(100) + pi.evalf(100)*I) == mpmath.pi + mpmath.pi*mpmath.j + assert mpmath.mpmathify(pi.evalf(100)*I) == mpmath.pi*mpmath.j + + +def test_relational(): + # real + x = S(.1) + assert (x != cos) is True + assert (x == cos) is False + + # rational + x = Rational(1, 3) + assert (x != cos) is True + assert (x == cos) is False + + # integer defers to rational so these tests are omitted + + # number symbol + x = pi + assert (x != cos) is True + assert (x == cos) is False + + +def test_Integer_as_index(): + assert 'hello'[Integer(2):] == 'llo' + + +def test_Rational_int(): + assert int( Rational(7, 5)) == 1 + assert int( S.Half) == 0 + assert int(Rational(-1, 2)) == 0 + assert int(-Rational(7, 5)) == -1 + + +def test_zoo(): + b = Symbol('b', finite=True) + nz = Symbol('nz', nonzero=True) + p = Symbol('p', positive=True) + n = Symbol('n', negative=True) + im = Symbol('i', imaginary=True) + c = Symbol('c', complex=True) + pb = Symbol('pb', positive=True) + nb = Symbol('nb', negative=True) + imb = Symbol('ib', imaginary=True, finite=True) + for i in [I, S.Infinity, S.NegativeInfinity, S.Zero, S.One, S.Pi, S.Half, S(3), log(3), + b, nz, p, n, im, pb, nb, imb, c]: + if i.is_finite and (i.is_real or i.is_imaginary): + assert i + zoo is zoo + assert i - zoo is zoo + assert zoo + i is zoo + assert zoo - i is zoo + elif i.is_finite is not False: + assert (i + zoo).is_Add + assert (i - zoo).is_Add + assert (zoo + i).is_Add + assert (zoo - i).is_Add + else: + assert (i + zoo) is S.NaN + assert (i - zoo) is S.NaN + assert (zoo + i) is S.NaN + assert (zoo - i) is S.NaN + + if fuzzy_not(i.is_zero) and (i.is_extended_real or i.is_imaginary): + assert i*zoo is zoo + assert zoo*i is zoo + elif i.is_zero: + assert i*zoo is S.NaN + assert zoo*i is S.NaN + else: + assert (i*zoo).is_Mul + assert (zoo*i).is_Mul + + if fuzzy_not((1/i).is_zero) and (i.is_real or i.is_imaginary): + assert zoo/i is zoo + elif (1/i).is_zero: + assert zoo/i is S.NaN + elif i.is_zero: + assert zoo/i is zoo + else: + assert (zoo/i).is_Mul + + 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 + assert zoo/zoo is S.NaN + assert zoo**zoo is S.NaN + assert zoo**0 is S.One + assert zoo**2 is zoo + assert 1/zoo is S.Zero + + assert Mul.flatten([S.NegativeOne, oo, S(0)]) == ([S.NaN], [], None) + + +def test_issue_4122(): + x = Symbol('x', nonpositive=True) + assert oo + x is oo + x = Symbol('x', extended_nonpositive=True) + assert (oo + x).is_Add + x = Symbol('x', finite=True) + assert (oo + x).is_Add # x could be imaginary + x = Symbol('x', nonnegative=True) + assert oo + x is oo + x = Symbol('x', extended_nonnegative=True) + assert oo + x is oo + x = Symbol('x', finite=True, real=True) + assert oo + x is oo + + # similarly for negative infinity + x = Symbol('x', nonnegative=True) + assert -oo + x is -oo + x = Symbol('x', extended_nonnegative=True) + assert (-oo + x).is_Add + x = Symbol('x', finite=True) + assert (-oo + x).is_Add + x = Symbol('x', nonpositive=True) + assert -oo + x is -oo + x = Symbol('x', extended_nonpositive=True) + assert -oo + x is -oo + x = Symbol('x', finite=True, real=True) + assert -oo + x is -oo + + +def test_GoldenRatio_expand(): + assert GoldenRatio.expand(func=True) == S.Half + sqrt(5)/2 + + +def test_TribonacciConstant_expand(): + assert TribonacciConstant.expand(func=True) == \ + (1 + cbrt(19 - 3*sqrt(33)) + cbrt(19 + 3*sqrt(33))) / 3 + + +def test_as_content_primitive(): + assert S.Zero.as_content_primitive() == (1, 0) + assert S.Half.as_content_primitive() == (S.Half, 1) + assert (Rational(-1, 2)).as_content_primitive() == (S.Half, -1) + assert S(3).as_content_primitive() == (3, 1) + assert S(3.1).as_content_primitive() == (1, 3.1) + + +def test_hashing_sympy_integers(): + # Test for issue 5072 + assert {Integer(3)} == {int(3)} + assert hash(Integer(4)) == hash(int(4)) + + +def test_rounding_issue_4172(): + 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 mpmath.libmp.libmpf import _normalize + import mpmath.libmp as mlib + rnd = mlib.round_nearest + mpf = (0, int(0), -123, -1, 53, rnd) # nan + assert _normalize(mpf, 53) != (0, int(0), 0, 0) + mpf = (0, int(0), -456, -2, 53, rnd) # +inf + assert _normalize(mpf, 53) != (0, int(0), 0, 0) + mpf = (1, int(0), -789, -3, 53, rnd) # -inf + assert _normalize(mpf, 53) != (0, int(0), 0, 0) + + from mpmath.libmp.libmpf import fnan + assert mlib.mpf_eq(fnan, fnan) + + +def test_Catalan_EulerGamma_prec(): + n = GoldenRatio + f = Float(n.n(), 5) + assert f._mpf_ == (0, int(212079), -17, 18) + assert f._prec == 20 + assert n._as_mpf_val(20) == f._mpf_ + + n = EulerGamma + f = Float(n.n(), 5) + assert f._mpf_ == (0, int(302627), -19, 19) + assert f._prec == 20 + assert n._as_mpf_val(20) == f._mpf_ + + +def test_Catalan_rewrite(): + k = Dummy('k', integer=True, nonnegative=True) + assert Catalan.rewrite(Sum).dummy_eq( + Sum((-1)**k/(2*k + 1)**2, (k, 0, oo))) + assert Catalan.rewrite() == Catalan + + +def test_bool_eq(): + assert 0 == False + assert S(0) == False + assert S(0) != S.false + assert 1 == True + assert S.One == True + assert S.One != S.true + + +def test_Float_eq(): + # Floats with different precision should not compare equal + assert Float(.5, 10) != Float(.5, 11) != Float(.5, 1) + # but floats that aren't exact in base-2 still + # don't compare the same because they have different + # underlying mpf values + assert Float(.12, 3) != Float(.12, 4) + assert Float(.12, 3) != .12 + assert 0.12 != Float(.12, 3) + assert Float('.12', 22) != .12 + # issue 11707 + # but Float/Rational -- except for 0 -- + # are exact so Rational(x) = Float(y) only if + # Rational(x) == Rational(Float(y)) + assert Float('1.1') != Rational(11, 10) + assert Rational(11, 10) != Float('1.1') + # coverage + assert not Float(3) == 2 + assert not Float(3) == Float(2) + assert not Float(3) == 3 + assert not Float(2**2) == S.Half + assert Float(2**2) == 4.0 + assert not Float(2**-2) == 1 + assert Float(2**-1) == 0.5 + assert not Float(2*3) == 3 + assert not Float(2*3) == 0.5 + assert Float(2*3) == 6.0 + assert not Float(2*3) == 6 + assert not Float(2*3) == 8 + assert not Float(.75) == Rational(3, 4) + assert Float(.75) == 0.75 + assert Float(5/18) == 5/18 + # 4473 + assert Float(2.) != 3 + assert not Float((0,1,-3)) == S.One/8 + assert Float((0,1,-3)) == 1/8 + assert Float((0,1,-3)) != S.One/9 + # 16196 + assert not 2 == Float(2) # unlike Python + assert t**2 != t**2.0 + + +def test_issue_6640(): + from mpmath.libmp.libmpf import finf, fninf + # 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_issue_6349(): + 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_ + + +def test_latex(): + assert latex(pi) == r"\pi" + assert latex(E) == r"e" + assert latex(GoldenRatio) == r"\phi" + assert latex(TribonacciConstant) == r"\text{TribonacciConstant}" + assert latex(EulerGamma) == r"\gamma" + assert latex(oo) == r"\infty" + assert latex(-oo) == r"-\infty" + assert latex(zoo) == r"\tilde{\infty}" + assert latex(nan) == r"\text{NaN}" + assert latex(I) == r"i" + + +def test_issue_7742(): + assert -oo % 1 is nan + + +def test_simplify_AlgebraicNumber(): + A = AlgebraicNumber + e = 3**(S.One/6)*(3 + (135 + 78*sqrt(3))**Rational(2, 3))/(45 + 26*sqrt(3))**(S.One/3) + assert simplify(A(e)) == A(12) # wester test_C20 + + e = (41 + 29*sqrt(2))**(S.One/5) + assert simplify(A(e)) == A(1 + sqrt(2)) # wester test_C21 + + e = (3 + 4*I)**Rational(3, 2) + assert simplify(A(e)) == A(2 + 11*I) # issue 4401 + + +def test_Float_idempotence(): + x = Float('1.23', '') + y = Float(x) + z = Float(x, 15) + assert same_and_same_prec(y, x) + assert not same_and_same_prec(z, x) + x = Float(10**20) + y = Float(x) + z = Float(x, 15) + assert same_and_same_prec(y, x) + assert not same_and_same_prec(z, x) + + +def test_comp1(): + # sqrt(2) = 1.414213 5623730950... + a = sqrt(2).n(7) + assert comp(a, 1.4142129) is False + assert comp(a, 1.4142130) + # ... + assert comp(a, 1.4142141) + assert comp(a, 1.4142142) is False + assert comp(sqrt(2).n(2), '1.4') + assert comp(sqrt(2).n(2), Float(1.4, 2), '') + assert comp(sqrt(2).n(2), 1.4, '') + assert comp(sqrt(2).n(2), Float(1.4, 3), '') is False + assert comp(sqrt(2) + sqrt(3)*I, 1.4 + 1.7*I, .1) + assert not comp(sqrt(2) + sqrt(3)*I, (1.5 + 1.7*I)*0.89, .1) + assert comp(sqrt(2) + sqrt(3)*I, (1.5 + 1.7*I)*0.90, .1) + assert comp(sqrt(2) + sqrt(3)*I, (1.5 + 1.7*I)*1.07, .1) + assert not comp(sqrt(2) + sqrt(3)*I, (1.5 + 1.7*I)*1.08, .1) + assert [(i, j) + for i in range(130, 150) + for j in range(170, 180) + if comp((sqrt(2)+ I*sqrt(3)).n(3), i/100. + I*j/100.)] == [ + (141, 173), (142, 173)] + raises(ValueError, lambda: comp(t, '1')) + raises(ValueError, lambda: comp(t, 1)) + assert comp(0, 0.0) + assert comp(.5, S.Half) + assert comp(2 + sqrt(2), 2.0 + sqrt(2)) + assert not comp(0, 1) + assert not comp(2, sqrt(2)) + assert not comp(2 + I, 2.0 + sqrt(2)) + assert not comp(2.0 + sqrt(2), 2 + I) + assert not comp(2.0 + sqrt(2), sqrt(3)) + assert comp(1/pi.n(4), 0.3183, 1e-5) + assert not comp(1/pi.n(4), 0.3183, 8e-6) + + +def test_issue_9491(): + assert oo**zoo is nan + + +def test_issue_10063(): + assert 2**Float(3) == Float(8) + + +def test_issue_10020(): + assert oo**I is S.NaN + assert oo**(1 + I) is S.ComplexInfinity + assert oo**(-1 + I) is S.Zero + assert (-oo)**I is S.NaN + assert (-oo)**(-1 + I) is S.Zero + assert oo**t == Pow(oo, t, evaluate=False) + assert (-oo)**t == Pow(-oo, t, evaluate=False) + + +def test_invert_numbers(): + assert S(2).invert(5) == 3 + assert S(2).invert(Rational(5, 2)) == S.Half + assert S(2).invert(5.) == S.Half + assert S(2).invert(S(5)) == 3 + assert S(2.).invert(5) == 0.5 + assert S(sqrt(2)).invert(5) == 1/sqrt(2) + assert S(sqrt(2)).invert(sqrt(3)) == 1/sqrt(2) + + +def test_mod_inverse(): + assert mod_inverse(3, 11) == 4 + assert mod_inverse(5, 11) == 9 + assert mod_inverse(21124921, 521512) == 7713 + assert mod_inverse(124215421, 5125) == 2981 + assert mod_inverse(214, 12515) == 1579 + assert mod_inverse(5823991, 3299) == 1442 + assert mod_inverse(123, 44) == 39 + assert mod_inverse(2, 5) == 3 + assert mod_inverse(-2, 5) == 2 + assert mod_inverse(2, -5) == -2 + assert mod_inverse(-2, -5) == -3 + assert mod_inverse(-3, -7) == -5 + x = Symbol('x') + assert S(2).invert(x) == S.Half + raises(TypeError, lambda: mod_inverse(2, x)) + raises(ValueError, lambda: mod_inverse(2, S.Half)) + raises(ValueError, lambda: mod_inverse(2, cos(1)**2 + sin(1)**2)) + + +def test_golden_ratio_rewrite_as_sqrt(): + assert GoldenRatio.rewrite(sqrt) == S.Half + sqrt(5)*S.Half + + +def test_tribonacci_constant_rewrite_as_sqrt(): + assert TribonacciConstant.rewrite(sqrt) == \ + (1 + cbrt(19 - 3*sqrt(33)) + cbrt(19 + 3*sqrt(33))) / 3 + + +def test_comparisons_with_unknown_type(): + class Foo: + """ + Class that is unaware of Basic, and relies on both classes returning + the NotImplemented singleton for equivalence to evaluate to False. + + """ + + ni, nf, nr = Integer(3), Float(1.0), Rational(1, 3) + foo = Foo() + + for n in ni, nf, nr, oo, -oo, zoo, nan: + assert n != foo + assert foo != n + assert not n == foo + assert not foo == n + raises(TypeError, lambda: n < foo) + raises(TypeError, lambda: foo > n) + raises(TypeError, lambda: n > foo) + raises(TypeError, lambda: foo < n) + raises(TypeError, lambda: n <= foo) + raises(TypeError, lambda: foo >= n) + raises(TypeError, lambda: n >= foo) + raises(TypeError, lambda: foo <= n) + + class Bar: + """ + Class that considers itself equal to any instance of Number except + infinities and nans, and relies on SymPy types returning the + NotImplemented singleton for symmetric equality relations. + + """ + def __eq__(self, other): + if other in (oo, -oo, zoo, nan): + return False + if isinstance(other, Number): + return True + return NotImplemented + + def __ne__(self, other): + return not self == other + + bar = Bar() + + for n in ni, nf, nr: + assert n == bar + assert bar == n + assert not n != bar + assert not bar != n + + for n in oo, -oo, zoo, nan: + assert n != bar + assert bar != n + assert not n == bar + assert not bar == n + + for n in ni, nf, nr, oo, -oo, zoo, nan: + raises(TypeError, lambda: n < bar) + raises(TypeError, lambda: bar > n) + raises(TypeError, lambda: n > bar) + raises(TypeError, lambda: bar < n) + raises(TypeError, lambda: n <= bar) + raises(TypeError, lambda: bar >= n) + raises(TypeError, lambda: n >= bar) + raises(TypeError, lambda: bar <= n) + + +def test_NumberSymbol_comparison(): + from sympy.core.tests.test_relational import rel_check + rpi = Rational('905502432259640373/288230376151711744') + fpi = Float(float(pi)) + assert rel_check(rpi, fpi) + + +def test_Integer_precision(): + # Make sure Integer inputs for keyword args work + assert Float('1.0', dps=Integer(15))._prec == 53 + assert Float('1.0', precision=Integer(15))._prec == 15 + assert type(Float('1.0', precision=Integer(15))._prec) == int + assert sympify(srepr(Float('1.0', precision=15))) == Float('1.0', precision=15) + + +def test_numpy_to_float(): + from sympy.testing.pytest import skip + from sympy.external import import_module + np = import_module('numpy') + if not np: + skip('numpy not installed. Abort numpy tests.') + + def check_prec_and_relerr(npval, ratval): + prec = np.finfo(npval).nmant + 1 + x = Float(npval) + assert x._prec == prec + y = Float(ratval, precision=prec) + assert abs((x - y)/y) < 2**(-(prec + 1)) + + check_prec_and_relerr(np.float16(2.0/3), Rational(2, 3)) + check_prec_and_relerr(np.float32(2.0/3), Rational(2, 3)) + check_prec_and_relerr(np.float64(2.0/3), Rational(2, 3)) + # extended precision, on some arch/compilers: + x = np.longdouble(2)/3 + check_prec_and_relerr(x, Rational(2, 3)) + y = Float(x, precision=10) + assert same_and_same_prec(y, Float(Rational(2, 3), precision=10)) + + raises(TypeError, lambda: Float(np.complex64(1+2j))) + raises(TypeError, lambda: Float(np.complex128(1+2j))) + + +def test_Integer_ceiling_floor(): + a = Integer(4) + + assert a.floor() == a + assert a.ceiling() == a + + +def test_ComplexInfinity(): + assert zoo.floor() is zoo + assert zoo.ceiling() is zoo + assert zoo**zoo is S.NaN + + +def test_Infinity_floor_ceiling_power(): + assert oo.floor() is oo + assert oo.ceiling() is oo + assert oo**S.NaN is S.NaN + assert oo**zoo is S.NaN + + +def test_One_power(): + assert S.One**12 is S.One + assert S.NegativeOne**S.NaN is S.NaN + + +def test_NegativeInfinity(): + assert (-oo).floor() is -oo + assert (-oo).ceiling() is -oo + assert (-oo)**11 is -oo + assert (-oo)**12 is oo + + +def test_issue_6133(): + raises(TypeError, lambda: (-oo < None)) + raises(TypeError, lambda: (S(-2) < None)) + raises(TypeError, lambda: (oo < None)) + raises(TypeError, lambda: (oo > None)) + raises(TypeError, lambda: (S(2) < None)) + + +def test_abc(): + x = numbers.Float(5) + assert(isinstance(x, nums.Number)) + assert(isinstance(x, numbers.Number)) + assert(isinstance(x, nums.Real)) + y = numbers.Rational(1, 3) + assert(isinstance(y, nums.Number)) + assert(y.numerator == 1) + assert(y.denominator == 3) + assert(isinstance(y, nums.Rational)) + z = numbers.Integer(3) + assert(isinstance(z, nums.Number)) + assert(isinstance(z, numbers.Number)) + assert(isinstance(z, nums.Rational)) + assert(isinstance(z, numbers.Rational)) + assert(isinstance(z, nums.Integral)) + + +def test_floordiv(): + assert S(2)//S.Half == 4 + + +def test_negation(): + assert -S.Zero is S.Zero + assert -Float(0) is not S.Zero and -Float(0) == 0.0 + + +def test_exponentiation_of_0(): + x = Symbol('x') + assert 0**-x == zoo**x + assert unchanged(Pow, 0, x) + x = Symbol('x', zero=True) + assert 0**-x == S.One + assert 0**x == S.One + + +def test_int_valued(): + x = Symbol('x') + assert int_valued(x) == False + assert int_valued(S.Half) == False + assert int_valued(S.One) == True + assert int_valued(Float(1)) == True + assert int_valued(Float(1.1)) == False + assert int_valued(pi) == False + + +def test_equal_valued(): + x = Symbol('x') + + equal_values = [ + [1, 1.0, S(1), S(1.0), S(1).n(5)], + [2, 2.0, S(2), S(2.0), S(2).n(5)], + [-1, -1.0, -S(1), -S(1.0), -S(1).n(5)], + [0.5, S(0.5), S(1)/2], + [-0.5, -S(0.5), -S(1)/2], + [0, 0.0, S(0), S(0.0), S(0).n()], + [pi], [pi.n()], # <-- not equal + [S(1)/10], [0.1, S(0.1)], # <-- not equal + [S(0.1).n(5)], + [oo], + [cos(x/2)], [cos(0.5*x)], # <-- no recursion + ] + + for m, values_m in enumerate(equal_values): + for value_i in values_m: + + # All values in same list equal + for value_j in values_m: + assert equal_valued(value_i, value_j) is True + + # Not equal to anything in any other list: + for n, values_n in enumerate(equal_values): + if n == m: + continue + for value_j in values_n: + assert equal_valued(value_i, value_j) is False + + +def test_all_close(): + x = Symbol('x') + y = Symbol('y') + z = Symbol('z') + assert all_close(2, 2) is True + assert all_close(2, 2.0000) is True + assert all_close(2, 2.0001) is False + assert all_close(1/3, 1/3.0001) is False + assert all_close(1/3, 1/3.0001, 1e-3, 1e-3) is True + assert all_close(1/3, Rational(1, 3)) is True + assert all_close(0.1*exp(0.2*x), exp(x/5)/10) is True + # The expressions should be structurally the same modulo identity: + assert all_close(1.4142135623730951, sqrt(2)) is False + assert all_close(1.4142135623730951, sqrt(2).evalf()) is True + assert all_close(x + 1e-20, x) is True + # We should be able to match terms of an Add/Mul in any order + assert all_close(Add(1, 2, evaluate=False), Add(2, 1, evaluate=False)) + # coverage + assert not all_close(2*x, 3*x) + assert all_close(2*x, 3*x, 1) + assert not all_close(2*x, 3*x, 0, 0.5) + assert all_close(2*x, 3*x, 0, 1) + assert not all_close(y*x, z*x) + assert all_close(2*x*exp(1.0*x), 2.0*x*exp(x)) + assert not all_close(2*x*exp(1.0*x), 2.0*x*exp(2.*x)) + assert all_close(x + 2.*y, 1.*x + 2*y) + assert all_close(x + exp(2.*x)*y, 1.*x + exp(2*x)*y) + assert not all_close(x + exp(2.*x)*y, 1.*x + 2*exp(2*x)*y) + assert not all_close(x + exp(2.*x)*y, 1.*x + exp(3*x)*y) + assert not all_close(x + 2.*y, 1.*x + 3*y) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_operations.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_operations.py new file mode 100644 index 0000000000000000000000000000000000000000..c60d691ef00ee9601ada04ef68e2db37794a81ad --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_operations.py @@ -0,0 +1,110 @@ +from sympy.core.expr import Expr +from sympy.core.numbers import Integer +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.core.operations import AssocOp, LatticeOp +from sympy.testing.pytest import raises +from sympy.core.sympify import SympifyError +from sympy.core.add import Add, add +from sympy.core.mul import Mul, mul + +# 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) + assert join(0, 2) == 0 + assert join(1, 2) == 2 + assert join(2, 2) == 2 + + assert join(join(2, 3), 4) == join(2, 3, 4) + assert join() == 1 + 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(join(2, 3, 4)) == {S(2), S(3), S(4)} + assert join.make_args(0) == {0} + assert list(join.make_args(0))[0] is S.Zero + assert Add.make_args(0)[0] is S.Zero + + +def test_issue_14025(): + a, b, c, d = symbols('a,b,c,d', commutative=False) + assert Mul(a, b, c).has(c*b) == False + assert Mul(a, b, c).has(b*c) == True + assert Mul(a, b, c, d).has(b*c*d) == True + + +def test_AssocOp_flatten(): + a, b, c, d = symbols('a,b,c,d') + + class MyAssoc(AssocOp): + identity = S.One + + assert MyAssoc(a, MyAssoc(b, c)).args == \ + MyAssoc(MyAssoc(a, b), c).args == \ + MyAssoc(MyAssoc(a, b, c)).args == \ + MyAssoc(a, b, c).args == \ + (a, b, c) + u = MyAssoc(b, c) + v = MyAssoc(u, d, evaluate=False) + assert v.args == (u, d) + # like Add, any unevaluated outer call will flatten inner args + assert MyAssoc(a, v).args == (a, b, c, d) + + +def test_add_dispatcher(): + + class NewBase(Expr): + @property + def _add_handler(self): + return NewAdd + class NewAdd(NewBase, Add): + pass + add.register_handlerclass((Add, NewAdd), NewAdd) + + a, b = Symbol('a'), NewBase() + + # Add called as fallback + assert add(1, 2) == Add(1, 2) + assert add(a, a) == Add(a, a) + + # selection by registered priority + assert add(a,b,a) == NewAdd(2*a, b) + + +def test_mul_dispatcher(): + + class NewBase(Expr): + @property + def _mul_handler(self): + return NewMul + class NewMul(NewBase, Mul): + pass + mul.register_handlerclass((Mul, NewMul), NewMul) + + a, b = Symbol('a'), NewBase() + + # Mul called as fallback + assert mul(1, 2) == Mul(1, 2) + assert mul(a, a) == Mul(a, a) + + # selection by registered priority + assert mul(a,b,a) == NewMul(a**2, b) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_parameters.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_parameters.py new file mode 100644 index 0000000000000000000000000000000000000000..21e03d717872a9a8165ceeebf7ef58e9842702c0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_parameters.py @@ -0,0 +1,126 @@ +from sympy.abc import x, y +from sympy.core.parameters import evaluate +from sympy.core import Mul, Add, Pow, S +from sympy.core.numbers import oo +from sympy.functions.elementary.miscellaneous import sqrt + +def test_add(): + with evaluate(False): + p = oo - oo + assert isinstance(p, Add) and p.args == (oo, -oo) + p = 5 - oo + assert isinstance(p, Add) and p.args == (-oo, 5) + p = oo - 5 + assert isinstance(p, Add) and p.args == (oo, -5) + p = oo + 5 + assert isinstance(p, Add) and p.args == (oo, 5) + p = 5 + oo + assert isinstance(p, Add) and p.args == (oo, 5) + p = -oo + 5 + assert isinstance(p, Add) and p.args == (-oo, 5) + p = -5 - oo + assert isinstance(p, Add) and p.args == (-oo, -5) + + with evaluate(False): + expr = x + x + assert isinstance(expr, Add) + assert expr.args == (x, x) + + with evaluate(True): + assert (x + x).args == (2, x) + + assert (x + x).args == (x, x) + + assert isinstance(x + x, Mul) + + with evaluate(False): + assert S.One + 1 == Add(1, 1) + assert 1 + S.One == Add(1, 1) + + assert S(4) - 3 == Add(4, -3) + assert -3 + S(4) == Add(4, -3) + + assert S(2) * 4 == Mul(2, 4) + assert 4 * S(2) == Mul(2, 4) + + assert S(6) / 3 == Mul(6, Pow(3, -1)) + assert S.One / 3 * 6 == Mul(S.One / 3, 6) + + assert 9 ** S(2) == Pow(9, 2) + assert S(2) ** 9 == Pow(2, 9) + + assert S(2) / 2 == Mul(2, Pow(2, -1)) + assert S.One / 2 * 2 == Mul(S.One / 2, 2) + + assert S(2) / 3 + 1 == Add(S(2) / 3, 1) + assert 1 + S(2) / 3 == Add(1, S(2) / 3) + + assert S(4) / 7 - 3 == Add(S(4) / 7, -3) + assert -3 + S(4) / 7 == Add(-3, S(4) / 7) + + assert S(2) / 4 * 4 == Mul(S(2) / 4, 4) + assert 4 * (S(2) / 4) == Mul(4, S(2) / 4) + + assert S(6) / 3 == Mul(6, Pow(3, -1)) + assert S.One / 3 * 6 == Mul(S.One / 3, 6) + + assert S.One / 3 + sqrt(3) == Add(S.One / 3, sqrt(3)) + assert sqrt(3) + S.One / 3 == Add(sqrt(3), S.One / 3) + + assert S.One / 2 * 10.333 == Mul(S.One / 2, 10.333) + assert 10.333 * (S.One / 2) == Mul(10.333, S.One / 2) + + assert sqrt(2) * sqrt(2) == Mul(sqrt(2), sqrt(2)) + + assert S.One / 2 + x == Add(S.One / 2, x) + assert x + S.One / 2 == Add(x, S.One / 2) + + assert S.One / x * x == Mul(S.One / x, x) + assert x * (S.One / x) == Mul(x, Pow(x, -1)) + + assert S.One / 3 == Pow(3, -1) + assert S.One / x == Pow(x, -1) + assert 1 / S(3) == Pow(3, -1) + assert 1 / x == Pow(x, -1) + +def test_nested(): + with evaluate(False): + expr = (x + x) + (y + y) + assert expr.args == ((x + x), (y + y)) + assert expr.args[0].args == (x, x) + +def test_reentrantcy(): + with evaluate(False): + expr = x + x + assert expr.args == (x, x) + with evaluate(True): + expr = x + x + assert expr.args == (2, x) + expr = x + x + assert expr.args == (x, x) + +def test_reusability(): + f = evaluate(False) + + with f: + expr = x + x + assert expr.args == (x, x) + + expr = x + x + assert expr.args == (2, x) + + with f: + expr = x + x + assert expr.args == (x, x) + + # Assure reentrancy with reusability + ctx = evaluate(False) + with ctx: + expr = x + x + assert expr.args == (x, x) + with ctx: + expr = x + x + assert expr.args == (x, x) + + expr = x + x + assert expr.args == (2, x) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_power.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_power.py new file mode 100644 index 0000000000000000000000000000000000000000..80ae48c525c20da6153deffbc9feadef81acf527 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_power.py @@ -0,0 +1,670 @@ +from sympy.core import ( + Basic, Rational, Symbol, S, Float, Integer, Mul, Number, Pow, + Expr, I, nan, pi, symbols, oo, zoo, N) +from sympy.core.parameters import global_parameters +from sympy.core.tests.test_evalf import NS +from sympy.core.function import expand_multinomial +from sympy.functions.elementary.miscellaneous import sqrt, cbrt +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.special.error_functions import erf +from sympy.functions.elementary.trigonometric import ( + sin, cos, tan, sec, csc, atan) +from sympy.functions.elementary.hyperbolic import cosh, sinh, tanh +from sympy.polys import Poly +from sympy.series.order import O +from sympy.sets import FiniteSet +from sympy.core.power import power +from sympy.core.intfunc import integer_nthroot +from sympy.testing.pytest import warns, _both_exp_pow +from sympy.utilities.exceptions import SymPyDeprecationWarning +from sympy.abc import a, b, c, x, y +from sympy.core.numbers import all_close + +def test_rational(): + a = Rational(1, 5) + + r = sqrt(5)/5 + assert sqrt(a) == r + assert 2*sqrt(a) == 2*r + + r = a*a**S.Half + assert a**Rational(3, 2) == r + assert 2*a**Rational(3, 2) == 2*r + + r = a**5*a**Rational(2, 3) + 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)) + + +def test_negative_real(): + def feq(a, b): + return abs(a - b) < 1E-10 + + assert feq(S.One / Float(-0.5), -Integer(2)) + + +def test_expand(): + assert (2**(-1 - x)).expand() == S.Half*2**(-x) + + +def test_issue_3449(): + #test if powers are simplified correctly + #see also issue 3995 + 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 (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 + + 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 (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**2)**b == (a**b)**2 + assert (a**Rational(2, 3))**x == a**(x*Rational(2, 3)) != (a**x)**Rational(2, 3) + + +def test_issue_3866(): + 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_issue_4362(): + neg = Symbol('neg', negative=True) + nonneg = Symbol('nonneg', nonnegative=True) + any = Symbol('any') + num, den = sqrt(1/neg).as_numer_denom() + assert num == sqrt(-1) + assert den == sqrt(-neg) + num, den = sqrt(1/nonneg).as_numer_denom() + assert num == 1 + assert den == sqrt(nonneg) + num, den = sqrt(1/any).as_numer_denom() + assert num == sqrt(1/any) + assert den == 1 + + def eqn(num, den, pow): + return (num/den)**pow + 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) + # 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 is False 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 is False and eq.as_numer_denom() == (-(-npos)**pow*(-dneg)**pow, npos) + 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) + 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 eq.is_Pow and 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.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 eq.is_Pow and 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) + + assert ((1/(1 + x/3))**(-S.One)).as_numer_denom() == (3 + x, 3) + 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) + + n = Symbol('n', negative=True) + assert (x**n).as_numer_denom() == (1, x**-n) + assert sqrt(1/n).as_numer_denom() == (S.ImaginaryUnit, sqrt(-n)) + n = Symbol('0 or neg', nonpositive=True) + # if x and n are split up without negating each term and n is negative + # then the answer might be wrong; if n is 0 it won't matter since + # 1/oo and 1/zoo are both zero as is sqrt(0)/sqrt(-x) unless x is also + # zero (in which case the negative sign doesn't matter): + # 1/sqrt(1/-1) = -I but sqrt(-1)/sqrt(1) = I + assert (1/sqrt(x/n)).as_numer_denom() == (sqrt(-n), sqrt(-x)) + c = Symbol('c', complex=True) + e = sqrt(1/c) + assert e.as_numer_denom() == (e, 1) + i = Symbol('i', integer=True) + assert ((1 + x/y)**i).as_numer_denom() == ((x + y)**i, y**i) + + +def test_Pow_Expr_args(): + bases = [Basic(), Poly(x, x), FiniteSet(x)] + for base in bases: + # The cache can mess with the stacklevel test + with warns(SymPyDeprecationWarning, test_stacklevel=False): + Pow(base, S.One) + + +def test_Pow_signs(): + """Cf. issues 4595 and 5250""" + 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 + + +def test_power_with_noncommutative_mul_as_base(): + x = Symbol('x', commutative=False) + y = Symbol('y', commutative=False) + assert not (x*y)**3 == x**3*y**3 + assert (2*x*y)**3 == 8*(x*y)**3 + + +@_both_exp_pow +def test_power_rewrite_exp(): + assert (I**I).rewrite(exp) == exp(-pi/2) + + expr = (2 + 3*I)**(4 + 5*I) + assert expr.rewrite(exp) == exp((4 + 5*I)*(log(sqrt(13)) + I*atan(Rational(3, 2)))) + assert expr.rewrite(exp).expand() == \ + 169*exp(5*I*log(13)/2)*exp(4*I*atan(Rational(3, 2)))*exp(-5*atan(Rational(3, 2))) + + assert ((6 + 7*I)**5).rewrite(exp) == 7225*sqrt(85)*exp(5*I*atan(Rational(7, 6))) + + expr = 5**(6 + 7*I) + assert expr.rewrite(exp) == exp((6 + 7*I)*log(5)) + assert expr.rewrite(exp).expand() == 15625*exp(7*I*log(5)) + + assert Pow(123, 789, evaluate=False).rewrite(exp) == 123**789 + assert (1**I).rewrite(exp) == 1**I + assert (0**I).rewrite(exp) == 0**I + + expr = (-2)**(2 + 5*I) + assert expr.rewrite(exp) == exp((2 + 5*I)*(log(2) + I*pi)) + assert expr.rewrite(exp).expand() == 4*exp(-5*pi)*exp(5*I*log(2)) + + assert ((-2)**S(-5)).rewrite(exp) == (-2)**S(-5) + + x, y = symbols('x y') + assert (x**y).rewrite(exp) == exp(y*log(x)) + if global_parameters.exp_is_pow: + assert (7**x).rewrite(exp) == Pow(S.Exp1, x*log(7), evaluate=False) + else: + assert (7**x).rewrite(exp) == exp(x*log(7), evaluate=False) + assert ((2 + 3*I)**x).rewrite(exp) == exp(x*(log(sqrt(13)) + I*atan(Rational(3, 2)))) + assert (y**(5 + 6*I)).rewrite(exp) == exp(log(y)*(5 + 6*I)) + + assert all((1/func(x)).rewrite(exp) == 1/(func(x).rewrite(exp)) for func in + (sin, cos, tan, sec, csc, sinh, cosh, tanh)) + + +def test_zero(): + assert 0**x != 0 + assert 0**(2*x) == 0**x + assert 0**(1.0*x) == 0**x + assert 0**(2.0*x) == 0**x + assert (0**(2 - x)).as_base_exp() == (0, 2 - x) + assert 0**(x - 2) != S.Infinity**(2 - x) + assert 0**(2*x*y) == 0**(x*y) + assert 0**(-2*x*y) == S.ComplexInfinity**(x*y) + assert Float(0)**2 is not S.Zero + assert Float(0)**2 == 0.0 + assert Float(0)**-2 is zoo + assert Float(0)**oo is S.Zero + + #Test issue 19572 + assert 0 ** -oo is zoo + assert power(0, -oo) is zoo + assert Float(0)**-oo is zoo + +def test_pow_as_base_exp(): + assert (S.Infinity**(2 - x)).as_base_exp() == (S.Infinity, 2 - x) + assert (S.Infinity**(x - 2)).as_base_exp() == (S.Infinity, x - 2) + p = S.Half**x + assert p.base, p.exp == p.as_base_exp() == (S(2), -x) + p = (S(3)/2)**x + assert p.base, p.exp == p.as_base_exp() == (3*S.Half, x) + p = (S(2)/3)**x + assert p.as_base_exp() == (S(2)/3, x) + assert p.base, p.exp == (S(2)/3, x) + # issue 8344: + assert Pow(1, 2, evaluate=False).as_base_exp() == (S.One, S(2)) + + +def test_nseries(): + assert sqrt(I*x - 1)._eval_nseries(x, 4, None, 1) == I + x/2 + I*x**2/8 - x**3/16 + O(x**4) + assert sqrt(I*x - 1)._eval_nseries(x, 4, None, -1) == -I - x/2 - I*x**2/8 + x**3/16 + O(x**4) + assert cbrt(I*x - 1)._eval_nseries(x, 4, None, 1) == (-1)**(S(1)/3) - (-1)**(S(5)/6)*x/3 + \ + (-1)**(S(1)/3)*x**2/9 + 5*(-1)**(S(5)/6)*x**3/81 + O(x**4) + assert cbrt(I*x - 1)._eval_nseries(x, 4, None, -1) == -(-1)**(S(2)/3) - (-1)**(S(1)/6)*x/3 - \ + (-1)**(S(2)/3)*x**2/9 + 5*(-1)**(S(1)/6)*x**3/81 + O(x**4) + assert (1 / (exp(-1/x) + 1/x))._eval_nseries(x, 2, None) == x + O(x**2) + # test issue 23752 + assert sqrt(-I*x**2 + x - 3)._eval_nseries(x, 4, None, 1) == -sqrt(3)*I + sqrt(3)*I*x/6 - \ + sqrt(3)*I*x**2*(-S(1)/72 + I/6) - sqrt(3)*I*x**3*(-S(1)/432 + I/36) + O(x**4) + assert sqrt(-I*x**2 + x - 3)._eval_nseries(x, 4, None, -1) == -sqrt(3)*I + sqrt(3)*I*x/6 - \ + sqrt(3)*I*x**2*(-S(1)/72 + I/6) - sqrt(3)*I*x**3*(-S(1)/432 + I/36) + O(x**4) + assert cbrt(-I*x**2 + x - 3)._eval_nseries(x, 4, None, 1) == -(-1)**(S(2)/3)*3**(S(1)/3) + \ + (-1)**(S(2)/3)*3**(S(1)/3)*x/9 - (-1)**(S(2)/3)*3**(S(1)/3)*x**2*(-S(1)/81 + I/9) - \ + (-1)**(S(2)/3)*3**(S(1)/3)*x**3*(-S(5)/2187 + 2*I/81) + O(x**4) + assert cbrt(-I*x**2 + x - 3)._eval_nseries(x, 4, None, -1) == -(-1)**(S(2)/3)*3**(S(1)/3) + \ + (-1)**(S(2)/3)*3**(S(1)/3)*x/9 - (-1)**(S(2)/3)*3**(S(1)/3)*x**2*(-S(1)/81 + I/9) - \ + (-1)**(S(2)/3)*3**(S(1)/3)*x**3*(-S(5)/2187 + 2*I/81) + O(x**4) + + +def test_issue_6100_12942_4473(): + assert x**1.0 != x + assert x != x**1.0 + assert True != x**1.0 + assert x**1.0 is not True + assert x is not True + assert x*y != (x*y)**1.0 + # Pow != Symbol + assert (x**1.0)**1.0 != x + assert (x**1.0)**2.0 != x**2 + b = Expr() + assert Pow(b, 1.0, evaluate=False) != b + # if the following gets distributed as a Mul (x**1.0*y**1.0 then + # __eq__ methods could be added to Symbol and Pow to detect the + # power-of-1.0 case. + assert ((x*y)**1.0).func is Pow + + +def test_issue_6208(): + from sympy.functions.elementary.miscellaneous import root + assert sqrt(33**(I*9/10)) == -33**(I*9/20) + 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) + assert sqrt(exp(5*I)) == -exp(5*I/2) + assert root(exp(5*I), 3).exp == Rational(1, 3) + + +def test_issue_6990(): + assert (sqrt(a + b*x + x**2)).series(x, 0, 3).removeO() == \ + sqrt(a)*x**2*(1/(2*a) - b**2/(8*a**2)) + sqrt(a) + b*x/(2*sqrt(a)) + + +def test_issue_6068(): + assert sqrt(sin(x)).series(x, 0, 7) == \ + sqrt(x) - x**Rational(5, 2)/12 + x**Rational(9, 2)/1440 - \ + x**Rational(13, 2)/24192 + O(x**7) + assert sqrt(sin(x)).series(x, 0, 9) == \ + sqrt(x) - x**Rational(5, 2)/12 + x**Rational(9, 2)/1440 - \ + x**Rational(13, 2)/24192 - 67*x**Rational(17, 2)/29030400 + O(x**9) + assert sqrt(sin(x**3)).series(x, 0, 19) == \ + x**Rational(3, 2) - x**Rational(15, 2)/12 + x**Rational(27, 2)/1440 + O(x**19) + assert sqrt(sin(x**3)).series(x, 0, 20) == \ + x**Rational(3, 2) - x**Rational(15, 2)/12 + x**Rational(27, 2)/1440 - \ + x**Rational(39, 2)/24192 + O(x**20) + + +def test_issue_6782(): + assert sqrt(sin(x**3)).series(x, 0, 7) == x**Rational(3, 2) + O(x**7) + assert sqrt(sin(x**4)).series(x, 0, 3) == x**2 + O(x**3) + + +def test_issue_6653(): + assert (1 / sqrt(1 + sin(x**2))).series(x, 0, 3) == 1 - x**2/2 + O(x**3) + + +def test_issue_6429(): + f = (c**2 + x)**(0.5) + assert f.series(x, x0=0, n=1) == (c**2)**0.5 + O(x) + assert f.taylor_term(0, x) == (c**2)**0.5 + assert f.taylor_term(1, x) == 0.5*x*(c**2)**(-0.5) + assert f.taylor_term(2, x) == -0.125*x**2*(c**2)**(-1.5) + + +def test_issue_7638(): + f = pi/log(sqrt(2)) + assert ((1 + I)**(I*f/2))**0.3 == (1 + I)**(0.15*I*f) + # if 1/3 -> 1.0/3 this should fail since it cannot be shown that the + # sign will be +/-1; for the previous "small arg" case, it didn't matter + # that this could not be proved + assert (1 + I)**(4*I*f) == ((1 + I)**(12*I*f))**Rational(1, 3) + + assert (((1 + I)**(I*(1 + 7*f)))**Rational(1, 3)).exp == Rational(1, 3) + r = symbols('r', real=True) + assert sqrt(r**2) == abs(r) + assert cbrt(r**3) != r + assert sqrt(Pow(2*I, 5*S.Half)) != (2*I)**Rational(5, 4) + p = symbols('p', positive=True) + assert cbrt(p**2) == p**Rational(2, 3) + assert NS(((0.2 + 0.7*I)**(0.7 + 1.0*I))**(0.5 - 0.1*I), 1) == '0.4 + 0.2*I' + assert sqrt(1/(1 + I)) == sqrt(1 - I)/sqrt(2) # or 1/sqrt(1 + I) + e = 1/(1 - sqrt(2)) + assert sqrt(e) == I/sqrt(-1 + sqrt(2)) + assert e**Rational(-1, 2) == -I*sqrt(-1 + sqrt(2)) + assert sqrt((cos(1)**2 + sin(1)**2 - 1)**(3 + I)).exp in [S.Half, + Rational(3, 2) + I/2] + assert sqrt(r**Rational(4, 3)) != r**Rational(2, 3) + assert sqrt((p + I)**Rational(4, 3)) == (p + I)**Rational(2, 3) + + for q in 1+I, 1-I: + assert sqrt(q**2) == q + for q in -1+I, -1-I: + assert sqrt(q**2) == -q + + assert sqrt((p + r*I)**2) != p + r*I + e = (1 + I/5) + assert sqrt(e**5) == e**(5*S.Half) + assert sqrt(e**6) == e**3 + assert sqrt((1 + I*r)**6) != (1 + I*r)**3 + + +def test_issue_8582(): + assert 1**oo is nan + assert 1**(-oo) is nan + assert 1**zoo is nan + assert 1**(oo + I) is nan + assert 1**(1 + I*oo) is nan + assert 1**(oo + I*oo) is nan + + +def test_issue_8650(): + n = Symbol('n', integer=True, nonnegative=True) + assert (n**n).is_positive is True + x = 5*n + 5 + assert (x**(5*(n + 1))).is_positive is True + + +def test_issue_13914(): + b = Symbol('b') + assert (-1)**zoo is nan + assert 2**zoo is nan + assert (S.Half)**(1 + zoo) is nan + assert I**(zoo + I) is nan + assert b**(I + zoo) is nan + + +def test_better_sqrt(): + n = Symbol('n', integer=True, nonnegative=True) + assert sqrt(3 + 4*I) == 2 + I + assert sqrt(3 - 4*I) == 2 - I + assert sqrt(-3 - 4*I) == 1 - 2*I + assert sqrt(-3 + 4*I) == 1 + 2*I + assert sqrt(32 + 24*I) == 6 + 2*I + assert sqrt(32 - 24*I) == 6 - 2*I + assert sqrt(-32 - 24*I) == 2 - 6*I + assert sqrt(-32 + 24*I) == 2 + 6*I + + # triple (3, 4, 5): + # parity of 3 matches parity of 5 and + # den, 4, is a square + assert sqrt((3 + 4*I)/4) == 1 + I/2 + # triple (8, 15, 17) + # parity of 8 doesn't match parity of 17 but + # den/2, 8/2, is a square + assert sqrt((8 + 15*I)/8) == (5 + 3*I)/4 + # handle the denominator + assert sqrt((3 - 4*I)/25) == (2 - I)/5 + assert sqrt((3 - 4*I)/26) == (2 - I)/sqrt(26) + # mul + # issue #12739 + assert sqrt((3 + 4*I)/(3 - 4*I)) == (3 + 4*I)/5 + assert sqrt(2/(3 + 4*I)) == sqrt(2)/5*(2 - I) + assert sqrt(n/(3 + 4*I)).subs(n, 2) == sqrt(2)/5*(2 - I) + assert sqrt(-2/(3 + 4*I)) == sqrt(2)/5*(1 + 2*I) + assert sqrt(-n/(3 + 4*I)).subs(n, 2) == sqrt(2)/5*(1 + 2*I) + # power + assert sqrt(1/(3 + I*4)) == (2 - I)/5 + assert sqrt(1/(3 - I)) == sqrt(10)*sqrt(3 + I)/10 + # symbolic + i = symbols('i', imaginary=True) + assert sqrt(3/i) == Mul(sqrt(3), 1/sqrt(i), evaluate=False) + # multiples of 1/2; don't make this too automatic + assert sqrt(3 + 4*I)**3 == (2 + I)**3 + assert Pow(3 + 4*I, Rational(3, 2)) == 2 + 11*I + assert Pow(6 + 8*I, Rational(3, 2)) == 2*sqrt(2)*(2 + 11*I) + n, d = (3 + 4*I), (3 - 4*I)**3 + a = n/d + assert a.args == (1/d, n) + eq = sqrt(a) + assert eq.args == (a, S.Half) + assert expand_multinomial(eq) == sqrt((-117 + 44*I)*(3 + 4*I))/125 + assert eq.expand() == (7 - 24*I)/125 + + # issue 12775 + # pos im part + assert sqrt(2*I) == (1 + I) + assert sqrt(2*9*I) == Mul(3, 1 + I, evaluate=False) + assert Pow(2*I, 3*S.Half) == (1 + I)**3 + # neg im part + assert sqrt(-I/2) == Mul(S.Half, 1 - I, evaluate=False) + # fractional im part + assert Pow(Rational(-9, 2)*I, Rational(3, 2)) == 27*(1 - I)**3/8 + + +def test_issue_2993(): + assert str((2.3*x - 4)**0.3) == '(2.3*x - 4)**0.3' + assert str((2.3*x + 4)**0.3) == '(2.3*x + 4)**0.3' + assert str((-2.3*x + 4)**0.3) == '(4 - 2.3*x)**0.3' + assert str((-2.3*x - 4)**0.3) == '(-2.3*x - 4)**0.3' + assert str((2.3*x - 2)**0.3) == '(2.3*x - 2)**0.3' + assert str((-2.3*x - 2)**0.3) == '(-2.3*x - 2)**0.3' + assert str((-2.3*x + 2)**0.3) == '(2 - 2.3*x)**0.3' + assert str((2.3*x + 2)**0.3) == '(2.3*x + 2)**0.3' + assert str((2.3*x - 4)**Rational(1, 3)) == '(2.3*x - 4)**(1/3)' + eq = (2.3*x + 4) + assert str(eq**2) == '(2.3*x + 4)**2' + assert (1/eq).args == (eq, -1) # don't change trivial power + # issue 17735 + q=.5*exp(x) - .5*exp(-x) + 0.1 + assert int((q**2).subs(x, 1)) == 1 + # issue 17756 + y = Symbol('y') + assert len(sqrt(x/(x + y)**2 + Float('0.008', 30)).subs(y, pi.n(25)).atoms(Float)) == 2 + # issue 17756 + a, b, c, d, e, f, g = symbols('a:g') + expr = sqrt(1 + a*(c**4 + g*d - 2*g*e - f*(-g + d))**2/ + (c**3*b**2*(d - 3*e + 2*f)**2))/2 + r = [ + (a, N('0.0170992456333788667034850458615', 30)), + (b, N('0.0966594956075474769169134801223', 30)), + (c, N('0.390911862903463913632151616184', 30)), + (d, N('0.152812084558656566271750185933', 30)), + (e, N('0.137562344465103337106561623432', 30)), + (f, N('0.174259178881496659302933610355', 30)), + (g, N('0.220745448491223779615401870086', 30))] + tru = expr.n(30, subs=dict(r)) + seq = expr.subs(r) + # although `tru` is the right way to evaluate + # expr with numerical values, `seq` will have + # significant loss of precision if extraction of + # the largest coefficient of a power's base's terms + # is done improperly + assert seq == tru + +def test_issue_17450(): + assert (erf(cosh(1)**7)**I).is_real is None + assert (erf(cosh(1)**7)**I).is_imaginary is False + assert (Pow(exp(1+sqrt(2)), ((1-sqrt(2))*I*pi), evaluate=False)).is_real is None + assert ((-10)**(10*I*pi/3)).is_real is False + assert ((-5)**(4*I*pi)).is_real is False + + +def test_issue_18190(): + assert sqrt(1 / tan(1 + I)) == 1 / sqrt(tan(1 + I)) + + +def test_issue_14815(): + x = Symbol('x', real=True) + assert sqrt(x).is_extended_negative is False + x = Symbol('x', real=False) + assert sqrt(x).is_extended_negative is None + x = Symbol('x', complex=True) + assert sqrt(x).is_extended_negative is False + x = Symbol('x', extended_real=True) + assert sqrt(x).is_extended_negative is False + assert sqrt(zoo, evaluate=False).is_extended_negative is False + assert sqrt(nan, evaluate=False).is_extended_negative is None + + +def test_issue_18509(): + x = Symbol('x', prime=True) + assert x**oo is oo + assert (1/x)**oo is S.Zero + assert (-1/x)**oo is S.Zero + assert (-x)**oo is zoo + assert (-oo)**(-1 + I) is S.Zero + assert (-oo)**(1 + I) is zoo + assert (oo)**(-1 + I) is S.Zero + assert (oo)**(1 + I) is zoo + + +def test_issue_18762(): + e, p = symbols('e p') + g0 = sqrt(1 + e**2 - 2*e*cos(p)) + assert len(g0.series(e, 1, 3).args) == 4 + + +def test_issue_21860(): + e = 3*2**Rational(66666666667,200000000000)*3**Rational(16666666667,50000000000)*x**Rational(66666666667, 200000000000) + ans = Mul(Rational(3, 2), + Pow(Integer(2), Rational(33333333333, 100000000000)), + Pow(Integer(3), Rational(26666666667, 40000000000))) + assert e.xreplace({x: Rational(3,8)}) == ans + + +def test_issue_21647(): + e = log((Integer(567)/500)**(811*(Integer(567)/500)**x/100)) + ans = log(Mul(Rational(64701150190720499096094005280169087619821081527, + 76293945312500000000000000000000000000000000000), + Pow(Integer(2), Rational(396204892125479941, 781250000000000000)), + Pow(Integer(3), Rational(385045107874520059, 390625000000000000)), + Pow(Integer(5), Rational(407364676376439823, 1562500000000000000)), + Pow(Integer(7), Rational(385045107874520059, 1562500000000000000)))) + assert e.xreplace({x: 6}) == ans + + +def test_issue_21762(): + e = (x**2 + 6)**(Integer(33333333333333333)/50000000000000000) + ans = Mul(Rational(5, 4), + Pow(Integer(2), Rational(16666666666666667, 25000000000000000)), + Pow(Integer(5), Rational(8333333333333333, 25000000000000000))) + assert e.xreplace({x: S.Half}) == ans + + +def test_issue_14704(): + a = 144**144 + x, xexact = integer_nthroot(a,a) + assert x == 1 and xexact is False + + +def test_rational_powers_larger_than_one(): + assert Rational(2, 3)**Rational(3, 2) == 2*sqrt(6)/9 + assert Rational(1, 6)**Rational(9, 4) == 6**Rational(3, 4)/216 + assert Rational(3, 7)**Rational(7, 3) == 9*3**Rational(1, 3)*7**Rational(2, 3)/343 + + +def test_power_dispatcher(): + + class NewBase(Expr): + pass + class NewPow(NewBase, Pow): + pass + a, b = Symbol('a'), NewBase() + + @power.register(Expr, NewBase) + @power.register(NewBase, Expr) + @power.register(NewBase, NewBase) + def _(a, b): + return NewPow(a, b) + + # Pow called as fallback + assert power(2, 3) == 8*S.One + assert power(a, 2) == Pow(a, 2) + assert power(a, a) == Pow(a, a) + + # NewPow called by dispatch + assert power(a, b) == NewPow(a, b) + assert power(b, a) == NewPow(b, a) + assert power(b, b) == NewPow(b, b) + + +def test_powers_of_I(): + assert [sqrt(I)**i for i in range(13)] == [ + 1, sqrt(I), I, sqrt(I)**3, -1, -sqrt(I), -I, -sqrt(I)**3, + 1, sqrt(I), I, sqrt(I)**3, -1] + assert sqrt(I)**(S(9)/2) == -I**(S(1)/4) + + +def test_issue_23918(): + b = S(2)/3 + assert (b**x).as_base_exp() == (b, x) + + +def test_issue_26546(): + x = Symbol('x', real=True) + assert x.is_extended_real is True + assert sqrt(x+I).is_extended_real is False + assert Pow(x+I, S.Half).is_extended_real is False + assert Pow(x+I, Rational(1,2)).is_extended_real is False + assert Pow(x+I, Rational(1,13)).is_extended_real is False + assert Pow(x+I, Rational(2,3)).is_extended_real is None + + +def test_issue_25165(): + e1 = (1/sqrt(( - x + 1)**2 + (x - 0.23)**4)).series(x, 0, 2) + e2 = 0.998603724830355 + 1.02004923189934*x + O(x**2) + assert all_close(e1, e2) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_priority.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_priority.py new file mode 100644 index 0000000000000000000000000000000000000000..276e653100f886243e07b866b699b8da53cdaf88 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_priority.py @@ -0,0 +1,145 @@ +from sympy.core.decorators import call_highest_priority +from sympy.core.expr import Expr +from sympy.core.mod import Mod +from sympy.core.numbers import Integer +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.integers import floor + + +class Higher(Integer): + ''' + Integer of value 1 and _op_priority 20 + + Operations handled by this class return 1 and reverse operations return 2 + ''' + + _op_priority = 20.0 + result: Expr = S.One + + def __new__(cls): + obj = Expr.__new__(cls) + obj.p = 1 + return obj + + @call_highest_priority('__rmul__') + def __mul__(self, other): + return self.result + + @call_highest_priority('__mul__') + def __rmul__(self, other): + return 2*self.result + + @call_highest_priority('__radd__') + def __add__(self, other): + return self.result + + @call_highest_priority('__add__') + def __radd__(self, other): + return 2*self.result + + @call_highest_priority('__rsub__') + def __sub__(self, other): + return self.result + + @call_highest_priority('__sub__') + def __rsub__(self, other): + return 2*self.result + + @call_highest_priority('__rpow__') + def __pow__(self, other): + return self.result + + @call_highest_priority('__pow__') + def __rpow__(self, other): + return 2*self.result + + @call_highest_priority('__rtruediv__') + def __truediv__(self, other): + return self.result + + @call_highest_priority('__truediv__') + def __rtruediv__(self, other): + return 2*self.result + + @call_highest_priority('__rmod__') + def __mod__(self, other): + return self.result + + @call_highest_priority('__mod__') + def __rmod__(self, other): + return 2*self.result + + @call_highest_priority('__rfloordiv__') + def __floordiv__(self, other): + return self.result + + @call_highest_priority('__floordiv__') + def __rfloordiv__(self, other): + return 2*self.result + + +class Lower(Higher): + ''' + Integer of value -1 and _op_priority 5 + + Operations handled by this class return -1 and reverse operations return -2 + ''' + + _op_priority = 5.0 + result: Expr = S.NegativeOne + + def __new__(cls): + obj = Expr.__new__(cls) + obj.p = -1 + return obj + + +x = Symbol('x') +h = Higher() +l = Lower() + + +def test_mul(): + assert h*l == h*x == 1 + assert l*h == x*h == 2 + assert x*l == l*x == -x + + +def test_add(): + assert h + l == h + x == 1 + assert l + h == x + h == 2 + assert x + l == l + x == x - 1 + + +def test_sub(): + assert h - l == h - x == 1 + assert l - h == x - h == 2 + assert x - l == -(l - x) == x + 1 + + +def test_pow(): + assert h**l == h**x == 1 + assert l**h == x**h == 2 + assert (x**l).args == (1/x).args and (x**l).is_Pow + assert (l**x).args == ((-1)**x).args and (l**x).is_Pow + + +def test_div(): + assert h/l == h/x == 1 + assert l/h == x/h == 2 + assert x/l == 1/(l/x) == -x + + +def test_mod(): + assert h%l == h%x == 1 + assert l%h == x%h == 2 + assert x%l == Mod(x, -1) + assert l%x == Mod(-1, x) + + +def test_floordiv(): + assert h//l == h//x == 1 + assert l//h == x//h == 2 + assert x//l == floor(-x) + assert l//x == floor(-1/x) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_random.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_random.py new file mode 100644 index 0000000000000000000000000000000000000000..01c677126285eb66349253368b94b3270fb97793 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_random.py @@ -0,0 +1,61 @@ +import random +from sympy.core.random import random as rand, seed, shuffle, _assumptions_shuffle +from sympy.core.symbol import Symbol, symbols +from sympy.functions.elementary.trigonometric import sin, acos +from sympy.abc import x + + +def test_random(): + random.seed(42) + a = random.random() + random.seed(42) + Symbol('z').is_finite + b = random.random() + assert a == b + + got = set() + for i in range(2): + random.seed(28) + m0, m1 = symbols('m_0 m_1', real=True) + _ = acos(-m0/m1) + got.add(random.uniform(0,1)) + assert len(got) == 1 + + random.seed(10) + y = 0 + for i in range(4): + y += sin(random.uniform(-10,10) * x) + random.seed(10) + z = 0 + for i in range(4): + z += sin(random.uniform(-10,10) * x) + assert y == z + + +def test_seed(): + assert rand() < 1 + seed(1) + a = rand() + b = rand() + seed(1) + c = rand() + d = rand() + assert a == c + if not c == d: + assert a != b + else: + assert a == b + + abc = 'abc' + first = list(abc) + second = list(abc) + third = list(abc) + + seed(123) + shuffle(first) + + seed(123) + shuffle(second) + _assumptions_shuffle(third) + + assert first == second == third diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_relational.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_relational.py new file mode 100644 index 0000000000000000000000000000000000000000..60c026fd5f5b8cee2e90e00582047cc7763bb8a4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_relational.py @@ -0,0 +1,1271 @@ +from sympy.core.logic import fuzzy_and +from sympy.core.sympify import _sympify +from sympy.multipledispatch import dispatch +from sympy.testing.pytest import XFAIL, raises +from sympy.assumptions.ask import Q +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.expr import Expr, unchanged +from sympy.core.function import Function +from sympy.core.mul import Mul +from sympy.core.numbers import (Float, I, Rational, nan, oo, pi, zoo) +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.complexes import sign, Abs +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.exponential import (exp, exp_polar, log) +from sympy.functions.elementary.integers import (ceiling, floor) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.logic.boolalg import (And, Implies, Not, Or, Xor) +from sympy.sets import Reals +from sympy.simplify.simplify import simplify +from sympy.simplify.trigsimp import trigsimp +from sympy.core.relational import (Relational, Equality, Unequality, + GreaterThan, LessThan, StrictGreaterThan, + StrictLessThan, Rel, Eq, Lt, Le, + Gt, Ge, Ne, is_le, is_gt, is_ge, is_lt, is_eq, is_neq) +from sympy.sets.sets import Interval, FiniteSet + +from itertools import combinations + +x, y, z, t = symbols('x,y,z,t') + + +def rel_check(a, b): + from sympy.testing.pytest import raises + assert a.is_number and b.is_number + for do in range(len({type(a), type(b)})): + if S.NaN in (a, b): + v = [(a == b), (a != b)] + assert len(set(v)) == 1 and v[0] == False + assert not (a != b) and not (a == b) + assert raises(TypeError, lambda: a < b) + assert raises(TypeError, lambda: a <= b) + assert raises(TypeError, lambda: a > b) + assert raises(TypeError, lambda: a >= b) + else: + E = [(a == b), (a != b)] + assert len(set(E)) == 2 + v = [ + (a < b), (a <= b), (a > b), (a >= b)] + i = [ + [True, True, False, False], + [False, True, False, True], # <-- i == 1 + [False, False, True, True]].index(v) + if i == 1: + assert E[0] or (a.is_Float != b.is_Float) # ugh + else: + assert E[1] + a, b = b, a + return True + + +def test_rel_ne(): + assert Relational(x, y, '!=') == Ne(x, y) + + # issue 6116 + p = Symbol('p', positive=True) + assert Ne(p, 0) is S.true + + +def test_rel_subs(): + e = Relational(x, y, '==') + 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) + + assert isinstance(e, GreaterThan) + assert e.lhs == z + assert e.rhs == y + + e = Relational(x, y, '<=') + 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) + + assert isinstance(e, StrictGreaterThan) + assert e.lhs == z + assert e.rhs == y + + e = Relational(x, y, '<') + 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) is S.true + assert e.subs(x, 1) is S.false + + +def test_wrappers(): + e = x + x**2 + + res = Relational(y, e, '==') + 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 + + res = Relational(y, e, '<=') + assert Le(y, x + x**2) == res + + res = Relational(y, e, '>') + assert Gt(y, x + x**2) == res + + res = Relational(y, e, '>=') + assert Ge(y, x + x**2) == res + + res = Relational(y, e, '!=') + assert Ne(y, x + x**2) == res + + +def test_Eq_Ne(): + + assert Eq(x, x) # issue 5719 + + # issue 6116 + p = Symbol('p', positive=True) + assert Eq(p, 0) is S.false + + # issue 13348; 19048 + # SymPy is strict about 0 and 1 not being + # interpreted as Booleans + assert Eq(True, 1) is S.false + assert Eq(False, 0) is S.false + assert Eq(~x, 0) is S.false + assert Eq(~x, 1) is S.false + assert Ne(True, 1) is S.true + assert Ne(False, 0) is S.true + assert Ne(~x, 0) is S.true + assert Ne(~x, 1) is S.true + + assert Eq((), 1) is S.false + assert Ne((), 1) is S.true + + +def test_as_poly(): + from sympy.polys.polytools import Poly + # Only Eq should have an as_poly method: + assert Eq(x, 1).as_poly() == Poly(x - 1, x, domain='ZZ') + raises(AttributeError, lambda: Ne(x, 1).as_poly()) + raises(AttributeError, lambda: Ge(x, 1).as_poly()) + raises(AttributeError, lambda: Gt(x, 1).as_poly()) + raises(AttributeError, lambda: Le(x, 1).as_poly()) + raises(AttributeError, lambda: Lt(x, 1).as_poly()) + + +def test_rel_Infinity(): + # NOTE: All of these are actually handled by sympy.core.Number, and do + # not create Relational objects. + assert (oo > oo) is S.false + assert (oo > -oo) is S.true + assert (oo > 1) is S.true + assert (oo < oo) is S.false + assert (oo < -oo) is S.false + assert (oo < 1) is S.false + assert (oo >= oo) is S.true + assert (oo >= -oo) is S.true + assert (oo >= 1) is S.true + assert (oo <= oo) is S.true + assert (oo <= -oo) is S.false + assert (oo <= 1) is S.false + assert (-oo > oo) is S.false + assert (-oo > -oo) is S.false + assert (-oo > 1) is S.false + assert (-oo < oo) is S.true + assert (-oo < -oo) is S.false + assert (-oo < 1) is S.true + assert (-oo >= oo) is S.false + assert (-oo >= -oo) is S.true + assert (-oo >= 1) is S.false + assert (-oo <= oo) is S.true + assert (-oo <= -oo) is S.true + assert (-oo <= 1) is S.true + + +def test_infinite_symbol_inequalities(): + x = Symbol('x', extended_positive=True, infinite=True) + y = Symbol('y', extended_positive=True, infinite=True) + z = Symbol('z', extended_negative=True, infinite=True) + w = Symbol('w', extended_negative=True, infinite=True) + + inf_set = (x, y, oo) + ninf_set = (z, w, -oo) + + for inf1 in inf_set: + assert (inf1 < 1) is S.false + assert (inf1 > 1) is S.true + assert (inf1 <= 1) is S.false + assert (inf1 >= 1) is S.true + + for inf2 in inf_set: + assert (inf1 < inf2) is S.false + assert (inf1 > inf2) is S.false + assert (inf1 <= inf2) is S.true + assert (inf1 >= inf2) is S.true + + for ninf1 in ninf_set: + assert (inf1 < ninf1) is S.false + assert (inf1 > ninf1) is S.true + assert (inf1 <= ninf1) is S.false + assert (inf1 >= ninf1) is S.true + assert (ninf1 < inf1) is S.true + assert (ninf1 > inf1) is S.false + assert (ninf1 <= inf1) is S.true + assert (ninf1 >= inf1) is S.false + + for ninf1 in ninf_set: + assert (ninf1 < 1) is S.true + assert (ninf1 > 1) is S.false + assert (ninf1 <= 1) is S.true + assert (ninf1 >= 1) is S.false + + for ninf2 in ninf_set: + assert (ninf1 < ninf2) is S.false + assert (ninf1 > ninf2) is S.false + assert (ninf1 <= ninf2) is S.true + assert (ninf1 >= ninf2) is S.true + + +def test_bool(): + assert Eq(0, 0) is S.true + assert Eq(1, 0) is S.false + assert Ne(0, 0) is S.false + assert Ne(1, 0) is S.true + assert Lt(0, 1) is S.true + assert Lt(1, 0) is S.false + assert Le(0, 1) is S.true + assert Le(1, 0) is S.false + assert Le(0, 0) is S.true + assert Gt(1, 0) is S.true + assert Gt(0, 1) is S.false + assert Ge(1, 0) is S.true + assert Ge(0, 1) is S.false + assert Ge(1, 1) is S.true + assert Eq(I, 2) is S.false + assert Ne(I, 2) is S.true + raises(TypeError, lambda: Gt(I, 2)) + raises(TypeError, lambda: Ge(I, 2)) + raises(TypeError, lambda: Lt(I, 2)) + raises(TypeError, lambda: Le(I, 2)) + a = Float('.000000000000000000001', '') + b = Float('.0000000000000000000001', '') + assert Eq(pi + a, pi + b) is S.false + + +def test_rich_cmp(): + 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.core.symbol import Symbol + p = Symbol('p', positive=True) + n = Symbol('n', negative=True) + np = Symbol('np', nonpositive=True) + nn = Symbol('nn', nonnegative=True) + + assert Gt(p, 0).doit() is S.true + assert Gt(p, 1).doit() == Gt(p, 1) + assert Ge(p, 0).doit() is S.true + assert Le(p, 0).doit() is S.false + assert Lt(n, 0).doit() is S.true + assert Le(np, 0).doit() is S.true + assert Gt(nn, 0).doit() == Gt(nn, 0) + assert Lt(nn, 0).doit() is S.false + + assert Eq(x, 0).doit() == Eq(x, 0) + + +def test_new_relational(): + x = Symbol('x') + + assert Eq(x, 0) == Relational(x, 0) # None ==> Equality + assert Eq(x, 0) == Relational(x, 0, '==') + assert Eq(x, 0) == Relational(x, 0, 'eq') + assert Eq(x, 0) == Equality(x, 0) + + assert Eq(x, 0) != Relational(x, 1) # None ==> Equality + assert Eq(x, 0) != Relational(x, 1, '==') + assert Eq(x, 0) != Relational(x, 1, 'eq') + assert Eq(x, 0) != 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') + assert Eq(x, -1) == 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') + assert Eq(x, -1) != Equality(x, 1) + + assert Ne(x, 0) == Relational(x, 0, '!=') + assert Ne(x, 0) == Relational(x, 0, '<>') + assert Ne(x, 0) == Relational(x, 0, 'ne') + assert Ne(x, 0) == Unequality(x, 0) + assert Ne(x, 0) != Relational(x, 1, '!=') + assert Ne(x, 0) != Relational(x, 1, '<>') + assert Ne(x, 0) != Relational(x, 1, 'ne') + assert Ne(x, 0) != Unequality(x, 1) + + assert Ge(x, 0) == Relational(x, 0, '>=') + assert Ge(x, 0) == Relational(x, 0, 'ge') + assert Ge(x, 0) == GreaterThan(x, 0) + assert Ge(x, 1) != Relational(x, 0, '>=') + assert Ge(x, 1) != Relational(x, 0, 'ge') + assert Ge(x, 1) != GreaterThan(x, 0) + assert (x >= 1) == Relational(x, 1, '>=') + assert (x >= 1) == Relational(x, 1, 'ge') + assert (x >= 1) == GreaterThan(x, 1) + assert (x >= 0) != Relational(x, 1, '>=') + assert (x >= 0) != Relational(x, 1, 'ge') + assert (x >= 0) != GreaterThan(x, 1) + + assert Le(x, 0) == Relational(x, 0, '<=') + assert Le(x, 0) == Relational(x, 0, 'le') + assert Le(x, 0) == LessThan(x, 0) + assert Le(x, 1) != Relational(x, 0, '<=') + assert Le(x, 1) != Relational(x, 0, 'le') + assert Le(x, 1) != LessThan(x, 0) + assert (x <= 1) == Relational(x, 1, '<=') + assert (x <= 1) == Relational(x, 1, 'le') + assert (x <= 1) == LessThan(x, 1) + assert (x <= 0) != Relational(x, 1, '<=') + assert (x <= 0) != Relational(x, 1, 'le') + assert (x <= 0) != LessThan(x, 1) + + assert Gt(x, 0) == Relational(x, 0, '>') + assert Gt(x, 0) == Relational(x, 0, 'gt') + assert Gt(x, 0) == StrictGreaterThan(x, 0) + assert Gt(x, 1) != Relational(x, 0, '>') + assert Gt(x, 1) != Relational(x, 0, 'gt') + assert Gt(x, 1) != StrictGreaterThan(x, 0) + assert (x > 1) == Relational(x, 1, '>') + assert (x > 1) == Relational(x, 1, 'gt') + assert (x > 1) == StrictGreaterThan(x, 1) + assert (x > 0) != Relational(x, 1, '>') + assert (x > 0) != Relational(x, 1, 'gt') + assert (x > 0) != StrictGreaterThan(x, 1) + + assert Lt(x, 0) == Relational(x, 0, '<') + assert Lt(x, 0) == Relational(x, 0, 'lt') + assert Lt(x, 0) == StrictLessThan(x, 0) + 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) + + # finally, some fuzz testing + from sympy.core.random import randint + for i in range(100): + while 1: + strtype, length = (chr, 65535) if randint(0, 1) else (chr, 255) + relation_type = strtype(randint(0, length)) + if randint(0, 1): + relation_type += strtype(randint(0, length)) + if relation_type not in ('==', 'eq', '!=', '<>', 'ne', '>=', 'ge', + '<=', 'le', '>', 'gt', '<', 'lt', ':=', + '+=', '-=', '*=', '/=', '%='): + break + + raises(ValueError, lambda: Relational(x, 1, relation_type)) + assert all(Relational(x, 0, op).rel_op == '==' for op in ('eq', '==')) + assert all(Relational(x, 0, op).rel_op == '!=' + for op in ('ne', '<>', '!=')) + assert all(Relational(x, 0, op).rel_op == '>' for op in ('gt', '>')) + assert all(Relational(x, 0, op).rel_op == '<' for op in ('lt', '<')) + assert all(Relational(x, 0, op).rel_op == '>=' for op in ('ge', '>=')) + assert all(Relational(x, 0, op).rel_op == '<=' for op in ('le', '<=')) + + +def test_relational_arithmetic(): + for cls in [Eq, Ne, Le, Lt, Ge, Gt]: + rel = cls(x, y) + raises(TypeError, lambda: 0+rel) + raises(TypeError, lambda: 1*rel) + raises(TypeError, lambda: 1**rel) + raises(TypeError, lambda: rel**1) + raises(TypeError, lambda: Add(0, rel)) + raises(TypeError, lambda: Mul(1, rel)) + raises(TypeError, lambda: Pow(1, rel)) + raises(TypeError, lambda: Pow(rel, 1)) + + +def test_relational_bool_output(): + # https://github.com/sympy/sympy/issues/5931 + raises(TypeError, lambda: bool(x > 3)) + raises(TypeError, lambda: bool(x >= 3)) + raises(TypeError, lambda: bool(x < 3)) + raises(TypeError, lambda: bool(x <= 3)) + raises(TypeError, lambda: bool(Eq(x, 3))) + raises(TypeError, lambda: bool(Ne(x, 3))) + + +def test_relational_logic_symbols(): + # See issue 6204 + assert (x < y) & (z < t) == And(x < y, z < t) + assert (x < y) | (z < t) == Or(x < y, z < t) + assert ~(x < y) == Not(x < y) + assert (x < y) >> (z < t) == Implies(x < y, z < t) + assert (x < y) << (z < t) == Implies(z < t, x < y) + assert (x < y) ^ (z < t) == Xor(x < y, z < t) + + assert isinstance((x < y) & (z < t), And) + assert isinstance((x < y) | (z < t), Or) + assert isinstance(~(x < y), GreaterThan) + assert isinstance((x < y) >> (z < t), Implies) + assert isinstance((x < y) << (z < t), Implies) + assert isinstance((x < y) ^ (z < t), (Or, Xor)) + + +def test_univariate_relational_as_set(): + assert (x > 0).as_set() == Interval(0, oo, True, True) + assert (x >= 0).as_set() == Interval(0, oo) + assert (x < 0).as_set() == Interval(-oo, 0, True, True) + assert (x <= 0).as_set() == Interval(-oo, 0) + assert Eq(x, 0).as_set() == FiniteSet(0) + assert Ne(x, 0).as_set() == Interval(-oo, 0, True, True) + \ + Interval(0, oo, True, True) + + assert (x**2 >= 4).as_set() == Interval(-oo, -2) + Interval(2, oo) + + +@XFAIL +def test_multivariate_relational_as_set(): + assert (x*y >= 0).as_set() == Interval(0, oo)*Interval(0, oo) + \ + Interval(-oo, 0)*Interval(-oo, 0) + + +def test_Not(): + assert Not(Equality(x, y)) == Unequality(x, y) + assert Not(Unequality(x, y)) == Equality(x, y) + assert Not(StrictGreaterThan(x, y)) == LessThan(x, y) + assert Not(StrictLessThan(x, y)) == GreaterThan(x, y) + assert Not(GreaterThan(x, y)) == StrictLessThan(x, y) + assert Not(LessThan(x, y)) == StrictGreaterThan(x, y) + + +def test_evaluate(): + assert str(Eq(x, x, evaluate=False)) == 'Eq(x, x)' + assert Eq(x, x, evaluate=False).doit() == S.true + assert str(Ne(x, x, evaluate=False)) == 'Ne(x, x)' + assert Ne(x, x, evaluate=False).doit() == S.false + + assert str(Ge(x, x, evaluate=False)) == 'x >= x' + assert str(Le(x, x, evaluate=False)) == 'x <= x' + assert str(Gt(x, x, evaluate=False)) == 'x > x' + assert str(Lt(x, x, evaluate=False)) == 'x < x' + + +def assert_all_ineq_raise_TypeError(a, b): + raises(TypeError, lambda: a > b) + raises(TypeError, lambda: a >= b) + raises(TypeError, lambda: a < b) + raises(TypeError, lambda: a <= b) + raises(TypeError, lambda: b > a) + raises(TypeError, lambda: b >= a) + raises(TypeError, lambda: b < a) + raises(TypeError, lambda: b <= a) + + +def assert_all_ineq_give_class_Inequality(a, b): + """All inequality operations on `a` and `b` result in class Inequality.""" + from sympy.core.relational import _Inequality as Inequality + assert isinstance(a > b, Inequality) + assert isinstance(a >= b, Inequality) + assert isinstance(a < b, Inequality) + assert isinstance(a <= b, Inequality) + assert isinstance(b > a, Inequality) + assert isinstance(b >= a, Inequality) + assert isinstance(b < a, Inequality) + assert isinstance(b <= a, Inequality) + + +def test_imaginary_compare_raises_TypeError(): + # See issue #5724 + assert_all_ineq_raise_TypeError(I, x) + + +def test_complex_compare_not_real(): + # two cases which are not real + y = Symbol('y', imaginary=True) + z = Symbol('z', complex=True, extended_real=False) + for w in (y, z): + assert_all_ineq_raise_TypeError(2, w) + # some cases which should remain un-evaluated + t = Symbol('t') + x = Symbol('x', real=True) + z = Symbol('z', complex=True) + for w in (x, z, t): + assert_all_ineq_give_class_Inequality(2, w) + + +def test_imaginary_and_inf_compare_raises_TypeError(): + # See pull request #7835 + y = Symbol('y', imaginary=True) + assert_all_ineq_raise_TypeError(oo, y) + assert_all_ineq_raise_TypeError(-oo, y) + + +def test_complex_pure_imag_not_ordered(): + raises(TypeError, lambda: 2*I < 3*I) + + # more generally + x = Symbol('x', real=True, nonzero=True) + y = Symbol('y', imaginary=True) + z = Symbol('z', complex=True) + assert_all_ineq_raise_TypeError(I, y) + + t = I*x # an imaginary number, should raise errors + assert_all_ineq_raise_TypeError(2, t) + + t = -I*y # a real number, so no errors + assert_all_ineq_give_class_Inequality(2, t) + + t = I*z # unknown, should be unevaluated + assert_all_ineq_give_class_Inequality(2, t) + + +def test_x_minus_y_not_same_as_x_lt_y(): + """ + A consequence of pull request #7792 is that `x - y < 0` and `x < y` + are not synonymous. + """ + x = I + 2 + y = I + 3 + raises(TypeError, lambda: x < y) + assert x - y < 0 + + ineq = Lt(x, y, evaluate=False) + raises(TypeError, lambda: ineq.doit()) + assert ineq.lhs - ineq.rhs < 0 + + t = Symbol('t', imaginary=True) + x = 2 + t + y = 3 + t + ineq = Lt(x, y, evaluate=False) + raises(TypeError, lambda: ineq.doit()) + assert ineq.lhs - ineq.rhs < 0 + + # this one should give error either way + x = I + 2 + y = 2*I + 3 + raises(TypeError, lambda: x < y) + raises(TypeError, lambda: x - y < 0) + + +def test_nan_equality_exceptions(): + # See issue #7774 + import random + assert Equality(nan, nan) is S.false + assert Unequality(nan, nan) is S.true + + # See issue #7773 + A = (x, S.Zero, S.One/3, pi, oo, -oo) + assert Equality(nan, random.choice(A)) is S.false + assert Equality(random.choice(A), nan) is S.false + assert Unequality(nan, random.choice(A)) is S.true + assert Unequality(random.choice(A), nan) is S.true + + +def test_nan_inequality_raise_errors(): + # See discussion in pull request #7776. We test inequalities with + # a set including examples of various classes. + for q in (x, S.Zero, S(10), S.One/3, pi, S(1.3), oo, -oo, nan): + assert_all_ineq_raise_TypeError(q, nan) + + +def test_nan_complex_inequalities(): + # Comparisons of NaN with non-real raise errors, we're not too + # fussy whether its the NaN error or complex error. + for r in (I, zoo, Symbol('z', imaginary=True)): + assert_all_ineq_raise_TypeError(r, nan) + + +def test_complex_infinity_inequalities(): + raises(TypeError, lambda: zoo > 0) + raises(TypeError, lambda: zoo >= 0) + raises(TypeError, lambda: zoo < 0) + raises(TypeError, lambda: zoo <= 0) + + +def test_inequalities_symbol_name_same(): + """Using the operator and functional forms should give same results.""" + # We test all combinations from a set + # FIXME: could replace with random selection after test passes + A = (x, y, S.Zero, S.One/3, pi, oo, -oo) + for a in A: + for b in A: + assert Gt(a, b) == (a > b) + assert Lt(a, b) == (a < b) + assert Ge(a, b) == (a >= b) + assert Le(a, b) == (a <= b) + + for b in (y, S.Zero, S.One/3, pi, oo, -oo): + assert Gt(x, b, evaluate=False) == (x > b) + assert Lt(x, b, evaluate=False) == (x < b) + assert Ge(x, b, evaluate=False) == (x >= b) + assert Le(x, b, evaluate=False) == (x <= b) + + for b in (y, S.Zero, S.One/3, pi, oo, -oo): + assert Gt(b, x, evaluate=False) == (b > x) + assert Lt(b, x, evaluate=False) == (b < x) + assert Ge(b, x, evaluate=False) == (b >= x) + assert Le(b, x, evaluate=False) == (b <= x) + + +def test_inequalities_symbol_name_same_complex(): + """Using the operator and functional forms should give same results. + With complex non-real numbers, both should raise errors. + """ + # FIXME: could replace with random selection after test passes + for a in (x, S.Zero, S.One/3, pi, oo, Rational(1, 3)): + raises(TypeError, lambda: Gt(a, I)) + raises(TypeError, lambda: a > I) + raises(TypeError, lambda: Lt(a, I)) + raises(TypeError, lambda: a < I) + raises(TypeError, lambda: Ge(a, I)) + raises(TypeError, lambda: a >= I) + raises(TypeError, lambda: Le(a, I)) + raises(TypeError, lambda: a <= I) + + +def test_inequalities_cant_sympify_other(): + # see issue 7833 + from operator import gt, lt, ge, le + + bar = "foo" + + for a in (x, S.Zero, S.One/3, pi, I, zoo, oo, -oo, nan, Rational(1, 3)): + for op in (lt, gt, le, ge): + raises(TypeError, lambda: op(a, bar)) + + +def test_ineq_avoid_wild_symbol_flip(): + # see issue #7951, we try to avoid this internally, e.g., by using + # __lt__ instead of "<". + from sympy.core.symbol import Wild + p = symbols('p', cls=Wild) + # x > p might flip, but Gt should not: + assert Gt(x, p) == Gt(x, p, evaluate=False) + # Previously failed as 'p > x': + e = Lt(x, y).subs({y: p}) + assert e == Lt(x, p, evaluate=False) + # Previously failed as 'p <= x': + e = Ge(x, p).doit() + assert e == Ge(x, p, evaluate=False) + + +def test_issue_8245(): + a = S("6506833320952669167898688709329/5070602400912917605986812821504") + assert rel_check(a, a.n(10)) + assert rel_check(a, a.n(20)) + assert rel_check(a, a.n()) + # prec of 31 is enough to fully capture a as mpf + assert Float(a, 31) == Float(str(a.p), '')/Float(str(a.q), '') + for i in range(31): + r = Rational(Float(a, i)) + f = Float(r) + assert (f < a) == (Rational(f) < a) + # test sign handling + assert (-f < -a) == (Rational(-f) < -a) + # test equivalence handling + isa = Float(a.p,'')/Float(a.q,'') + assert isa <= a + assert not isa < a + assert isa >= a + assert not isa > a + assert isa > 0 + + a = sqrt(2) + r = Rational(str(a.n(30))) + assert rel_check(a, r) + + a = sqrt(2) + r = Rational(str(a.n(29))) + assert rel_check(a, r) + + assert Eq(log(cos(2)**2 + sin(2)**2), 0) is S.true + + +def test_issue_8449(): + p = Symbol('p', nonnegative=True) + assert Lt(-oo, p) + assert Ge(-oo, p) is S.false + assert Gt(oo, -p) + assert Le(oo, -p) is S.false + + +def test_simplify_relational(): + assert simplify(x*(y + 1) - x*y - x + 1 < x) == (x > 1) + assert simplify(x*(y + 1) - x*y - x - 1 < x) == (x > -1) + assert simplify(x < x*(y + 1) - x*y - x + 1) == (x < 1) + q, r = symbols("q r") + assert (((-q + r) - (q - r)) <= 0).simplify() == (q >= r) + root2 = sqrt(2) + equation = ((root2 * (-q + r) - root2 * (q - r)) <= 0).simplify() + assert equation == (q >= r) + r = S.One < x + # canonical operations are not the same as simplification, + # so if there is no simplification, canonicalization will + # be done unless the measure forbids it + assert simplify(r) == r.canonical + assert simplify(r, ratio=0) != r.canonical + # this is not a random test; in _eval_simplify + # this will simplify to S.false and that is the + # reason for the 'if r.is_Relational' in Relational's + # _eval_simplify routine + assert simplify(-(2**(pi*Rational(3, 2)) + 6**pi)**(1/pi) + + 2*(2**(pi/2) + 3**pi)**(1/pi) < 0) is S.false + # canonical at least + assert Eq(y, x).simplify() == Eq(x, y) + assert Eq(x - 1, 0).simplify() == Eq(x, 1) + assert Eq(x - 1, x).simplify() == S.false + assert Eq(2*x - 1, x).simplify() == Eq(x, 1) + assert Eq(2*x, 4).simplify() == Eq(x, 2) + z = cos(1)**2 + sin(1)**2 - 1 # z.is_zero is None + assert Eq(z*x, 0).simplify() == S.true + + assert Ne(y, x).simplify() == Ne(x, y) + assert Ne(x - 1, 0).simplify() == Ne(x, 1) + assert Ne(x - 1, x).simplify() == S.true + assert Ne(2*x - 1, x).simplify() == Ne(x, 1) + assert Ne(2*x, 4).simplify() == Ne(x, 2) + assert Ne(z*x, 0).simplify() == S.false + + # No real-valued assumptions + assert Ge(y, x).simplify() == Le(x, y) + assert Ge(x - 1, 0).simplify() == Ge(x, 1) + assert Ge(x - 1, x).simplify() == S.false + assert Ge(2*x - 1, x).simplify() == Ge(x, 1) + assert Ge(2*x, 4).simplify() == Ge(x, 2) + assert Ge(z*x, 0).simplify() == S.true + assert Ge(x, -2).simplify() == Ge(x, -2) + assert Ge(-x, -2).simplify() == Le(x, 2) + assert Ge(x, 2).simplify() == Ge(x, 2) + assert Ge(-x, 2).simplify() == Le(x, -2) + + assert Le(y, x).simplify() == Ge(x, y) + assert Le(x - 1, 0).simplify() == Le(x, 1) + assert Le(x - 1, x).simplify() == S.true + assert Le(2*x - 1, x).simplify() == Le(x, 1) + assert Le(2*x, 4).simplify() == Le(x, 2) + assert Le(z*x, 0).simplify() == S.true + assert Le(x, -2).simplify() == Le(x, -2) + assert Le(-x, -2).simplify() == Ge(x, 2) + assert Le(x, 2).simplify() == Le(x, 2) + assert Le(-x, 2).simplify() == Ge(x, -2) + + assert Gt(y, x).simplify() == Lt(x, y) + assert Gt(x - 1, 0).simplify() == Gt(x, 1) + assert Gt(x - 1, x).simplify() == S.false + assert Gt(2*x - 1, x).simplify() == Gt(x, 1) + assert Gt(2*x, 4).simplify() == Gt(x, 2) + assert Gt(z*x, 0).simplify() == S.false + assert Gt(x, -2).simplify() == Gt(x, -2) + assert Gt(-x, -2).simplify() == Lt(x, 2) + assert Gt(x, 2).simplify() == Gt(x, 2) + assert Gt(-x, 2).simplify() == Lt(x, -2) + + assert Lt(y, x).simplify() == Gt(x, y) + assert Lt(x - 1, 0).simplify() == Lt(x, 1) + assert Lt(x - 1, x).simplify() == S.true + assert Lt(2*x - 1, x).simplify() == Lt(x, 1) + assert Lt(2*x, 4).simplify() == Lt(x, 2) + assert Lt(z*x, 0).simplify() == S.false + assert Lt(x, -2).simplify() == Lt(x, -2) + assert Lt(-x, -2).simplify() == Gt(x, 2) + assert Lt(x, 2).simplify() == Lt(x, 2) + assert Lt(-x, 2).simplify() == Gt(x, -2) + + # Test particular branches of _eval_simplify + m = exp(1) - exp_polar(1) + assert simplify(m*x > 1) is S.false + # These two test the same branch + assert simplify(m*x + 2*m*y > 1) is S.false + assert simplify(m*x + y > 1 + y) is S.false + + +def test_equals(): + w, x, y, z = symbols('w:z') + f = Function('f') + assert Eq(x, 1).equals(Eq(x*(y + 1) - x*y - x + 1, x)) + assert Eq(x, y).equals(x < y, True) == False + assert Eq(x, f(1)).equals(Eq(x, f(2)), True) == f(1) - f(2) + assert Eq(f(1), y).equals(Eq(f(2), y), True) == f(1) - f(2) + assert Eq(x, f(1)).equals(Eq(f(2), x), True) == f(1) - f(2) + assert Eq(f(1), x).equals(Eq(x, f(2)), True) == f(1) - f(2) + assert Eq(w, x).equals(Eq(y, z), True) == False + assert Eq(f(1), f(2)).equals(Eq(f(3), f(4)), True) == f(1) - f(3) + assert (x < y).equals(y > x, True) == True + assert (x < y).equals(y >= x, True) == False + assert (x < y).equals(z < y, True) == False + assert (x < y).equals(x < z, True) == False + assert (x < f(1)).equals(x < f(2), True) == f(1) - f(2) + assert (f(1) < x).equals(f(2) < x, True) == f(1) - f(2) + + +def test_reversed(): + assert (x < y).reversed == (y > x) + assert (x <= y).reversed == (y >= x) + assert Eq(x, y, evaluate=False).reversed == Eq(y, x, evaluate=False) + assert Ne(x, y, evaluate=False).reversed == Ne(y, x, evaluate=False) + assert (x >= y).reversed == (y <= x) + assert (x > y).reversed == (y < x) + + +def test_canonical(): + c = [i.canonical for i in ( + x + y < z, + x + 2 > 3, + x < 2, + S(2) > x, + x**2 > -x/y, + Gt(3, 2, evaluate=False) + )] + assert [i.canonical for i in c] == c + assert [i.reversed.canonical for i in c] == c + assert not any(i.lhs.is_Number and not i.rhs.is_Number for i in c) + + c = [i.reversed.func(i.rhs, i.lhs, evaluate=False).canonical for i in c] + assert [i.canonical for i in c] == c + assert [i.reversed.canonical for i in c] == c + assert not any(i.lhs.is_Number and not i.rhs.is_Number for i in c) + assert Eq(y < x, x > y).canonical is S.true + + +@XFAIL +def test_issue_8444_nonworkingtests(): + x = symbols('x', real=True) + assert (x <= oo) == (x >= -oo) == True + + x = symbols('x') + assert x >= floor(x) + assert (x < floor(x)) == False + assert x <= ceiling(x) + assert (x > ceiling(x)) == False + + +def test_issue_8444_workingtests(): + x = symbols('x') + assert Gt(x, floor(x)) == Gt(x, floor(x), evaluate=False) + assert Ge(x, floor(x)) == Ge(x, floor(x), evaluate=False) + assert Lt(x, ceiling(x)) == Lt(x, ceiling(x), evaluate=False) + assert Le(x, ceiling(x)) == Le(x, ceiling(x), evaluate=False) + i = symbols('i', integer=True) + assert (i > floor(i)) == False + assert (i < ceiling(i)) == False + + +def test_issue_10304(): + d = cos(1)**2 + sin(1)**2 - 1 + assert d.is_comparable is False # if this fails, find a new d + e = 1 + d*I + assert simplify(Eq(e, 0)) is S.false + + +def test_issue_18412(): + d = (Rational(1, 6) + z / 4 / y) + assert Eq(x, pi * y**3 * d).replace(y**3, z) == Eq(x, pi * z * d) + + +def test_issue_10401(): + x = symbols('x') + fin = symbols('inf', finite=True) + inf = symbols('inf', infinite=True) + inf2 = symbols('inf2', infinite=True) + infx = symbols('infx', infinite=True, extended_real=True) + # Used in the commented tests below: + #infx2 = symbols('infx2', infinite=True, extended_real=True) + infnx = symbols('inf~x', infinite=True, extended_real=False) + infnx2 = symbols('inf~x2', infinite=True, extended_real=False) + infp = symbols('infp', infinite=True, extended_positive=True) + infp1 = symbols('infp1', infinite=True, extended_positive=True) + infn = symbols('infn', infinite=True, extended_negative=True) + zero = symbols('z', zero=True) + nonzero = symbols('nz', zero=False, finite=True) + + assert Eq(1/(1/x + 1), 1).func is Eq + assert Eq(1/(1/x + 1), 1).subs(x, S.ComplexInfinity) is S.true + assert Eq(1/(1/fin + 1), 1) is S.false + + T, F = S.true, S.false + assert Eq(fin, inf) is F + assert Eq(inf, inf2) not in (T, F) and inf != inf2 + assert Eq(1 + inf, 2 + inf2) not in (T, F) and inf != inf2 + assert Eq(infp, infp1) is T + assert Eq(infp, infn) is F + assert Eq(1 + I*oo, I*oo) is F + assert Eq(I*oo, 1 + I*oo) is F + assert Eq(1 + I*oo, 2 + I*oo) is F + assert Eq(1 + I*oo, 2 + I*infx) is F + assert Eq(1 + I*oo, 2 + infx) is F + # FIXME: The test below fails because (-infx).is_extended_positive is True + # (should be None) + #assert Eq(1 + I*infx, 1 + I*infx2) not in (T, F) and infx != infx2 + # + assert Eq(zoo, sqrt(2) + I*oo) is F + assert Eq(zoo, oo) is F + r = Symbol('r', real=True) + i = Symbol('i', imaginary=True) + assert Eq(i*I, r) not in (T, F) + assert Eq(infx, infnx) is F + assert Eq(infnx, infnx2) not in (T, F) and infnx != infnx2 + assert Eq(zoo, oo) is F + assert Eq(inf/inf2, 0) is F + assert Eq(inf/fin, 0) is F + assert Eq(fin/inf, 0) is T + assert Eq(zero/nonzero, 0) is T and ((zero/nonzero) != 0) + # The commented out test below is incorrect because: + assert zoo == -zoo + assert Eq(zoo, -zoo) is T + assert Eq(oo, -oo) is F + assert Eq(inf, -inf) not in (T, F) + + assert Eq(fin/(fin + 1), 1) is S.false + + o = symbols('o', odd=True) + assert Eq(o, 2*o) is S.false + + p = symbols('p', positive=True) + assert Eq(p/(p - 1), 1) is F + + +def test_issue_10633(): + assert Eq(True, False) == False + assert Eq(False, True) == False + assert Eq(True, True) == True + assert Eq(False, False) == True + + +def test_issue_10927(): + x = symbols('x') + assert str(Eq(x, oo)) == 'Eq(x, oo)' + assert str(Eq(x, -oo)) == 'Eq(x, -oo)' + + +def test_issues_13081_12583_12534(): + # 13081 + r = Rational('905502432259640373/288230376151711744') + assert (r < pi) is S.false + assert (r > pi) is S.true + # 12583 + v = sqrt(2) + u = sqrt(v) + 2/sqrt(10 - 8/sqrt(2 - v) + 4*v*(1/sqrt(2 - v) - 1)) + assert (u >= 0) is S.true + # 12534; Rational vs NumberSymbol + # here are some precisions for which Rational forms + # at a lower and higher precision bracket the value of pi + # e.g. for p = 20: + # Rational(pi.n(p + 1)).n(25) = 3.14159265358979323846 2834 + # pi.n(25) = 3.14159265358979323846 2643 + # Rational(pi.n(p )).n(25) = 3.14159265358979323846 1987 + assert [p for p in range(20, 50) if + (Rational(pi.n(p)) < pi) and + (pi < Rational(pi.n(p + 1)))] == [20, 24, 27, 33, 37, 43, 48] + # pick one such precision and affirm that the reversed operation + # gives the opposite result, i.e. if x < y is true then x > y + # must be false + for i in (20, 21): + v = pi.n(i) + assert rel_check(Rational(v), pi) + assert rel_check(v, pi) + assert rel_check(pi.n(20), pi.n(21)) + # Float vs Rational + # the rational form is less than the floating representation + # at the same precision + assert [i for i in range(15, 50) if Rational(pi.n(i)) > pi.n(i)] == [] + # this should be the same if we reverse the relational + assert [i for i in range(15, 50) if pi.n(i) < Rational(pi.n(i))] == [] + +def test_issue_18188(): + from sympy.sets.conditionset import ConditionSet + result1 = Eq(x*cos(x) - 3*sin(x), 0) + assert result1.as_set() == ConditionSet(x, Eq(x*cos(x) - 3*sin(x), 0), Reals) + + result2 = Eq(x**2 + sqrt(x*2) + sin(x), 0) + assert result2.as_set() == ConditionSet(x, Eq(sqrt(2)*sqrt(x) + x**2 + sin(x), 0), Reals) + +def test_binary_symbols(): + ans = {x} + for f in Eq, Ne: + for t in S.true, S.false: + eq = f(x, S.true) + assert eq.binary_symbols == ans + assert eq.reversed.binary_symbols == ans + assert f(x, 1).binary_symbols == set() + + +def test_rel_args(): + # can't have Boolean args; this is automatic for True/False + # with Python 3 and we confirm that SymPy does the same + # for true/false + for op in ['<', '<=', '>', '>=']: + for b in (S.true, x < 1, And(x, y)): + for v in (0.1, 1, 2**32, t, S.One): + raises(TypeError, lambda: Relational(b, v, op)) + + +def test_nothing_happens_to_Eq_condition_during_simplify(): + # issue 25701 + r = symbols('r', real=True) + assert Eq(2*sign(r + 3)/(5*Abs(r + 3)**Rational(3, 5)), 0 + ).simplify() == Eq(Piecewise( + (0, Eq(r, -3)), ((r + 3)/(5*Abs((r + 3)**Rational(8, 5)))*2, True)), 0) + + +def test_issue_15847(): + a = Ne(x*(x + y), x**2 + x*y) + assert simplify(a) == False + + +def test_negated_property(): + eq = Eq(x, y) + assert eq.negated == Ne(x, y) + + eq = Ne(x, y) + assert eq.negated == Eq(x, y) + + eq = Ge(x + y, y - x) + assert eq.negated == Lt(x + y, y - x) + + for f in (Eq, Ne, Ge, Gt, Le, Lt): + assert f(x, y).negated.negated == f(x, y) + + +def test_reversedsign_property(): + eq = Eq(x, y) + assert eq.reversedsign == Eq(-x, -y) + + eq = Ne(x, y) + assert eq.reversedsign == Ne(-x, -y) + + eq = Ge(x + y, y - x) + assert eq.reversedsign == Le(-x - y, x - y) + + for f in (Eq, Ne, Ge, Gt, Le, Lt): + assert f(x, y).reversedsign.reversedsign == f(x, y) + + for f in (Eq, Ne, Ge, Gt, Le, Lt): + assert f(-x, y).reversedsign.reversedsign == f(-x, y) + + for f in (Eq, Ne, Ge, Gt, Le, Lt): + assert f(x, -y).reversedsign.reversedsign == f(x, -y) + + for f in (Eq, Ne, Ge, Gt, Le, Lt): + assert f(-x, -y).reversedsign.reversedsign == f(-x, -y) + + +def test_reversed_reversedsign_property(): + for f in (Eq, Ne, Ge, Gt, Le, Lt): + assert f(x, y).reversed.reversedsign == f(x, y).reversedsign.reversed + + for f in (Eq, Ne, Ge, Gt, Le, Lt): + assert f(-x, y).reversed.reversedsign == f(-x, y).reversedsign.reversed + + for f in (Eq, Ne, Ge, Gt, Le, Lt): + assert f(x, -y).reversed.reversedsign == f(x, -y).reversedsign.reversed + + for f in (Eq, Ne, Ge, Gt, Le, Lt): + assert f(-x, -y).reversed.reversedsign == \ + f(-x, -y).reversedsign.reversed + + +def test_improved_canonical(): + def test_different_forms(listofforms): + for form1, form2 in combinations(listofforms, 2): + assert form1.canonical == form2.canonical + + def generate_forms(expr): + return [expr, expr.reversed, expr.reversedsign, + expr.reversed.reversedsign] + + test_different_forms(generate_forms(x > -y)) + test_different_forms(generate_forms(x >= -y)) + test_different_forms(generate_forms(Eq(x, -y))) + test_different_forms(generate_forms(Ne(x, -y))) + test_different_forms(generate_forms(pi < x)) + test_different_forms(generate_forms(pi - 5*y < -x + 2*y**2 - 7)) + + assert (pi >= x).canonical == (x <= pi) + + +def test_set_equality_canonical(): + a, b, c = symbols('a b c') + + A = Eq(FiniteSet(a, b, c), FiniteSet(1, 2, 3)) + B = Ne(FiniteSet(a, b, c), FiniteSet(4, 5, 6)) + + assert A.canonical == A.reversed + assert B.canonical == B.reversed + + +def test_trigsimp(): + # issue 16736 + s, c = sin(2*x), cos(2*x) + eq = Eq(s, c) + assert trigsimp(eq) == eq # no rearrangement of sides + # simplification of sides might result in + # an unevaluated Eq + changed = trigsimp(Eq(s + c, sqrt(2))) + assert isinstance(changed, Eq) + assert changed.subs(x, pi/8) is S.true + # or an evaluated one + assert trigsimp(Eq(cos(x)**2 + sin(x)**2, 1)) is S.true + + +def test_polynomial_relation_simplification(): + assert Ge(3*x*(x + 1) + 4, 3*x).simplify() in [Ge(x**2, -Rational(4,3)), Le(-x**2, Rational(4, 3))] + assert Le(-(3*x*(x + 1) + 4), -3*x).simplify() in [Ge(x**2, -Rational(4,3)), Le(-x**2, Rational(4, 3))] + assert ((x**2+3)*(x**2-1)+3*x >= 2*x**2).simplify() in [(x**4 + 3*x >= 3), (-x**4 - 3*x <= -3)] + + +def test_multivariate_linear_function_simplification(): + assert Ge(x + y, x - y).simplify() == Ge(y, 0) + assert Le(-x + y, -x - y).simplify() == Le(y, 0) + assert Eq(2*x + y, 2*x + y - 3).simplify() == False + assert (2*x + y > 2*x + y - 3).simplify() == True + assert (2*x + y < 2*x + y - 3).simplify() == False + assert (2*x + y < 2*x + y + 3).simplify() == True + a, b, c, d, e, f, g = symbols('a b c d e f g') + assert Lt(a + b + c + 2*d, 3*d - f + g). simplify() == Lt(a, -b - c + d - f + g) + + +def test_nonpolymonial_relations(): + assert Eq(cos(x), 0).simplify() == Eq(cos(x), 0) + +def test_18778(): + raises(TypeError, lambda: is_le(Basic(), Basic())) + raises(TypeError, lambda: is_gt(Basic(), Basic())) + raises(TypeError, lambda: is_ge(Basic(), Basic())) + raises(TypeError, lambda: is_lt(Basic(), Basic())) + +def test_EvalEq(): + """ + + This test exists to ensure backwards compatibility. + The method to use is _eval_is_eq + """ + from sympy.core.expr import Expr + + class PowTest(Expr): + def __new__(cls, base, exp): + return Basic.__new__(PowTest, _sympify(base), _sympify(exp)) + + def _eval_Eq(lhs, rhs): + if type(lhs) == PowTest and type(rhs) == PowTest: + return lhs.args[0] == rhs.args[0] and lhs.args[1] == rhs.args[1] + + assert is_eq(PowTest(3, 4), PowTest(3,4)) + assert is_eq(PowTest(3, 4), _sympify(4)) is None + assert is_neq(PowTest(3, 4), PowTest(3,7)) + + +def test_is_eq(): + # test assumptions + assert is_eq(x, y, Q.infinite(x) & Q.finite(y)) is False + assert is_eq(x, y, Q.infinite(x) & Q.infinite(y) & Q.extended_real(x) & ~Q.extended_real(y)) is False + assert is_eq(x, y, Q.infinite(x) & Q.infinite(y) & Q.extended_positive(x) & Q.extended_negative(y)) is False + + assert is_eq(x+I, y+I, Q.infinite(x) & Q.finite(y)) is False + assert is_eq(1+x*I, 1+y*I, Q.infinite(x) & Q.finite(y)) is False + + assert is_eq(x, S(0), assumptions=Q.zero(x)) + assert is_eq(x, S(0), assumptions=~Q.zero(x)) is False + assert is_eq(x, S(0), assumptions=Q.nonzero(x)) is False + assert is_neq(x, S(0), assumptions=Q.zero(x)) is False + assert is_neq(x, S(0), assumptions=~Q.zero(x)) + assert is_neq(x, S(0), assumptions=Q.nonzero(x)) + + # test registration + class PowTest(Expr): + def __new__(cls, base, exp): + return Basic.__new__(cls, _sympify(base), _sympify(exp)) + + @dispatch(PowTest, PowTest) + def _eval_is_eq(lhs, rhs): + if type(lhs) == PowTest and type(rhs) == PowTest: + return fuzzy_and([is_eq(lhs.args[0], rhs.args[0]), is_eq(lhs.args[1], rhs.args[1])]) + + assert is_eq(PowTest(3, 4), PowTest(3,4)) + assert is_eq(PowTest(3, 4), _sympify(4)) is None + assert is_neq(PowTest(3, 4), PowTest(3,7)) + + +def test_is_ge_le(): + # test assumptions + assert is_ge(x, S(0), Q.nonnegative(x)) is True + assert is_ge(x, S(0), Q.negative(x)) is False + + # test registration + class PowTest(Expr): + def __new__(cls, base, exp): + return Basic.__new__(cls, _sympify(base), _sympify(exp)) + + @dispatch(PowTest, PowTest) + def _eval_is_ge(lhs, rhs): + if type(lhs) == PowTest and type(rhs) == PowTest: + return fuzzy_and([is_ge(lhs.args[0], rhs.args[0]), is_ge(lhs.args[1], rhs.args[1])]) + + assert is_ge(PowTest(3, 9), PowTest(3,2)) + assert is_gt(PowTest(3, 9), PowTest(3,2)) + assert is_le(PowTest(3, 2), PowTest(3,9)) + assert is_lt(PowTest(3, 2), PowTest(3,9)) + + +def test_weak_strict(): + for func in (Eq, Ne): + eq = func(x, 1) + assert eq.strict == eq.weak == eq + eq = Gt(x, 1) + assert eq.weak == Ge(x, 1) + assert eq.strict == eq + eq = Lt(x, 1) + assert eq.weak == Le(x, 1) + assert eq.strict == eq + eq = Ge(x, 1) + assert eq.strict == Gt(x, 1) + assert eq.weak == eq + eq = Le(x, 1) + assert eq.strict == Lt(x, 1) + assert eq.weak == eq + + +def test_issue_23731(): + i = symbols('i', integer=True) + assert unchanged(Eq, i, 1.0) + assert unchanged(Eq, i/2, 0.5) + ni = symbols('ni', integer=False) + assert Eq(ni, 1) == False + assert unchanged(Eq, ni, .1) + assert Eq(ni, 1.0) == False + nr = symbols('nr', rational=False) + assert Eq(nr, .1) == False + + +def test_rewrite_Add(): + from sympy.testing.pytest import warns_deprecated_sympy + with warns_deprecated_sympy(): + assert Eq(x, y).rewrite(Add) == x - y diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_rules.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_rules.py new file mode 100644 index 0000000000000000000000000000000000000000..31cb88b52db21f39653033b4567526e992be99f0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_rules.py @@ -0,0 +1,14 @@ +from sympy.core.rules import Transform + +from sympy.testing.pytest import raises + + +def test_Transform(): + 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 + + raises(KeyError, lambda: add1[2]) + assert (2 in add1) is False + assert add1.get(2) is None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_singleton.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_singleton.py new file mode 100644 index 0000000000000000000000000000000000000000..893713f27d74b884391ad800d186eafe5337ab1c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_singleton.py @@ -0,0 +1,76 @@ +from sympy.core.basic import Basic +from sympy.core.numbers import Rational +from sympy.core.singleton import S, Singleton + +def test_Singleton(): + + class MySingleton(Basic, metaclass=Singleton): + pass + + MySingleton() # force instantiation + assert MySingleton() is not Basic() + assert MySingleton() is MySingleton() + assert S.MySingleton is MySingleton() + + class MySingleton_sub(MySingleton): + pass + + MySingleton_sub() + assert MySingleton_sub() is not MySingleton() + assert MySingleton_sub() is MySingleton_sub() + +def test_singleton_redefinition(): + class TestSingleton(Basic, metaclass=Singleton): + pass + + assert TestSingleton() is S.TestSingleton + + class TestSingleton(Basic, metaclass=Singleton): + pass + + assert TestSingleton() is S.TestSingleton + +def test_names_in_namespace(): + # Every singleton name should be accessible from the 'from sympy import *' + # namespace in addition to the S object. However, it does not need to be + # by the same name (e.g., oo instead of S.Infinity). + + # As a general rule, things should only be added to the singleton registry + # if they are used often enough that code can benefit either from the + # performance benefit of being able to use 'is' (this only matters in very + # tight loops), or from the memory savings of having exactly one instance + # (this matters for the numbers singletons, but very little else). The + # singleton registry is already a bit overpopulated, and things cannot be + # removed from it without breaking backwards compatibility. So if you got + # here by adding something new to the singletons, ask yourself if it + # really needs to be singletonized. Note that SymPy classes compare to one + # another just fine, so Class() == Class() will give True even if each + # Class() returns a new instance. Having unique instances is only + # necessary for the above noted performance gains. It should not be needed + # for any behavioral purposes. + + # If you determine that something really should be a singleton, it must be + # accessible to sympify() without using 'S' (hence this test). Also, its + # str printer should print a form that does not use S. This is because + # sympify() disables attribute lookups by default for safety purposes. + d = {} + exec('from sympy import *', d) + + for name in dir(S) + list(S._classes_to_install): + if name.startswith('_'): + continue + if name == 'register': + continue + if isinstance(getattr(S, name), Rational): + continue + if getattr(S, name).__module__.startswith('sympy.physics'): + continue + if name in ['MySingleton', 'MySingleton_sub', 'TestSingleton']: + # From the tests above + continue + if name == 'NegativeInfinity': + # Accessible by -oo + continue + + # Use is here to ensure it is the exact same object + assert any(getattr(S, name) is i for i in d.values()), name diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_sorting.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_sorting.py new file mode 100644 index 0000000000000000000000000000000000000000..a18dbfb624552cf2fa11bb7f3c3a9e865caeb0c4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_sorting.py @@ -0,0 +1,28 @@ +from sympy.core.sorting import default_sort_key, ordered +from sympy.testing.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] + + class C: + def __repr__(self): + return 'x.y' + func = C() + assert sorted([x, func], key=default_sort_key) == [func, x] + + +def test_ordered(): + # Issue 7210 - this had been failing with python2/3 problems + assert (list(ordered([{1:3, 2:4, 9:10}, {1:3}])) == \ + [{1: 3}, {1: 3, 2: 4, 9: 10}]) + # warnings should not be raised for identical items + l = [1, 1] + assert list(ordered(l, warn=True)) == l + l = [[1], [2], [1]] + assert list(ordered(l, warn=True)) == [[1], [1], [2]] + raises(ValueError, lambda: list(ordered(['a', 'ab'], keys=[lambda x: x[0]], + default=False, warn=True))) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_subs.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_subs.py new file mode 100644 index 0000000000000000000000000000000000000000..0803a4b1b5e93b8a35f43516ccef3ab9a16f08ec --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_subs.py @@ -0,0 +1,895 @@ +from sympy.calculus.accumulationbounds import AccumBounds +from sympy.core.add import Add +from sympy.core.basic import Basic +from sympy.core.containers import (Dict, Tuple) +from sympy.core.function import (Derivative, Function, Lambda, Subs) +from sympy.core.mul import Mul +from sympy.core.numbers import (Float, I, Integer, Rational, oo, pi, zoo) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, Wild, symbols) +from sympy.core.sympify import SympifyError +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (atan2, cos, cot, sin, tan) +from sympy.matrices.dense import (Matrix, zeros) +from sympy.matrices.expressions.special import ZeroMatrix +from sympy.polys.polytools import factor +from sympy.polys.rootoftools import RootOf +from sympy.simplify.cse_main import cse +from sympy.simplify.simplify import nsimplify +from sympy.core.basic import _aresame +from sympy.testing.pytest import XFAIL, raises +from sympy.abc import a, x, y, z, t + + +def test_subs(): + n3 = Rational(3) + e = x + e = e.subs(x, n3) + assert e == Rational(3) + + e = 2*x + assert e == 2*x + e = e.subs(x, n3) + assert e == Rational(6) + + +def test_subs_Matrix(): + z = zeros(2) + z1 = ZeroMatrix(2, 2) + assert (x*y).subs({x:z, y:0}) in [z, z1] + assert (x*y).subs({y:z, x:0}) == 0 + assert (x*y).subs({y:z, x:0}, simultaneous=True) in [z, z1] + assert (x + y).subs({x: z, y: z}, simultaneous=True) in [z, z1] + assert (x + y).subs({x: z, y: z}) in [z, z1] + + # Issue #15528 + assert Mul(Matrix([[3]]), x).subs(x, 2.0) == Matrix([[6.0]]) + # Does not raise a TypeError, see comment on the MatAdd postprocessor + assert Add(Matrix([[3]]), x).subs(x, 2.0) == Add(Matrix([[3]]), 2.0) + + +def test_subs_AccumBounds(): + e = x + e = e.subs(x, AccumBounds(1, 3)) + assert e == AccumBounds(1, 3) + + e = 2*x + e = e.subs(x, AccumBounds(1, 3)) + assert e == AccumBounds(2, 6) + + e = x + x**2 + e = e.subs(x, AccumBounds(-1, 1)) + assert e == AccumBounds(-1, 2) + + +def test_trigonometric(): + n3 = Rational(3) + e = (sin(x)**2).diff(x) + assert e == 2*sin(x)*cos(x) + e = e.subs(x, n3) + assert e == 2*cos(n3)*sin(n3) + + e = (sin(x)**2).diff(x) + assert e == 2*sin(x)*cos(x) + e = e.subs(sin(x), cos(x)) + assert e == 2*cos(x)**2 + + assert exp(pi).subs(exp, sin) == 0 + assert cos(exp(pi)).subs(exp, sin) == 1 + + i = Symbol('i', integer=True) + zoo = S.ComplexInfinity + assert tan(x).subs(x, pi/2) is zoo + assert cot(x).subs(x, pi) is zoo + assert cot(i*x).subs(x, pi) is zoo + assert tan(i*x).subs(x, pi/2) == tan(i*pi/2) + assert tan(i*x).subs(x, pi/2).subs(i, 1) is zoo + o = Symbol('o', odd=True) + assert tan(o*x).subs(x, pi/2) == tan(o*pi/2) + + +def test_powers(): + assert sqrt(1 - sqrt(x)).subs(x, 4) == I + assert (sqrt(1 - x**2)**3).subs(x, 2) == - 3*I*sqrt(3) + assert (x**Rational(1, 3)).subs(x, 27) == 3 + assert (x**Rational(1, 3)).subs(x, -27) == 3*(-1)**Rational(1, 3) + assert ((-x)**Rational(1, 3)).subs(x, 27) == 3*(-1)**Rational(1, 3) + n = Symbol('n', negative=True) + assert (x**n).subs(x, 0) is S.ComplexInfinity + assert exp(-1).subs(S.Exp1, 0) is S.ComplexInfinity + assert (x**(4.0*y)).subs(x**(2.0*y), n) == n**2.0 + assert (2**(x + 2)).subs(2, 3) == 3**(x + 3) + + +def test_logexppow(): # no eval() + x = Symbol('x', real=True) + w = Symbol('w') + e = (3**(1 + x) + 2**(1 + x))/(3**x + 2**x) + assert e.subs(2**x, w) != e + assert e.subs(exp(x*log(Rational(2))), w) != e + + +def test_bug(): + x1 = Symbol('x1') + x2 = Symbol('x2') + y = x1*x2 + assert y.subs(x1, Float(3.0)) == Float(3.0)*x2 + + +def test_subbug1(): + # see that they don't fail + (x**x).subs(x, 1) + (x**x).subs(x, 1.0) + + +def test_subbug2(): + # Ensure this does not cause infinite recursion + assert Float(7.7).epsilon_eq(abs(x).subs(x, -7.7)) + + +def test_dict_set(): + a, b, c = map(Wild, 'abc') + + f = 3*cos(4*x) + r = f.match(a*cos(b*x)) + assert r == {a: 3, b: 4} + e = a/b*sin(b*x) + assert e.subs(r) == r[a]/r[b]*sin(r[b]*x) + assert e.subs(r) == 3*sin(4*x) / 4 + s = set(r.items()) + assert e.subs(s) == r[a]/r[b]*sin(r[b]*x) + assert e.subs(s) == 3*sin(4*x) / 4 + + assert e.subs(r) == r[a]/r[b]*sin(r[b]*x) + assert e.subs(r) == 3*sin(4*x) / 4 + assert x.subs(Dict((x, 1))) == 1 + + +def test_dict_ambigous(): # see issue 3566 + f = x*exp(x) + g = z*exp(z) + + df = {x: y, exp(x): y} + dg = {z: y, exp(z): y} + + assert f.subs(df) == y**2 + assert g.subs(dg) == y**2 + + # and this is how order can affect the result + assert f.subs(x, y).subs(exp(x), y) == y*exp(y) + assert f.subs(exp(x), y).subs(x, y) == y**2 + + # length of args and count_ops are the same so + # default_sort_key resolves ordering...if one + # doesn't want this result then an unordered + # sequence should not be used. + e = 1 + x*y + assert e.subs({x: y, y: 2}) == 5 + # here, there are no obviously clashing keys or values + # but the results depend on the order + assert exp(x/2 + y).subs({exp(y + 1): 2, x: 2}) == exp(y + 1) + + +def test_deriv_sub_bug3(): + f = Function('f') + pat = Derivative(f(x), x, x) + assert pat.subs(y, y**2) == Derivative(f(x), x, x) + assert pat.subs(y, y**2) != Derivative(f(x), x) + + +def test_equality_subs1(): + f = Function('f') + eq = Eq(f(x)**2, x) + res = Eq(Integer(16), x) + assert eq.subs(f(x), 4) == res + + +def test_equality_subs2(): + f = Function('f') + eq = Eq(f(x)**2, 16) + assert bool(eq.subs(f(x), 3)) is False + assert bool(eq.subs(f(x), 4)) is True + + +def test_issue_3742(): + e = sqrt(x)*exp(y) + assert e.subs(sqrt(x), 1) == exp(y) + + +def test_subs_dict1(): + assert (1 + x*y).subs(x, pi) == 1 + pi*y + assert (1 + x*y).subs({x: pi, y: 2}) == 1 + 2*pi + + c2, c3, q1p, q2p, c1, s1, s2, s3 = symbols('c2 c3 q1p q2p c1 s1 s2 s3') + test = (c2**2*q2p*c3 + c1**2*s2**2*q2p*c3 + s1**2*s2**2*q2p*c3 + - c1**2*q1p*c2*s3 - s1**2*q1p*c2*s3) + assert (test.subs({c1**2: 1 - s1**2, c2**2: 1 - s2**2, c3**3: 1 - s3**2}) + == c3*q2p*(1 - s2**2) + c3*q2p*s2**2*(1 - s1**2) + - c2*q1p*s3*(1 - s1**2) + c3*q2p*s1**2*s2**2 - c2*q1p*s3*s1**2) + + +def test_mul(): + x, y, z, a, b, c = symbols('x y z a b c') + A, B, C = symbols('A B C', commutative=0) + assert (x*y*z).subs(z*x, y) == y**2 + assert (z*x).subs(1/x, z) == 1 + assert (x*y/z).subs(1/z, a) == a*x*y + assert (x*y/z).subs(x/z, a) == a*y + assert (x*y/z).subs(y/z, a) == a*x + assert (x*y/z).subs(x/z, 1/a) == y/a + assert (x*y/z).subs(x, 1/a) == y/(z*a) + assert (2*x*y).subs(5*x*y, z) != z*Rational(2, 5) + assert (x*y*A).subs(x*y, a) == a*A + assert (x**2*y**(x*Rational(3, 2))).subs(x*y**(x/2), 2) == 4*y**(x/2) + assert (x*exp(x*2)).subs(x*exp(x), 2) == 2*exp(x) + assert ((x**(2*y))**3).subs(x**y, 2) == 64 + assert (x*A*B).subs(x*A, y) == y*B + assert (x*y*(1 + x)*(1 + x*y)).subs(x*y, 2) == 6*(1 + x) + assert ((1 + A*B)*A*B).subs(A*B, x*A*B) + assert (x*a/z).subs(x/z, A) == a*A + assert (x**3*A).subs(x**2*A, a) == a*x + assert (x**2*A*B).subs(x**2*B, a) == a*A + assert (x**2*A*B).subs(x**2*A, a) == a*B + assert (b*A**3/(a**3*c**3)).subs(a**4*c**3*A**3/b**4, z) == \ + b*A**3/(a**3*c**3) + assert (6*x).subs(2*x, y) == 3*y + assert (y*exp(x*Rational(3, 2))).subs(y*exp(x), 2) == 2*exp(x/2) + assert (y*exp(x*Rational(3, 2))).subs(y*exp(x), 2) == 2*exp(x/2) + assert (A**2*B*A**2*B*A**2).subs(A*B*A, C) == A*C**2*A + assert (x*A**3).subs(x*A, y) == y*A**2 + assert (x**2*A**3).subs(x*A, y) == y**2*A + assert (x*A**3).subs(x*A, B) == B*A**2 + assert (x*A*B*A*exp(x*A*B)).subs(x*A, B) == B**2*A*exp(B*B) + assert (x**2*A*B*A*exp(x*A*B)).subs(x*A, B) == B**3*exp(B**2) + assert (x**3*A*exp(x*A*B)*A*exp(x*A*B)).subs(x*A, B) == \ + x*B*exp(B**2)*B*exp(B**2) + assert (x*A*B*C*A*B).subs(x*A*B, C) == C**2*A*B + assert (-I*a*b).subs(a*b, 2) == -2*I + + # issue 6361 + assert (-8*I*a).subs(-2*a, 1) == 4*I + assert (-I*a).subs(-a, 1) == I + + # issue 6441 + assert (4*x**2).subs(2*x, y) == y**2 + assert (2*4*x**2).subs(2*x, y) == 2*y**2 + assert (-x**3/9).subs(-x/3, z) == -z**2*x + assert (-x**3/9).subs(x/3, z) == -z**2*x + assert (-2*x**3/9).subs(x/3, z) == -2*x*z**2 + assert (-2*x**3/9).subs(-x/3, z) == -2*x*z**2 + assert (-2*x**3/9).subs(-2*x, z) == z*x**2/9 + assert (-2*x**3/9).subs(2*x, z) == -z*x**2/9 + assert (2*(3*x/5/7)**2).subs(3*x/5, z) == 2*(Rational(1, 7))**2*z**2 + assert (4*x).subs(-2*x, z) == 4*x # try keep subs literal + + +def test_subs_simple(): + a = symbols('a', commutative=True) + x = symbols('x', commutative=False) + + assert (2*a).subs(1, 3) == 2*a + assert (2*a).subs(2, 3) == 3*a + assert (2*a).subs(a, 3) == 6 + assert sin(2).subs(1, 3) == sin(2) + assert sin(2).subs(2, 3) == sin(3) + assert sin(a).subs(a, 3) == sin(3) + + assert (2*x).subs(1, 3) == 2*x + assert (2*x).subs(2, 3) == 3*x + assert (2*x).subs(x, 3) == 6 + assert sin(x).subs(x, 3) == sin(3) + + +def test_subs_constants(): + a, b = symbols('a b', commutative=True) + x, y = symbols('x y', commutative=False) + + assert (a*b).subs(2*a, 1) == a*b + assert (1.5*a*b).subs(a, 1) == 1.5*b + assert (2*a*b).subs(2*a, 1) == b + assert (2*a*b).subs(4*a, 1) == 2*a*b + + assert (x*y).subs(2*x, 1) == x*y + assert (1.5*x*y).subs(x, 1) == 1.5*y + assert (2*x*y).subs(2*x, 1) == y + assert (2*x*y).subs(4*x, 1) == 2*x*y + + +def test_subs_commutative(): + a, b, c, d, K = symbols('a b c d K', commutative=True) + + assert (a*b).subs(a*b, K) == K + assert (a*b*a*b).subs(a*b, K) == K**2 + assert (a*a*b*b).subs(a*b, K) == K**2 + assert (a*b*c*d).subs(a*b*c, K) == d*K + assert (a*b**c).subs(a, K) == K*b**c + assert (a*b**c).subs(b, K) == a*K**c + assert (a*b**c).subs(c, K) == a*b**K + assert (a*b*c*b*a).subs(a*b, K) == c*K**2 + assert (a**3*b**2*a).subs(a*b, K) == a**2*K**2 + + +def test_subs_noncommutative(): + w, x, y, z, L = symbols('w x y z L', commutative=False) + alpha = symbols('alpha', commutative=True) + someint = symbols('someint', commutative=True, integer=True) + + assert (x*y).subs(x*y, L) == L + assert (w*y*x).subs(x*y, L) == w*y*x + assert (w*x*y*z).subs(x*y, L) == w*L*z + assert (x*y*x*y).subs(x*y, L) == L**2 + assert (x*x*y).subs(x*y, L) == x*L + assert (x*x*y*y).subs(x*y, L) == x*L*y + assert (w*x*y).subs(x*y*z, L) == w*x*y + assert (x*y**z).subs(x, L) == L*y**z + assert (x*y**z).subs(y, L) == x*L**z + assert (x*y**z).subs(z, L) == x*y**L + assert (w*x*y*z*x*y).subs(x*y*z, L) == w*L*x*y + assert (w*x*y*y*w*x*x*y*x*y*y*x*y).subs(x*y, L) == w*L*y*w*x*L**2*y*L + + # Check fractional power substitutions. It should not do + # substitutions that choose a value for noncommutative log, + # or inverses that don't already appear in the expressions. + assert (x*x*x).subs(x*x, L) == L*x + assert (x*x*x*y*x*x*x*x).subs(x*x, L) == L*x*y*L**2 + for p in range(1, 5): + for k in range(10): + assert (y * x**k).subs(x**p, L) == y * L**(k//p) * x**(k % p) + assert (x**Rational(3, 2)).subs(x**S.Half, L) == x**Rational(3, 2) + assert (x**S.Half).subs(x**S.Half, L) == L + assert (x**Rational(-1, 2)).subs(x**S.Half, L) == x**Rational(-1, 2) + assert (x**Rational(-1, 2)).subs(x**Rational(-1, 2), L) == L + + assert (x**(2*someint)).subs(x**someint, L) == L**2 + assert (x**(2*someint + 3)).subs(x**someint, L) == L**2*x**3 + assert (x**(3*someint + 3)).subs(x**someint, L) == L**3*x**3 + assert (x**(3*someint)).subs(x**(2*someint), L) == L * x**someint + assert (x**(4*someint)).subs(x**(2*someint), L) == L**2 + assert (x**(4*someint + 1)).subs(x**(2*someint), L) == L**2 * x + assert (x**(4*someint)).subs(x**(3*someint), L) == L * x**someint + assert (x**(4*someint + 1)).subs(x**(3*someint), L) == L * x**(someint + 1) + + assert (x**(2*alpha)).subs(x**alpha, L) == x**(2*alpha) + assert (x**(2*alpha + 2)).subs(x**2, L) == x**(2*alpha + 2) + assert ((2*z)**alpha).subs(z**alpha, y) == (2*z)**alpha + assert (x**(2*someint*alpha)).subs(x**someint, L) == x**(2*someint*alpha) + assert (x**(2*someint + alpha)).subs(x**someint, L) == x**(2*someint + alpha) + + # This could in principle be substituted, but is not currently + # because it requires recognizing that someint**2 is divisible by + # someint. + assert (x**(someint**2 + 3)).subs(x**someint, L) == x**(someint**2 + 3) + + # alpha**z := exp(log(alpha) z) is usually well-defined + assert (4**z).subs(2**z, y) == y**2 + + # Negative powers + assert (x**(-1)).subs(x**3, L) == x**(-1) + assert (x**(-2)).subs(x**3, L) == x**(-2) + assert (x**(-3)).subs(x**3, L) == L**(-1) + assert (x**(-4)).subs(x**3, L) == L**(-1) * x**(-1) + assert (x**(-5)).subs(x**3, L) == L**(-1) * x**(-2) + + assert (x**(-1)).subs(x**(-3), L) == x**(-1) + assert (x**(-2)).subs(x**(-3), L) == x**(-2) + assert (x**(-3)).subs(x**(-3), L) == L + assert (x**(-4)).subs(x**(-3), L) == L * x**(-1) + assert (x**(-5)).subs(x**(-3), L) == L * x**(-2) + + assert (x**1).subs(x**(-3), L) == x + assert (x**2).subs(x**(-3), L) == x**2 + assert (x**3).subs(x**(-3), L) == L**(-1) + assert (x**4).subs(x**(-3), L) == L**(-1) * x + assert (x**5).subs(x**(-3), L) == L**(-1) * x**2 + + +def test_subs_basic_funcs(): + a, b, c, d, K = symbols('a b c d K', commutative=True) + w, x, y, z, L = symbols('w x y z L', commutative=False) + + assert (x + y).subs(x + y, L) == L + assert (x - y).subs(x - y, L) == L + assert (x/y).subs(x, L) == L/y + assert (x**y).subs(x, L) == L**y + assert (x**y).subs(y, L) == x**L + assert ((a - c)/b).subs(b, K) == (a - c)/K + assert (exp(x*y - z)).subs(x*y, L) == exp(L - z) + assert (a*exp(x*y - w*z) + b*exp(x*y + w*z)).subs(z, 0) == \ + a*exp(x*y) + b*exp(x*y) + assert ((a - b)/(c*d - a*b)).subs(c*d - a*b, K) == (a - b)/K + assert (w*exp(a*b - c)*x*y/4).subs(x*y, L) == w*exp(a*b - c)*L/4 + + +def test_subs_wild(): + R, S, T, U = symbols('R S T U', cls=Wild) + + assert (R*S).subs(R*S, T) == T + assert (S*R).subs(R*S, T) == T + assert (R + S).subs(R + S, T) == T + assert (R**S).subs(R, T) == T**S + assert (R**S).subs(S, T) == R**T + assert (R*S**T).subs(R, U) == U*S**T + assert (R*S**T).subs(S, U) == R*U**T + assert (R*S**T).subs(T, U) == R*S**U + + +def test_subs_mixed(): + a, b, c, d, K = symbols('a b c d K', commutative=True) + w, x, y, z, L = symbols('w x y z L', commutative=False) + R, S, T, U = symbols('R S T U', cls=Wild) + + assert (a*x*y).subs(x*y, L) == a*L + assert (a*b*x*y*x).subs(x*y, L) == a*b*L*x + assert (R*x*y*exp(x*y)).subs(x*y, L) == R*L*exp(L) + assert (a*x*y*y*x - x*y*z*exp(a*b)).subs(x*y, L) == a*L*y*x - L*z*exp(a*b) + e = c*y*x*y*x**(R*S - a*b) - T*(a*R*b*S) + assert e.subs(x*y, L).subs(a*b, K).subs(R*S, U) == \ + c*y*L*x**(U - K) - T*(U*K) + + +def test_division(): + a, b, c = symbols('a b c', commutative=True) + x, y, z = symbols('x y z', commutative=True) + + assert (1/a).subs(a, c) == 1/c + assert (1/a**2).subs(a, c) == 1/c**2 + assert (1/a**2).subs(a, -2) == Rational(1, 4) + assert (-(1/a**2)).subs(a, -2) == Rational(-1, 4) + + assert (1/x).subs(x, z) == 1/z + assert (1/x**2).subs(x, z) == 1/z**2 + assert (1/x**2).subs(x, -2) == Rational(1, 4) + assert (-(1/x**2)).subs(x, -2) == Rational(-1, 4) + + #issue 5360 + assert (1/x).subs(x, 0) == 1/S.Zero + + +def test_add(): + a, b, c, d, x, y, t = symbols('a b c d x y t') + + assert (a**2 - b - c).subs(a**2 - b, d) in [d - c, a**2 - b - c] + assert (a**2 - c).subs(a**2 - c, d) == d + assert (a**2 - b - c).subs(a**2 - c, d) in [d - b, a**2 - b - c] + assert (a**2 - x - c).subs(a**2 - c, d) in [d - x, a**2 - x - c] + assert (a**2 - b - sqrt(a)).subs(a**2 - sqrt(a), c) == c - b + assert (a + b + exp(a + b)).subs(a + b, c) == c + exp(c) + assert (c + b + exp(c + b)).subs(c + b, a) == a + exp(a) + assert (a + b + c + d).subs(b + c, x) == a + d + x + assert (a + b + c + d).subs(-b - c, x) == a + d - x + assert ((x + 1)*y).subs(x + 1, t) == t*y + assert ((-x - 1)*y).subs(x + 1, t) == -t*y + assert ((x - 1)*y).subs(x + 1, t) == y*(t - 2) + assert ((-x + 1)*y).subs(x + 1, t) == y*(-t + 2) + + # this should work every time: + e = a**2 - b - c + assert e.subs(Add(*e.args[:2]), d) == d + e.args[2] + assert e.subs(a**2 - c, d) == d - b + + # the fallback should recognize when a change has + # been made; while .1 == Rational(1, 10) they are not the same + # and the change should be made + assert (0.1 + a).subs(0.1, Rational(1, 10)) == Rational(1, 10) + a + + e = (-x*(-y + 1) - y*(y - 1)) + ans = (-x*(x) - y*(-x)).expand() + assert e.subs(-y + 1, x) == ans + + #Test issue 18747 + assert (exp(x) + cos(x)).subs(x, oo) == oo + assert Add(*[AccumBounds(-1, 1), oo]) == oo + assert Add(*[oo, AccumBounds(-1, 1)]) == oo + + +def test_subs_issue_4009(): + assert (I*Symbol('a')).subs(1, 2) == I*Symbol('a') + + +def test_functions_subs(): + f, g = symbols('f g', cls=Function) + l = Lambda((x, y), sin(x) + y) + assert (g(y, x) + cos(x)).subs(g, l) == sin(y) + x + cos(x) + assert (f(x)**2).subs(f, sin) == sin(x)**2 + assert (f(x, y)).subs(f, log) == log(x, y) + assert (f(x, y)).subs(f, sin) == f(x, y) + assert (sin(x) + atan2(x, y)).subs([[atan2, f], [sin, g]]) == \ + f(x, y) + g(x) + assert (g(f(x + y, x))).subs([[f, l], [g, exp]]) == exp(x + sin(x + y)) + + +def test_derivative_subs(): + f = Function('f') + g = Function('g') + assert Derivative(f(x), x).subs(f(x), y) != 0 + # need xreplace to put the function back, see #13803 + assert Derivative(f(x), x).subs(f(x), y).xreplace({y: f(x)}) == \ + Derivative(f(x), x) + # issues 5085, 5037 + assert cse(Derivative(f(x), x) + f(x))[1][0].has(Derivative) + assert cse(Derivative(f(x, y), x) + + Derivative(f(x, y), y))[1][0].has(Derivative) + eq = Derivative(g(x), g(x)) + assert eq.subs(g, f) == Derivative(f(x), f(x)) + assert eq.subs(g(x), f(x)) == Derivative(f(x), f(x)) + assert eq.subs(g, cos) == Subs(Derivative(y, y), y, cos(x)) + + +def test_derivative_subs2(): + f_func, g_func = symbols('f g', cls=Function) + f, g = f_func(x, y, z), g_func(x, y, z) + assert Derivative(f, x, y).subs(Derivative(f, x, y), g) == g + assert Derivative(f, y, x).subs(Derivative(f, x, y), g) == g + assert Derivative(f, x, y).subs(Derivative(f, x), g) == Derivative(g, y) + assert Derivative(f, x, y).subs(Derivative(f, y), g) == Derivative(g, x) + assert (Derivative(f, x, y, z).subs( + Derivative(f, x, z), g) == Derivative(g, y)) + assert (Derivative(f, x, y, z).subs( + Derivative(f, z, y), g) == Derivative(g, x)) + assert (Derivative(f, x, y, z).subs( + Derivative(f, z, y, x), g) == g) + + # Issue 9135 + assert (Derivative(f, x, x, y).subs( + Derivative(f, y, y), g) == Derivative(f, x, x, y)) + assert (Derivative(f, x, y, y, z).subs( + Derivative(f, x, y, y, y), g) == Derivative(f, x, y, y, z)) + + assert Derivative(f, x, y).subs(Derivative(f_func(x), x, y), g) == Derivative(f, x, y) + + +def test_derivative_subs3(): + dex = Derivative(exp(x), x) + assert Derivative(dex, x).subs(dex, exp(x)) == dex + assert dex.subs(exp(x), dex) == Derivative(exp(x), x, x) + + +def test_issue_5284(): + A, B = symbols('A B', commutative=False) + assert (x*A).subs(x**2*A, B) == x*A + assert (A**2).subs(A**3, B) == A**2 + assert (A**6).subs(A**3, B) == B**2 + + +def test_subs_iter(): + assert x.subs(reversed([[x, y]])) == y + it = iter([[x, y]]) + assert x.subs(it) == y + assert x.subs(Tuple((x, y))) == y + + +def test_subs_dict(): + a, b, c, d, e = symbols('a b c d e') + + assert (2*x + y + z).subs({"x": 1, "y": 2}) == 4 + z + + l = [(sin(x), 2), (x, 1)] + assert (sin(x)).subs(l) == \ + (sin(x)).subs(dict(l)) == 2 + assert sin(x).subs(reversed(l)) == sin(1) + + expr = sin(2*x) + sqrt(sin(2*x))*cos(2*x)*sin(exp(x)*x) + reps = {sin(2*x): c, + sqrt(sin(2*x)): a, + cos(2*x): b, + exp(x): e, + x: d,} + assert expr.subs(reps) == c + a*b*sin(d*e) + + l = [(x, 3), (y, x**2)] + assert (x + y).subs(l) == 3 + x**2 + assert (x + y).subs(reversed(l)) == 12 + + # If changes are made to convert lists into dictionaries and do + # a dictionary-lookup replacement, these tests will help to catch + # some logical errors that might occur + l = [(y, z + 2), (1 + z, 5), (z, 2)] + assert (y - 1 + 3*x).subs(l) == 5 + 3*x + l = [(y, z + 2), (z, 3)] + assert (y - 2).subs(l) == 3 + + +def test_no_arith_subs_on_floats(): + assert (x + 3).subs(x + 3, a) == a + assert (x + 3).subs(x + 2, a) == a + 1 + + assert (x + y + 3).subs(x + 3, a) == a + y + assert (x + y + 3).subs(x + 2, a) == a + y + 1 + + assert (x + 3.0).subs(x + 3.0, a) == a + assert (x + 3.0).subs(x + 2.0, a) == x + 3.0 + + assert (x + y + 3.0).subs(x + 3.0, a) == a + y + assert (x + y + 3.0).subs(x + 2.0, a) == x + y + 3.0 + + +def test_issue_5651(): + a, b, c, K = symbols('a b c K', commutative=True) + assert (a/(b*c)).subs(b*c, K) == a/K + assert (a/(b**2*c**3)).subs(b*c, K) == a/(c*K**2) + assert (1/(x*y)).subs(x*y, 2) == S.Half + assert ((1 + x*y)/(x*y)).subs(x*y, 1) == 2 + assert (x*y*z).subs(x*y, 2) == 2*z + assert ((1 + x*y)/(x*y)/z).subs(x*y, 1) == 2/z + + +def test_issue_6075(): + assert Tuple(1, True).subs(1, 2) == Tuple(2, True) + + +def test_issue_6079(): + # since x + 2.0 == x + 2 we can't do a simple equality test + assert _aresame((x + 2.0).subs(2, 3), x + 2.0) + assert _aresame((x + 2.0).subs(2.0, 3), x + 3) + assert not _aresame(x + 2, x + 2.0) + assert not _aresame(Basic(cos(x), S(1)), Basic(cos(x), S(1.))) + assert _aresame(cos, cos) + assert not _aresame(1, S.One) + assert not _aresame(x, symbols('x', positive=True)) + + +def test_issue_4680(): + N = Symbol('N') + assert N.subs({"N": 3}) == 3 + + +def test_issue_6158(): + assert (x - 1).subs(1, y) == x - y + assert (x - 1).subs(-1, y) == x + y + assert (x - oo).subs(oo, y) == x - y + assert (x - oo).subs(-oo, y) == x + y + + +def test_Function_subs(): + f, g, h, i = symbols('f g h i', cls=Function) + p = Piecewise((g(f(x, y)), x < -1), (g(x), x <= 1)) + assert p.subs(g, h) == Piecewise((h(f(x, y)), x < -1), (h(x), x <= 1)) + assert (f(y) + g(x)).subs({f: h, g: i}) == i(x) + h(y) + + +def test_simultaneous_subs(): + reps = {x: 0, y: 0} + assert (x/y).subs(reps) != (y/x).subs(reps) + assert (x/y).subs(reps, simultaneous=True) == \ + (y/x).subs(reps, simultaneous=True) + reps = reps.items() + assert (x/y).subs(reps) != (y/x).subs(reps) + assert (x/y).subs(reps, simultaneous=True) == \ + (y/x).subs(reps, simultaneous=True) + assert Derivative(x, y, z).subs(reps, simultaneous=True) == \ + Subs(Derivative(0, y, z), y, 0) + + +def test_issue_6419_6421(): + assert (1/(1 + x/y)).subs(x/y, x) == 1/(1 + x) + assert (-2*I).subs(2*I, x) == -x + assert (-I*x).subs(I*x, x) == -x + assert (-3*I*y**4).subs(3*I*y**2, x) == -x*y**2 + + +def test_issue_6559(): + assert (-12*x + y).subs(-x, 1) == 12 + y + # though this involves cse it generated a failure in Mul._eval_subs + x0, x1 = symbols('x0 x1') + e = -log(-12*sqrt(2) + 17)/24 - log(-2*sqrt(2) + 3)/12 + sqrt(2)/3 + # XXX modify cse so x1 is eliminated and x0 = -sqrt(2)? + assert cse(e) == ( + [(x0, sqrt(2))], [x0/3 - log(-12*x0 + 17)/24 - log(-2*x0 + 3)/12]) + + +def test_issue_5261(): + x = symbols('x', real=True) + e = I*x + assert exp(e).subs(exp(x), y) == y**I + assert (2**e).subs(2**x, y) == y**I + eq = (-2)**e + assert eq.subs((-2)**x, y) == eq + + +def test_issue_6923(): + assert (-2*x*sqrt(2)).subs(2*x, y) == -sqrt(2)*y + + +def test_2arg_hack(): + N = Symbol('N', commutative=False) + ans = Mul(2, y + 1, evaluate=False) + assert (2*x*(y + 1)).subs(x, 1, hack2=True) == ans + assert (2*(y + 1 + N)).subs(N, 0, hack2=True) == ans + + +@XFAIL +def test_mul2(): + """When this fails, remove things labelled "2-arg hack" + 1) remove special handling in the fallback of subs that + was added in the same commit as this test + 2) remove the special handling in Mul.flatten + """ + assert (2*(x + 1)).is_Mul + + +def test_noncommutative_subs(): + x,y = symbols('x,y', commutative=False) + assert (x*y*x).subs([(x, x*y), (y, x)], simultaneous=True) == (x*y*x**2*y) + + +def test_issue_2877(): + f = Float(2.0) + assert (x + f).subs({f: 2}) == x + 2 + + def r(a, b, c): + return factor(a*x**2 + b*x + c) + e = r(5.0/6, 10, 5) + assert nsimplify(e) == 5*x**2/6 + 10*x + 5 + + +def test_issue_5910(): + t = Symbol('t') + assert (1/(1 - t)).subs(t, 1) is zoo + n = t + d = t - 1 + assert (n/d).subs(t, 1) is zoo + assert (-n/-d).subs(t, 1) is zoo + + +def test_issue_5217(): + s = Symbol('s') + z = (1 - 2*x*x) + w = (1 + 2*x*x) + q = 2*x*x*2*y*y + sub = {2*x*x: s} + assert w.subs(sub) == 1 + s + assert z.subs(sub) == 1 - s + assert q == 4*x**2*y**2 + assert q.subs(sub) == 2*y**2*s + + +def test_issue_10829(): + assert (4**x).subs(2**x, y) == y**2 + assert (9**x).subs(3**x, y) == y**2 + + +def test_pow_eval_subs_no_cache(): + # Tests pull request 9376 is working + from sympy.core.cache import clear_cache + + s = 1/sqrt(x**2) + # This bug only appeared when the cache was turned off. + # We need to approximate running this test without the cache. + # This creates approximately the same situation. + clear_cache() + + # This used to fail with a wrong result. + # It incorrectly returned 1/sqrt(x**2) before this pull request. + result = s.subs(sqrt(x**2), y) + assert result == 1/y + + +def test_RootOf_issue_10092(): + x = Symbol('x', real=True) + eq = x**3 - 17*x**2 + 81*x - 118 + r = RootOf(eq, 0) + assert (x < r).subs(x, r) is S.false + + +def test_issue_8886(): + from sympy.physics.mechanics import ReferenceFrame as R + # if something can't be sympified we assume that it + # doesn't play well with SymPy and disallow the + # substitution + v = R('A').x + raises(SympifyError, lambda: x.subs(x, v)) + raises(SympifyError, lambda: v.subs(v, x)) + assert v.__eq__(x) is False + + +def test_issue_12657(): + # treat -oo like the atom that it is + reps = [(-oo, 1), (oo, 2)] + assert (x < -oo).subs(reps) == (x < 1) + assert (x < -oo).subs(list(reversed(reps))) == (x < 1) + reps = [(-oo, 2), (oo, 1)] + assert (x < oo).subs(reps) == (x < 1) + assert (x < oo).subs(list(reversed(reps))) == (x < 1) + + +def test_recurse_Application_args(): + F = Lambda((x, y), exp(2*x + 3*y)) + f = Function('f') + A = f(x, f(x, x)) + C = F(x, F(x, x)) + assert A.subs(f, F) == A.replace(f, F) == C + + +def test_Subs_subs(): + assert Subs(x*y, x, x).subs(x, y) == Subs(x*y, x, y) + assert Subs(x*y, x, x + 1).subs(x, y) == \ + Subs(x*y, x, y + 1) + assert Subs(x*y, y, x + 1).subs(x, y) == \ + Subs(y**2, y, y + 1) + a = Subs(x*y*z, (y, x, z), (x + 1, x + z, x)) + b = Subs(x*y*z, (y, x, z), (x + 1, y + z, y)) + assert a.subs(x, y) == b and \ + a.doit().subs(x, y) == a.subs(x, y).doit() + f = Function('f') + g = Function('g') + assert Subs(2*f(x, y) + g(x), f(x, y), 1).subs(y, 2) == Subs( + 2*f(x, y) + g(x), (f(x, y), y), (1, 2)) + + +def test_issue_13333(): + eq = 1/x + assert eq.subs({"x": '1/2'}) == 2 + assert eq.subs({"x": '(1/2)'}) == 2 + + +def test_issue_15234(): + x, y = symbols('x y', real=True) + p = 6*x**5 + x**4 - 4*x**3 + 4*x**2 - 2*x + 3 + p_subbed = 6*x**5 - 4*x**3 - 2*x + y**4 + 4*y**2 + 3 + assert p.subs([(x**i, y**i) for i in [2, 4]]) == p_subbed + x, y = symbols('x y', complex=True) + p = 6*x**5 + x**4 - 4*x**3 + 4*x**2 - 2*x + 3 + p_subbed = 6*x**5 - 4*x**3 - 2*x + y**4 + 4*y**2 + 3 + assert p.subs([(x**i, y**i) for i in [2, 4]]) == p_subbed + + +def test_issue_6976(): + x, y = symbols('x y') + assert (sqrt(x)**3 + sqrt(x) + x + x**2).subs(sqrt(x), y) == \ + y**4 + y**3 + y**2 + y + assert (x**4 + x**3 + x**2 + x + sqrt(x)).subs(x**2, y) == \ + sqrt(x) + x**3 + x + y**2 + y + assert x.subs(x**3, y) == x + assert x.subs(x**Rational(1, 3), y) == y**3 + + # More substitutions are possible with nonnegative symbols + x, y = symbols('x y', nonnegative=True) + assert (x**4 + x**3 + x**2 + x + sqrt(x)).subs(x**2, y) == \ + y**Rational(1, 4) + y**Rational(3, 2) + sqrt(y) + y**2 + y + assert x.subs(x**3, y) == y**Rational(1, 3) + + +def test_issue_11746(): + assert (1/x).subs(x**2, 1) == 1/x + assert (1/(x**3)).subs(x**2, 1) == x**(-3) + assert (1/(x**4)).subs(x**2, 1) == 1 + assert (1/(x**3)).subs(x**4, 1) == x**(-3) + assert (1/(y**5)).subs(x**5, 1) == y**(-5) + + +def test_issue_17823(): + from sympy.physics.mechanics import dynamicsymbols + q1, q2 = dynamicsymbols('q1, q2') + expr = q1.diff().diff()**2*q1 + q1.diff()*q2.diff() + reps={q1: a, q1.diff(): a*x*y, q1.diff().diff(): z} + assert expr.subs(reps) == a*x*y*Derivative(q2, t) + a*z**2 + + +def test_issue_19326(): + x, y = [i(t) for i in map(Function, 'xy')] + assert (x*y).subs({x: 1 + x, y: x}) == (1 + x)*x + + +def test_issue_19558(): + e = (7*x*cos(x) - 12*log(x)**3)*(-log(x)**4 + 2*sin(x) + 1)**2/ \ + (2*(x*cos(x) - 2*log(x)**3)*(3*log(x)**4 - 7*sin(x) + 3)**2) + + assert e.subs(x, oo) == AccumBounds(-oo, oo) + assert (sin(x) + cos(x)).subs(x, oo) == AccumBounds(-2, 2) + + +def test_issue_22033(): + xr = Symbol('xr', real=True) + e = (1/xr) + assert e.subs(xr**2, y) == e + + +def test_guard_against_indeterminate_evaluation(): + eq = x**y + assert eq.subs([(x, 1), (y, oo)]) == 1 # because 1**y == 1 + assert eq.subs([(y, oo), (x, 1)]) is S.NaN + assert eq.subs({x: 1, y: oo}) is S.NaN + assert eq.subs([(x, 1), (y, oo)], simultaneous=True) is S.NaN diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_symbol.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_symbol.py new file mode 100644 index 0000000000000000000000000000000000000000..acf27700825c4822456207afe95108480505ce2c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_symbol.py @@ -0,0 +1,421 @@ +import threading + +from sympy.core.function import Function, UndefinedFunction +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.relational import (GreaterThan, LessThan, StrictGreaterThan, StrictLessThan) +from sympy.core.symbol import (Dummy, Symbol, Wild, symbols) +from sympy.core.sympify import sympify # can't import as S yet +from sympy.core.symbol import uniquely_named_symbol, _symbol, Str + +from sympy.testing.pytest import raises, skip_under_pyodide +from sympy.core.symbol import disambiguate + + +def test_Str(): + a1 = Str('a') + a2 = Str('a') + b = Str('b') + assert a1 == a2 != b + raises(TypeError, lambda: Str()) + + +def test_Symbol(): + a = Symbol("a") + x1 = Symbol("x") + x2 = Symbol("x") + xdummy1 = Dummy("x") + xdummy2 = Dummy("x") + + assert a != x1 + assert a != x2 + assert x1 == x2 + assert x1 != xdummy1 + assert xdummy1 != xdummy2 + + assert Symbol("x") == Symbol("x") + assert Dummy("x") != Dummy("x") + d = symbols('d', cls=Dummy) + assert isinstance(d, Dummy) + c, d = symbols('c,d', cls=Dummy) + assert isinstance(c, Dummy) + assert isinstance(d, Dummy) + raises(TypeError, lambda: Symbol()) + + +def test_Dummy(): + assert Dummy() != Dummy() + + +def test_Dummy_force_dummy_index(): + raises(AssertionError, lambda: Dummy(dummy_index=1)) + assert Dummy('d', dummy_index=2) == Dummy('d', dummy_index=2) + assert Dummy('d1', dummy_index=2) != Dummy('d2', dummy_index=2) + d1 = Dummy('d', dummy_index=3) + d2 = Dummy('d') + # might fail if d1 were created with dummy_index >= 10**6 + assert d1 != d2 + d3 = Dummy('d', dummy_index=3) + assert d1 == d3 + assert Dummy()._count == Dummy('d', dummy_index=3)._count + + +def test_lt_gt(): + S = sympify + x, y = Symbol('x'), Symbol('y') + + 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 (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 (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) == LessThan(e, 0) + assert (0 >= e) == LessThan(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) + + +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 + ) + + left_e = e[:-1] + for i, e1 in enumerate( left_e ): + for e2 in e[i + 1:]: + assert e1 != e2 + + +def test_Wild_properties(): + S = sympify + # 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) + + given_patterns = [ x, y, p, k, -k, n, -n, S(-3), S(3), + pi, Rational(3, 2), I ] + + integerp = lambda k: k.is_integer + positivep = lambda k: k.is_positive + symbolp = lambda k: k.is_Symbol + realp = lambda k: k.is_extended_real + + S = Wild("S", properties=[symbolp]) + R = Wild("R", properties=[realp]) + Y = Wild("Y", exclude=[x, p, k, n]) + P = Wild("P", properties=[positivep]) + K = Wild("K", properties=[integerp]) + N = Wild("N", properties=[positivep, integerp]) + + 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)} + + for A in given_wildcards: + for pat in given_patterns: + d = pat.match(A) + if pat in goodmatch[A]: + assert d[A] in goodmatch[A] + else: + assert d is None + + +def test_symbols(): + x = Symbol('x') + y = Symbol('y') + z = Symbol('z') + + assert symbols('x') == x + assert symbols('x ') == x + assert symbols(' x ') == x + assert symbols('x,') == (x,) + assert symbols('x, ') == (x,) + assert symbols('x ,') == (x,) + + assert symbols('x , y') == (x, y) + + assert symbols('x,y,z') == (x, y, z) + assert symbols('x y z') == (x, y, z) + + assert symbols('x,y,z,') == (x, y, z) + assert symbols('x y z ') == (x, y, z) + + xyz = Symbol('xyz') + abc = Symbol('abc') + + assert symbols('xyz') == xyz + assert symbols('xyz,') == (xyz,) + assert symbols('xyz,abc') == (xyz, abc) + + assert symbols(('xyz',)) == (xyz,) + assert symbols(('xyz,',)) == ((xyz,),) + assert symbols(('x,y,z,',)) == ((x, y, z),) + assert symbols(('xyz', 'abc')) == (xyz, abc) + assert symbols(('xyz,abc',)) == ((xyz, abc),) + assert symbols(('xyz,abc', 'x,y,z')) == ((xyz, abc), (x, y, z)) + + assert symbols(('x', 'y', 'z')) == (x, y, z) + assert symbols(['x', 'y', 'z']) == [x, y, z] + assert symbols({'x', 'y', 'z'}) == {x, y, z} + + raises(ValueError, lambda: symbols('')) + raises(ValueError, lambda: symbols(',')) + raises(ValueError, lambda: symbols('x,,y,,z')) + raises(ValueError, lambda: symbols(('x', '', 'y', '', 'z'))) + + a, b = symbols('x,y', real=True) + assert a.is_real and b.is_real + + x0 = Symbol('x0') + x1 = Symbol('x1') + x2 = Symbol('x2') + + y0 = Symbol('y0') + y1 = Symbol('y1') + + assert symbols('x0:0') == () + assert symbols('x0:1') == (x0,) + assert symbols('x0:2') == (x0, x1) + assert symbols('x0:3') == (x0, x1, x2) + + assert symbols('x:0') == () + assert symbols('x:1') == (x0,) + assert symbols('x:2') == (x0, x1) + assert symbols('x:3') == (x0, x1, x2) + + assert symbols('x1:1') == () + assert symbols('x1:2') == (x1,) + assert symbols('x1:3') == (x1, x2) + + assert symbols('x1:3,x,y,z') == (x1, x2, x, y, z) + + assert symbols('x:3,y:2') == (x0, x1, x2, y0, y1) + assert symbols(('x:3', 'y:2')) == ((x0, x1, x2), (y0, y1)) + + a = Symbol('a') + b = Symbol('b') + c = Symbol('c') + d = Symbol('d') + + assert symbols('x:z') == (x, y, z) + 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)) + + assert type(symbols(('q:2', 'u:2'), cls=Function)[0][0]) == UndefinedFunction # issue 23532 + + # issue 6675 + 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(r'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_symbols_become_functions_issue_3539(): + from sympy.abc import alpha, phi, beta, t + raises(TypeError, lambda: beta(2)) + raises(TypeError, lambda: beta(2.5)) + raises(TypeError, lambda: phi(2.5)) + raises(TypeError, lambda: alpha(2.5)) + raises(TypeError, lambda: phi(t)) + + +def test_unicode(): + xu = Symbol('x') + x = Symbol('x') + assert x == xu + + raises(TypeError, lambda: Symbol(1)) + + +def test_uniquely_named_symbol_and_Symbol(): + F = uniquely_named_symbol + x = Symbol('x') + assert F(x) == x + assert F('x') == x + assert str(F('x', x)) == 'x0' + assert str(F('x', (x + 1, 1/x))) == 'x0' + _x = Symbol('x', real=True) + assert F(('x', _x)) == _x + assert F((x, _x)) == _x + assert F('x', real=True).is_real + y = Symbol('y') + assert F(('x', y), real=True).is_real + r = Symbol('x', real=True) + assert F(('x', r)).is_real + assert F(('x', r), real=False).is_real + assert F('x1', Symbol('x1'), + compare=lambda i: str(i).rstrip('1')).name == 'x0' + assert F('x1', Symbol('x1'), + modify=lambda i: i + '_').name == 'x1_' + assert _symbol(x, _x) == x + + +def test_disambiguate(): + x, y, y_1, _x, x_1, x_2 = symbols('x y y_1 _x x_1 x_2') + t1 = Dummy('y'), _x, Dummy('x'), Dummy('x') + t2 = Dummy('x'), Dummy('x') + t3 = Dummy('x'), Dummy('y') + t4 = x, Dummy('x') + t5 = Symbol('x', integer=True), x, Symbol('x_1') + + assert disambiguate(*t1) == (y, x_2, x, x_1) + assert disambiguate(*t2) == (x, x_1) + assert disambiguate(*t3) == (x, y) + assert disambiguate(*t4) == (x_1, x) + assert disambiguate(*t5) == (t5[0], x_2, x_1) + assert disambiguate(*t5)[0] != x # assumptions are retained + + t6 = _x, Dummy('x')/y + t7 = y*Dummy('y'), y + + assert disambiguate(*t6) == (x_1, x/y) + assert disambiguate(*t7) == (y*y_1, y_1) + assert disambiguate(Dummy('x_1'), Dummy('x_1') + ) == (x_1, Symbol('x_1_1')) + + +@skip_under_pyodide("Cannot create threads under pyodide.") +def test_issue_gh_16734(): + # https://github.com/sympy/sympy/issues/16734 + + syms = list(symbols('x, y')) + + def thread1(): + for n in range(1000): + syms[0], syms[1] = symbols(f'x{n}, y{n}') + syms[0].is_positive # Check an assumption in this thread. + syms[0] = None + + def thread2(): + while syms[0] is not None: + # Compare the symbol in this thread. + result = (syms[0] == syms[1]) # noqa + + # Previously this would be very likely to raise an exception: + thread = threading.Thread(target=thread1) + thread.start() + thread2() + thread.join() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_sympify.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_sympify.py new file mode 100644 index 0000000000000000000000000000000000000000..40be30c25d5826ceadde6d176c160a0090967659 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_sympify.py @@ -0,0 +1,892 @@ +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.function import (Function, Lambda) +from sympy.core.mul import Mul +from sympy.core.numbers import (Float, I, Integer, Rational, pi, oo) +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.logic.boolalg import (false, Or, true, Xor) +from sympy.matrices.dense import Matrix +from sympy.parsing.sympy_parser import null +from sympy.polys.polytools import Poly +from sympy.printing.repr import srepr +from sympy.sets.fancysets import Range +from sympy.sets.sets import Interval +from sympy.abc import x, y +from sympy.core.sympify import (sympify, _sympify, SympifyError, kernS, + CantSympify, converter) +from sympy.core.decorators import _sympifyit +from sympy.external import import_module +from sympy.testing.pytest import raises, XFAIL, skip +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.external.gmpy import gmpy as _gmpy, flint as _flint +from sympy.sets import FiniteSet, EmptySet +from sympy.tensor.array.dense_ndim_array import ImmutableDenseNDimArray + +import mpmath +from collections import defaultdict, OrderedDict + + +numpy = import_module('numpy') + + +def test_issue_3538(): + 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") + assert sympify(" x ") == Symbol("x") + # issue 4877 + assert sympify('--.5') == 0.5 + assert sympify('-1/2') == -S.Half + assert sympify('-+--.5') == -0.5 + assert sympify('-.[3]') == Rational(-1, 3) + assert sympify('.[3]') == Rational(1, 3) + assert sympify('+.[3]') == Rational(1, 3) + assert sympify('+0.[3]*10**-2') == Rational(1, 300) + assert sympify('.[052631578947368421]') == Rational(1, 19) + 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=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) + # ... even if they come from repetend notation + assert sympify('1/.2[123456789012]') == Rational(333333333333, 70781892967) + # ... or from high precision reals + assert sympify('.1234567890123456', rational=True) == \ + Rational(19290123283179, 156250000000000) + + +def test_sympify_Fraction(): + try: + import fractions + except ImportError: + pass + else: + value = sympify(fractions.Fraction(101, 127)) + assert value == Rational(101, 127) and type(value) is Rational + + +def test_sympify_gmpy(): + if _gmpy is not None: + import gmpy2 + + value = sympify(gmpy2.mpz(1000001)) + assert value == Integer(1000001) and type(value) is Integer + + value = sympify(gmpy2.mpq(101, 127)) + assert value == Rational(101, 127) and type(value) is Rational + + +def test_sympify_flint(): + if _flint is not None: + import flint + + value = sympify(flint.fmpz(1000001)) + assert value == Integer(1000001) and type(value) is Integer + + value = sympify(flint.fmpq(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")) == True + assert sympify( + mpmath.pi).epsilon_eq(Float("3.14159265359"), Float("1e-13")) == False + + mpmath.mp.dps = 6 + assert sympify( + mpmath.pi).epsilon_eq(Float("3.14159"), Float("1e-5")) == True + assert sympify( + mpmath.pi).epsilon_eq(Float("3.14159"), Float("1e-6")) == False + + mpmath.mp.dps = 15 + assert sympify(mpmath.mpc(1.0 + 2.0j)) == Float(1.0) + Float(2.0)*I + + +def test_sympify2(): + class A: + def _sympy_(self): + return Symbol("x")**3 + + a = A() + + 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 + assert sympify("1/2") == Integer(1)/2 + + 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(): + assert sympify(True) is true + assert sympify(False) is false + + +def test_sympify_iterables(): + ans = [Rational(3, 10), Rational(1, 5)] + assert sympify(['.3', '.2'], rational=True) == ans + assert sympify({"x": 0, "y": 1}) == {x: 0, y: 1} + assert sympify(['1', '2', ['3', '4']]) == [S(1), S(2), [S(3), S(4)]] + + +@XFAIL +def test_issue_16772(): + # because there is a converter for tuple, the + # args are only sympified without the flags being passed + # along; list, on the other hand, is not converted + # with a converter so its args are traversed later + ans = [Rational(3, 10), Rational(1, 5)] + assert sympify(('.3', '.2'), rational=True) == Tuple(*ans) + + +def test_issue_16859(): + class no(float, CantSympify): + pass + raises(SympifyError, lambda: sympify(no(1.2))) + + +def test_sympify4(): + class A: + def _sympy_(self): + return Symbol("x") + + a = A() + + 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') 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('sin(pi/2)*cos(pi)') == -Integer(1) + + +def test_sympify_poly(): + 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('(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('(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) + assert sympify('factorial2(x)!') == factorial(factorial2(x)) + + raises(SympifyError, lambda: sympify("+!!")) + raises(SympifyError, lambda: sympify(")!!")) + raises(SympifyError, lambda: sympify("!")) + raises(SympifyError, lambda: sympify("(!)")) + raises(SympifyError, lambda: sympify("x!!!")) + + +def test_issue_3595(): + assert sympify("a_") == Symbol("a_") + assert sympify("_a") == Symbol("_a") + + +def test_lambda(): + x = Symbol('x') + assert sympify('lambda: 1') == Lambda((), 1) + assert sympify('lambda x: x') == Lambda(x, x) + assert sympify('lambda x: 2*x') == Lambda(x, 2*x) + assert sympify('lambda x, y: 2*x+y') == Lambda((x, y), 2*x + y) + + +def test_lambda_raises(): + raises(SympifyError, lambda: sympify("lambda *args: args")) # args argument error + raises(SympifyError, lambda: sympify("lambda **kwargs: kwargs[0]")) # kwargs argument error + raises(SympifyError, lambda: sympify("lambda x = 1: x")) # Keyword argument error + with raises(SympifyError): + _sympify('lambda: 1') + + +def test_sympify_raises(): + raises(SympifyError, lambda: sympify("fx)")) + + class A: + def __str__(self): + return 'x' + + raises(SympifyError, lambda: sympify(A())) + + +def test__sympify(): + x = Symbol('x') + f = Function('f') + + # positive _sympify + assert _sympify(x) is x + assert _sympify(1) == Integer(1) + assert _sympify(0.5) == Float("0.5") + assert _sympify(1 + 1j) == 1.0 + I*1.0 + + # Function f is not Basic and can't sympify to Basic. We allow it to pass + # with sympify but not with _sympify. + # https://github.com/sympy/sympy/issues/20124 + assert sympify(f) is f + raises(SympifyError, lambda: _sympify(f)) + + class A: + def _sympy_(self): + return Integer(5) + + a = A() + assert _sympify(a) == Integer(5) + + # negative _sympify + raises(SympifyError, lambda: _sympify('1')) + raises(SympifyError, lambda: _sympify([1, 2, 3])) + + +def test_sympifyit(): + x = Symbol('x') + y = Symbol('y') + + @_sympifyit('b', NotImplemented) + def add(a, b): + return a + b + + assert add(x, 1) == x + 1 + assert add(x, 0.5) == x + Float('0.5') + assert add(x, y) == x + y + + assert add(x, '1') == NotImplemented + + @_sympifyit('b') + def add_raises(a, b): + return a + b + + assert add_raises(x, 1) == x + 1 + assert add_raises(x, 0.5) == x + Float('0.5') + assert add_raises(x, y) == x + y + + raises(SympifyError, lambda: add_raises(x, '1')) + + +def test_int_float(): + class F1_1: + def __float__(self): + return 1.1 + + class F1_1b: + """ + This class is still a float, even though it also implements __int__(). + """ + def __float__(self): + return 1.1 + + def __int__(self): + return 1 + + class F1_1c: + """ + This class is still a float, because it implements _sympy_() + """ + def __float__(self): + return 1.1 + + def __int__(self): + return 1 + + def _sympy_(self): + return Float(1.1) + + class I5: + def __int__(self): + return 5 + + class I5b: + """ + This class implements both __int__() and __float__(), so it will be + treated as Float in SymPy. One could change this behavior, by using + float(a) == int(a), but deciding that integer-valued floats represent + exact numbers is arbitrary and often not correct, so we do not do it. + If, in the future, we decide to do it anyway, the tests for I5b need to + be changed. + """ + def __float__(self): + return 5.0 + + def __int__(self): + return 5 + + class I5c: + """ + This class implements both __int__() and __float__(), but also + a _sympy_() method, so it will be Integer. + """ + def __float__(self): + return 5.0 + + def __int__(self): + return 5 + + def _sympy_(self): + return Integer(5) + + i5 = I5() + i5b = I5b() + i5c = I5c() + f1_1 = F1_1() + f1_1b = F1_1b() + f1_1c = F1_1c() + assert sympify(i5) == 5 + assert isinstance(sympify(i5), Integer) + assert sympify(i5b) == 5.0 + assert isinstance(sympify(i5b), Float) + assert sympify(i5c) == 5 + assert isinstance(sympify(i5c), Integer) + assert abs(sympify(f1_1) - 1.1) < 1e-5 + assert abs(sympify(f1_1b) - 1.1) < 1e-5 + assert abs(sympify(f1_1c) - 1.1) < 1e-5 + + assert _sympify(i5) == 5 + assert isinstance(_sympify(i5), Integer) + assert _sympify(i5b) == 5.0 + assert isinstance(_sympify(i5b), Float) + assert _sympify(i5c) == 5 + assert isinstance(_sympify(i5c), Integer) + assert abs(_sympify(f1_1) - 1.1) < 1e-5 + assert abs(_sympify(f1_1b) - 1.1) < 1e-5 + assert abs(_sympify(f1_1c) - 1.1) < 1e-5 + + +def test_evaluate_false(): + cases = { + '2 + 3': Add(2, 3, evaluate=False), + '2**2 / 3': Mul(Pow(2, 2, evaluate=False), Pow(3, -1, evaluate=False), evaluate=False), + '2 + 3 * 5': Add(2, Mul(3, 5, evaluate=False), evaluate=False), + '2 - 3 * 5': Add(2, Mul(-1, Mul(3, 5,evaluate=False), evaluate=False), evaluate=False), + '1 / 3': Mul(1, Pow(3, -1, evaluate=False), evaluate=False), + 'True | False': Or(True, False, evaluate=False), + '1 + 2 + 3 + 5*3 + integrate(x)': Add(1, 2, 3, Mul(5, 3, evaluate=False), x**2/2, evaluate=False), + '2 * 4 * 6 + 8': Add(Mul(2, 4, 6, evaluate=False), 8, evaluate=False), + '2 - 8 / 4': Add(2, Mul(-1, Mul(8, Pow(4, -1, evaluate=False), evaluate=False), evaluate=False), evaluate=False), + '2 - 2**2': Add(2, Mul(-1, Pow(2, 2, evaluate=False), evaluate=False), evaluate=False), + } + for case, result in cases.items(): + assert sympify(case, evaluate=False) == result + + +def test_issue_4133(): + a = sympify('Integer(4)') + + assert a == Integer(4) + assert a.is_Integer + + +def test_issue_3982(): + 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)) == FiniteSet(Integer(3), Float(2.0)) + + +def test_S_sympify(): + assert S(1)/2 == sympify(1)/2 == S.Half + assert (-2)**(S(1)/2) == sqrt(2)*I + + +def test_issue_4788(): + assert srepr(S(1.0 + 0J)) == srepr(S(1.0)) == srepr(Float(1.0)) + + +def test_issue_4798_None(): + assert S(None) is None + + +def test_issue_3218(): + assert sympify("x+\ny") == x + y + +def test_issue_19399(): + if not numpy: + skip("numpy not installed.") + + a = numpy.array(Rational(1, 2)) + b = Rational(1, 3) + assert (a * b, type(a * b)) == (b * a, type(b * a)) + + +def test_issue_4988_builtins(): + C = Symbol('C') + vars = {'C': C} + exp1 = sympify('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 + + +def test_geometry(): + p = sympify(Point(0, 1)) + assert p == Point(0, 1) and isinstance(p, Point) + L = sympify(Line(p, (1, 0))) + assert L == Line((0, 1), (1, 0)) and isinstance(L, Line) + + +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 = 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 6687 + assert (kernS('Interval(-1,-2 - 4*(-3))') + == Interval(-1, Add(-2, Mul(12, 1, evaluate=False), evaluate=False))) + 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 + # issue 15132 + assert kernS('(1 - x)/(1 - x*(1-y))') == kernS('(1-x)/(1-(1-y)*x)') + assert kernS('(1-2**-(4+1)*(1-y)*x)') == (1 - x*(1 - y)/32) + assert kernS('(1-2**(4+1)*(1-y)*x)') == (1 - 32*x*(1 - y)) + assert kernS('(1-2.*(1-y)*x)') == 1 - 2.*x*(1 - y) + one = kernS('x - (x - 1)') + assert one != 1 and one.expand() == 1 + assert kernS("(2*x)/(x-1)") == 2*x/(x-1) + + +def test_issue_6540_6552(): + 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], (S.Half,)] + assert S('[[[2*(1)]]]') == [[[2]]] + assert S('Matrix([2*(1)])') == Matrix([2]) + + +def test_issue_6046(): + assert str(S("Q & C", locals=_clash1)) == 'C & Q' + assert str(S('pi(x)', locals=_clash2)) == 'pi(x)' + locals = {} + exec("from sympy.abc import Q, C", locals) + assert str(S('C&Q', locals)) == 'C & Q' + # clash can act as Symbol or Function + assert str(S('pi(C, Q)', locals=_clash)) == 'pi(C, Q)' + assert len(S('pi + x', locals=_clash2).free_symbols) == 2 + # but not both + raises(TypeError, lambda: S('pi + pi(x)', locals=_clash2)) + assert all(set(i.values()) == {null} for i in ( + _clash, _clash1, _clash2)) + + +def test_issue_8821_highprec_from_str(): + s = str(pi.evalf(128)) + p = sympify(s) + assert Abs(sin(p)) < 1e-127 + + +def test_issue_10295(): + if not numpy: + skip("numpy not installed.") + + A = numpy.array([[1, 3, -1], + [0, 1, 7]]) + sA = S(A) + assert sA.shape == (2, 3) + for (ri, ci), val in numpy.ndenumerate(A): + assert sA[ri, ci] == val + + B = numpy.array([-7, x, 3*y**2]) + sB = S(B) + assert sB.shape == (3,) + assert B[0] == sB[0] == -7 + assert B[1] == sB[1] == x + assert B[2] == sB[2] == 3*y**2 + + C = numpy.arange(0, 24) + C.resize(2,3,4) + sC = S(C) + assert sC[0, 0, 0].is_integer + assert sC[0, 0, 0] == 0 + + a1 = numpy.array([1, 2, 3]) + a2 = numpy.array(list(range(24))) + a2.resize(2, 4, 3) + assert sympify(a1) == ImmutableDenseNDimArray([1, 2, 3]) + assert sympify(a2) == ImmutableDenseNDimArray(list(range(24)), (2, 4, 3)) + + +def test_Range(): + # Only works in Python 3 where range returns a range type + assert sympify(range(10)) == Range(10) + assert _sympify(range(10)) == Range(10) + + +def test_sympify_set(): + n = Symbol('n') + assert sympify({n}) == FiniteSet(n) + assert sympify(set()) == EmptySet + + +def test_sympify_numpy(): + if not numpy: + skip('numpy not installed. Abort numpy tests.') + np = numpy + + def equal(x, y): + return x == y and type(x) == type(y) + + assert sympify(np.bool_(1)) is S(True) + try: + assert equal( + sympify(np.int_(1234567891234567891)), S(1234567891234567891)) + assert equal( + sympify(np.intp(1234567891234567891)), S(1234567891234567891)) + except OverflowError: + # May fail on 32-bit systems: Python int too large to convert to C long + pass + assert equal(sympify(np.intc(1234567891)), S(1234567891)) + assert equal(sympify(np.int8(-123)), S(-123)) + assert equal(sympify(np.int16(-12345)), S(-12345)) + assert equal(sympify(np.int32(-1234567891)), S(-1234567891)) + assert equal( + sympify(np.int64(-1234567891234567891)), S(-1234567891234567891)) + assert equal(sympify(np.uint8(123)), S(123)) + assert equal(sympify(np.uint16(12345)), S(12345)) + assert equal(sympify(np.uint32(1234567891)), S(1234567891)) + assert equal( + sympify(np.uint64(1234567891234567891)), S(1234567891234567891)) + assert equal(sympify(np.float32(1.123456)), Float(1.123456, precision=24)) + assert equal(sympify(np.float64(1.1234567891234)), + Float(1.1234567891234, precision=53)) + + # The exact precision of np.longdouble, npfloat128 and other extended + # precision dtypes is platform dependent. + ldprec = np.finfo(np.longdouble(1)).nmant + 1 + assert equal(sympify(np.longdouble(1.123456789)), + Float(1.123456789, precision=ldprec)) + + assert equal(sympify(np.complex64(1 + 2j)), S(1.0 + 2.0*I)) + assert equal(sympify(np.complex128(1 + 2j)), S(1.0 + 2.0*I)) + + lcprec = np.finfo(np.clongdouble(1)).nmant + 1 + assert equal(sympify(np.clongdouble(1 + 2j)), + Float(1.0, precision=lcprec) + Float(2.0, precision=lcprec)*I) + + #float96 does not exist on all platforms + if hasattr(np, 'float96'): + f96prec = np.finfo(np.float96(1)).nmant + 1 + assert equal(sympify(np.float96(1.123456789)), + Float(1.123456789, precision=f96prec)) + + #float128 does not exist on all platforms + if hasattr(np, 'float128'): + f128prec = np.finfo(np.float128(1)).nmant + 1 + assert equal(sympify(np.float128(1.123456789123)), + Float(1.123456789123, precision=f128prec)) + + +@XFAIL +def test_sympify_rational_numbers_set(): + ans = [Rational(3, 10), Rational(1, 5)] + assert sympify({'.3', '.2'}, rational=True) == FiniteSet(*ans) + + +def test_sympify_mro(): + """Tests the resolution order for classes that implement _sympy_""" + class a: + def _sympy_(self): + return Integer(1) + class b(a): + def _sympy_(self): + return Integer(2) + class c(a): + pass + + assert sympify(a()) == Integer(1) + assert sympify(b()) == Integer(2) + assert sympify(c()) == Integer(1) + + +def test_sympify_converter(): + """Tests the resolution order for classes in converter""" + class a: + pass + class b(a): + pass + class c(a): + pass + + converter[a] = lambda x: Integer(1) + converter[b] = lambda x: Integer(2) + + assert sympify(a()) == Integer(1) + assert sympify(b()) == Integer(2) + assert sympify(c()) == Integer(1) + + class MyInteger(Integer): + pass + + if int in converter: + int_converter = converter[int] + else: + int_converter = None + + try: + converter[int] = MyInteger + assert sympify(1) == MyInteger(1) + finally: + if int_converter is None: + del converter[int] + else: + converter[int] = int_converter + + +def test_issue_13924(): + if not numpy: + skip("numpy not installed.") + + a = sympify(numpy.array([1])) + assert isinstance(a, ImmutableDenseNDimArray) + assert a[0] == 1 + + +def test_numpy_sympify_args(): + # Issue 15098. Make sure sympify args work with numpy types (like numpy.str_) + if not numpy: + skip("numpy not installed.") + + a = sympify(numpy.str_('a')) + assert type(a) is Symbol + assert a == Symbol('a') + + class CustomSymbol(Symbol): + pass + + a = sympify(numpy.str_('a'), {"Symbol": CustomSymbol}) + assert isinstance(a, CustomSymbol) + + a = sympify(numpy.str_('x^y')) + assert a == x**y + a = sympify(numpy.str_('x^y'), convert_xor=False) + assert a == Xor(x, y) + + raises(SympifyError, lambda: sympify(numpy.str_('x'), strict=True)) + + a = sympify(numpy.str_('1.1')) + assert isinstance(a, Float) + assert a == 1.1 + + a = sympify(numpy.str_('1.1'), rational=True) + assert isinstance(a, Rational) + assert a == Rational(11, 10) + + a = sympify(numpy.str_('x + x')) + assert isinstance(a, Mul) + assert a == 2*x + + a = sympify(numpy.str_('x + x'), evaluate=False) + assert isinstance(a, Add) + assert a == Add(x, x, evaluate=False) + + +def test_issue_5939(): + a = Symbol('a') + b = Symbol('b') + assert sympify('''a+\nb''') == a + b + + +def test_issue_16759(): + d = sympify({.5: 1}) + assert S.Half not in d + assert Float(.5) in d + assert d[.5] is S.One + d = sympify(OrderedDict({.5: 1})) + assert S.Half not in d + assert Float(.5) in d + assert d[.5] is S.One + d = sympify(defaultdict(int, {.5: 1})) + assert S.Half not in d + assert Float(.5) in d + assert d[.5] is S.One + + +def test_issue_17811(): + a = Function('a') + assert sympify('a(x)*5', evaluate=False) == Mul(a(x), 5, evaluate=False) + + +def test_issue_8439(): + assert sympify(float('inf')) == oo + assert x + float('inf') == x + oo + assert S(float('inf')) == oo + + +def test_issue_14706(): + if not numpy: + skip("numpy not installed.") + + z1 = numpy.zeros((1, 1), dtype=numpy.float64) + z2 = numpy.zeros((2, 2), dtype=numpy.float64) + z3 = numpy.zeros((), dtype=numpy.float64) + + y1 = numpy.ones((1, 1), dtype=numpy.float64) + y2 = numpy.ones((2, 2), dtype=numpy.float64) + y3 = numpy.ones((), dtype=numpy.float64) + + assert numpy.all(x + z1 == numpy.full((1, 1), x)) + assert numpy.all(x + z2 == numpy.full((2, 2), x)) + assert numpy.all(z1 + x == numpy.full((1, 1), x)) + assert numpy.all(z2 + x == numpy.full((2, 2), x)) + for z in [z3, + numpy.int64(0), + numpy.float64(0), + numpy.complex64(0)]: + assert x + z == x + assert z + x == x + assert isinstance(x + z, Symbol) + assert isinstance(z + x, Symbol) + + # If these tests fail, then it means that numpy has finally + # fixed the issue of scalar conversion for rank>0 arrays + # which is mentioned in numpy/numpy#10404. In that case, + # some changes have to be made in sympify.py. + # Note: For future reference, for anyone who takes up this + # issue when numpy has finally fixed their side of the problem, + # the changes for this temporary fix were introduced in PR 18651 + assert numpy.all(x + y1 == numpy.full((1, 1), x + 1.0)) + assert numpy.all(x + y2 == numpy.full((2, 2), x + 1.0)) + assert numpy.all(y1 + x == numpy.full((1, 1), x + 1.0)) + assert numpy.all(y2 + x == numpy.full((2, 2), x + 1.0)) + for y_ in [y3, + numpy.int64(1), + numpy.float64(1), + numpy.complex64(1)]: + assert x + y_ == y_ + x + assert isinstance(x + y_, Add) + assert isinstance(y_ + x, Add) + + assert x + numpy.array(x) == 2 * x + assert x + numpy.array([x]) == numpy.array([2*x], dtype=object) + + assert sympify(numpy.array([1])) == ImmutableDenseNDimArray([1], 1) + assert sympify(numpy.array([[[1]]])) == ImmutableDenseNDimArray([1], (1, 1, 1)) + assert sympify(z1) == ImmutableDenseNDimArray([0.0], (1, 1)) + assert sympify(z2) == ImmutableDenseNDimArray([0.0, 0.0, 0.0, 0.0], (2, 2)) + assert sympify(z3) == ImmutableDenseNDimArray([0.0], ()) + assert sympify(z3, strict=True) == 0.0 + + raises(SympifyError, lambda: sympify(numpy.array([1]), strict=True)) + raises(SympifyError, lambda: sympify(z1, strict=True)) + raises(SympifyError, lambda: sympify(z2, strict=True)) + + +def test_issue_21536(): + #test to check evaluate=False in case of iterable input + u = sympify("x+3*x+2", evaluate=False) + v = sympify("2*x+4*x+2+4", evaluate=False) + + assert u.is_Add and set(u.args) == {x, 3*x, 2} + assert v.is_Add and set(v.args) == {2*x, 4*x, 2, 4} + assert sympify(["x+3*x+2", "2*x+4*x+2+4"], evaluate=False) == [u, v] + + #test to check evaluate=True in case of iterable input + u = sympify("x+3*x+2", evaluate=True) + v = sympify("2*x+4*x+2+4", evaluate=True) + + assert u.is_Add and set(u.args) == {4*x, 2} + assert v.is_Add and set(v.args) == {6*x, 6} + assert sympify(["x+3*x+2", "2*x+4*x+2+4"], evaluate=True) == [u, v] + + #test to check evaluate with no input in case of iterable input + u = sympify("x+3*x+2") + v = sympify("2*x+4*x+2+4") + + assert u.is_Add and set(u.args) == {4*x, 2} + assert v.is_Add and set(v.args) == {6*x, 6} + assert sympify(["x+3*x+2", "2*x+4*x+2+4"]) == [u, v] + +def test_issue_27284(): + if not numpy: + skip("numpy not installed.") + + assert Float(numpy.float32(float('inf'))) == S.Infinity + assert Float(numpy.float32(float('-inf'))) == S.NegativeInfinity diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_traversal.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_traversal.py new file mode 100644 index 0000000000000000000000000000000000000000..8bf067283eaba5d4a073a73feb07aac199055a7f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_traversal.py @@ -0,0 +1,119 @@ +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.sorting import default_sort_key +from sympy.core.symbol import symbols +from sympy.core.singleton import S +from sympy.core.function import expand, Function +from sympy.core.numbers import I +from sympy.integrals.integrals import Integral +from sympy.polys.polytools import factor +from sympy.core.traversal import preorder_traversal, use, postorder_traversal, iterargs, iterfreeargs +from sympy.functions.elementary.piecewise import ExprCondPair, Piecewise +from sympy.testing.pytest import warns_deprecated_sympy +from sympy.utilities.iterables import capture + +b1 = Basic() +b2 = Basic(b1) +b3 = Basic(b2) +b21 = Basic(b2, b1) + + +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(('abc', ('d', 'ef')))) == [ + ('abc', ('d', 'ef')), 'abc', ('d', 'ef'), 'd', 'ef'] + + result = [] + pt = preorder_traversal(expr) + for i in pt: + result.append(i) + if i == b2: + pt.skip() + 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], 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_use(): + x, y = symbols('x y') + + assert use(0, expand) == 0 + + f = (x + y)**2*x + 1 + + assert use(f, expand, level=0) == x**3 + 2*x**2*y + x*y**2 + + 1 + assert use(f, expand, level=1) == x**3 + 2*x**2*y + x*y**2 + + 1 + assert use(f, expand, level=2) == 1 + x*(2*x*y + x**2 + y**2) + assert use(f, expand, level=3) == (x + y)**2*x + 1 + + f = (x**2 + 1)**2 - 1 + kwargs = {'gaussian': True} + + assert use(f, factor, level=0, kwargs=kwargs) == x**2*(x**2 + 2) + assert use(f, factor, level=1, kwargs=kwargs) == (x + I)**2*(x - I)**2 - 1 + assert use(f, factor, level=2, kwargs=kwargs) == (x + I)**2*(x - I)**2 - 1 + assert use(f, factor, level=3, kwargs=kwargs) == (x**2 + 1)**2 - 1 + + +def test_postorder_traversal(): + x, y, z, w = symbols('x y z w') + expr = z + w*(x + y) + expected = [z, w, x, y, x + y, w*(x + y), w*(x + y) + z] + assert list(postorder_traversal(expr, keys=default_sort_key)) == expected + assert list(postorder_traversal(expr, keys=True)) == expected + + expr = Piecewise((x, x < 1), (x**2, True)) + expected = [ + x, 1, x, x < 1, ExprCondPair(x, x < 1), + 2, x, x**2, S.true, + ExprCondPair(x**2, True), Piecewise((x, x < 1), (x**2, True)) + ] + assert list(postorder_traversal(expr, keys=default_sort_key)) == expected + assert list(postorder_traversal( + [expr], keys=default_sort_key)) == expected + [[expr]] + + assert list(postorder_traversal(Integral(x**2, (x, 0, 1)), + keys=default_sort_key)) == [ + 2, x, x**2, 0, 1, x, Tuple(x, 0, 1), + Integral(x**2, Tuple(x, 0, 1)) + ] + assert list(postorder_traversal(('abc', ('d', 'ef')))) == [ + 'abc', 'd', 'ef', ('d', 'ef'), ('abc', ('d', 'ef'))] + + +def test_iterargs(): + f = Function('f') + x = symbols('x') + assert list(iterfreeargs(Integral(f(x), (f(x), 1)))) == [ + Integral(f(x), (f(x), 1)), 1] + assert list(iterargs(Integral(f(x), (f(x), 1)))) == [ + Integral(f(x), (f(x), 1)), f(x), (f(x), 1), x, f(x), 1, x] + +def test_deprecated_imports(): + x = symbols('x') + + with warns_deprecated_sympy(): + from sympy.core.basic import preorder_traversal + preorder_traversal(x) + with warns_deprecated_sympy(): + from sympy.simplify.simplify import bottom_up + bottom_up(x, lambda x: x) + with warns_deprecated_sympy(): + from sympy.simplify.simplify import walk + walk(x, lambda x: x) + with warns_deprecated_sympy(): + from sympy.simplify.traversaltools import use + use(x, lambda x: x) + with warns_deprecated_sympy(): + from sympy.utilities.iterables import postorder_traversal + postorder_traversal(x) + with warns_deprecated_sympy(): + from sympy.utilities.iterables import interactive_traversal + capture(lambda: interactive_traversal(x)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_truediv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_truediv.py new file mode 100644 index 0000000000000000000000000000000000000000..1fcf9e1ab754d05a3b47e7ec0c2be5ea9929da02 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_truediv.py @@ -0,0 +1,54 @@ +#this module tests that SymPy works with true division turned on + +from sympy.core.numbers import (Float, Rational) +from sympy.core.symbol import Symbol + + +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 + ] + for x in l: + for y in l: + s(x, y) + return True + + +def test_basic(): + 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 + del x + assert dotest(s) + + +def test_ibasic(): + def s(a, b): + x = a + x += b + x = a + x -= b + x = a + x *= b + x = a + x /= b + assert dotest(s) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_var.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_var.py new file mode 100644 index 0000000000000000000000000000000000000000..a02709464c9878082fecaf70fa47067ac8838ac6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/core/tests/test_var.py @@ -0,0 +1,62 @@ +from sympy.core.function import (Function, FunctionClass) +from sympy.core.symbol import (Symbol, var) +from sympy.testing.pytest import raises + +def test_var(): + ns = {"var": var, "raises": raises} + eval("var('a')", ns) + assert ns["a"] == Symbol("a") + + eval("var('b bb cc zz _x')", ns) + assert ns["b"] == Symbol("b") + assert ns["bb"] == Symbol("bb") + assert ns["cc"] == Symbol("cc") + assert ns["zz"] == Symbol("zz") + assert ns["_x"] == Symbol("_x") + + v = eval("var(['d', 'e', 'fg'])", ns) + assert ns['d'] == Symbol('d') + assert ns['e'] == Symbol('e') + assert ns['fg'] == Symbol('fg') + +# check return value + assert v != ['d', 'e', 'fg'] + assert v == [Symbol('d'), Symbol('e'), Symbol('fg')] + + +def test_var_return(): + ns = {"var": var, "raises": raises} + "raises(ValueError, lambda: var(''))" + v2 = eval("var('q')", ns) + v3 = eval("var('q p')", ns) + + assert v2 == Symbol('q') + assert v3 == (Symbol('q'), Symbol('p')) + + +def test_var_accepts_comma(): + ns = {"var": var} + v1 = eval("var('x y z')", ns) + v2 = eval("var('x,y,z')", ns) + v3 = eval("var('x,y z')", ns) + + assert v1 == v2 + assert v1 == v3 + + +def test_var_keywords(): + ns = {"var": var} + eval("var('x y', real=True)", ns) + assert ns['x'].is_real and ns['y'].is_real + + +def test_var_cls(): + ns = {"var": var, "Function": Function} + eval("var('f', cls=Function)", ns) + + assert isinstance(ns['f'], FunctionClass) + + eval("var('g,h', cls=Function)", ns) + + assert isinstance(ns['g'], FunctionClass) + assert isinstance(ns['h'], FunctionClass) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..309bdac4081dce60c792190f521f2e4523f76e36 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..80152ca4d7de556c8e27abc6cedbdd9f07698a7f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/tests/__pycache__/test_crypto.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/tests/__pycache__/test_crypto.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53ed388f96757085c1e0be970894e4a58c3200c3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/tests/__pycache__/test_crypto.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/tests/test_crypto.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/tests/test_crypto.py new file mode 100644 index 0000000000000000000000000000000000000000..c671138f9a61325f6e65cc7cafddc7cd46f19229 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/crypto/tests/test_crypto.py @@ -0,0 +1,562 @@ +from sympy.core import symbols +from sympy.crypto.crypto import (cycle_list, + encipher_shift, encipher_affine, encipher_substitution, + check_and_join, encipher_vigenere, decipher_vigenere, + encipher_hill, decipher_hill, encipher_bifid5, encipher_bifid6, + bifid5_square, bifid6_square, bifid5, bifid6, + decipher_bifid5, decipher_bifid6, encipher_kid_rsa, + decipher_kid_rsa, kid_rsa_private_key, kid_rsa_public_key, + decipher_rsa, rsa_private_key, rsa_public_key, encipher_rsa, + lfsr_connection_polynomial, lfsr_autocorrelation, lfsr_sequence, + encode_morse, decode_morse, elgamal_private_key, elgamal_public_key, + encipher_elgamal, decipher_elgamal, dh_private_key, dh_public_key, + dh_shared_key, decipher_shift, decipher_affine, encipher_bifid, + decipher_bifid, bifid_square, padded_key, uniq, decipher_gm, + encipher_gm, gm_public_key, gm_private_key, encipher_bg, decipher_bg, + bg_private_key, bg_public_key, encipher_rot13, decipher_rot13, + encipher_atbash, decipher_atbash, NonInvertibleCipherWarning, + encipher_railfence, decipher_railfence) +from sympy.external.gmpy import gcd +from sympy.matrices import Matrix +from sympy.ntheory import isprime, is_primitive_root +from sympy.polys.domains import FF + +from sympy.testing.pytest import raises, warns + +from sympy.core.random import randrange + +def test_encipher_railfence(): + assert encipher_railfence("hello world",2) == "hlowrdel ol" + assert encipher_railfence("hello world",3) == "horel ollwd" + assert encipher_railfence("hello world",4) == "hwe olordll" + +def test_decipher_railfence(): + assert decipher_railfence("hlowrdel ol",2) == "hello world" + assert decipher_railfence("horel ollwd",3) == "hello world" + assert decipher_railfence("hwe olordll",4) == "hello world" + + +def test_cycle_list(): + assert cycle_list(3, 4) == [3, 0, 1, 2] + assert cycle_list(-1, 4) == [3, 0, 1, 2] + assert cycle_list(1, 4) == [1, 2, 3, 0] + + +def test_encipher_shift(): + assert encipher_shift("ABC", 0) == "ABC" + assert encipher_shift("ABC", 1) == "BCD" + assert encipher_shift("ABC", -1) == "ZAB" + assert decipher_shift("ZAB", -1) == "ABC" + +def test_encipher_rot13(): + assert encipher_rot13("ABC") == "NOP" + assert encipher_rot13("NOP") == "ABC" + assert decipher_rot13("ABC") == "NOP" + assert decipher_rot13("NOP") == "ABC" + + +def test_encipher_affine(): + assert encipher_affine("ABC", (1, 0)) == "ABC" + assert encipher_affine("ABC", (1, 1)) == "BCD" + assert encipher_affine("ABC", (-1, 0)) == "AZY" + assert encipher_affine("ABC", (-1, 1), symbols="ABCD") == "BAD" + assert encipher_affine("123", (-1, 1), symbols="1234") == "214" + assert encipher_affine("ABC", (3, 16)) == "QTW" + assert decipher_affine("QTW", (3, 16)) == "ABC" + +def test_encipher_atbash(): + assert encipher_atbash("ABC") == "ZYX" + assert encipher_atbash("ZYX") == "ABC" + assert decipher_atbash("ABC") == "ZYX" + assert decipher_atbash("ZYX") == "ABC" + +def test_encipher_substitution(): + assert encipher_substitution("ABC", "BAC", "ABC") == "BAC" + assert encipher_substitution("123", "1243", "1234") == "124" + + +def test_check_and_join(): + assert check_and_join("abc") == "abc" + assert check_and_join(uniq("aaabc")) == "abc" + assert check_and_join("ab c".split()) == "abc" + assert check_and_join("abc", "a", filter=True) == "a" + raises(ValueError, lambda: check_and_join('ab', 'a')) + + +def test_encipher_vigenere(): + assert encipher_vigenere("ABC", "ABC") == "ACE" + assert encipher_vigenere("ABC", "ABC", symbols="ABCD") == "ACA" + assert encipher_vigenere("ABC", "AB", symbols="ABCD") == "ACC" + assert encipher_vigenere("AB", "ABC", symbols="ABCD") == "AC" + assert encipher_vigenere("A", "ABC", symbols="ABCD") == "A" + + +def test_decipher_vigenere(): + assert decipher_vigenere("ABC", "ABC") == "AAA" + assert decipher_vigenere("ABC", "ABC", symbols="ABCD") == "AAA" + assert decipher_vigenere("ABC", "AB", symbols="ABCD") == "AAC" + assert decipher_vigenere("AB", "ABC", symbols="ABCD") == "AA" + assert decipher_vigenere("A", "ABC", symbols="ABCD") == "A" + + +def test_encipher_hill(): + A = Matrix(2, 2, [1, 2, 3, 5]) + assert encipher_hill("ABCD", A) == "CFIV" + A = Matrix(2, 2, [1, 0, 0, 1]) + assert encipher_hill("ABCD", A) == "ABCD" + assert encipher_hill("ABCD", A, symbols="ABCD") == "ABCD" + A = Matrix(2, 2, [1, 2, 3, 5]) + assert encipher_hill("ABCD", A, symbols="ABCD") == "CBAB" + assert encipher_hill("AB", A, symbols="ABCD") == "CB" + # message length, n, does not need to be a multiple of k; + # it is padded + assert encipher_hill("ABA", A) == "CFGC" + assert encipher_hill("ABA", A, pad="Z") == "CFYV" + + +def test_decipher_hill(): + A = Matrix(2, 2, [1, 2, 3, 5]) + assert decipher_hill("CFIV", A) == "ABCD" + A = Matrix(2, 2, [1, 0, 0, 1]) + assert decipher_hill("ABCD", A) == "ABCD" + assert decipher_hill("ABCD", A, symbols="ABCD") == "ABCD" + A = Matrix(2, 2, [1, 2, 3, 5]) + assert decipher_hill("CBAB", A, symbols="ABCD") == "ABCD" + assert decipher_hill("CB", A, symbols="ABCD") == "AB" + # n does not need to be a multiple of k + assert decipher_hill("CFA", A) == "ABAA" + + +def test_encipher_bifid5(): + assert encipher_bifid5("AB", "AB") == "AB" + assert encipher_bifid5("AB", "CD") == "CO" + assert encipher_bifid5("ab", "c") == "CH" + assert encipher_bifid5("a bc", "b") == "BAC" + + +def test_bifid5_square(): + A = bifid5 + f = lambda i, j: symbols(A[5*i + j]) + M = Matrix(5, 5, f) + assert bifid5_square("") == M + + +def test_decipher_bifid5(): + assert decipher_bifid5("AB", "AB") == "AB" + assert decipher_bifid5("CO", "CD") == "AB" + assert decipher_bifid5("ch", "c") == "AB" + assert decipher_bifid5("b ac", "b") == "ABC" + + +def test_encipher_bifid6(): + assert encipher_bifid6("AB", "AB") == "AB" + assert encipher_bifid6("AB", "CD") == "CP" + assert encipher_bifid6("ab", "c") == "CI" + assert encipher_bifid6("a bc", "b") == "BAC" + + +def test_decipher_bifid6(): + assert decipher_bifid6("AB", "AB") == "AB" + assert decipher_bifid6("CP", "CD") == "AB" + assert decipher_bifid6("ci", "c") == "AB" + assert decipher_bifid6("b ac", "b") == "ABC" + + +def test_bifid6_square(): + A = bifid6 + f = lambda i, j: symbols(A[6*i + j]) + M = Matrix(6, 6, f) + assert bifid6_square("") == M + + +def test_rsa_public_key(): + assert rsa_public_key(2, 3, 1) == (6, 1) + assert rsa_public_key(5, 3, 3) == (15, 3) + + with warns(NonInvertibleCipherWarning): + assert rsa_public_key(2, 2, 1) == (4, 1) + assert rsa_public_key(8, 8, 8) is False + + +def test_rsa_private_key(): + assert rsa_private_key(2, 3, 1) == (6, 1) + assert rsa_private_key(5, 3, 3) == (15, 3) + assert rsa_private_key(23,29,5) == (667,493) + + with warns(NonInvertibleCipherWarning): + assert rsa_private_key(2, 2, 1) == (4, 1) + assert rsa_private_key(8, 8, 8) is False + + +def test_rsa_large_key(): + # Sample from + # http://www.herongyang.com/Cryptography/JCE-Public-Key-RSA-Private-Public-Key-Pair-Sample.html + p = int('101565610013301240713207239558950144682174355406589305284428666'\ + '903702505233009') + q = int('894687191887545488935455605955948413812376003053143521429242133'\ + '12069293984003') + e = int('65537') + d = int('893650581832704239530398858744759129594796235440844479456143566'\ + '6999402846577625762582824202269399672579058991442587406384754958587'\ + '400493169361356902030209') + assert rsa_public_key(p, q, e) == (p*q, e) + assert rsa_private_key(p, q, e) == (p*q, d) + + +def test_encipher_rsa(): + puk = rsa_public_key(2, 3, 1) + assert encipher_rsa(2, puk) == 2 + puk = rsa_public_key(5, 3, 3) + assert encipher_rsa(2, puk) == 8 + + with warns(NonInvertibleCipherWarning): + puk = rsa_public_key(2, 2, 1) + assert encipher_rsa(2, puk) == 2 + + +def test_decipher_rsa(): + prk = rsa_private_key(2, 3, 1) + assert decipher_rsa(2, prk) == 2 + prk = rsa_private_key(5, 3, 3) + assert decipher_rsa(8, prk) == 2 + + with warns(NonInvertibleCipherWarning): + prk = rsa_private_key(2, 2, 1) + assert decipher_rsa(2, prk) == 2 + + +def test_mutltiprime_rsa_full_example(): + # Test example from + # https://iopscience.iop.org/article/10.1088/1742-6596/995/1/012030 + puk = rsa_public_key(2, 3, 5, 7, 11, 13, 7) + prk = rsa_private_key(2, 3, 5, 7, 11, 13, 7) + assert puk == (30030, 7) + assert prk == (30030, 823) + + msg = 10 + encrypted = encipher_rsa(2 * msg - 15, puk) + assert encrypted == 18065 + decrypted = (decipher_rsa(encrypted, prk) + 15) / 2 + assert decrypted == msg + + # Test example from + # https://www.scirp.org/pdf/JCC_2018032215502008.pdf + puk1 = rsa_public_key(53, 41, 43, 47, 41) + prk1 = rsa_private_key(53, 41, 43, 47, 41) + puk2 = rsa_public_key(53, 41, 43, 47, 97) + prk2 = rsa_private_key(53, 41, 43, 47, 97) + + assert puk1 == (4391633, 41) + assert prk1 == (4391633, 294041) + assert puk2 == (4391633, 97) + assert prk2 == (4391633, 455713) + + msg = 12321 + encrypted = encipher_rsa(encipher_rsa(msg, puk1), puk2) + assert encrypted == 1081588 + decrypted = decipher_rsa(decipher_rsa(encrypted, prk2), prk1) + assert decrypted == msg + + +def test_rsa_crt_extreme(): + p = int( + '10177157607154245068023861503693082120906487143725062283406501' \ + '54082258226204046999838297167140821364638180697194879500245557' \ + '65445186962893346463841419427008800341257468600224049986260471' \ + '92257248163014468841725476918639415726709736077813632961290911' \ + '0256421232977833028677441206049309220354796014376698325101693') + + q = int( + '28752342353095132872290181526607275886182793241660805077850801' \ + '75689512797754286972952273553128181861830576836289738668745250' \ + '34028199691128870676414118458442900035778874482624765513861643' \ + '27966696316822188398336199002306588703902894100476186823849595' \ + '103239410527279605442148285816149368667083114802852804976893') + + r = int( + '17698229259868825776879500736350186838850961935956310134378261' \ + '89771862186717463067541369694816245225291921138038800171125596' \ + '07315449521981157084370187887650624061033066022458512942411841' \ + '18747893789972315277160085086164119879536041875335384844820566' \ + '0287479617671726408053319619892052000850883994343378882717849') + + s = int( + '68925428438585431029269182233502611027091755064643742383515623' \ + '64321310582896893395529367074942808353187138794422745718419645' \ + '28291231865157212604266903677599180789896916456120289112752835' \ + '98502265889669730331688206825220074713977607415178738015831030' \ + '364290585369150502819743827343552098197095520550865360159439' + ) + + t = int( + '69035483433453632820551311892368908779778144568711455301541094' \ + '31487047642322695357696860925747923189635033183069823820910521' \ + '71172909106797748883261493224162414050106920442445896819806600' \ + '15448444826108008217972129130625571421904893252804729877353352' \ + '739420480574842850202181462656251626522910618936534699566291' + ) + + e = 65537 + puk = rsa_public_key(p, q, r, s, t, e) + prk = rsa_private_key(p, q, r, s, t, e) + + plaintext = 1000 + ciphertext_1 = encipher_rsa(plaintext, puk) + ciphertext_2 = encipher_rsa(plaintext, puk, [p, q, r, s, t]) + assert ciphertext_1 == ciphertext_2 + assert decipher_rsa(ciphertext_1, prk) == \ + decipher_rsa(ciphertext_1, prk, [p, q, r, s, t]) + + +def test_rsa_exhaustive(): + p, q = 61, 53 + e = 17 + puk = rsa_public_key(p, q, e, totient='Carmichael') + prk = rsa_private_key(p, q, e, totient='Carmichael') + + for msg in range(puk[0]): + encrypted = encipher_rsa(msg, puk) + decrypted = decipher_rsa(encrypted, prk) + try: + assert decrypted == msg + except AssertionError: + raise AssertionError( + "The RSA is not correctly decrypted " \ + "(Original : {}, Encrypted : {}, Decrypted : {})" \ + .format(msg, encrypted, decrypted) + ) + + +def test_rsa_multiprime_exhanstive(): + primes = [3, 5, 7, 11] + e = 7 + args = primes + [e] + puk = rsa_public_key(*args, totient='Carmichael') + prk = rsa_private_key(*args, totient='Carmichael') + n = puk[0] + + for msg in range(n): + encrypted = encipher_rsa(msg, puk) + decrypted = decipher_rsa(encrypted, prk) + try: + assert decrypted == msg + except AssertionError: + raise AssertionError( + "The RSA is not correctly decrypted " \ + "(Original : {}, Encrypted : {}, Decrypted : {})" \ + .format(msg, encrypted, decrypted) + ) + + +def test_rsa_multipower_exhanstive(): + primes = [5, 5, 7] + e = 7 + args = primes + [e] + puk = rsa_public_key(*args, multipower=True) + prk = rsa_private_key(*args, multipower=True) + n = puk[0] + + for msg in range(n): + if gcd(msg, n) != 1: + continue + + encrypted = encipher_rsa(msg, puk) + decrypted = decipher_rsa(encrypted, prk) + try: + assert decrypted == msg + except AssertionError: + raise AssertionError( + "The RSA is not correctly decrypted " \ + "(Original : {}, Encrypted : {}, Decrypted : {})" \ + .format(msg, encrypted, decrypted) + ) + + +def test_kid_rsa_public_key(): + assert kid_rsa_public_key(1, 2, 1, 1) == (5, 2) + assert kid_rsa_public_key(1, 2, 2, 1) == (8, 3) + assert kid_rsa_public_key(1, 2, 1, 2) == (7, 2) + + +def test_kid_rsa_private_key(): + assert kid_rsa_private_key(1, 2, 1, 1) == (5, 3) + assert kid_rsa_private_key(1, 2, 2, 1) == (8, 3) + assert kid_rsa_private_key(1, 2, 1, 2) == (7, 4) + + +def test_encipher_kid_rsa(): + assert encipher_kid_rsa(1, (5, 2)) == 2 + assert encipher_kid_rsa(1, (8, 3)) == 3 + assert encipher_kid_rsa(1, (7, 2)) == 2 + + +def test_decipher_kid_rsa(): + assert decipher_kid_rsa(2, (5, 3)) == 1 + assert decipher_kid_rsa(3, (8, 3)) == 1 + assert decipher_kid_rsa(2, (7, 4)) == 1 + + +def test_encode_morse(): + assert encode_morse('ABC') == '.-|-...|-.-.' + assert encode_morse('SMS ') == '...|--|...||' + assert encode_morse('SMS\n') == '...|--|...||' + assert encode_morse('') == '' + assert encode_morse(' ') == '||' + assert encode_morse(' ', sep='`') == '``' + assert encode_morse(' ', sep='``') == '````' + assert encode_morse('!@#$%^&*()_+') == '-.-.--|.--.-.|...-..-|-.--.|-.--.-|..--.-|.-.-.' + assert encode_morse('12345') == '.----|..---|...--|....-|.....' + assert encode_morse('67890') == '-....|--...|---..|----.|-----' + + +def test_decode_morse(): + assert decode_morse('-.-|.|-.--') == 'KEY' + assert decode_morse('.-.|..-|-.||') == 'RUN' + raises(KeyError, lambda: decode_morse('.....----')) + + +def test_lfsr_sequence(): + raises(TypeError, lambda: lfsr_sequence(1, [1], 1)) + raises(TypeError, lambda: lfsr_sequence([1], 1, 1)) + F = FF(2) + assert lfsr_sequence([F(1)], [F(1)], 2) == [F(1), F(1)] + assert lfsr_sequence([F(0)], [F(1)], 2) == [F(1), F(0)] + F = FF(3) + assert lfsr_sequence([F(1)], [F(1)], 2) == [F(1), F(1)] + assert lfsr_sequence([F(0)], [F(2)], 2) == [F(2), F(0)] + assert lfsr_sequence([F(1)], [F(2)], 2) == [F(2), F(2)] + + +def test_lfsr_autocorrelation(): + raises(TypeError, lambda: lfsr_autocorrelation(1, 2, 3)) + F = FF(2) + s = lfsr_sequence([F(1), F(0)], [F(0), F(1)], 5) + assert lfsr_autocorrelation(s, 2, 0) == 1 + assert lfsr_autocorrelation(s, 2, 1) == -1 + + +def test_lfsr_connection_polynomial(): + F = FF(2) + x = symbols("x") + s = lfsr_sequence([F(1), F(0)], [F(0), F(1)], 5) + assert lfsr_connection_polynomial(s) == x**2 + 1 + s = lfsr_sequence([F(1), F(1)], [F(0), F(1)], 5) + assert lfsr_connection_polynomial(s) == x**2 + x + 1 + + +def test_elgamal_private_key(): + a, b, _ = elgamal_private_key(digit=100) + assert isprime(a) + assert is_primitive_root(b, a) + assert len(bin(a)) >= 102 + + +def test_elgamal(): + dk = elgamal_private_key(5) + ek = elgamal_public_key(dk) + P = ek[0] + assert P - 1 == decipher_elgamal(encipher_elgamal(P - 1, ek), dk) + raises(ValueError, lambda: encipher_elgamal(P, dk)) + raises(ValueError, lambda: encipher_elgamal(-1, dk)) + + +def test_dh_private_key(): + p, g, _ = dh_private_key(digit = 100) + assert isprime(p) + assert is_primitive_root(g, p) + assert len(bin(p)) >= 102 + + +def test_dh_public_key(): + p1, g1, a = dh_private_key(digit = 100) + p2, g2, ga = dh_public_key((p1, g1, a)) + assert p1 == p2 + assert g1 == g2 + assert ga == pow(g1, a, p1) + + +def test_dh_shared_key(): + prk = dh_private_key(digit = 100) + p, _, ga = dh_public_key(prk) + b = randrange(2, p) + sk = dh_shared_key((p, _, ga), b) + assert sk == pow(ga, b, p) + raises(ValueError, lambda: dh_shared_key((1031, 14, 565), 2000)) + + +def test_padded_key(): + assert padded_key('b', 'ab') == 'ba' + raises(ValueError, lambda: padded_key('ab', 'ace')) + raises(ValueError, lambda: padded_key('ab', 'abba')) + + +def test_bifid(): + raises(ValueError, lambda: encipher_bifid('abc', 'b', 'abcde')) + assert encipher_bifid('abc', 'b', 'abcd') == 'bdb' + raises(ValueError, lambda: decipher_bifid('bdb', 'b', 'abcde')) + assert encipher_bifid('bdb', 'b', 'abcd') == 'abc' + raises(ValueError, lambda: bifid_square('abcde')) + assert bifid5_square("B") == \ + bifid5_square('BACDEFGHIKLMNOPQRSTUVWXYZ') + assert bifid6_square('B0') == \ + bifid6_square('B0ACDEFGHIJKLMNOPQRSTUVWXYZ123456789') + + +def test_encipher_decipher_gm(): + ps = [131, 137, 139, 149, 151, 157, 163, 167, + 173, 179, 181, 191, 193, 197, 199] + qs = [89, 97, 101, 103, 107, 109, 113, 127, + 131, 137, 139, 149, 151, 157, 47] + messages = [ + 0, 32855, 34303, 14805, 1280, 75859, 38368, + 724, 60356, 51675, 76697, 61854, 18661, + ] + for p, q in zip(ps, qs): + pri = gm_private_key(p, q) + for msg in messages: + pub = gm_public_key(p, q) + enc = encipher_gm(msg, pub) + dec = decipher_gm(enc, pri) + assert dec == msg + + +def test_gm_private_key(): + raises(ValueError, lambda: gm_public_key(13, 15)) + raises(ValueError, lambda: gm_public_key(0, 0)) + raises(ValueError, lambda: gm_public_key(0, 5)) + assert 17, 19 == gm_public_key(17, 19) + + +def test_gm_public_key(): + assert 323 == gm_public_key(17, 19)[1] + assert 15 == gm_public_key(3, 5)[1] + raises(ValueError, lambda: gm_public_key(15, 19)) + +def test_encipher_decipher_bg(): + ps = [67, 7, 71, 103, 11, 43, 107, 47, + 79, 19, 83, 23, 59, 127, 31] + qs = qs = [7, 71, 103, 11, 43, 107, 47, + 79, 19, 83, 23, 59, 127, 31, 67] + messages = [ + 0, 328, 343, 148, 1280, 758, 383, + 724, 603, 516, 766, 618, 186, + ] + + for p, q in zip(ps, qs): + pri = bg_private_key(p, q) + for msg in messages: + pub = bg_public_key(p, q) + enc = encipher_bg(msg, pub) + dec = decipher_bg(enc, pri) + assert dec == msg + +def test_bg_private_key(): + raises(ValueError, lambda: bg_private_key(8, 16)) + raises(ValueError, lambda: bg_private_key(8, 8)) + raises(ValueError, lambda: bg_private_key(13, 17)) + assert 23, 31 == bg_private_key(23, 31) + +def test_bg_public_key(): + assert 5293 == bg_public_key(67, 79) + assert 713 == bg_public_key(23, 31) + raises(ValueError, lambda: bg_private_key(13, 17)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e763c8c03a37c1d73afde118236a8f111cdee326 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/gmpy.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/gmpy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..290ef0f9bcf92ee39292ad6bc743058f0ef995f3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/gmpy.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/importtools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/importtools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6db2bf49ecb7bee54528c9da52b00f715273be8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/importtools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/ntheory.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/ntheory.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..857ce3c222b82db9a9be0a34b869c9181ad5d7ea Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/ntheory.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/pythonmpq.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/pythonmpq.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f917dd195ebb5c241918bf8a160a7c419c70cba6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/__pycache__/pythonmpq.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a106e80274033267bdc53ecfdac9be97e1c4f582 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_autowrap.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_autowrap.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c46cae9a4050e5f83de175f0cc89c3d2e2f61c83 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_autowrap.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_codegen.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_codegen.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1738338763cdc9bf3a3a5af611f8fa44793dbe64 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_codegen.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_gmpy.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_gmpy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0fb3bae7a8a04a9c8ae62de3c1f61b6c4d750865 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_gmpy.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_importtools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_importtools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..20a199c1a9fc01bd8ed809b948a357be62d73c5e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_importtools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_ntheory.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_ntheory.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd3059d2214e36abe26acef7cfd58c3bbcd71813 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_ntheory.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_numpy.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_numpy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..77094de9baf0bba93b1c60e124d152788029645a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_numpy.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_pythonmpq.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_pythonmpq.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb5d3384eae0946f2d1cf38cd5aaad83a4819ea3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_pythonmpq.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_scipy.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_scipy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c50983ca136dc69e1c006c8547a6ab2d2c934021 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/__pycache__/test_scipy.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_autowrap.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_autowrap.py new file mode 100644 index 0000000000000000000000000000000000000000..d469b552995b7625f786f3296089e41f42da75cb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_autowrap.py @@ -0,0 +1,313 @@ +import sympy +import tempfile +import os +from pathlib import Path +from sympy.core.mod import Mod +from sympy.core.relational import Eq +from sympy.core.symbol import symbols +from sympy.external import import_module +from sympy.tensor import IndexedBase, Idx +from sympy.utilities.autowrap import autowrap, ufuncify, CodeWrapError +from sympy.testing.pytest import skip + +numpy = import_module('numpy', min_module_version='1.6.1') +Cython = import_module('Cython', min_module_version='0.15.1') +f2py = import_module('numpy.f2py', import_kwargs={'fromlist': ['f2py']}) + +f2pyworks = False +if f2py: + try: + autowrap(symbols('x'), 'f95', 'f2py') + 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(). + + module should be a string. + """ + # 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} + + if modnames[module]: + if module == 'f2py' and not f2pyworks: + skip("Couldn't run f2py.") + return True + skip("Couldn't import %s." % module) + +# +# test runners used by several language-backend combinations +# + +def runtest_autowrap_twice(language, backend): + 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 + + +def runtest_autowrap_trace(language, backend): + has_module('numpy') + trace = autowrap(A[i, i], language, backend) + assert trace(numpy.eye(100)) == 100 + + +def runtest_autowrap_matrix_vector(language, backend): + has_module('numpy') + x, y = symbols('x y', cls=IndexedBase) + expr = Eq(y[i], A[i, j]*x[j]) + mv = autowrap(expr, language, backend) + + # compare with numpy's dot product + M = numpy.random.rand(10, 20) + x = numpy.random.rand(20) + 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') + expr = Eq(C[i, j], A[i, k]*B[k, j]) + matmat = autowrap(expr, language, backend) + + # compare with numpy's dot product + M1 = numpy.random.rand(10, 20) + M2 = numpy.random.rand(20, 15) + 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') + fabc = ufuncify([a, b, c], a*b + c, backend=backend) + facb = ufuncify([a, c, b], a*b + c, backend=backend) + grid = numpy.linspace(-2, 2, 50) + b = numpy.linspace(-5, 4, 50) + c = numpy.linspace(-1, 1, 50) + expected = grid*b + c + numpy.testing.assert_allclose(fabc(grid, b, c), expected) + numpy.testing.assert_allclose(facb(grid, c, b), expected) + + +def runtest_issue_10274(language, backend): + expr = (a - b + c)**(13) + tmp = tempfile.mkdtemp() + f = autowrap(expr, language, backend, tempdir=tmp, + helpers=('helper', a - b + c, (a, b, c))) + assert f(1, 1, 1) == 1 + + for file in os.listdir(tmp): + if not (file.startswith("wrapped_code_") and file.endswith(".c")): + continue + + with open(tmp + '/' + file) as fil: + lines = fil.readlines() + assert lines[0] == "/******************************************************************************\n" + assert "Code generated with SymPy " + sympy.__version__ in lines[1] + assert lines[2:] == [ + " * *\n", + " * See http://www.sympy.org/ for more information. *\n", + " * *\n", + " * This file is part of 'autowrap' *\n", + " ******************************************************************************/\n", + "#include " + '"' + file[:-1]+ 'h"' + "\n", + "#include \n", + "\n", + "double helper(double a, double b, double c) {\n", + "\n", + " double helper_result;\n", + " helper_result = a - b + c;\n", + " return helper_result;\n", + "\n", + "}\n", + "\n", + "double autofunc(double a, double b, double c) {\n", + "\n", + " double autofunc_result;\n", + " autofunc_result = pow(helper(a, b, c), 13);\n", + " return autofunc_result;\n", + "\n", + "}\n", + ] + + +def runtest_issue_15337(language, backend): + has_module('numpy') + # NOTE : autowrap was originally designed to only accept an iterable for + # the kwarg "helpers", but in issue 10274 the user mistakenly thought that + # if there was only a single helper it did not need to be passed via an + # iterable that wrapped the helper tuple. There were no tests for this + # behavior so when the code was changed to accept a single tuple it broke + # the original behavior. These tests below ensure that both now work. + a, b, c, d, e = symbols('a, b, c, d, e') + expr = (a - b + c - d + e)**13 + exp_res = (1. - 2. + 3. - 4. + 5.)**13 + + f = autowrap(expr, language, backend, args=(a, b, c, d, e), + helpers=('f1', a - b + c, (a, b, c))) + numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res) + + f = autowrap(expr, language, backend, args=(a, b, c, d, e), + helpers=(('f1', a - b, (a, b)), ('f2', c - d, (c, d)))) + numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res) + + +def test_issue_15230(): + has_module('f2py') + + x, y = symbols('x, y') + expr = Mod(x, 3.0) - Mod(y, -2.0) + f = autowrap(expr, args=[x, y], language='F95') + exp_res = float(expr.xreplace({x: 3.5, y: 2.7}).evalf()) + assert abs(f(3.5, 2.7) - exp_res) < 1e-14 + + x, y = symbols('x, y', integer=True) + expr = Mod(x, 3) - Mod(y, -2) + f = autowrap(expr, args=[x, y], language='F95') + assert f(3, 2) == expr.xreplace({x: 3, y: 2}) + +# +# tests of language-backend combinations +# + +# 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') + + +def test_issue_15337_f95_f2py(): + has_module('f2py') + runtest_issue_15337('f95', 'f2py') + +# Cython + + +def test_wrap_twice_c_cython(): + has_module('Cython') + runtest_autowrap_twice('C', 'cython') + + +def test_autowrap_trace_C_Cython(): + has_module('Cython') + runtest_autowrap_trace('C99', 'cython') + + +def test_autowrap_matrix_vector_C_cython(): + has_module('Cython') + runtest_autowrap_matrix_vector('C99', 'cython') + + +def test_autowrap_matrix_matrix_C_cython(): + has_module('Cython') + runtest_autowrap_matrix_matrix('C99', 'cython') + + +def test_ufuncify_C_Cython(): + has_module('Cython') + runtest_ufuncify('C99', 'cython') + + +def test_issue_10274_C_cython(): + has_module('Cython') + runtest_issue_10274('C89', 'cython') + + +def test_issue_15337_C_cython(): + has_module('Cython') + runtest_issue_15337('C89', 'cython') + + +def test_autowrap_custom_printer(): + has_module('Cython') + + from sympy.core.numbers import pi + from sympy.utilities.codegen import C99CodeGen + from sympy.printing.c import C99CodePrinter + + class PiPrinter(C99CodePrinter): + def _print_Pi(self, expr): + return "S_PI" + + printer = PiPrinter() + gen = C99CodeGen(printer=printer) + gen.preprocessor_statements.append('#include "shortpi.h"') + + expr = pi * a + + expected = ( + '#include "%s"\n' + '#include \n' + '#include "shortpi.h"\n' + '\n' + 'double autofunc(double a) {\n' + '\n' + ' double autofunc_result;\n' + ' autofunc_result = S_PI*a;\n' + ' return autofunc_result;\n' + '\n' + '}\n' + ) + + tmpdir = tempfile.mkdtemp() + # write a trivial header file to use in the generated code + Path(os.path.join(tmpdir, 'shortpi.h')).write_text('#define S_PI 3.14') + + func = autowrap(expr, backend='cython', tempdir=tmpdir, code_gen=gen) + + assert func(4.2) == 3.14 * 4.2 + + # check that the generated code is correct + for filename in os.listdir(tmpdir): + if filename.startswith('wrapped_code') and filename.endswith('.c'): + with open(os.path.join(tmpdir, filename)) as f: + lines = f.readlines() + expected = expected % filename.replace('.c', '.h') + assert ''.join(lines[7:]) == expected + + +# Numpy + +def test_ufuncify_numpy(): + # This test doesn't use Cython, but if Cython works, then there is a valid + # C compiler, which is needed. + has_module('Cython') + runtest_ufuncify('C99', 'numpy') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_codegen.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_codegen.py new file mode 100644 index 0000000000000000000000000000000000000000..8a4fe28300b86fb0b38d98fcf2fcbbe514cf720f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_codegen.py @@ -0,0 +1,375 @@ +# This tests the compilation and execution of the source code generated with +# utilities.codegen. The compilation takes place in a temporary directory that +# is removed after the test. By default the test directory is always removed, +# but this behavior can be changed by setting the environment variable +# SYMPY_TEST_CLEAN_TEMP to: +# export SYMPY_TEST_CLEAN_TEMP=always : the default behavior. +# export SYMPY_TEST_CLEAN_TEMP=success : only remove the directories of working tests. +# export SYMPY_TEST_CLEAN_TEMP=never : never remove the directories with the test code. +# When a directory is not removed, the necessary information is printed on +# screen to find the files that belong to the (failed) tests. If a test does +# not fail, py.test captures all the output and you will not see the directories +# corresponding to the successful tests. Use the --nocapture option to see all +# the output. + +# All tests below have a counterpart in utilities/test/test_codegen.py. In the +# latter file, the resulting code is compared with predefined strings, without +# compilation or execution. + +# All the generated Fortran code should conform with the Fortran 95 standard, +# and all the generated C code should be ANSI C, which facilitates the +# incorporation in various projects. The tests below assume that the binary cc +# is somewhere in the path and that it can compile ANSI C code. + +from sympy.abc import x, y, z +from sympy.testing.pytest import IS_WASM, skip +from sympy.utilities.codegen import codegen, make_routine, get_code_generator +import sys +import os +import tempfile +import subprocess +from pathlib import Path + + +# templates for the main program that will test the generated code. + +main_template = {} +main_template['F95'] = """ +program main + include "codegen.h" + integer :: result; + result = 0 + + %(statements)s + + call exit(result) +end program +""" + +main_template['C89'] = """ +#include "codegen.h" +#include +#include + +int main() { + int result = 0; + + %(statements)s + + return result; +} +""" +main_template['C99'] = main_template['C89'] +# templates for the numerical tests + +numerical_test_template = {} +numerical_test_template['C89'] = """ + if (fabs(%(call)s)>%(threshold)s) { + printf("Numerical validation failed: %(call)s=%%e threshold=%(threshold)s\\n", %(call)s); + result = -1; + } +""" +numerical_test_template['C99'] = numerical_test_template['C89'] + +numerical_test_template['F95'] = """ + if (abs(%(call)s)>%(threshold)s) then + write(6,"('Numerical validation failed:')") + write(6,"('%(call)s=',e15.5,'threshold=',e15.5)") %(call)s, %(threshold)s + result = -1; + end if +""" +# command sequences for supported compilers + +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" +] + +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" +] + +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" +] + +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" +] + +combinations_lang_compiler = [ + ('C89', 'cc'), + ('C99', 'cc'), + ('F95', 'ifort'), + ('F95', 'gfortran'), + ('F95', 'g95') +] + +def try_run(commands): + """Run a series of commands and only return True if all ran fine.""" + if IS_WASM: + return False + with open(os.devnull, 'w') as null: + for command in commands: + retcode = subprocess.call(command, stdout=null, shell=True, + stderr=subprocess.STDOUT) + if retcode != 0: + return False + return True + + +def run_test(label, routines, numerical_tests, language, commands, friendly=True): + """A driver for the codegen tests. + + This driver assumes that a compiler ifort is present in the PATH and that + ifort is (at least) a Fortran 90 compiler. The generated code is written in + a temporary directory, together with a main program that validates the + generated code. The test passes when the compilation and the validation + run correctly. + """ + + # Check input arguments before touching the file system + language = language.upper() + assert language in main_template + assert language in numerical_test_template + + # Check that environment variable makes sense + clean = os.getenv('SYMPY_TEST_CLEAN_TEMP', 'always').lower() + if clean not in ('always', 'success', 'never'): + raise ValueError("SYMPY_TEST_CLEAN_TEMP must be one of the following: 'always', 'success' or 'never'.") + + # Do all the magic to compile, run and validate the test code + # 1) prepare the temporary working directory, switch to that dir + work = tempfile.mkdtemp("_sympy_%s_test" % language, "%s_" % label) + oldwork = os.getcwd() + os.chdir(work) + + # 2) write the generated code + if friendly: + # interpret the routines as a name_expr list and call the friendly + # function codegen + codegen(routines, language, "codegen", to_files=True) + else: + code_gen = get_code_generator(language, "codegen") + code_gen.write(routines, "codegen", to_files=True) + + # 3) write a simple main program that links to the generated code, and that + # 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) + if language == "F95": + call_string = fortranize_double_constants(call_string) + threshold = fortranize_double_constants(str(threshold)) + test_strings.append(numerical_test_template[language] % { + "call": call_string, + "threshold": threshold, + }) + + if language == "F95": + f_name = "main.f90" + elif language.startswith("C"): + f_name = "main.c" + else: + raise NotImplementedError( + "FIXME: filename extension unknown for language: %s" % language) + + Path(f_name).write_text( + main_template[language] % {'statements': "".join(test_strings)}) + + # 4) Compile and link + compiled = try_run(commands) + + # 5) Run if compiled + if compiled: + executed = try_run(["./test.exe"]) + else: + executed = False + + # 6) Clean up stuff + if clean == 'always' or (clean == 'success' and compiled and executed): + def safe_remove(filename): + if os.path.isfile(filename): + os.remove(filename) + safe_remove("codegen.f90") + safe_remove("codegen.c") + safe_remove("codegen.h") + safe_remove("codegen.o") + safe_remove("main.f90") + safe_remove("main.c") + safe_remove("main.o") + safe_remove("test.exe") + os.chdir(oldwork) + os.rmdir(work) + else: + print("TEST NOT REMOVED: %s" % work, file=sys.stderr) + 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)) + + +def fortranize_double_constants(code_string): + """ + Replaces every literal float with literal doubles + """ + import re + pattern_exp = re.compile(r'\d+(\.)?\d*[eE]-?\d+') + pattern_float = re.compile(r'\d+\.\d*(?!\d*d)') + + def subs_exp(matchobj): + return re.sub('[eE]', 'd', matchobj.group(0)) + + def subs_float(matchobj): + return "%sd0" % matchobj.group(0) + + code_string = pattern_exp.sub(subs_exp, code_string) + code_string = pattern_float.sub(subs_float, code_string) + + return code_string + + +def is_feasible(language, commands): + # This test should always work, otherwise the compiler is not present. + routine = make_routine("test", x) + numerical_tests = [ + ("test", ( 1.0,), 1.0, 1e-15), + ("test", (-1.0,), -1.0, 1e-15), + ] + try: + run_test("is_feasible", [routine], numerical_tests, language, commands, + friendly=False) + return True + except AssertionError: + return False + +valid_lang_commands = [] +invalid_lang_compilers = [] +for lang, compiler in combinations_lang_compiler: + commands = compile_commands[compiler] + if is_feasible(lang, commands): + valid_lang_commands.append((lang, commands)) + else: + invalid_lang_compilers.append((lang, compiler)) + +# We test all language-compiler combinations, just to report what is skipped + +def test_C89_cc(): + if ("C89", 'cc') in invalid_lang_compilers: + skip("`cc' command didn't work as expected (C89)") + + +def test_C99_cc(): + if ("C99", 'cc') in invalid_lang_compilers: + skip("`cc' command didn't work as expected (C99)") + + +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(): + 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)] + 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.core.evalf import N + from sympy.functions import ln + from sympy.functions.elementary.exponential import log + from sympy.functions.elementary.hyperbolic import (cosh, sinh, tanh) + from sympy.functions.elementary.integers import (ceiling, floor) + from sympy.functions.elementary.miscellaneous import sqrt + from sympy.functions.elementary.trigonometric import (acos, asin, atan, cos, sin, tan) + name_expr = [ + ("test_fabs", abs(x)), + ("test_acos", acos(x)), + ("test_asin", asin(x)), + ("test_atan", atan(x)), + ("test_cos", cos(x)), + ("test_cosh", cosh(x)), + ("test_log", log(x)), + ("test_ln", ln(x)), + ("test_sin", sin(x)), + ("test_sinh", sinh(x)), + ("test_sqrt", sqrt(x)), + ("test_tan", tan(x)), + ("test_tanh", tanh(x)), + ] + numerical_tests = [] + for name, expr in name_expr: + for xval in 0.2, 0.5, 0.8: + expected = N(expr.subs(x, xval)) + numerical_tests.append((name, (xval,), expected, 1e-14)) + for lang, commands in valid_lang_commands: + if lang.startswith("C"): + 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) + + +def test_instrinsic_math2_codegen(): + # not included: frexp, ldexp, modf, fmod + from sympy.core.evalf import N + from sympy.functions.elementary.trigonometric import atan2 + name_expr = [ + ("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): + expected = N(expr.subs(x, xval).subs(y, yval)) + 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.core.evalf import N + from sympy.functions.elementary.trigonometric import (cos, sin, tan) + name_expr = [ + ("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): + expected = N(expr.subs(x, xval).subs(y, yval).subs(z, zval)) + 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) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_gmpy.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_gmpy.py new file mode 100644 index 0000000000000000000000000000000000000000..d88f9da0c6c26c15f529ce485fff5b72342170ea --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_gmpy.py @@ -0,0 +1,12 @@ +from sympy.external.gmpy import LONG_MAX, iroot +from sympy.testing.pytest import raises + + +def test_iroot(): + assert iroot(2, LONG_MAX) == (1, False) + assert iroot(2, LONG_MAX + 1) == (1, False) + for x in range(3): + assert iroot(x, 1) == (x, True) + raises(ValueError, lambda: iroot(-1, 1)) + raises(ValueError, lambda: iroot(0, 0)) + raises(ValueError, lambda: iroot(0, -1)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_importtools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_importtools.py new file mode 100644 index 0000000000000000000000000000000000000000..0b954070c179282ed2bcf5735d802c5f22a3a261 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_importtools.py @@ -0,0 +1,40 @@ +from sympy.external import import_module +from sympy.testing.pytest import warns + +# fixes issue that arose in addressing issue 6533 +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 + +def test_min_module_version_python3_basestring_error(): + with warns(UserWarning): + import_module('mpmath', min_module_version='1000.0.1') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_ntheory.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_ntheory.py new file mode 100644 index 0000000000000000000000000000000000000000..00824481ad27aa9071ea5801fb3bde75cacbc3c8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_ntheory.py @@ -0,0 +1,307 @@ +from itertools import permutations + +from sympy.external.ntheory import (bit_scan1, remove, bit_scan0, is_fermat_prp, + is_euler_prp, is_strong_prp, gcdext, _lucas_sequence, + is_fibonacci_prp, is_lucas_prp, is_selfridge_prp, + is_strong_lucas_prp, is_strong_selfridge_prp, + is_bpsw_prp, is_strong_bpsw_prp) +from sympy.testing.pytest import raises + + +def test_bit_scan1(): + assert bit_scan1(0) is None + assert bit_scan1(1) == 0 + assert bit_scan1(-1) == 0 + assert bit_scan1(2) == 1 + assert bit_scan1(7) == 0 + assert bit_scan1(-7) == 0 + for i in range(100): + assert bit_scan1(1 << i) == i + assert bit_scan1((1 << i) * 31337) == i + for i in range(500): + n = (1 << 500) + (1 << i) + assert bit_scan1(n) == i + assert bit_scan1(1 << 1000001) == 1000001 + assert bit_scan1((1 << 273956)*7**37) == 273956 + # issue 12709 + for i in range(1, 10): + big = 1 << i + assert bit_scan1(-big) == bit_scan1(big) + + +def test_bit_scan0(): + assert bit_scan0(-1) is None + assert bit_scan0(0) == 0 + assert bit_scan0(1) == 1 + assert bit_scan0(-2) == 0 + + +def test_remove(): + raises(ValueError, lambda: remove(1, 1)) + assert remove(0, 3) == (0, 0) + for f in range(2, 10): + for y in range(2, 1000): + for z in [1, 17, 101, 1009]: + assert remove(z*f**y, f) == (z, y) + + +def test_gcdext(): + assert gcdext(0, 0) == (0, 0, 0) + assert gcdext(3, 0) == (3, 1, 0) + assert gcdext(0, 4) == (4, 0, 1) + + for n in range(1, 10): + assert gcdext(n, 1) == gcdext(-n, 1) == (1, 0, 1) + assert gcdext(n, -1) == gcdext(-n, -1) == (1, 0, -1) + assert gcdext(n, n) == gcdext(-n, n) == (n, 0, 1) + assert gcdext(n, -n) == gcdext(-n, -n) == (n, 0, -1) + + for n in range(2, 10): + assert gcdext(1, n) == gcdext(1, -n) == (1, 1, 0) + assert gcdext(-1, n) == gcdext(-1, -n) == (1, -1, 0) + + for a, b in permutations([2**5, 3, 5, 7**2, 11], 2): + g, x, y = gcdext(a, b) + assert g == a*x + b*y == 1 + + +def test_is_fermat_prp(): + # invalid input + raises(ValueError, lambda: is_fermat_prp(0, 10)) + raises(ValueError, lambda: is_fermat_prp(5, 1)) + + # n = 1 + assert not is_fermat_prp(1, 3) + + # n is prime + assert is_fermat_prp(2, 4) + assert is_fermat_prp(3, 2) + assert is_fermat_prp(11, 3) + assert is_fermat_prp(2**31-1, 5) + + # A001567 + pseudorpime = [341, 561, 645, 1105, 1387, 1729, 1905, 2047, + 2465, 2701, 2821, 3277, 4033, 4369, 4371, 4681] + for n in pseudorpime: + assert is_fermat_prp(n, 2) + + # A020136 + pseudorpime = [15, 85, 91, 341, 435, 451, 561, 645, 703, 1105, + 1247, 1271, 1387, 1581, 1695, 1729, 1891, 1905] + for n in pseudorpime: + assert is_fermat_prp(n, 4) + + +def test_is_euler_prp(): + # invalid input + raises(ValueError, lambda: is_euler_prp(0, 10)) + raises(ValueError, lambda: is_euler_prp(5, 1)) + + # n = 1 + assert not is_euler_prp(1, 3) + + # n is prime + assert is_euler_prp(2, 4) + assert is_euler_prp(3, 2) + assert is_euler_prp(11, 3) + assert is_euler_prp(2**31-1, 5) + + # A047713 + pseudorpime = [561, 1105, 1729, 1905, 2047, 2465, 3277, 4033, + 4681, 6601, 8321, 8481, 10585, 12801, 15841] + for n in pseudorpime: + assert is_euler_prp(n, 2) + + # A048950 + pseudorpime = [121, 703, 1729, 1891, 2821, 3281, 7381, 8401, + 8911, 10585, 12403, 15457, 15841, 16531, 18721] + for n in pseudorpime: + assert is_euler_prp(n, 3) + + +def test_is_strong_prp(): + # invalid input + raises(ValueError, lambda: is_strong_prp(0, 10)) + raises(ValueError, lambda: is_strong_prp(5, 1)) + + # n = 1 + assert not is_strong_prp(1, 3) + + # n is prime + assert is_strong_prp(2, 4) + assert is_strong_prp(3, 2) + assert is_strong_prp(11, 3) + assert is_strong_prp(2**31-1, 5) + + # A001262 + pseudorpime = [2047, 3277, 4033, 4681, 8321, 15841, 29341, + 42799, 49141, 52633, 65281, 74665, 80581] + for n in pseudorpime: + assert is_strong_prp(n, 2) + + # A020229 + pseudorpime = [121, 703, 1891, 3281, 8401, 8911, 10585, 12403, + 16531, 18721, 19345, 23521, 31621, 44287, 47197] + for n in pseudorpime: + assert is_strong_prp(n, 3) + + +def test_lucas_sequence(): + def lucas_u(P, Q, length): + array = [0] * length + array[1] = 1 + for k in range(2, length): + array[k] = P * array[k - 1] - Q * array[k - 2] + return array + + def lucas_v(P, Q, length): + array = [0] * length + array[0] = 2 + array[1] = P + for k in range(2, length): + array[k] = P * array[k - 1] - Q * array[k - 2] + return array + + length = 20 + for P in range(-10, 10): + for Q in range(-10, 10): + D = P**2 - 4*Q + if D == 0: + continue + us = lucas_u(P, Q, length) + vs = lucas_v(P, Q, length) + for n in range(3, 100, 2): + for k in range(length): + U, V, Qk = _lucas_sequence(n, P, Q, k) + assert U == us[k] % n + assert V == vs[k] % n + assert pow(Q, k, n) == Qk + + +def test_is_fibonacci_prp(): + # invalid input + raises(ValueError, lambda: is_fibonacci_prp(3, 2, 1)) + raises(ValueError, lambda: is_fibonacci_prp(3, -5, 1)) + raises(ValueError, lambda: is_fibonacci_prp(3, 5, 2)) + raises(ValueError, lambda: is_fibonacci_prp(0, 5, -1)) + + # n = 1 + assert not is_fibonacci_prp(1, 3, 1) + + # n is prime + assert is_fibonacci_prp(2, 5, 1) + assert is_fibonacci_prp(3, 6, -1) + assert is_fibonacci_prp(11, 7, 1) + assert is_fibonacci_prp(2**31-1, 8, -1) + + # A005845 + pseudorpime = [705, 2465, 2737, 3745, 4181, 5777, 6721, + 10877, 13201, 15251, 24465, 29281, 34561] + for n in pseudorpime: + assert is_fibonacci_prp(n, 1, -1) + + +def test_is_lucas_prp(): + # invalid input + raises(ValueError, lambda: is_lucas_prp(3, 2, 1)) + raises(ValueError, lambda: is_lucas_prp(0, 5, -1)) + raises(ValueError, lambda: is_lucas_prp(15, 3, 1)) + + # n = 1 + assert not is_lucas_prp(1, 3, 1) + + # n is prime + assert is_lucas_prp(2, 5, 2) + assert is_lucas_prp(3, 6, -1) + assert is_lucas_prp(11, 7, 5) + assert is_lucas_prp(2**31-1, 8, -3) + + # A081264 + pseudorpime = [323, 377, 1891, 3827, 4181, 5777, 6601, 6721, + 8149, 10877, 11663, 13201, 13981, 15251, 17119] + for n in pseudorpime: + assert is_lucas_prp(n, 1, -1) + + +def test_is_selfridge_prp(): + # invalid input + raises(ValueError, lambda: is_selfridge_prp(0)) + + # n = 1 + assert not is_selfridge_prp(1) + + # n is prime + assert is_selfridge_prp(2) + assert is_selfridge_prp(3) + assert is_selfridge_prp(11) + assert is_selfridge_prp(2**31-1) + + # A217120 + pseudorpime = [323, 377, 1159, 1829, 3827, 5459, 5777, 9071, + 9179, 10877, 11419, 11663, 13919, 14839, 16109] + for n in pseudorpime: + assert is_selfridge_prp(n) + + +def test_is_strong_lucas_prp(): + # invalid input + raises(ValueError, lambda: is_strong_lucas_prp(3, 2, 1)) + raises(ValueError, lambda: is_strong_lucas_prp(0, 5, -1)) + raises(ValueError, lambda: is_strong_lucas_prp(15, 3, 1)) + + # n = 1 + assert not is_strong_lucas_prp(1, 3, 1) + + # n is prime + assert is_strong_lucas_prp(2, 5, 2) + assert is_strong_lucas_prp(3, 6, -1) + assert is_strong_lucas_prp(11, 7, 5) + assert is_strong_lucas_prp(2**31-1, 8, -3) + + +def test_is_strong_selfridge_prp(): + # invalid input + raises(ValueError, lambda: is_strong_selfridge_prp(0)) + + # n = 1 + assert not is_strong_selfridge_prp(1) + + # n is prime + assert is_strong_selfridge_prp(2) + assert is_strong_selfridge_prp(3) + assert is_strong_selfridge_prp(11) + assert is_strong_selfridge_prp(2**31-1) + + # A217255 + pseudorpime = [5459, 5777, 10877, 16109, 18971, 22499, 24569, + 25199, 40309, 58519, 75077, 97439, 100127, 113573] + for n in pseudorpime: + assert is_strong_selfridge_prp(n) + + +def test_is_bpsw_prp(): + # invalid input + raises(ValueError, lambda: is_bpsw_prp(0)) + + # n = 1 + assert not is_bpsw_prp(1) + + # n is prime + assert is_bpsw_prp(2) + assert is_bpsw_prp(3) + assert is_bpsw_prp(11) + assert is_bpsw_prp(2**31-1) + + +def test_is_strong_bpsw_prp(): + # invalid input + raises(ValueError, lambda: is_strong_bpsw_prp(0)) + + # n = 1 + assert not is_strong_bpsw_prp(1) + + # n is prime + assert is_strong_bpsw_prp(2) + assert is_strong_bpsw_prp(3) + assert is_strong_bpsw_prp(11) + assert is_strong_bpsw_prp(2**31-1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_numpy.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_numpy.py new file mode 100644 index 0000000000000000000000000000000000000000..cd456d0d6cc49138c29d7ab28ee02694448d578f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_numpy.py @@ -0,0 +1,335 @@ +# This testfile tests SymPy <-> NumPy compatibility + +# Don't test any SymPy features here. Just pure interaction with NumPy. +# Always write regular SymPy tests for anything, that can be tested in pure +# Python (without numpy). Here we test everything, that a user may need when +# using SymPy with NumPy +from sympy.external.importtools import version_tuple +from sympy.external import import_module + +numpy = import_module('numpy') +if numpy: + array, matrix, ndarray = numpy.array, numpy.matrix, numpy.ndarray +else: + #bin/test will not execute any tests now + disabled = True + + +from sympy.core.numbers import (Float, Integer, Rational) +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.trigonometric import sin +from sympy.matrices.dense import (Matrix, list2numpy, matrix2numpy, symarray) +from sympy.utilities.lambdify import lambdify +import sympy + +import mpmath +from sympy.abc import x, y, z +from sympy.utilities.decorator import conserve_mpmath_dps +from sympy.utilities.exceptions import ignore_warnings +from sympy.testing.pytest import raises + + +# first, systematically check, that all operations are implemented and don't +# raise an exception + + +def test_systematic_basic(): + def s(sympy_object, numpy_array): + _ = [sympy_object + numpy_array, + numpy_array + sympy_object, + sympy_object - numpy_array, + numpy_array - sympy_object, + sympy_object * numpy_array, + numpy_array * sympy_object, + sympy_object / numpy_array, + numpy_array / sympy_object, + sympy_object ** numpy_array, + numpy_array ** sympy_object] + 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), + ] + numpy_objs = [ + 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) + + +# now some random tests, that test particular problems and that also +# check that the results of the operations are correct + +def test_basics(): + one = Rational(1) + zero = Rational(0) + 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) + + 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")]) + Y = Y + 1 + assert Y == array([2 + 2*Symbol("a")]) + Y = X - X + assert Y == array([0]) + + +def test_conversion1(): + a = list2numpy([x**2, x]) + #looks like an array? + assert isinstance(a, ndarray) + assert a[0] == x**2 + assert a[1] == x + assert len(a) == 2 + #yes, it's the array + + +def test_conversion2(): + a = 2*list2numpy([x**2, x]) + b = list2numpy([2*x**2, 2*x]) + assert (a == b).all() + + one = Rational(1) + 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")]) + Y = Y + 1 + assert Y == array([2 + 2*Symbol("a")]) + Y = X - X + assert Y == array([0]) + + +def test_list2numpy(): + assert (array([x**2, x]) == list2numpy([x**2, x])).all() + + +def test_Matrix1(): + m = Matrix([[x, x**2], [5, 2/x]]) + 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() + + +def test_Matrix2(): + m = Matrix([[x, x**2], [5, 2/x]]) + with ignore_warnings(PendingDeprecationWarning): + assert (matrix(m.subs(x, 2)) == matrix([[2, 4], [5, 1]])).all() + m = Matrix([[sin(x), x**2], [5, 2/x]]) + with ignore_warnings(PendingDeprecationWarning): + assert (matrix(m.subs(x, 2)) == matrix([[sin(2), 4], [5, 1]])).all() + + +def test_Matrix3(): + 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]]) + + +def test_Matrix4(): + with ignore_warnings(PendingDeprecationWarning): + a = matrix([[2, 4], [5, 1]]) + assert Matrix(a) == Matrix([[2, 4], [5, 1]]) + assert Matrix(a) != Matrix([[2, 4], [5, 2]]) + with ignore_warnings(PendingDeprecationWarning): + 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]]) + + +def test_Matrix_sum(): + M = Matrix([[1, 2, 3], [x, y, x], [2*y, -50, z*x]]) + with ignore_warnings(PendingDeprecationWarning): + 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(): + M = Matrix([[1, 2, 3], [x, y, x]]) + with ignore_warnings(PendingDeprecationWarning): + 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], + ]) + + 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], + ]) + a = array([2]) + assert a[0] * M == 2 * M + assert M * a[0] == 2 * M + + +def test_Matrix_array(): + class matarray: + def __array__(self, dtype=object, copy=None): + if copy is not None and not copy: + raise TypeError("Cannot implement copy=False when converting Matrix to ndarray") + from numpy import array + 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]]) + + +def test_matrix2numpy(): + a = matrix2numpy(Matrix([[1, x**2], [3*sin(x), 0]])) + assert isinstance(a, ndarray) + assert a.shape == (2, 2) + assert a[0, 0] == 1 + assert a[0, 1] == x**2 + assert a[1, 0] == 3*sin(x) + assert a[1, 1] == 0 + + +def test_matrix2numpy_conversion(): + a = Matrix([[1, 2, sin(x)], [x**2, x, Rational(1, 2)]]) + b = array([[1, 2, sin(x)], [x**2, x, Rational(1, 2)]]) + assert (matrix2numpy(a) == b).all() + assert matrix2numpy(a).dtype == numpy.dtype('object') + + c = matrix2numpy(Matrix([[1, 2], [10, 20]]), dtype='int8') + d = matrix2numpy(Matrix([[1, 2], [10, 20]]), dtype='float64') + assert c.dtype == numpy.dtype('int8') + assert d.dtype == numpy.dtype('float64') + + +def test_issue_3728(): + 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() + + +@conserve_mpmath_dps +def test_lambdify(): + mpmath.mp.dps = 16 + sin02 = mpmath.mpf("0.198669330795061215459412627") + f = lambdify(x, sin(x), "numpy") + prec = 1e-15 + assert -prec < f(0.2) - sin02 < prec + + # if this succeeds, it can't be a numpy function + + if version_tuple(numpy.__version__) >= version_tuple('1.17'): + with raises(TypeError): + f(x) + else: + with raises(AttributeError): + f(x) + + +def test_lambdify_matrix(): + f = lambdify(x, Matrix([[x, 2*x], [1, 2]]), [{'ImmutableMatrix': numpy.array}, "numpy"]) + assert (f(1) == array([[1, 2], [1, 2]])).all() + + +def test_lambdify_matrix_multi_input(): + 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, [{'ImmutableMatrix': numpy.array}, "numpy"]) + + xh, yh, zh = 1.0, 2.0, 3.0 + expected = array([[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) + + +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]]) + f = lambdify(X, M, [{'ImmutableMatrix': numpy.array}, "numpy"]) + + Xh = array([1.0, 2.0, 3.0]) + expected = array([[Xh[0]**2, Xh[0]*Xh[1], Xh[0]*Xh[2]], + [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) + + +def test_lambdify_transl(): + from sympy.utilities.lambdify import NUMPY_TRANSLATIONS + for sym, mat in NUMPY_TRANSLATIONS.items(): + assert sym in sympy.__dict__ + assert mat in numpy.__dict__ + + +def test_symarray(): + """Test creation of numpy arrays of SymPy symbols.""" + + import numpy as np + import numpy.testing as npt + + syms = symbols('_0,_1,_2') + s1 = symarray("", 3) + s2 = symarray("", 3) + npt.assert_array_equal(s1, np.array(syms, dtype=object)) + assert s1[0] == s2[0] + + a = symarray('a', 3) + b = symarray('b', 3) + assert not(a[0] == b[0]) + + asyms = symbols('a_0,a_1,a_2') + npt.assert_array_equal(a, np.array(asyms, dtype=object)) + + # Multidimensional checks + a2d = symarray('a', (2, 3)) + assert a2d.shape == (2, 3) + a00, a12 = symbols('a_0_0,a_1_2') + assert a2d[0, 0] == a00 + assert a2d[1, 2] == a12 + + 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] == a000 + assert a3d[1, 2, 0] == a120 + assert a3d[1, 2, 1] == a121 + + +def test_vectorize(): + assert (numpy.vectorize( + sin)([1, 2, 3]) == numpy.array([sin(1), sin(2), sin(3)])).all() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_pythonmpq.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_pythonmpq.py new file mode 100644 index 0000000000000000000000000000000000000000..137cfdf5c858544f0811ae666f000cfb368787a0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_pythonmpq.py @@ -0,0 +1,176 @@ +""" +test_pythonmpq.py + +Test the PythonMPQ class for consistency with gmpy2's mpq type. If gmpy2 is +installed run the same tests for both. +""" +from fractions import Fraction +from decimal import Decimal +import pickle +from typing import Callable, List, Tuple, Type + +from sympy.testing.pytest import raises + +from sympy.external.pythonmpq import PythonMPQ + +# +# If gmpy2 is installed then run the tests for both mpq and PythonMPQ. +# That should ensure consistency between the implementation here and mpq. +# +rational_types: List[Tuple[Callable, Type, Callable, Type]] +rational_types = [(PythonMPQ, PythonMPQ, int, int)] +try: + from gmpy2 import mpq, mpz + rational_types.append((mpq, type(mpq(1)), mpz, type(mpz(1)))) +except ImportError: + pass + + +def test_PythonMPQ(): + # + # Test PythonMPQ and also mpq if gmpy/gmpy2 is installed. + # + for Q, TQ, Z, TZ in rational_types: + + def check_Q(q): + assert isinstance(q, TQ) + assert isinstance(q.numerator, TZ) + assert isinstance(q.denominator, TZ) + return q.numerator, q.denominator + + # Check construction from different types + assert check_Q(Q(3)) == (3, 1) + assert check_Q(Q(3, 5)) == (3, 5) + assert check_Q(Q(Q(3, 5))) == (3, 5) + assert check_Q(Q(0.5)) == (1, 2) + assert check_Q(Q('0.5')) == (1, 2) + assert check_Q(Q(Fraction(3, 5))) == (3, 5) + + # https://github.com/aleaxit/gmpy/issues/327 + if Q is PythonMPQ: + assert check_Q(Q(Decimal('0.6'))) == (3, 5) + + # Invalid types + raises(TypeError, lambda: Q([])) + raises(TypeError, lambda: Q([], [])) + + # Check normalisation of signs + assert check_Q(Q(2, 3)) == (2, 3) + assert check_Q(Q(-2, 3)) == (-2, 3) + assert check_Q(Q(2, -3)) == (-2, 3) + assert check_Q(Q(-2, -3)) == (2, 3) + + # Check gcd calculation + assert check_Q(Q(12, 8)) == (3, 2) + + # __int__/__float__ + assert int(Q(5, 3)) == 1 + assert int(Q(-5, 3)) == -1 + assert float(Q(5, 2)) == 2.5 + assert float(Q(-5, 2)) == -2.5 + + # __str__/__repr__ + assert str(Q(2, 1)) == "2" + assert str(Q(1, 2)) == "1/2" + if Q is PythonMPQ: + assert repr(Q(2, 1)) == "MPQ(2,1)" + assert repr(Q(1, 2)) == "MPQ(1,2)" + else: + assert repr(Q(2, 1)) == "mpq(2,1)" + assert repr(Q(1, 2)) == "mpq(1,2)" + + # __bool__ + assert bool(Q(1, 2)) is True + assert bool(Q(0)) is False + + # __eq__/__ne__ + assert (Q(2, 3) == Q(2, 3)) is True + assert (Q(2, 3) == Q(2, 5)) is False + assert (Q(2, 3) != Q(2, 3)) is False + assert (Q(2, 3) != Q(2, 5)) is True + + # __hash__ + assert hash(Q(3, 5)) == hash(Fraction(3, 5)) + + # __reduce__ + q = Q(2, 3) + assert pickle.loads(pickle.dumps(q)) == q + + # __ge__/__gt__/__le__/__lt__ + assert (Q(1, 3) < Q(2, 3)) is True + assert (Q(2, 3) < Q(2, 3)) is False + assert (Q(2, 3) < Q(1, 3)) is False + assert (Q(-2, 3) < Q(1, 3)) is True + assert (Q(1, 3) < Q(-2, 3)) is False + + assert (Q(1, 3) <= Q(2, 3)) is True + assert (Q(2, 3) <= Q(2, 3)) is True + assert (Q(2, 3) <= Q(1, 3)) is False + assert (Q(-2, 3) <= Q(1, 3)) is True + assert (Q(1, 3) <= Q(-2, 3)) is False + + assert (Q(1, 3) > Q(2, 3)) is False + assert (Q(2, 3) > Q(2, 3)) is False + assert (Q(2, 3) > Q(1, 3)) is True + assert (Q(-2, 3) > Q(1, 3)) is False + assert (Q(1, 3) > Q(-2, 3)) is True + + assert (Q(1, 3) >= Q(2, 3)) is False + assert (Q(2, 3) >= Q(2, 3)) is True + assert (Q(2, 3) >= Q(1, 3)) is True + assert (Q(-2, 3) >= Q(1, 3)) is False + assert (Q(1, 3) >= Q(-2, 3)) is True + + # __abs__/__pos__/__neg__ + assert abs(Q(2, 3)) == abs(Q(-2, 3)) == Q(2, 3) + assert +Q(2, 3) == Q(2, 3) + assert -Q(2, 3) == Q(-2, 3) + + # __add__/__radd__ + assert Q(2, 3) + Q(5, 7) == Q(29, 21) + assert Q(2, 3) + 1 == Q(5, 3) + assert 1 + Q(2, 3) == Q(5, 3) + raises(TypeError, lambda: [] + Q(1)) + raises(TypeError, lambda: Q(1) + []) + + # __sub__/__rsub__ + assert Q(2, 3) - Q(5, 7) == Q(-1, 21) + assert Q(2, 3) - 1 == Q(-1, 3) + assert 1 - Q(2, 3) == Q(1, 3) + raises(TypeError, lambda: [] - Q(1)) + raises(TypeError, lambda: Q(1) - []) + + # __mul__/__rmul__ + assert Q(2, 3) * Q(5, 7) == Q(10, 21) + assert Q(2, 3) * 1 == Q(2, 3) + assert 1 * Q(2, 3) == Q(2, 3) + raises(TypeError, lambda: [] * Q(1)) + raises(TypeError, lambda: Q(1) * []) + + # __pow__/__rpow__ + assert Q(2, 3) ** 2 == Q(4, 9) + assert Q(2, 3) ** 1 == Q(2, 3) + assert Q(-2, 3) ** 2 == Q(4, 9) + assert Q(-2, 3) ** -1 == Q(-3, 2) + if Q is PythonMPQ: + raises(TypeError, lambda: 1 ** Q(2, 3)) + raises(TypeError, lambda: Q(1, 4) ** Q(1, 2)) + raises(TypeError, lambda: [] ** Q(1)) + raises(TypeError, lambda: Q(1) ** []) + + # __div__/__rdiv__ + assert Q(2, 3) / Q(5, 7) == Q(14, 15) + assert Q(2, 3) / 1 == Q(2, 3) + assert 1 / Q(2, 3) == Q(3, 2) + raises(TypeError, lambda: [] / Q(1)) + raises(TypeError, lambda: Q(1) / []) + raises(ZeroDivisionError, lambda: Q(1, 2) / Q(0)) + + # __divmod__ + if Q is PythonMPQ: + raises(TypeError, lambda: Q(2, 3) // Q(1, 3)) + raises(TypeError, lambda: Q(2, 3) % Q(1, 3)) + raises(TypeError, lambda: 1 // Q(1, 3)) + raises(TypeError, lambda: 1 % Q(1, 3)) + raises(TypeError, lambda: Q(2, 3) // 1) + raises(TypeError, lambda: Q(2, 3) % 1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_scipy.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_scipy.py new file mode 100644 index 0000000000000000000000000000000000000000..3746d1a311eb68bb1af16e18ab152c7236b42bb5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/external/tests/test_scipy.py @@ -0,0 +1,35 @@ +# This testfile tests SymPy <-> SciPy compatibility + +# Don't test any SymPy features here. Just pure interaction with SciPy. +# Always write regular SymPy tests for anything, that can be tested in pure +# Python (without scipy). Here we test everything, that a user may need when +# using SymPy with SciPy + +from sympy.external import import_module + +scipy = import_module('scipy') +if not scipy: + #bin/test will not execute any tests now + disabled = True + +from sympy.functions.special.bessel import jn_zeros + + +def eq(a, b, tol=1e-6): + for x, y in zip(a, b): + 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]) + assert eq(jn_zeros(1, 4, method="scipy"), + [4.493409, 7.725251, 10.904121, 14.066193]) + assert eq(jn_zeros(2, 4, method="scipy"), + [5.763459, 9.095011, 12.322940, 15.514603]) + assert eq(jn_zeros(3, 4, method="scipy"), + [6.987932, 10.417118, 13.698023, 16.923621]) + assert eq(jn_zeros(4, 4, method="scipy"), + [8.182561, 11.704907, 15.039664, 18.301255]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c7934a5bda404b1eaabfaaeccadb0efc60ac052 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/deltafunctions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/deltafunctions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6477fbd6a244c561939378a29afe2d6e2bae9cd2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/deltafunctions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/heurisch.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/heurisch.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14ea2842d9ba64b32c3aca3f114a4de15980e215 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/heurisch.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/integrals.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/integrals.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad65fba4f32e99e1ee4b683fd19ec42bdf3f1d19 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/integrals.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/intpoly.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/intpoly.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b88729e6b5ac07d7186a89ef1541b0b41d79a2d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/intpoly.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/meijerint_doc.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/meijerint_doc.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..68b5dc3eaf25a9e4f8412ca19c749ef980917c88 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/meijerint_doc.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/prde.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/prde.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51d91b13e94a527a8d764fb81b227dc2aa57124a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/prde.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/quadrature.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/quadrature.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..846e2e3dc1e66bb89b59cb7df28998d700c3b294 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/quadrature.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/rationaltools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/rationaltools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2daba3747a8147f23c94920c3967f16ab2f8fbad Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/rationaltools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/rde.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/rde.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7178e17fd69482e2b9d5679e9ba974f3f63ea31e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/rde.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/risch.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/risch.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7793dc69e3a8cd75bd0c8180e5bc483f06e752f9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/risch.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/singularityfunctions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/singularityfunctions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..80e2afe7b7a2e025a12a2ab50c64bd47764f25df Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/singularityfunctions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/transforms.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/transforms.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd1af295d9f6dcdd0db8b2f9589574abbaa13787 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/transforms.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/trigonometry.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/trigonometry.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..89f418f6c24d3b7a18cf490b9c6e5a63400a984c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/__pycache__/trigonometry.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..03d10ff7c5caa138d7e81e2d41522b6f01c3fa25 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/bench_integrate.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/bench_integrate.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..695a3c036f8c874dc74b85282f5bd525217bf364 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/bench_integrate.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/bench_trigintegrate.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/bench_trigintegrate.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bee88219d612d76f9194f3acd2212e126d52cbe2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/__pycache__/bench_trigintegrate.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/bench_integrate.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/bench_integrate.py new file mode 100644 index 0000000000000000000000000000000000000000..833bc57403b34df1e75c798084ffc4d8afe9eae6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/bench_integrate.py @@ -0,0 +1,21 @@ +from sympy.core.symbol import Symbol +from sympy.functions.elementary.trigonometric import sin +from sympy.integrals.integrals import integrate + +x = Symbol('x') + + +def bench_integrate_sin(): + integrate(sin(x), x) + + +def bench_integrate_x1sin(): + integrate(x**1*sin(x), x) + + +def bench_integrate_x2sin(): + integrate(x**2*sin(x), x) + + +def bench_integrate_x3sin(): + integrate(x**3*sin(x), x) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/bench_trigintegrate.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/bench_trigintegrate.py new file mode 100644 index 0000000000000000000000000000000000000000..403c5471b8048ff2aa97bf2f837b9ea05f0fd904 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/benchmarks/bench_trigintegrate.py @@ -0,0 +1,13 @@ +from sympy.core.symbol import Symbol +from sympy.functions.elementary.trigonometric import sin +from sympy.integrals.trigonometry import trigintegrate + +x = Symbol('x') + + +def timeit_trigintegrate_sin3x(): + trigintegrate(sin(x)**3, x) + + +def timeit_trigintegrate_x2(): + trigintegrate(x**2, x) # -> None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d42e40a98bc6522c2c988e542800b5240c2a337 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_deltafunctions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_deltafunctions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5ba1182a678fdf9c86b804f33aba27bb0aec3eb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_deltafunctions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_failing_integrals.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_failing_integrals.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..968ee32de982f6cc6338d58e8c691fe7870484f9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_failing_integrals.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_heurisch.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_heurisch.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0cbd09ff868b7bbf11846ae0be823390f3bc3db Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_heurisch.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_intpoly.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_intpoly.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a8fcddfd7bc81e2617874e77f52fafa456e96f3c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_intpoly.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_laplace.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_laplace.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9e6ad00b4a1b1a698e152269972d375e5389e5d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_laplace.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_lineintegrals.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_lineintegrals.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a4e5026676b93eb1d37a3bfcf1614c544c4aa6a2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_lineintegrals.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_manual.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_manual.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b192cb80c8e03b14932159d0ce7e9ca2217d51d4 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_manual.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_meijerint.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_meijerint.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d53f50c58f89193fd4464009f1b7bd79d58d0d2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_meijerint.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_prde.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_prde.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3f3b8b5f6146517868cf1448ced3a825410349e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_prde.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_quadrature.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_quadrature.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a43ece1cb512af6e4de6c285c8202039735dc87e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_quadrature.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_rationaltools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_rationaltools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..85d57811eeedc05f8f312f6ac7cafe07d3c0a1a1 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_rationaltools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_rde.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_rde.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e25a68a6fc956d5cb42df408f79eecc5650adb64 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_rde.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_risch.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_risch.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b48247396869606df8ccd2efc94114c331763909 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_risch.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_singularityfunctions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_singularityfunctions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4f8ce5e58f7df1f3ff4b5ed4b3b3a9bb57d2f2a0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_singularityfunctions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_transforms.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_transforms.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5618204256d8e3b1a9b0b2ca83939336894214c2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_transforms.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_trigonometry.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_trigonometry.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..090f9bb63e77d1b3a6f5b0806e171c84a8d3bd41 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/__pycache__/test_trigonometry.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_deltafunctions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_deltafunctions.py new file mode 100644 index 0000000000000000000000000000000000000000..d4fd567349b50f795e08d583fd08db67b1596577 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_deltafunctions.py @@ -0,0 +1,79 @@ +from sympy.core.function import Function +from sympy.core.numbers import (Rational, pi) +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.functions.special.delta_functions import (DiracDelta, Heaviside) +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) == (None, None) + 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), x) == DiracDelta(x, 0) + assert deltaintegrate(y*DiracDelta(x, 1), x) == y*DiracDelta(x, 0) + assert deltaintegrate(DiracDelta(x, 1)**2, x) == -DiracDelta(0, 2)*Heaviside(x) + assert deltaintegrate(y*DiracDelta(x, 1)**2, x) == -y*DiracDelta(0, 2)*Heaviside(x) + + + 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.Half * Heaviside(x) + assert deltaintegrate((x + 1)*DiracDelta(x*Rational(2, 3) + Rational(4, 9)), x) == \ + S.Half * Heaviside(x + Rational(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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_failing_integrals.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_failing_integrals.py new file mode 100644 index 0000000000000000000000000000000000000000..9bb434cf0009cd96ad2b7882d109b7fbe23193c2 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_failing_integrals.py @@ -0,0 +1,277 @@ +# A collection of failing integrals from the issues. + +from sympy.core.numbers import (I, Rational, oo, pi) +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.complexes import sign +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.hyperbolic import (sech, sinh) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (acos, atan, cos, sin, tan) +from sympy.functions.special.delta_functions import DiracDelta +from sympy.functions.special.gamma_functions import gamma +from sympy.integrals.integrals import (Integral, integrate) +from sympy.simplify.fu import fu + + +from sympy.testing.pytest import XFAIL, slow, tooslow + +from sympy.abc import x, k, c, y, b, h, a, m, z, n, t + + +@tooslow +@XFAIL +def test_issue_3880(): + # 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) + + +def test_issue_4212_real(): + xr = symbols('xr', real=True) + negabsx = Piecewise((-xr, xr < 0), (xr, True)) + assert integrate(sign(xr), xr) == negabsx + + +@XFAIL +def test_issue_4212(): + # XXX: Maybe this should be expected to fail without real assumptions on x. + # As a complex function sign(x) is not analytic and so there is no complex + # function whose complex derivative is sign(x). With real assumptions this + # works (see test_issue_4212_real above). + assert not integrate(sign(x), x).has(Integral) + + +def test_issue_4511(): + # This works, but gives a slightly over-complicated answer. + f = integrate(cos(x)**2 / (1 - sin(x)), x) + assert fu(f) == x - cos(x) - 1 + assert f == ((x*tan(x/2)**2 + x - 2)/(tan(x/2)**2 + 1)).expand() + + +def test_integrate_DiracDelta_no_meijerg(): + assert integrate(integrate(integrate( + DiracDelta(x - y - z), (z, 0, oo)), (y, 0, 1), meijerg=False), (x, 0, 1)) == S.Half + + +@XFAIL +def test_integrate_DiracDelta_fails(): + # issue 6427 + # works without meijerg. See test_integrate_DiracDelta_no_meijerg above. + assert integrate(integrate(integrate( + DiracDelta(x - y - z), (z, 0, oo)), (y, 0, 1)), (x, 0, 1)) == S.Half + + +@XFAIL +@slow +def test_issue_4525(): + # 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 +@tooslow +def test_issue_4540(): + # 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 +@slow +def test_issue_4891(): + # Requires the hypergeometric function. + assert not integrate(cos(x)**y, x).has(Integral) + + +@XFAIL +@slow +def test_issue_1796a(): + assert not integrate(exp(2*b*x)*exp(-a*x**2), x).has(Integral) + + +@XFAIL +def test_issue_4895b(): + assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, -oo, 0)).has(Integral) + + +@XFAIL +def test_issue_4895c(): + assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, -oo, oo)).has(Integral) + + +@XFAIL +def test_issue_4895d(): + assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, 0, oo)).has(Integral) + + +@XFAIL +@slow +def test_issue_4941(): + assert not integrate(sqrt(1 + sinh(x/20)**2), (x, -25, 25)).has(Integral) + + +@XFAIL +def test_issue_4992(): + # Nonelementary integral. Requires hypergeometric/Meijer-G handling. + assert not integrate(log(x) * x**(k - 1) * exp(-x) / gamma(k), (x, 0, oo)).has(Integral) + + +@XFAIL +def test_issue_16396a(): + i = integrate(1/(1+sqrt(tan(x))), (x, pi/3, pi/6)) + assert not i.has(Integral) + + +@XFAIL +def test_issue_16396b(): + i = integrate(x*sin(x)/(1+cos(x)**2), (x, 0, pi)) + assert not i.has(Integral) + + +@XFAIL +def test_issue_16046(): + assert integrate(exp(exp(I*x)), [x, 0, 2*pi]) == 2*pi + + +@XFAIL +def test_issue_15925a(): + assert not integrate(sqrt((1+sin(x))**2+(cos(x))**2), (x, -pi/2, pi/2)).has(Integral) + + +def test_issue_15925b(): + f = sqrt((-12*cos(x)**2*sin(x))**2+(12*cos(x)*sin(x)**2)**2) + assert integrate(f, (x, 0, pi/6)) == Rational(3, 2) + + +@XFAIL +def test_issue_15925b_manual(): + assert not integrate(sqrt((-12*cos(x)**2*sin(x))**2+(12*cos(x)*sin(x)**2)**2), + (x, 0, pi/6), manual=True).has(Integral) + + +@XFAIL +@tooslow +def test_issue_15227(): + i = integrate(log(1-x)*log((1+x)**2)/x, (x, 0, 1)) + assert not i.has(Integral) + # assert i == -5*zeta(3)/4 + + +@XFAIL +@slow +def test_issue_14716(): + i = integrate(log(x + 5)*cos(pi*x),(x, S.Half, 1)) + assert not i.has(Integral) + # Mathematica can not solve it either, but + # integrate(log(x + 5)*cos(pi*x),(x, S.Half, 1)).transform(x, y - 5).doit() + # works + # assert i == -log(Rational(11, 2))/pi - Si(pi*Rational(11, 2))/pi + Si(6*pi)/pi + + +@XFAIL +def test_issue_14709a(): + i = integrate(x*acos(1 - 2*x/h), (x, 0, h)) + assert not i.has(Integral) + # assert i == 5*h**2*pi/16 + + +@slow +@XFAIL +def test_issue_14398(): + assert not integrate(exp(x**2)*cos(x), x).has(Integral) + + +@XFAIL +def test_issue_14074(): + i = integrate(log(sin(x)), (x, 0, pi/2)) + assert not i.has(Integral) + # assert i == -pi*log(2)/2 + + +@XFAIL +@slow +def test_issue_14078b(): + i = integrate((atan(4*x)-atan(2*x))/x, (x, 0, oo)) + assert not i.has(Integral) + # assert i == pi*log(2)/2 + + +@XFAIL +def test_issue_13792(): + i = integrate(log(1/x) / (1 - x), (x, 0, 1)) + assert not i.has(Integral) + # assert i in [polylog(2, -exp_polar(I*pi)), pi**2/6] + + +@XFAIL +def test_issue_11845a(): + assert not integrate(exp(y - x**3), (x, 0, 1)).has(Integral) + + +@XFAIL +def test_issue_11845b(): + assert not integrate(exp(-y - x**3), (x, 0, 1)).has(Integral) + + +@XFAIL +def test_issue_11813(): + assert not integrate((a - x)**Rational(-1, 2)*x, (x, 0, a)).has(Integral) + + +@XFAIL +def test_issue_11254c(): + assert not integrate(sech(x)**2, (x, 0, 1)).has(Integral) + + +@XFAIL +def test_issue_10584(): + assert not integrate(sqrt(x**2 + 1/x**2), x).has(Integral) + + +@XFAIL +def test_issue_9101(): + assert not integrate(log(x + sqrt(x**2 + y**2 + z**2)), z).has(Integral) + + +@XFAIL +def test_issue_7147(): + assert not integrate(x/sqrt(a*x**2 + b*x + c)**3, x).has(Integral) + + +@XFAIL +def test_issue_7109(): + assert not integrate(sqrt(a**2/(a**2 - x**2)), x).has(Integral) + + +@XFAIL +def test_integrate_Piecewise_rational_over_reals(): + f = Piecewise( + (0, t - 478.515625*pi < 0), + (13.2075145209219*pi/(0.000871222*t + 0.995)**2, t - 478.515625*pi >= 0)) + + assert abs((integrate(f, (t, 0, oo)) - 15235.9375*pi).evalf()) <= 1e-7 + + +@XFAIL +def test_issue_4311_slow(): + # Not slow when bypassing heurish + assert not integrate(x*abs(9-x**2), x).has(Integral) + +@XFAIL +def test_issue_20370(): + a = symbols('a', positive=True) + assert integrate((1 + a * cos(x))**-1, (x, 0, 2 * pi)) == (2 * pi / sqrt(1 - a**2)) + + +@XFAIL +def test_polylog(): + # log(1/x)*log(x+1)-polylog(2, -x) + assert not integrate(log(1/x)/(x + 1), x).has(Integral) + + +@XFAIL +def test_polylog_manual(): + # Make sure _parts_rule does not go into an infinite loop here + assert not integrate(log(1/x)/(x + 1), x, manual=True).has(Integral) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_heurisch.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_heurisch.py new file mode 100644 index 0000000000000000000000000000000000000000..f02556dedd597721529cab47bf53609110e0ce2a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_heurisch.py @@ -0,0 +1,417 @@ +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.function import (Derivative, Function, diff) +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.relational import Eq, Ne +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.exponential import (LambertW, exp, log) +from sympy.functions.elementary.hyperbolic import (asinh, cosh, sinh, tanh) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (acos, asin, atan, cos, sin, tan) +from sympy.functions.special.bessel import (besselj, besselk, bessely, jn) +from sympy.functions.special.error_functions import erf +from sympy.integrals.integrals import Integral +from sympy.logic.boolalg import And +from sympy.matrices import Matrix +from sympy.simplify.ratsimp import ratsimp +from sympy.simplify.simplify import simplify +from sympy.integrals.heurisch import components, heurisch, heurisch_wrapper +from sympy.testing.pytest import XFAIL, slow +from sympy.integrals.integrals import integrate +from sympy import S + +x, y, z, nu = symbols('x,y,z,nu') +f = Function('f') + + +def test_components(): + assert components(x*y, x) == {x} + assert components(1/(x + y), x) == {x} + assert components(sin(x), x) == {sin(x), x} + assert components(sin(x)*sqrt(log(x)), x) == \ + {log(x), sin(x), sqrt(log(x)), x} + assert components(x*sin(exp(x)*y), x) == \ + {sin(y*exp(x)), x, exp(x)} + assert components(x**Rational(17, 54)/sqrt(sin(x)), x) == \ + {sin(x), x**Rational(1, 54), sqrt(sin(x)), x} + + assert components(f(x), x) == \ + {x, f(x)} + assert components(Derivative(f(x), x), x) == \ + {x, f(x), Derivative(f(x), x)} + assert components(f(x)*diff(f(x), x), x) == \ + {x, f(x), Derivative(f(x), x), Derivative(f(x), x)} + + +def test_issue_10680(): + assert isinstance(integrate(x**log(x**log(x**log(x))),x), Integral) + + +def test_issue_21166(): + assert integrate(sin(x/sqrt(abs(x))), (x, -1, 1)) == 0 + + +def test_heurisch_polynomials(): + assert heurisch(1, x) == x + assert heurisch(x, x) == x**2/2 + assert heurisch(x**17, x) == x**18/18 + # For coverage + assert heurisch_wrapper(y, x) == y*x + + +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 = pi*I*Rational(5, 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) + + assert heurisch(Integral(x**z*y, (y, 1, 2), (z, 2, 3)).function, x) == (x*x**z*y)/(z+1) + assert heurisch(Sum(x**z, (z, 1, 2)).function, z) == x**z/log(x) + + # https://github.com/sympy/sympy/issues/23707 + anti = -exp(z)/(sqrt(x - y)*exp(z*sqrt(x - y)) - exp(z*sqrt(x - y))) + assert heurisch(exp(z)*exp(-z*sqrt(x - y)), z) == anti + + +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) + + assert heurisch(sin(x)/(cos(x)**2+1), x) == -atan(cos(x)) #fixes issue 13723 + assert heurisch(1/(cos(x)+2), x) == 2*sqrt(3)*atan(sqrt(3)*tan(x/2)/3)/3 + assert heurisch(2*sin(x)*cos(x)/(sin(x)**4 + 1), x) == atan(sqrt(2)*sin(x) + - 1) - atan(sqrt(2)*sin(x) + 1) + + assert heurisch(1/cosh(x), x) == 2*atan(tanh(x/2)) + + +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 + assert heurisch(sin(x/sqrt(-x)), x) == 2*x*cos(x/sqrt(-x))/sqrt(-x) - 2*sin(x/sqrt(-x)) + + +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( + (-2*sqrt(x)*cos(sqrt(x)*y)/y + 2*sin(sqrt(x)*y)/y**2, Ne(y, 0)), + (0, 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( + (log(x - sqrt(-y))/(2*sqrt(-y)) - log(x + sqrt(-y))/(2*sqrt(-y)), + Ne(y, 0)), (-1/x, True)) + y = Symbol('y', positive=True) + assert heurisch_wrapper(1/(x**2 + y), x) == (atan(x/sqrt(y))/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(x*Rational(2, 3))/2 + + assert heurisch(1/sqrt(9 + 4*x**2), x, hints=[]) == \ + asinh(x*Rational(2, 3))/2 + + assert heurisch(1/sqrt(3*x**2-4), x, hints=[]) == \ + sqrt(3)*log(3*x + sqrt(3)*sqrt(3*x**2 - 4))/3 + + +def test_heurisch_function(): + assert heurisch(f(x), x) is None + +@XFAIL +def test_heurisch_function_derivative(): + # TODO: it looks like this used to work just by coincindence and + # thanks to sloppy implementation. Investigate why this used to + # work at all and if support for this can be restored. + + df = diff(f(x), x) + + 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( + (-log(x - y)/(2*y) + log(x + y)/(2*y), Ne(y, 0)), (1/x, True)) + # issue 6926 + f = sqrt(x**2/((y - x)*(y + x))) + assert heurisch_wrapper(f, x) == x*sqrt(-x**2/(x**2 - y**2)) \ + - y**2*sqrt(-x**2/(x**2 - y**2))/x + + +def test_issue_3609(): + assert heurisch(1/(x * (1 + log(x)**2)), x) == atan(log(x)) + +### These are examples from the Poor Man's Integrator +### http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/examples/ + + +def test_pmint_rat(): + # TODO: heurisch() is off by a constant: -3/4. Possibly different permutation + # would give the optimal result? + + def drop_const(expr, x): + if expr.is_Add: + return Add(*[ arg for arg in expr.args if arg.has(x) ]) + else: + return expr + + 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**5 + 4*x**3 + 4*x) + log(x) + + assert drop_const(ratsimp(heurisch(f, x)), x) == g + + +def test_pmint_trig(): + f = (x - tan(x)) / tan(x)**2 + tan(x) + g = -x**2/2 - x/tan(x) + log(tan(x)**2 + 1)/2 + + assert heurisch(f, x) == g + + +def test_pmint_logexp(): + f = (1 + x + x*exp(x))*(x + log(x) + exp(x) - 1)/(x + log(x) + exp(x))**2/x + g = log(x + exp(x) + log(x)) + 1/(x + exp(x) + log(x)) + + assert ratsimp(heurisch(f, x)) == g + + +def test_pmint_erf(): + f = exp(-x**2)*erf(x)/(erf(x)**3 - erf(x)**2 - erf(x) + 1) + g = sqrt(pi)*log(erf(x) - 1)/8 - sqrt(pi)*log(erf(x) + 1)/8 - sqrt(pi)/(4*erf(x) - 4) + + assert ratsimp(heurisch(f, x)) == g + + +def test_pmint_LambertW(): + f = LambertW(x) + g = x*LambertW(x) - x + x/LambertW(x) + + assert heurisch(f, x) == g + + +def test_pmint_besselj(): + f = besselj(nu + 1, x)/besselj(nu, x) + g = nu*log(x) - log(besselj(nu, x)) + + assert heurisch(f, x) == g + + f = (nu*besselj(nu, x) - x*besselj(nu + 1, x))/x + g = besselj(nu, x) + + assert heurisch(f, x) == g + + f = jn(nu + 1, x)/jn(nu, x) + g = nu*log(x) - log(jn(nu, x)) + + assert heurisch(f, x) == g + + +@slow +def test_pmint_bessel_products(): + f = x*besselj(nu, x)*bessely(nu, 2*x) + g = -2*x*besselj(nu, x)*bessely(nu - 1, 2*x)/3 + x*besselj(nu - 1, x)*bessely(nu, 2*x)/3 + + assert heurisch(f, x) == g + + f = x*besselj(nu, x)*besselk(nu, 2*x) + g = -2*x*besselj(nu, x)*besselk(nu - 1, 2*x)/5 - x*besselj(nu - 1, x)*besselk(nu, 2*x)/5 + + assert heurisch(f, x) == g + + +def test_pmint_WrightOmega(): + def omega(x): + return LambertW(exp(x)) + + f = (1 + omega(x) * (2 + cos(omega(x)) * (x + omega(x))))/(1 + omega(x))/(x + omega(x)) + g = log(x + LambertW(exp(x))) + sin(LambertW(exp(x))) + + assert heurisch(f, x) == g + + +def test_RR(): + # Make sure the algorithm does the right thing if the ring is RR. See + # issue 8685. + assert heurisch(sqrt(1 + 0.25*x**2), x, hints=[]) == \ + 0.5*x*sqrt(0.25*x**2 + 1) + 1.0*asinh(0.5*x) + +# 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 +# Whittaker functions +# f = WhittakerW(mu + 1, nu, x) / (WhittakerW(mu, nu, x) * x) +# g = x/2 - mu*ln(x) - ln(WhittakerW(mu, nu, x)) + + +def test_issue_22527(): + t, R = symbols(r't R') + z = Function('z')(t) + def f(x): + return x/sqrt(R**2 - x**2) + Uz = integrate(f(z), z) + Ut = integrate(f(t), t) + assert Ut == Uz.subs(z, t) + + +def test_heurisch_complex_erf_issue_26338(): + r = symbols('r', real=True) + a = sqrt(pi)*erf((1 + I)/2)/2 + assert integrate(exp(-I*r**2/2), (r, 0, 1)) == a - I*a + + a = exp(-x**2/(2*(2 - I)**2)) + assert heurisch(a, x, hints=[]) is None # None, not a wrong soln + a = exp(-r**2/(2*(2 - I)**2)) + assert heurisch(a, r, hints=[]) is None + a = sqrt(pi)*erf((1 + I)/2)/2 + assert integrate(exp(-I*x**2/2), (x, 0, 1)) == a - I*a + + +def test_issue_15498(): + Z0 = Function('Z0') + k01, k10, t, s= symbols('k01 k10 t s', real=True, positive=True) + m = Matrix([[exp(-k10*t)]]) + _83 = Rational(83, 100) # 0.83 works, too + [a, b, c, d, e, f, g] = [100, 0.5, _83, 50, 0.6, 2, 120] + AIF_btf = a*(d*e*(1 - exp(-(t - b)/e)) + f*g*(1 - exp(-(t - b)/g))) + AIF_atf = a*(d*e*exp(-(t - b)/e)*(exp((c - b)/e) - 1 + ) + f*g*exp(-(t - b)/g)*(exp((c - b)/g) - 1)) + AIF_sym = Piecewise((0, t < b), (AIF_btf, And(b <= t, t < c)), (AIF_atf, c <= t)) + aif_eq = Eq(Z0(t), AIF_sym) + f_vec = Matrix([[k01*Z0(t)]]) + integrand = m*m.subs(t, s)**-1*f_vec.subs(aif_eq.lhs, aif_eq.rhs).subs(t, s) + solution = integrate(integrand[0], (s, 0, t)) + assert solution is not None # does not hang and takes less than 10 s + + +@slow +def test_heurisch_issue_26930(): + integrand = x**Rational(4, 3)*log(x) + anti = 3*x**(S(7)/3)*log(x)/7 - 9*x**(S(7)/3)/49 + assert heurisch(integrand, x) == anti + assert integrate(integrand, x) == anti + assert integrate(integrand, (x, 0, 1)) == -S(9)/49 + + +def test_heurisch_issue_26922(): + + a, b, x = symbols("a, b, x", real=True, positive=True) + C = symbols("C", real=True) + i1 = -C*x*exp(-a*x**2 - sqrt(b)*x) + i2 = C*x*exp(-a*x**2 + sqrt(b)*x) + i = Integral(i1, x) + Integral(i2, x) + res = ( + -C*exp(-a*x**2)*exp(sqrt(b)*x)/(2*a) + + C*exp(-a*x**2)*exp(-sqrt(b)*x)/(2*a) + + sqrt(pi)*C*sqrt(b)*exp(b/(4*a))*erf(sqrt(a)*x - sqrt(b)/(2*sqrt(a)))/(4*a**(S(3)/2)) + + sqrt(pi)*C*sqrt(b)*exp(b/(4*a))*erf(sqrt(a)*x + sqrt(b)/(2*sqrt(a)))/(4*a**(S(3)/2)) + ) + + assert i.doit(heurisch=False).expand() == res diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_integrals.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_integrals.py new file mode 100644 index 0000000000000000000000000000000000000000..41e1ef3aa36334189f14cf734ac2ad26d001b506 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_integrals.py @@ -0,0 +1,2187 @@ +import math +from sympy.concrete.summations import (Sum, summation) +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import (Derivative, Function, Lambda, diff) +from sympy.core import EulerGamma +from sympy.core.numbers import (E, I, Rational, nan, oo, pi, zoo, all_close) +from sympy.core.relational import (Eq, Ne) +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.core.sympify import sympify +from sympy.functions.elementary.complexes import (Abs, im, polar_lift, re, sign) +from sympy.functions.elementary.exponential import (LambertW, exp, exp_polar, log) +from sympy.functions.elementary.hyperbolic import (acosh, asinh, cosh, coth, csch, sinh, tanh, sech) +from sympy.functions.elementary.miscellaneous import (Max, Min, sqrt) +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (acos, asin, atan, cos, sin, sinc, tan, sec) +from sympy.functions.special.delta_functions import DiracDelta, Heaviside +from sympy.functions.special.error_functions import (Ci, Ei, Si, erf, erfc, erfi, fresnelc, li) +from sympy.functions.special.gamma_functions import (gamma, polygamma) +from sympy.functions.special.hyper import (hyper, meijerg) +from sympy.functions.special.singularity_functions import SingularityFunction +from sympy.functions.special.zeta_functions import lerchphi +from sympy.integrals.integrals import integrate +from sympy.logic.boolalg import And +from sympy.matrices.dense import Matrix +from sympy.polys.polytools import (Poly, factor) +from sympy.printing.str import sstr +from sympy.series.order import O +from sympy.sets.sets import Interval +from sympy.simplify.gammasimp import gammasimp +from sympy.simplify.simplify import simplify +from sympy.simplify.trigsimp import trigsimp +from sympy.tensor.indexed import (Idx, IndexedBase) +from sympy.core.expr import unchanged +from sympy.functions.elementary.integers import floor +from sympy.integrals.integrals import Integral +from sympy.integrals.risch import NonElementaryIntegral +from sympy.physics import units +from sympy.testing.pytest import raises, slow, warns_deprecated_sympy, warns +from sympy.utilities.exceptions import SymPyDeprecationWarning +from sympy.core.random import verify_numerically + + +x, y, z, a, b, c, d, e, s, t, x_1, x_2 = symbols('x y z a b c d e s t x_1 x_2') +n = Symbol('n', integer=True) +f = Function('f') + + +def NS(e, n=15, **options): + return sstr(sympify(e).evalf(n, **options), full_prec=True) + + +def test_poly_deprecated(): + p = Poly(2*x, x) + assert p.integrate(x) == Poly(x**2, x, domain='QQ') + # The stacklevel is based on Integral(Poly) + with warns(SymPyDeprecationWarning, test_stacklevel=False): + integrate(p, x) + with warns(SymPyDeprecationWarning, test_stacklevel=False): + Integral(p, (x,)) + + +@slow +def test_principal_value(): + g = 1 / x + assert Integral(g, (x, -oo, oo)).principal_value() == 0 + assert Integral(g, (y, -oo, oo)).principal_value() == oo * sign(1 / x) + raises(ValueError, lambda: Integral(g, (x)).principal_value()) + raises(ValueError, lambda: Integral(g).principal_value()) + + l = 1 / ((x ** 3) - 1) + assert Integral(l, (x, -oo, oo)).principal_value().together() == -sqrt(3)*pi/3 + raises(ValueError, lambda: Integral(l, (x, -oo, 1)).principal_value()) + + d = 1 / (x ** 2 - 1) + assert Integral(d, (x, -oo, oo)).principal_value() == 0 + assert Integral(d, (x, -2, 2)).principal_value() == -log(3) + + v = x / (x ** 2 - 1) + assert Integral(v, (x, -oo, oo)).principal_value() == 0 + assert Integral(v, (x, -2, 2)).principal_value() == 0 + + s = x ** 2 / (x ** 2 - 1) + assert Integral(s, (x, -oo, oo)).principal_value() is oo + assert Integral(s, (x, -2, 2)).principal_value() == -log(3) + 4 + + f = 1 / ((x ** 2 - 1) * (1 + x ** 2)) + assert Integral(f, (x, -oo, oo)).principal_value() == -pi / 2 + assert Integral(f, (x, -2, 2)).principal_value() == -atan(2) - log(3) / 2 + + +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 + the assertion will fail, causing the test to fail.""" + syms = i.free_symbols + for s in syms: + 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 + assert integrate(1/(1 + exp(x)), (x, 0, oo)) == log(2) + + +def test_constructor(): + # this is shared by Sum, so testing Integral's constructor + # is equivalent to testing Sum's + s1 = Integral(n, n) + assert s1.limits == (Tuple(n),) + s2 = Integral(n, (n,)) + assert s2.limits == (Tuple(n),) + s3 = Integral(Sum(x, (x, 1, y))) + assert s3.limits == (Tuple(y),) + s4 = Integral(n, Tuple(n,)) + assert s4.limits == (Tuple(n),) + + s5 = Integral(n, (n, Interval(1, 2))) + assert s5.limits == (Tuple(n, 1, 2),) + + # Testing constructor with inequalities: + s6 = Integral(n, n > 10) + assert s6.limits == (Tuple(n, 10, oo),) + s7 = Integral(n, (n > 2) & (n < 5)) + assert s7.limits == (Tuple(n, 2, 5),) + + +def test_basics(): + + assert Integral(0, x) != 0 + assert Integral(x, (x, 1, 1)) != 0 + assert Integral(oo, x) != oo + assert Integral(S.NaN, x) is 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 + + 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(t**2, (t, x, 2*x)).diff(x) == 7*x**2 + + assert Integral(x, x).atoms() == {x} + assert Integral(f(x), (x, 0, 1)).atoms() == {S.Zero, S.One, x} + + assert diff_test(Integral(x, (x, 3*y))) == {y} + assert diff_test(Integral(x, (a, 3*y))) == {x, y} + + assert integrate(x, (x, oo, oo)) == 0 #issue 8171 + assert integrate(x, (x, -oo, -oo)) == 0 + + # sum integral of terms + assert integrate(y + x + exp(x), x) == x*y + x**2/2 + exp(x) + + assert Integral(x).is_commutative + n = Symbol('n', commutative=False) + assert Integral(n + x, x).is_commutative is False + + +def test_diff_wrt(): + class Test(Expr): + _diff_wrt = True + is_commutative = True + + t = Test() + assert integrate(t + 1, t) == t**2/2 + t + assert integrate(t + 1, (t, 0, 1)) == Rational(3, 2) + + raises(ValueError, lambda: integrate(x + 1, x + 1)) + raises(ValueError, lambda: integrate(x + 1, (x + 1, 0, 1))) + + +def test_basics_multiple(): + assert diff_test(Integral(x, (x, 3*x, 5*y), (y, x, 2*x))) == {x} + assert diff_test(Integral(x, (x, 5*y), (y, x, 2*x))) == {x} + assert diff_test(Integral(x, (x, 5*y), (y, y, 2*x))) == {x, y} + assert diff_test(Integral(y, y, x)) == {x, y} + assert diff_test(Integral(y*x, x, y)) == {x, y} + assert diff_test(Integral(x + y, y, (y, 1, x))) == {x} + assert diff_test(Integral(x + y, (x, x, y), (y, y, x))) == {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(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 + + +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) == \ + log(3 + x)*Rational(-1, 8) + log(1 + x)*Rational(1, 8) + x/(4 + 8*x + 4*x**2) + assert integrate(sin(x*y)*y, (x, 0, 1), (y, 0, 1)) == -sin(1) + 1 + + +def test_issue_3532(): + assert integrate(exp(-x), (x, 0, oo)) == 1 + + +def test_issue_3560(): + 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_issue_18038(): + raises(AttributeError, lambda: integrate((x, x))) + + +def test_integrate_poly(): + p = Poly(x + x**2*y + y**3, x, y) + + # The stacklevel is based on Integral(Poly) + with warns_deprecated_sympy(): + qx = Integral(p, x) + with warns(SymPyDeprecationWarning, test_stacklevel=False): + qx = integrate(p, x) + with warns(SymPyDeprecationWarning, test_stacklevel=False): + qy = integrate(p, y) + + assert isinstance(qx, Poly) is True + assert isinstance(qy, Poly) is True + + assert qx.gens == (x, y) + assert qy.gens == (x, y) + + 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_definite(): + p = Poly(x + x**2*y + y**3, x, y) + + with warns_deprecated_sympy(): + Qx = Integral(p, (x, 0, 1)) + with warns(SymPyDeprecationWarning, test_stacklevel=False): + Qx = integrate(p, (x, 0, 1)) + with warns(SymPyDeprecationWarning, test_stacklevel=False): + Qy = integrate(p, (y, 0, pi)) + + assert isinstance(Qx, Poly) is True + assert isinstance(Qy, Poly) is True + + assert Qx.gens == (y,) + assert Qy.gens == (x,) + + assert Qx.as_expr() == S.Half + 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') + + assert integrate(x) == x**2/2 + + 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 + + # 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_issue_3635(): + 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) -- issue 3499 + 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_issue_3618(): + 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_issue_3623(): + assert integrate(cos((n + 1)*x), x) == Piecewise( + (sin(x*(n + 1))/(n + 1), Ne(n + 1, 0)), (x, True)) + assert integrate(cos((n - 1)*x), x) == Piecewise( + (sin(x*(n - 1))/(n - 1), Ne(n - 1, 0)), (x, True)) + assert integrate(cos((n + 1)*x) + cos((n - 1)*x), x) == \ + Piecewise((sin(x*(n - 1))/(n - 1), Ne(n - 1, 0)), (x, True)) + \ + Piecewise((sin(x*(n + 1))/(n + 1), Ne(n + 1, 0)), (x, True)) + + +def test_issue_3664(): + n = Symbol('n', integer=True, nonzero=True) + assert integrate(-1./2 * x * sin(n * pi * x/2), [x, -2, 0]) == \ + 2.0*cos(pi*n)/(pi*n) + assert integrate(x * sin(n * pi * x/2) * Rational(-1, 2), [x, -2, 0]) == \ + 2*cos(pi*n)/(pi*n) + + +def test_issue_3679(): + # definite integration of rational functions gives wrong answers + assert NS(Integral(1/(x**2 - 8*x + 17), (x, 2, 4))) == '1.10714871779409' + + +def test_issue_3686(): # remove this when fresnel integrals are implemented + from sympy.core.function import expand_func + from sympy.functions.special.error_functions import fresnels + assert expand_func(integrate(sin(x**2), x)) == \ + 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) + + +def test_log_polylog(): + assert integrate(log(1 - x)/x, (x, 0, 1)) == -pi**2/6 + assert integrate(log(x)*(1 - x)**(-1), (x, 0, 1)) == -pi**2/6 + + +def test_issue_3740(): + 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_issue_3788(): + assert integrate(1/(1 + x**2), x) == atan(x) + + +def test_issue_3952(): + f = sin(x) + assert integrate(f, x) == -cos(x) + raises(ValueError, lambda: integrate(f, 2*x)) + + +def test_issue_4516(): + assert integrate(2**x - 2*x, x) == 2**x/log(2) - x**2 + + +def test_issue_7450(): + ans = integrate(exp(-(1 + I)*x), (x, 0, oo)) + assert re(ans) == S.Half and im(ans) == Rational(-1, 2) + + +def test_issue_8623(): + assert integrate((1 + cos(2*x)) / (3 - 2*cos(2*x)), (x, 0, pi)) == -pi/2 + sqrt(5)*pi/2 + assert integrate((1 + cos(2*x))/(3 - 2*cos(2*x))) == -x/2 + sqrt(5)*(atan(sqrt(5)*tan(x)) + \ + pi*floor((x - pi/2)/pi))/2 + + +def test_issue_9569(): + assert integrate(1 / (2 - cos(x)), (x, 0, pi)) == pi/sqrt(3) + assert integrate(1/(2 - cos(x))) == 2*sqrt(3)*(atan(sqrt(3)*tan(x/2)) + pi*floor((x/2 - pi/2)/pi))/3 + + +def test_issue_13733(): + s = Symbol('s', positive=True) + pz = exp(-(z - y)**2/(2*s*s))/sqrt(2*pi*s*s) + pzgx = integrate(pz, (z, x, oo)) + assert integrate(pzgx, (x, 0, oo)) == sqrt(2)*s*exp(-y**2/(2*s**2))/(2*sqrt(pi)) + \ + y*erf(sqrt(2)*y/(2*s))/2 + y/2 + + +def test_issue_13749(): + assert integrate(1 / (2 + cos(x)), (x, 0, pi)) == pi/sqrt(3) + assert integrate(1/(2 + cos(x))) == 2*sqrt(3)*(atan(sqrt(3)*tan(x/2)/3) + pi*floor((x/2 - pi/2)/pi))/3 + + +def test_issue_18133(): + assert integrate(exp(x)/(1 + x)**2, x) == NonElementaryIntegral(exp(x)/(x + 1)**2, x) + + +def test_issue_21741(): + a = 4e6 + b = 2.5e-7 + r = Piecewise((b*I*exp(-a*I*pi*t*y)*exp(-a*I*pi*x*z)/(pi*x), Ne(x, 0)), + (z*exp(-a*I*pi*t*y), True)) + fun = E**((-2*I*pi*(z*x+t*y))/(500*10**(-9))) + assert all_close(integrate(fun, z), r) + + +def test_matrices(): + 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(2*x), -cos(3*x)], + ]) + + +def test_integrate_functions(): + # issue 4111 + 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)) + + +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) + assert integrate(Derivative(f(x), x)**2, x) == \ + Integral(Derivative(f(x), x)**2, x) + + +def test_transform(): + a = Integral(x**2 + 1, (x, -1, 2)) + fx = x + fy = 3*y + 1 + assert a.doit() == a.transform(fx, fy).doit() + assert a.transform(fx, fy).transform(fy, fx) == a + fx = 3*x + 1 + fy = y + assert a.transform(fx, fy).transform(fy, fx) == a + a = Integral(sin(1/x), (x, 0, 1)) + assert a.transform(x, 1/y) == Integral(sin(y)/y**2, (y, 1, oo)) + assert a.transform(x, 1/y).transform(y, 1/x) == a + 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() + _3 = S(3) + assert Integral(x, (x, 0, -_3)).transform(x, 1/y).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)) + # issue 8400 + i = Integral(x + y, (x, 1, 2), (y, 1, 2)) + assert i.transform(x, (x + 2*y, x)).doit() == \ + i.transform(x, (x + 2*z, x)).doit() == 3 + + i = Integral(x, (x, a, b)) + assert i.transform(x, 2*s) == Integral(4*s, (s, a/2, b/2)) + raises(ValueError, lambda: i.transform(x, 1)) + raises(ValueError, lambda: i.transform(x, s*t)) + raises(ValueError, lambda: i.transform(x, -s)) + raises(ValueError, lambda: i.transform(x, (s, t))) + raises(ValueError, lambda: i.transform(2*x, 2*s)) + + i = Integral(x**2, (x, 1, 2)) + raises(ValueError, lambda: i.transform(x**2, s)) + + am = Symbol('a', negative=True) + bp = Symbol('b', positive=True) + i = Integral(x, (x, bp, am)) + i.transform(x, 2*s) + assert i.transform(x, 2*s) == Integral(-4*s, (s, am/2, bp/2)) + + i = Integral(x, (x, a)) + assert i.transform(x, 2*s) == Integral(4*s, (s, a/2)) + + +def test_issue_4052(): + f = S.Half*asin(x) + x*sqrt(1 - x**2)/2 + + assert integrate(cos(asin(x)), x) == f + assert integrate(sin(acos(x)), x) == f + + +@slow +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') + # 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 + 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) + # 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) + # 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) + # 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) + # 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) + # Needs zero handling + 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' + # indefinite integrals aren't evaluated + assert NS(Integral(x, x)) == 'Integral(x, x)' + assert NS(Integral(x, (x, y))) == 'Integral(x, (x, y))' + + +def test_evalf_issue_939(): + # https://github.com/sympy/sympy/issues/4038 + + # The output form of an integral may differ by a step function between + # 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 \ + ['-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' + + +def test_double_previously_failing_integrals(): + # Double integrals not implemented <- Sure it is! + res = integrate(sqrt(x) + x*y, (x, 1, 2), (y, -1, 1)) + # Old numerical test + assert NS(res, 15) == '2.43790283299492' + # Symbolic test + assert res == Rational(-4, 3) + 8*sqrt(2)/3 + # double integral + zero detection + assert integrate(sin(x + x*y), (x, -1, 1), (y, -1, 1)) is S.Zero + + +def test_integrate_SingularityFunction(): + in_1 = SingularityFunction(x, a, 3) + SingularityFunction(x, 5, -1) + out_1 = SingularityFunction(x, a, 4)/4 + SingularityFunction(x, 5, 0) + assert integrate(in_1, x) == out_1 + + in_2 = 10*SingularityFunction(x, 4, 0) - 5*SingularityFunction(x, -6, -2) + out_2 = 10*SingularityFunction(x, 4, 1) - 5*SingularityFunction(x, -6, -1) + assert integrate(in_2, x) == out_2 + + in_3 = 2*x**2*y -10*SingularityFunction(x, -4, 7) - 2*SingularityFunction(y, 10, -2) + out_3_1 = 2*x**3*y/3 - 2*x*SingularityFunction(y, 10, -2) - 5*SingularityFunction(x, -4, 8)/4 + out_3_2 = x**2*y**2 - 10*y*SingularityFunction(x, -4, 7) - 2*SingularityFunction(y, 10, -1) + assert integrate(in_3, x) == out_3_1 + assert integrate(in_3, y) == out_3_2 + + assert unchanged(Integral, in_3, (x,)) + assert Integral(in_3, x) == Integral(in_3, (x,)) + assert Integral(in_3, x).doit() == out_3_1 + + in_4 = 10*SingularityFunction(x, -4, 7) - 2*SingularityFunction(x, 10, -2) + out_4 = 5*SingularityFunction(x, -4, 8)/4 - 2*SingularityFunction(x, 10, -1) + assert integrate(in_4, (x, -oo, x)) == out_4 + + assert integrate(SingularityFunction(x, 5, -1), x) == SingularityFunction(x, 5, 0) + assert integrate(SingularityFunction(x, 0, -1), (x, -oo, oo)) == 1 + assert integrate(5*SingularityFunction(x, 5, -1), (x, -oo, oo)) == 5 + assert integrate(SingularityFunction(x, 5, -1) * f(x), (x, -oo, oo)) == f(5) + + +def test_integrate_DiracDelta(): + # 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)**2, (x, -oo, oo)) == DiracDelta(0) + # issue 4522 + assert integrate(integrate((4 - 4*x + x*y - 4*y) * \ + DiracDelta(x)*DiracDelta(y - 1), (x, 0, 1)), (y, 0, 1)) == 0 + # issue 5729 + 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) + + +def test_integrate_returns_piecewise(): + assert integrate(x**y, x) == Piecewise( + (x**(y + 1)/(y + 1), Ne(y, -1)), (log(x), True)) + assert integrate(x**y, y) == Piecewise( + (x**y/log(x), Ne(log(x), 0)), (y, True)) + assert integrate(exp(n*x), x) == Piecewise( + (exp(n*x)/n, Ne(n, 0)), (x, True)) + assert integrate(x*exp(n*x), x) == Piecewise( + ((n*x - 1)*exp(n*x)/n**2, Ne(n**2, 0)), (x**2/2, True)) + assert integrate(x**(n*y), x) == Piecewise( + (x**(n*y + 1)/(n*y + 1), Ne(n*y, -1)), (log(x), True)) + assert integrate(x**(n*y), y) == Piecewise( + (x**(n*y)/(n*log(x)), Ne(n*log(x), 0)), (y, True)) + assert integrate(cos(n*x), x) == Piecewise( + (sin(n*x)/n, Ne(n, 0)), (x, True)) + assert integrate(cos(n*x)**2, x) == Piecewise( + ((n*x/2 + sin(n*x)*cos(n*x)/2)/n, Ne(n, 0)), (x, True)) + assert integrate(x*cos(n*x), x) == Piecewise( + (x*sin(n*x)/n + cos(n*x)/n**2, Ne(n, 0)), (x**2/2, True)) + assert integrate(sin(n*x), x) == Piecewise( + (-cos(n*x)/n, Ne(n, 0)), (0, True)) + assert integrate(sin(n*x)**2, x) == Piecewise( + ((n*x/2 - sin(n*x)*cos(n*x)/2)/n, Ne(n, 0)), (0, True)) + assert integrate(x*sin(n*x), x) == Piecewise( + (-x*cos(n*x)/n + sin(n*x)/n**2, Ne(n, 0)), (0, True)) + assert integrate(exp(x*y), (x, 0, z)) == Piecewise( + (exp(y*z)/y - 1/y, (y > -oo) & (y < oo) & Ne(y, 0)), (z, True)) + # https://github.com/sympy/sympy/issues/23707 + assert integrate(exp(t)*exp(-t*sqrt(x - y)), t) == Piecewise( + (-exp(t)/(sqrt(x - y)*exp(t*sqrt(x - y)) - exp(t*sqrt(x - y))), + Ne(x, y + 1)), (t, True)) + + +def test_integrate_max_min(): + x = symbols('x', real=True) + assert integrate(Min(x, 2), (x, 0, 3)) == 4 + assert integrate(Max(x**2, x**3), (x, 0, 2)) == Rational(49, 12) + assert integrate(Min(exp(x), exp(-x))**2, x) == Piecewise( \ + (exp(2*x)/2, x <= 0), (1 - exp(-2*x)/2, True)) + # issue 7907 + c = symbols('c', extended_real=True) + int1 = integrate(Max(c, x)*exp(-x**2), (x, -oo, oo)) + int2 = integrate(c*exp(-x**2), (x, -oo, c)) + int3 = integrate(x*exp(-x**2), (x, c, oo)) + assert int1 == int2 + int3 == sqrt(pi)*c*erf(c)/2 + \ + sqrt(pi)*c/2 + exp(-c**2)/2 + + +def test_integrate_Abs_sign(): + assert integrate(Abs(x), (x, -2, 1)) == Rational(5, 2) + assert integrate(Abs(x), (x, 0, 1)) == S.Half + assert integrate(Abs(x + 1), (x, 0, 1)) == Rational(3, 2) + assert integrate(Abs(x**2 - 1), (x, -2, 2)) == 4 + assert integrate(Abs(x**2 - 3*x), (x, -15, 15)) == 2259 + assert integrate(sign(x), (x, -1, 2)) == 1 + assert integrate(sign(x)*sin(x), (x, -pi, pi)) == 4 + assert integrate(sign(x - 2) * x**2, (x, 0, 3)) == Rational(11, 3) + + t, s = symbols('t s', real=True) + assert integrate(Abs(t), t) == Piecewise( + (-t**2/2, t <= 0), (t**2/2, True)) + assert integrate(Abs(2*t - 6), t) == Piecewise( + (-t**2 + 6*t, t <= 3), (t**2 - 6*t + 18, True)) + assert (integrate(abs(t - s**2), (t, 0, 2)) == + 2*s**2*Min(2, s**2) - 2*s**2 - Min(2, s**2)**2 + 2) + assert integrate(exp(-Abs(t)), t) == Piecewise( + (exp(t), t <= 0), (2 - exp(-t), True)) + assert integrate(sign(2*t - 6), t) == Piecewise( + (-t, t < 3), (t - 6, True)) + assert integrate(2*t*sign(t**2 - 1), t) == Piecewise( + (t**2, t < -1), (-t**2 + 2, t < 1), (t**2, True)) + assert integrate(sign(t), (t, s + 1)) == Piecewise( + (s + 1, s + 1 > 0), (-s - 1, s + 1 < 0), (0, True)) + + +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)) + 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)) + + +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)) + 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)) + + +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)) + 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)) + + +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)) + + +def test_subs5(): + e = Integral(exp(-x**2), (x, -oo, oo)) + assert e.subs(x, 5) == e + e = Integral(exp(-x**2 + y), x) + assert e.subs(y, 5) == Integral(exp(-x**2 + 5), 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) + e = Integral(exp(-x**2 + y), (y, -oo, oo), (x, -oo, oo)) + assert e.subs(x, 5) == e + assert e.subs(y, 5) == e + # Test evaluation of antiderivatives + e = Integral(exp(-x**2), (x, x)) + assert e.subs(x, 5) == Integral(exp(-x**2), (x, 5)) + e = Integral(exp(x), x) + assert (e.subs(x,1) - e.subs(x,0) - Integral(exp(x), (x, 0, 1)) + ).doit().is_zero + + +def test_subs6(): + a, b = symbols('a b') + e = Integral(x*y, (x, f(x), f(y))) + assert e.subs(x, 1) == Integral(x*y, (x, f(1), f(y))) + assert e.subs(y, 1) == Integral(x, (x, f(x), f(1))) + e = Integral(x*y, (x, f(x), f(y)), (y, f(x), f(y))) + assert e.subs(x, 1) == Integral(x*y, (x, f(1), f(y)), (y, f(1), f(y))) + assert e.subs(y, 1) == Integral(x*y, (x, f(x), f(y)), (y, f(x), f(1))) + 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 + 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)) + +def test_expand(): + e = Integral(f(x)+f(x**2), (x, 1, y)) + assert e.expand() == Integral(f(x), (x, 1, y)) + Integral(f(x**2), (x, 1, y)) + e = Integral(f(x)+f(x**2), (x, 1, oo)) + assert e.expand() == e + assert e.expand(force=True) == Integral(f(x), (x, 1, oo)) + \ + Integral(f(x**2), (x, 1, oo)) + + +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), (x, 0, 1)) + \ + Integral(cos(x**2), (x, 0, 1)) + assert Integral(cos(x**2)*(sin(x**2) + 1), x).expand() == \ + Integral(cos(x**2)*sin(x**2), x) + \ + Integral(cos(x**2), x) + + +def test_as_sum_midpoint1(): + 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 + assert e.as_sum(4, method="midpoint") == 2*sqrt(730) + \ + 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)) + raises(NotImplementedError, lambda: e.as_sum(4)) + + +def test_as_sum_midpoint2(): + e = Integral((x + y)**2, (x, 0, 1)) + n = Symbol('n', positive=True, integer=True) + assert e.as_sum(1, method="midpoint").expand() == Rational(1, 4) + y + y**2 + assert e.as_sum(2, method="midpoint").expand() == Rational(5, 16) + y + y**2 + assert e.as_sum(3, method="midpoint").expand() == Rational(35, 108) + y + y**2 + assert e.as_sum(4, method="midpoint").expand() == Rational(21, 64) + y + y**2 + assert e.as_sum(n, method="midpoint").expand() == \ + y**2 + y + Rational(1, 3) - 1/(12*n**2) + + +def test_as_sum_left(): + 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() == Rational(1, 8) + y/2 + y**2 + assert e.as_sum(3, method="left").expand() == Rational(5, 27) + y*Rational(2, 3) + y**2 + assert e.as_sum(4, method="left").expand() == Rational(7, 32) + y*Rational(3, 4) + y**2 + assert e.as_sum(n, method="left").expand() == \ + y**2 + y + Rational(1, 3) - y/n - 1/(2*n) + 1/(6*n**2) + assert e.as_sum(10, method="left", evaluate=False).has(Sum) + + +def test_as_sum_right(): + 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() == Rational(5, 8) + y*Rational(3, 2) + y**2 + assert e.as_sum(3, method="right").expand() == Rational(14, 27) + y*Rational(4, 3) + y**2 + assert e.as_sum(4, method="right").expand() == Rational(15, 32) + y*Rational(5, 4) + y**2 + assert e.as_sum(n, method="right").expand() == \ + y**2 + y + Rational(1, 3) + y/n + 1/(2*n) + 1/(6*n**2) + + +def test_as_sum_trapezoid(): + e = Integral((x + y)**2, (x, 0, 1)) + assert e.as_sum(1, method="trapezoid").expand() == y**2 + y + S.Half + assert e.as_sum(2, method="trapezoid").expand() == y**2 + y + Rational(3, 8) + assert e.as_sum(3, method="trapezoid").expand() == y**2 + y + Rational(19, 54) + assert e.as_sum(4, method="trapezoid").expand() == y**2 + y + Rational(11, 32) + assert e.as_sum(n, method="trapezoid").expand() == \ + y**2 + y + Rational(1, 3) + 1/(6*n**2) + assert Integral(sign(x), (x, 0, 1)).as_sum(1, 'trapezoid') == S.Half + + +def test_as_sum_raises(): + 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(ValueError, lambda: e.as_sum(oo)) + raises(ValueError, 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_issue_4665(): + # Allow only upper or lower limit evaluation + e = Integral(x**2, (x, None, 1)) + f = Integral(x**2, (x, 1, None)) + assert e.doit() == Rational(1, 3) + assert f.doit() == Rational(-1, 3) + assert Integral(x*y, (x, None, y)).subs(y, t) == Integral(x*t, (x, None, t)) + assert Integral(x*y, (x, y, None)).subs(y, t) == Integral(x*t, (x, t, None)) + assert integrate(x**2, (x, None, 1)) == Rational(1, 3) + 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_integrals(): + e = Integral(Integral(2*x), (x, 0, 1)) + assert e.doit() == Rational(1, 3) + assert e.doit(deep=False) == Rational(1, 3) + f = Function('f') + # doesn't matter if the integral can't be performed + assert Integral(f(x), (x, 1, 1)).doit() == 0 + # doesn't matter if the limits can't be evaluated + assert Integral(0, (x, 1, Integral(f(x), x))).doit() == 0 + assert Integral(x, (a, 0)).doit() == 0 + limits = ((a, 1, exp(x)), (x, 0)) + assert Integral(a, *limits).doit() == Rational(1, 4) + assert Integral(a, *list(reversed(limits))).doit() == 0 + + +def test_issue_4884(): + 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_issue_18153(): + assert integrate(x**n*log(x),x) == \ + Piecewise( + (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) + , Ne(n, -1)), (log(x)**2/2, True) + ) + + +def test_is_number(): + from sympy.abc import x, y, z + 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(1, (x, 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 + # `foo.is_number` should always be equivalent to `not foo.free_symbols` + # in each of these cases, there are pseudo-free symbols + i = Integral(x, (y, 1, 1)) + assert i.is_number is False and i.n() == 0 + i = Integral(x, (y, z, z)) + assert i.is_number is False and i.n() == 0 + i = Integral(1, (y, z, z + 2)) + assert i.is_number is False and i.n() == 2.0 + + 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 + assert Integral(Sum(z, (z, 1, 2)), (x, 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 is False + assert Integral(f(x), (x, 0, 1)).is_number is True + + +def test_free_symbols(): + from sympy.abc import x, y, z + assert Integral(0, x).free_symbols == {x} + assert Integral(x).free_symbols == {x} + assert Integral(x, (x, None, y)).free_symbols == {y} + assert Integral(x, (x, y, None)).free_symbols == {y} + assert Integral(x, (x, 1, y)).free_symbols == {y} + assert Integral(x, (x, y, 1)).free_symbols == {y} + assert Integral(x, (x, x, y)).free_symbols == {x, y} + assert Integral(x, x, y).free_symbols == {x, y} + assert Integral(x, (x, 1, 2)).free_symbols == set() + assert Integral(x, (y, 1, 2)).free_symbols == {x} + # pseudo-free in this case + assert Integral(x, (y, z, z)).free_symbols == {x, z} + assert Integral(x, (y, 1, 2), (y, None, None) + ).free_symbols == {x, y} + assert Integral(x, (y, 1, 2), (x, 1, y) + ).free_symbols == {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 == {x} + assert Integral(f(x), (f(x), 1, y)).free_symbols == {y} + assert Integral(f(x), (f(x), 1, x)).free_symbols == {x} + + +def test_is_zero(): + from sympy.abc import x, m + assert Integral(0, (x, 1, x)).is_zero + assert Integral(1, (x, 1, 1)).is_zero + assert Integral(1, (x, 1, 2), (y, 2)).is_zero is False + assert Integral(x, (m, 0)).is_zero + assert Integral(x + m, (m, 0)).is_zero is None + i = Integral(m, (m, 1, exp(x)), (x, 0)) + assert i.is_zero is None + assert Integral(m, (x, 0), (m, 1, exp(x))).is_zero is True + + assert Integral(x, (x, oo, oo)).is_zero # issue 8171 + assert Integral(x, (x, -oo, -oo)).is_zero + + # this is zero but is beyond the scope of what is_zero + # should be doing + assert Integral(sin(x), (x, 0, 2*pi)).is_zero is None + + +def test_series(): + from sympy.abc import x + i = Integral(cos(x), (x, x)) + e = i.lseries(x) + assert i.nseries(x, n=8).removeO() == Add(*[next(e) for j in range(4)]) + + +def test_trig_nonelementary_integrals(): + x = Symbol('x') + assert integrate((1 + sin(x))/x, x) == log(x) + Si(x) + # next one comes out as log(x) + log(x**2)/2 + Ci(x) + # so not hardcoding this log ugliness + assert integrate((cos(x) + 2)/x, x).has(Ci) + + +def test_issue_4403(): + x = Symbol('x') + y = Symbol('y') + 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) == \ + x*sqrt(x**2 - z**2)/2 - z**2*log(x + sqrt(x**2 - z**2))/2 + + x = Symbol('x', real=True) + y = Symbol('y', positive=True) + assert integrate(1/(x**2 + y**2)**S('3/2'), x) == \ + x/(y**2*sqrt(x**2 + y**2)) + # If y is real and nonzero, we get x*Abs(y)/(y**3*sqrt(x**2 + y**2)), + # which results from sqrt(1 + x**2/y**2) = sqrt(x**2 + y**2)/|y|. + + +def test_issue_4403_2(): + assert integrate(sqrt(-x**2 - 4), x) == \ + -2*atan(x/sqrt(-4 - x**2)) + x*sqrt(-4 - x**2)/2 + + +def test_issue_4100(): + R = Symbol('R', positive=True) + assert integrate(sqrt(R**2 - x**2), (x, 0, R)) == pi*R**2/4 + + +def test_issue_5167(): + from sympy.abc import w, x, y, z + f = Function('f') + assert Integral(Integral(f(x), x), x) == Integral(f(x), x, x) + assert Integral(f(x)).args == (f(x), Tuple(x)) + assert Integral(Integral(f(x))).args == (f(x), Tuple(x), Tuple(x)) + 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)) + assert integrate(Integral(f(x), x), x) == Integral(f(x), x, x) + assert integrate(Integral(f(x), y), x) == y*Integral(f(x), x) + assert integrate(Integral(f(x), x), y) in [Integral(y*f(x), x), y*Integral(f(x), x)] + assert integrate(Integral(2, x), x) == x**2 + assert integrate(Integral(2, x), y) == 2*x*y + # don't re-order given limits + assert Integral(1, x, y).args != Integral(1, y, x).args + # do as many as possible + assert Integral(f(x), y, x, y, x).doit() == y**2*Integral(f(x), x, x)/2 + assert Integral(f(x), (x, 1, 2), (w, 1, x), (z, 1, y)).doit() == \ + y*(x - 1)*Integral(f(x), (x, 1, 2)) - (x - 1)*Integral(f(x), (x, 1, 2)) + + +def test_issue_4890(): + z = Symbol('z', positive=True) + assert integrate(exp(-log(x)**2), x) == \ + sqrt(pi)*exp(Rational(1, 4))*erf(log(x) - S.Half)/2 + assert integrate(exp(log(x)**2), x) == \ + sqrt(pi)*exp(Rational(-1, 4))*erfi(log(x)+S.Half)/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_4551(): + assert not integrate(1/(x*sqrt(1 - x**2)), x).has(Integral) + + +def test_issue_4376(): + 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 + + +def test_issue_4517(): + 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_4527(): + k, m = symbols('k m', integer=True) + assert integrate(sin(k*x)*sin(m*x), (x, 0, pi)).simplify() == \ + Piecewise((0, Eq(k, 0) | Eq(m, 0)), + (-pi/2, Eq(k, -m) | (Eq(k, 0) & Eq(m, 0))), + (pi/2, Eq(k, m) | (Eq(k, 0) & Eq(m, 0))), + (0, True)) + # Should be possible to further simplify to: + # Piecewise( + # (0, 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_4199(): + ypos = Symbol('y', positive=True) + # 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_3940(): + a, b, c, d = symbols('a:d', positive=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).equals( + sqrt(pi)*exp(c - b**2/(4*a))*erfi((2*a*x + b)/(2*sqrt(a)))/(2*sqrt(a))) + + from sympy.core.function 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) + 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) + + +def test_issue_5413(): + # Note that this is not the same as testing ratint() because integrate() + # pulls out the coefficient. + assert integrate(-a/(a**2 + x**2), x) == I*log(-I*a + x)/2 - I*log(I*a + x)/2 + + +def test_issue_4892a(): + A, z = symbols('A z') + c = Symbol('c', nonzero=True) + P1 = -A*exp(-z) + P2 = -A/(c*t)*(sin(x)**2 + cos(y)**2) + + 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)), + (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_4892b(): + # Issues relating to issue 4596 are making the actual result of this hard + # to test. The answer should be something like + # + # (-sin(y) + sqrt(-72 + 48*cos(y) - 8*cos(y)**2)/2)*log(x + sqrt(-72 + + # 48*cos(y) - 8*cos(y)**2)/(2*(3 - cos(y)))) + (-sin(y) - sqrt(-72 + + # 48*cos(y) - 8*cos(y)**2)/2)*log(x - sqrt(-72 + 48*cos(y) - + # 8*cos(y)**2)/(2*(3 - cos(y)))) + x**2*sin(y)/2 + 2*x*cos(y) + + 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_5178(): + assert integrate(sin(x)*f(y, z), (x, 0, pi), (y, 0, pi), (z, 0, pi)) == \ + 2*Integral(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) + + assert integrate(f, x) == g + assert diff(integrate(f, x), x) == f + + assert integrate(O(x**5), x) == O(x**6) + + +def test_atom_bug(): + from sympy.integrals.heurisch import heurisch + assert heurisch(meijerg([], [], [1], [], x), x) is None + + +def test_limit_bug(): + z = Symbol('z', zero=False) + assert integrate(sin(x*y*z), (x, 0, pi), (y, 0, pi)).together() == \ + (log(z) - Ci(pi**2*z) + EulerGamma + 2*log(pi))/z + + +def test_issue_4703(): + 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_issue_3558(): + assert integrate(cos(x*y), (x, -pi/2, pi/2), (y, 0, pi)) == 2*Si(pi**2/2) + + +def test_issue_4422(): + assert integrate(1/sqrt(16 + 4*x**2), x) == asinh(x/2) / 2 + + +def test_issue_4493(): + assert simplify(integrate(x*sqrt(1 + 2*x), x)) == \ + sqrt(2*x + 1)*(6*x**2 + x - 1)/15 + + +def test_issue_4737(): + assert integrate(sin(x)/x, (x, -oo, oo)) == pi + assert integrate(sin(x)/x, (x, 0, oo)) == pi/2 + assert integrate(sin(x)/x, x) == Si(x) + + +def test_issue_4992(): + # Note: psi in _check_antecedents becomes NaN. + from sympy.core.function import expand_func + 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) + + +def test_issue_4487(): + from sympy.functions.special.gamma_functions import lowergamma + assert simplify(integrate(exp(-x)*x**y, x)) == lowergamma(y + 1, x) + + +def test_issue_4215(): + x = Symbol("x") + assert integrate(1/(x**2), (x, -1, 1)) is oo + + +def test_issue_4400(): + 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) + + +def test_issue_6253(): + # Note: this used to raise NotImplementedError + # Note: psi in _check_antecedents becomes NaN. + 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_issue_4153(): + 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_4326(): + 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. + e = integrate(((h*(x - R + b))/b)*sqrt(R**2 - x**2), (x, R - b, R)) + assert not e.has(nan) + # See that it evaluates + assert not e.has(Integral) + + +def test_powers(): + assert integrate(2**x + 3**x, x) == 2**x/log(2) + 3**x/log(3) + + +def test_manual_option(): + raises(ValueError, lambda: integrate(1/x, x, manual=True, meijerg=True)) + # an example of a function that manual integration cannot handle + assert integrate(log(1+x)/x, (x, 0, 1), manual=True).has(Integral) + + +def test_meijerg_option(): + raises(ValueError, lambda: integrate(1/x, x, meijerg=True, risch=True)) + # an example of a function that meijerg integration cannot handle + assert integrate(tan(x), x, meijerg=True) == Integral(tan(x), x) + + +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? + + +@slow +def test_heurisch_option(): + raises(ValueError, lambda: integrate(1/x, x, risch=True, heurisch=True)) + # an integral that heurisch can handle + assert integrate(exp(x**2), x, heurisch=True) == sqrt(pi)*erfi(x)/2 + # an integral that heurisch currently cannot handle + assert integrate(exp(x)/x, x, heurisch=True) == Integral(exp(x)/x, x) + # an integral where heurisch currently hangs, issue 15471 + assert integrate(log(x)*cos(log(x))/x**Rational(3, 4), x, heurisch=False) == ( + -128*x**Rational(1, 4)*sin(log(x))/289 + 240*x**Rational(1, 4)*cos(log(x))/289 + + (16*x**Rational(1, 4)*sin(log(x))/17 + 4*x**Rational(1, 4)*cos(log(x))/17)*log(x)) + + +def test_issue_6828(): + f = 1/(1.08*x**2 - 4.3) + g = integrate(f, x).diff(x) + assert verify_numerically(f, g, tol=1e-12) + + +def test_issue_4803(): + x_max = Symbol("x_max") + assert integrate(y/pi*exp(-(x_max - x)/cos(a)), x) == \ + y*exp((x - x_max)/cos(a))*cos(a)/pi + + +def test_issue_4234(): + assert integrate(1/sqrt(1 + tan(x)**2)) == tan(x)/sqrt(1 + tan(x)**2) + + +def test_issue_4492(): + assert simplify(integrate(x**2 * sqrt(5 - x**2), x)).factor( + deep=True) == Piecewise( + (I*(2*x**5 - 15*x**3 + 25*x - 25*sqrt(x**2 - 5)*acosh(sqrt(5)*x/5)) / + (8*sqrt(x**2 - 5)), (x > sqrt(5)) | (x < -sqrt(5))), + ((2*x**5 - 15*x**3 + 25*x - 25*sqrt(5 - x**2)*asin(sqrt(5)*x/5)) / + (-8*sqrt(-x**2 + 5)), True)) + + +def test_issue_2708(): + # This test needs to use an integration function that can + # not be evaluated in closed form. Update as needed. + f = 1/(a + z + log(z)) + integral_f = NonElementaryIntegral(f, (z, 2, 3)) + assert Integral(f, (z, 2, 3)).doit() == integral_f + assert integrate(f + exp(z), (z, 2, 3)) == integral_f - exp(2) + exp(3) + assert integrate(2*f + exp(z), (z, 2, 3)) == \ + 2*integral_f - exp(2) + exp(3) + assert integrate(exp(1.2*n*s*z*(-t + z)/t), (z, 0, x)) == \ + NonElementaryIntegral(exp(-1.2*n*s*z)*exp(1.2*n*s*z**2/t), + (z, 0, x)) + + +def test_issue_2884(): + f = (4.000002016020*x + 4.000002016020*y + 4.000006024032)*exp(10.0*x) + e = integrate(f, (x, 0.1, 0.2)) + assert str(e) == '1.86831064982608*y + 2.16387491480008' + + +def test_issue_8368i(): + from sympy.functions.elementary.complexes import arg, Abs + assert integrate(exp(-s*x)*cosh(x), (x, 0, oo)) == \ + Piecewise( + ( pi*Piecewise( + ( -s/(pi*(-s**2 + 1)), + Abs(s**2) < 1), + ( 1/(pi*s*(1 - 1/s**2)), + Abs(s**(-2)) < 1), + ( meijerg( + ((S.Half,), (0, 0)), + ((0, S.Half), (0,)), + polar_lift(s)**2), + True) + ), + s**2 > 1 + ), + ( + Integral(exp(-s*x)*cosh(x), (x, 0, oo)), + True)) + assert integrate(exp(-s*x)*sinh(x), (x, 0, oo)) == \ + Piecewise( + ( -1/(s + 1)/2 - 1/(-s + 1)/2, + And( + Abs(s) > 1, + Abs(arg(s)) < pi/2, + Abs(arg(s)) <= pi/2 + )), + ( Integral(exp(-s*x)*sinh(x), (x, 0, oo)), + True)) + + +def test_issue_8901(): + assert integrate(sinh(1.0*x)) == 1.0*cosh(1.0*x) + assert integrate(tanh(1.0*x)) == 1.0*x - 1.0*log(tanh(1.0*x) + 1) + assert integrate(tanh(x)) == x - log(tanh(x) + 1) + + +@slow +def test_issue_8945(): + assert integrate(sin(x)**3/x, (x, 0, 1)) == -Si(3)/4 + 3*Si(1)/4 + assert integrate(sin(x)**3/x, (x, 0, oo)) == pi/4 + assert integrate(cos(x)**2/x**2, x) == -Si(2*x) - cos(2*x)/(2*x) - 1/(2*x) + + +@slow +def test_issue_7130(): + i, L, a, b = symbols('i L a b') + integrand = (cos(pi*i*x/L)**2 / (a + b*x)).rewrite(exp) + assert x not in integrate(integrand, (x, 0, L)).free_symbols + + +def test_issue_10567(): + a, b, c, t = symbols('a b c t') + vt = Matrix([a*t, b, c]) + assert integrate(vt, t) == Integral(vt, t).doit() + assert integrate(vt, t) == Matrix([[a*t**2/2], [b*t], [c*t]]) + + +def test_issue_11742(): + assert integrate(sqrt(-x**2 + 8*x + 48), (x, 4, 12)) == 16*pi + + +def test_issue_11856(): + t = symbols('t') + assert integrate(sinc(pi*t), t) == Si(pi*t)/pi + + +@slow +def test_issue_11876(): + assert integrate(sqrt(log(1/x)), (x, 0, 1)) == sqrt(pi)/2 + + +def test_issue_4950(): + assert integrate((-60*exp(x) - 19.2*exp(4*x))*exp(4*x), x) ==\ + -2.4*exp(8*x) - 12.0*exp(5*x) + + +def test_issue_4968(): + assert integrate(sin(log(x**2))) == x*sin(log(x**2))/5 - 2*x*cos(log(x**2))/5 + + +def test_singularities(): + assert integrate(1/x**2, (x, -oo, oo)) is oo + assert integrate(1/x**2, (x, -1, 1)) is oo + assert integrate(1/(x - 1)**2, (x, -2, 2)) is oo + + assert integrate(1/x**2, (x, 1, -1)) is -oo + assert integrate(1/(x - 1)**2, (x, 2, -2)) is -oo + + +def test_issue_12645(): + x, y = symbols('x y', real=True) + assert (integrate(sin(x*x*x + y*y), + (x, -sqrt(pi - y*y), sqrt(pi - y*y)), + (y, -sqrt(pi), sqrt(pi))) + == Integral(sin(x**3 + y**2), + (x, -sqrt(-y**2 + pi), sqrt(-y**2 + pi)), + (y, -sqrt(pi), sqrt(pi)))) + + +def test_issue_12677(): + assert integrate(sin(x) / (cos(x)**3), (x, 0, pi/6)) == Rational(1, 6) + + +def test_issue_14078(): + assert integrate((cos(3*x)-cos(x))/x, (x, 0, oo)) == -log(3) + + +def test_issue_14064(): + assert integrate(1/cosh(x), (x, 0, oo)) == pi/2 + + +def test_issue_14027(): + assert integrate(1/(1 + exp(x - S.Half)/(1 + exp(x))), x) == \ + x - exp(S.Half)*log(exp(x) + exp(S.Half)/(1 + exp(S.Half)))/(exp(S.Half) + E) + + +def test_issue_8170(): + assert integrate(tan(x), (x, 0, pi/2)) is S.Infinity + + +def test_issue_8440_14040(): + assert integrate(1/x, (x, -1, 1)) is S.NaN + assert integrate(1/(x + 1), (x, -2, 3)) is S.NaN + + +def test_issue_14096(): + assert integrate(1/(x + y)**2, (x, 0, 1)) == -1/(y + 1) + 1/y + assert integrate(1/(1 + x + y + z)**2, (x, 0, 1), (y, 0, 1), (z, 0, 1)) == \ + -4*log(4) - 6*log(2) + 9*log(3) + + +def test_issue_14144(): + assert Abs(integrate(1/sqrt(1 - x**3), (x, 0, 1)).n() - 1.402182) < 1e-6 + assert Abs(integrate(sqrt(1 - x**3), (x, 0, 1)).n() - 0.841309) < 1e-6 + + +def test_issue_14375(): + # This raised a TypeError. The antiderivative has exp_polar, which + # may be possible to unpolarify, so the exact output is not asserted here. + assert integrate(exp(I*x)*log(x), x).has(Ei) + + +def test_issue_14437(): + f = Function('f')(x, y, z) + assert integrate(f, (x, 0, 1), (y, 0, 2), (z, 0, 3)) == \ + Integral(f, (x, 0, 1), (y, 0, 2), (z, 0, 3)) + + +def test_issue_14470(): + assert integrate(1/sqrt(exp(x) + 1), x) == log(sqrt(exp(x) + 1) - 1) - log(sqrt(exp(x) + 1) + 1) + + +def test_issue_14877(): + f = exp(1 - exp(x**2)*x + 2*x**2)*(2*x**3 + x)/(1 - exp(x**2)*x)**2 + assert integrate(f, x) == \ + -exp(2*x**2 - x*exp(x**2) + 1)/(x*exp(3*x**2) - exp(2*x**2)) + + +def test_issue_14782(): + f = sqrt(-x**2 + 1)*(-x**2 + x) + assert integrate(f, [x, -1, 1]) == - pi / 8 + + +@slow +def test_issue_14782_slow(): + f = sqrt(-x**2 + 1)*(-x**2 + x) + assert integrate(f, [x, 0, 1]) == S.One / 3 - pi / 16 + + +def test_issue_12081(): + f = x**(Rational(-3, 2))*exp(-x) + assert integrate(f, [x, 0, oo]) is oo + + +def test_issue_15285(): + y = 1/x - 1 + f = 4*y*exp(-2*y)/x**2 + assert integrate(f, [x, 0, 1]) == 1 + + +def test_issue_15432(): + assert integrate(x**n * exp(-x) * log(x), (x, 0, oo)).gammasimp() == Piecewise( + (gamma(n + 1)*polygamma(0, n) + gamma(n + 1)/n, re(n) + 1 > 0), + (Integral(x**n*exp(-x)*log(x), (x, 0, oo)), True)) + + +def test_issue_15124(): + omega = IndexedBase('omega') + m, p = symbols('m p', cls=Idx) + assert integrate(exp(x*I*(omega[m] + omega[p])), x, conds='none') == \ + -I*exp(I*x*omega[m])*exp(I*x*omega[p])/(omega[m] + omega[p]) + + +def test_issue_15218(): + with warns_deprecated_sympy(): + Integral(Eq(x, y)) + with warns_deprecated_sympy(): + assert Integral(Eq(x, y), x) == Eq(Integral(x, x), Integral(y, x)) + with warns_deprecated_sympy(): + assert Integral(Eq(x, y), x).doit() == Eq(x**2/2, x*y) + with warns(SymPyDeprecationWarning, test_stacklevel=False): + # The warning is made in the ExprWithLimits superclass. The stacklevel + # is correct for integrate(Eq) but not Eq.integrate + assert Eq(x, y).integrate(x) == Eq(x**2/2, x*y) + + # These are not deprecated because they are definite integrals + assert integrate(Eq(x, y), (x, 0, 1)) == Eq(S.Half, y) + assert Eq(x, y).integrate((x, 0, 1)) == Eq(S.Half, y) + + +def test_issue_15292(): + res = integrate(exp(-x**2*cos(2*t)) * cos(x**2*sin(2*t)), (x, 0, oo)) + assert isinstance(res, Piecewise) + assert gammasimp((res - sqrt(pi)/2 * cos(t)).subs(t, pi/6)) == 0 + + +def test_issue_4514(): + assert integrate(sin(2*x)/sin(x), x) == 2*sin(x) + + +def test_issue_15457(): + x, a, b = symbols('x a b', real=True) + definite = integrate(exp(Abs(x-2)), (x, a, b)) + indefinite = integrate(exp(Abs(x-2)), x) + assert definite.subs({a: 1, b: 3}) == -2 + 2*E + assert indefinite.subs(x, 3) - indefinite.subs(x, 1) == -2 + 2*E + assert definite.subs({a: -3, b: -1}) == -exp(3) + exp(5) + assert indefinite.subs(x, -1) - indefinite.subs(x, -3) == -exp(3) + exp(5) + + +def test_issue_15431(): + assert integrate(x*exp(x)*log(x), x) == \ + (x*exp(x) - exp(x))*log(x) - exp(x) + Ei(x) + + +def test_issue_15640_log_substitutions(): + f = x/log(x) + F = Ei(2*log(x)) + assert integrate(f, x) == F and F.diff(x) == f + f = x**3/log(x)**2 + F = -x**4/log(x) + 4*Ei(4*log(x)) + assert integrate(f, x) == F and F.diff(x) == f + f = sqrt(log(x))/x**2 + F = -sqrt(pi)*erfc(sqrt(log(x)))/2 - sqrt(log(x))/x + assert integrate(f, x) == F and F.diff(x) == f + + +def test_issue_15509(): + from sympy.vector import CoordSys3D + N = CoordSys3D('N') + x = N.x + assert integrate(cos(a*x + b), (x, x_1, x_2), heurisch=True) == Piecewise( + (-sin(a*x_1 + b)/a + sin(a*x_2 + b)/a, (a > -oo) & (a < oo) & Ne(a, 0)), \ + (-x_1*cos(b) + x_2*cos(b), True)) + + +def test_issue_4311_fast(): + x = symbols('x', real=True) + assert integrate(x*abs(9-x**2), x) == Piecewise( + (x**4/4 - 9*x**2/2, x <= -3), + (-x**4/4 + 9*x**2/2 - Rational(81, 2), x <= 3), + (x**4/4 - 9*x**2/2, True)) + + +def test_integrate_with_complex_constants(): + K = Symbol('K', positive=True) + x = Symbol('x', real=True) + m = Symbol('m', real=True) + t = Symbol('t', real=True) + assert integrate(exp(-I*K*x**2+m*x), x) == sqrt(pi)*exp(-I*m**2 + /(4*K))*erfi((-2*I*K*x + m)/(2*sqrt(K)*sqrt(-I)))/(2*sqrt(K)*sqrt(-I)) + assert integrate(1/(1 + I*x**2), x) == (-I*(sqrt(-I)*log(x - I*sqrt(-I))/2 + - sqrt(-I)*log(x + I*sqrt(-I))/2)) + assert integrate(exp(-I*x**2), x) == sqrt(pi)*erf(sqrt(I)*x)/(2*sqrt(I)) + + assert integrate((1/(exp(I*t)-2)), t) == -t/2 - I*log(exp(I*t) - 2)/2 + assert integrate((1/(exp(I*t)-2)), (t, 0, 2*pi)) == -pi + + +def test_issue_14241(): + x = Symbol('x') + n = Symbol('n', positive=True, integer=True) + assert integrate(n * x ** (n - 1) / (x + 1), x) == \ + n**2*x**n*lerchphi(x*exp_polar(I*pi), 1, n)*gamma(n)/gamma(n + 1) + + +def test_issue_13112(): + assert integrate(sin(t)**2 / (5 - 4*cos(t)), [t, 0, 2*pi]) == pi / 4 + + +def test_issue_14709b(): + h = Symbol('h', positive=True) + i = integrate(x*acos(1 - 2*x/h), (x, 0, h)) + assert i == 5*h**2*pi/16 + + +def test_issue_8614(): + x = Symbol('x') + t = Symbol('t') + assert integrate(exp(t)/t, (t, -oo, x)) == Ei(x) + assert integrate((exp(-x) - exp(-2*x))/x, (x, 0, oo)) == log(2) + + +@slow +def test_issue_15494(): + s = symbols('s', positive=True) + + integrand = (exp(s/2) - 2*exp(1.6*s) + exp(s))*exp(s) + solution = integrate(integrand, s) + assert solution != S.NaN + # Not sure how to test this properly as it is a symbolic expression with floats + # assert str(solution) == '0.666666666666667*exp(1.5*s) + 0.5*exp(2.0*s) - 0.769230769230769*exp(2.6*s)' + # Maybe + assert abs(solution.subs(s, 1) - (-3.67440080236188)) <= 1e-8 + + integrand = (exp(s/2) - 2*exp(S(8)/5*s) + exp(s))*exp(s) + assert integrate(integrand, s) == -10*exp(13*s/5)/13 + 2*exp(3*s/2)/3 + exp(2*s)/2 + + +def test_li_integral(): + y = Symbol('y') + assert Integral(li(y*x**2), x).doit() == Piecewise((x*li(x**2*y) - \ + x*Ei(3*log(x**2*y)/2)/sqrt(x**2*y), + Ne(y, 0)), (0, True)) + + +def test_issue_17473(): + x = Symbol('x') + n = Symbol('n') + h = S.Half + ans = x**(n + 1)*gamma(h + h/n)*hyper((h + h/n,), + (3*h, 3*h + h/n), -x**(2*n)/4)/(2*n*gamma(3*h + h/n)) + got = integrate(sin(x**n), x) + assert got == ans + _x = Symbol('x', zero=False) + reps = {x: _x} + assert integrate(sin(_x**n), _x) == ans.xreplace(reps).expand() + + +def test_issue_17671(): + assert integrate(log(log(x)) / x**2, [x, 1, oo]) == -EulerGamma + assert integrate(log(log(x)) / x**3, [x, 1, oo]) == -log(2)/2 - EulerGamma/2 + assert integrate(log(log(x)) / x**10, [x, 1, oo]) == -log(9)/9 - EulerGamma/9 + + +def test_issue_2975(): + w = Symbol('w') + C = Symbol('C') + y = Symbol('y') + assert integrate(1/(y**2+C)**(S(3)/2), (y, -w/2, w/2)) == w/(C**(S(3)/2)*sqrt(1 + w**2/(4*C))) + + +def test_issue_7827(): + x, n, M = symbols('x n M') + N = Symbol('N', integer=True) + assert integrate(summation(x*n, (n, 1, N)), x) == x**2*(N**2/4 + N/4) + assert integrate(summation(x*sin(n), (n,1,N)), x) == \ + Sum(x**2*sin(n)/2, (n, 1, N)) + assert integrate(summation(sin(n*x), (n,1,N)), x) == \ + Sum(Piecewise((-cos(n*x)/n, Ne(n, 0)), (0, True)), (n, 1, N)) + assert integrate(integrate(summation(sin(n*x), (n,1,N)), x), x) == \ + Piecewise((Sum(Piecewise((-sin(n*x)/n**2, Ne(n, 0)), (-x/n, True)), + (n, 1, N)), (n > -oo) & (n < oo) & Ne(n, 0)), (0, True)) + assert integrate(Sum(x, (n, 1, M)), x) == M*x**2/2 + raises(ValueError, lambda: integrate(Sum(x, (x, y, n)), y)) + raises(ValueError, lambda: integrate(Sum(x, (x, 1, n)), n)) + raises(ValueError, lambda: integrate(Sum(x, (x, 1, y)), x)) + + +def test_issue_4231(): + f = (1 + 2*x + sqrt(x + log(x))*(1 + 3*x) + x**2)/(x*(x + sqrt(x + log(x)))*sqrt(x + log(x))) + assert integrate(f, x) == 2*sqrt(x + log(x)) + 2*log(x + sqrt(x + log(x))) + + +def test_issue_17841(): + f = diff(1/(x**2+x+I), x) + assert integrate(f, x) == 1/(x**2 + x + I) + + +def test_issue_21034(): + x = Symbol('x', real=True, nonzero=True) + f1 = x*(-x**4/asin(5)**4 - x*sinh(x + log(asin(5))) + 5) + f2 = (x + cosh(cos(4)))/(x*(x + 1/(12*x))) + + assert integrate(f1, x) == \ + -x**6/(6*asin(5)**4) - x**2*cosh(x + log(asin(5))) + 5*x**2/2 + 2*x*sinh(x + log(asin(5))) - 2*cosh(x + log(asin(5))) + + assert integrate(f2, x) == \ + log(x**2 + S(1)/12)/2 + 2*sqrt(3)*cosh(cos(4))*atan(2*sqrt(3)*x) + + +def test_issue_4187(): + assert integrate(log(x)*exp(-x), x) == Ei(-x) - exp(-x)*log(x) + assert integrate(log(x)*exp(-x), (x, 0, oo)) == -EulerGamma + + +def test_issue_5547(): + L = Symbol('L') + z = Symbol('z') + r0 = Symbol('r0') + R0 = Symbol('R0') + + assert integrate(r0**2*cos(z)**2, (z, -L/2, L/2)) == -r0**2*(-L/4 - + sin(L/2)*cos(L/2)/2) + r0**2*(L/4 + sin(L/2)*cos(L/2)/2) + + assert integrate(r0**2*cos(R0*z)**2, (z, -L/2, L/2)) == Piecewise( + (-r0**2*(-L*R0/4 - sin(L*R0/2)*cos(L*R0/2)/2)/R0 + + r0**2*(L*R0/4 + sin(L*R0/2)*cos(L*R0/2)/2)/R0, (R0 > -oo) & (R0 < oo) & Ne(R0, 0)), + (L*r0**2, True)) + + w = 2*pi*z/L + + sol = sqrt(2)*sqrt(L)*r0**2*fresnelc(sqrt(2)*sqrt(L))*gamma(S.One/4)/(16*gamma(S(5)/4)) + L*r0**2/2 + + assert integrate(r0**2*cos(w*z)**2, (z, -L/2, L/2)) == sol + + +def test_issue_15810(): + assert integrate(1/(2**(2*x/3) + 1), (x, 0, oo)) == Rational(3, 2) + + +def test_issue_21024(): + x = Symbol('x', real=True, nonzero=True) + f = log(x)*log(4*x) + log(3*x + exp(2)) + F = x*log(x)**2 + x*log(3*x + exp(2)) + x*(1 - 2*log(2)) + \ + (-2*x + 2*x*log(2))*log(x) + exp(2)*log(3*x + exp(2))/3 + assert F == integrate(f, x) + + f = (x + exp(3))/x**2 + F = log(x) - exp(3)/x + assert F == integrate(f, x) + + f = (x**2 + exp(5))/x + F = x**2/2 + exp(5)*log(x) + assert F == integrate(f, x) + + f = x/(2*x + tanh(1)) + F = x/2 - log(2*x + tanh(1))*tanh(1)/4 + assert F == integrate(f, x) + + f = x - sinh(4)/x + F = x**2/2 - log(x)*sinh(4) + assert F == integrate(f, x) + + f = log(x + exp(5)/x) + F = x*log(x + exp(5)/x) - x + 2*exp(Rational(5, 2))*atan(x*exp(Rational(-5, 2))) + assert F == integrate(f, x) + + f = x**5/(x + E) + F = x**5/5 - E*x**4/4 + x**3*exp(2)/3 - x**2*exp(3)/2 + x*exp(4) - exp(5)*log(x + E) + assert F == integrate(f, x) + + f = 4*x/(x + sinh(5)) + F = 4*x - 4*log(x + sinh(5))*sinh(5) + assert F == integrate(f, x) + + f = x**2/(2*x + sinh(2)) + F = x**2/4 - x*sinh(2)/4 + log(2*x + sinh(2))*sinh(2)**2/8 + assert F == integrate(f, x) + + f = -x**2/(x + E) + F = -x**2/2 + E*x - exp(2)*log(x + E) + assert F == integrate(f, x) + + f = (2*x + 3)*exp(5)/x + F = 2*x*exp(5) + 3*exp(5)*log(x) + assert F == integrate(f, x) + + f = x + 2 + cosh(3)/x + F = x**2/2 + 2*x + log(x)*cosh(3) + assert F == integrate(f, x) + + f = x - tanh(1)/x**3 + F = x**2/2 + tanh(1)/(2*x**2) + assert F == integrate(f, x) + + f = (3*x - exp(6))/x + F = 3*x - exp(6)*log(x) + assert F == integrate(f, x) + + f = x**4/(x + exp(5))**2 + x + F = x**3/3 + x**2*(Rational(1, 2) - exp(5)) + 3*x*exp(10) - 4*exp(15)*log(x + exp(5)) - exp(20)/(x + exp(5)) + assert F == integrate(f, x) + + f = x*(x + exp(10)/x**2) + x + F = x**3/3 + x**2/2 + exp(10)*log(x) + assert F == integrate(f, x) + + f = x + x/(5*x + sinh(3)) + F = x**2/2 + x/5 - log(5*x + sinh(3))*sinh(3)/25 + assert F == integrate(f, x) + + f = (x + exp(3))/(2*x**2 + 2*x) + F = exp(3)*log(x)/2 - exp(3)*log(x + 1)/2 + log(x + 1)/2 + assert F == integrate(f, x).expand() + + f = log(x + 4*sinh(4)) + F = x*log(x + 4*sinh(4)) - x + 4*log(x + 4*sinh(4))*sinh(4) + assert F == integrate(f, x) + + f = -x + 20*(exp(-5) - atan(4)/x)**3*sin(4)/x + F = (-x**2*exp(15)/2 + 20*log(x)*sin(4) - (-180*x**2*exp(5)*sin(4)*atan(4) + 90*x*exp(10)*sin(4)*atan(4)**2 - \ + 20*exp(15)*sin(4)*atan(4)**3)/(3*x**3))*exp(-15) + assert F == integrate(f, x) + + f = 2*x**2*exp(-4) + 6/x + F_true = (2*x**3/3 + 6*exp(4)*log(x))*exp(-4) + assert F_true == integrate(f, x) + + +def test_issue_21721(): + a = Symbol('a') + assert integrate(1/(pi*(1+(x-a)**2)),(x,-oo,oo)).expand() == \ + -Heaviside(im(a) - 1, 0) + Heaviside(im(a) + 1, 0) + + +def test_issue_21831(): + theta = symbols('theta') + assert integrate(cos(3*theta)/(5-4*cos(theta)), (theta, 0, 2*pi)) == pi/12 + integrand = cos(2*theta)/(5 - 4*cos(theta)) + assert integrate(integrand, (theta, 0, 2*pi)) == pi/6 + + +@slow +def test_issue_22033_integral(): + assert integrate((x**2 - Rational(1, 4))**2 * sqrt(1 - x**2), (x, -1, 1)) == pi/32 + + +@slow +def test_issue_21671(): + assert integrate(1,(z,x**2+y**2,2-x**2-y**2),(y,-sqrt(1-x**2),sqrt(1-x**2)),(x,-1,1)) == pi + assert integrate(-4*(1 - x**2)**(S(3)/2)/3 + 2*sqrt(1 - x**2)*(2 - 2*x**2), (x, -1, 1)) == pi + + +def test_issue_18527(): + # The manual integrator can not currently solve this. Assert that it does + # not give an incorrect result involving Abs when x has real assumptions. + xr = symbols('xr', real=True) + expr = (cos(x)/(4+(sin(x))**2)) + res_real = integrate(expr.subs(x, xr), xr, manual=True).subs(xr, x) + assert integrate(expr, x, manual=True) == res_real == Integral(expr, x) + + +def test_issue_23718(): + f = 1/(b*cos(x) + a*sin(x)) + Fpos = (-log(-a/b + tan(x/2) - sqrt(a**2 + b**2)/b)/sqrt(a**2 + b**2) + +log(-a/b + tan(x/2) + sqrt(a**2 + b**2)/b)/sqrt(a**2 + b**2)) + F = Piecewise( + # XXX: The zoo case here is for a=b=0 so it should just be zoo or maybe + # it doesn't really need to be included at all given that the original + # integrand is really undefined in that case anyway. + (zoo*(-log(tan(x/2) - 1) + log(tan(x/2) + 1)), Eq(a, 0) & Eq(b, 0)), + (log(tan(x/2))/a, Eq(b, 0)), + (-I/(-I*b*sin(x) + b*cos(x)), Eq(a, -I*b)), + (I/(I*b*sin(x) + b*cos(x)), Eq(a, I*b)), + (Fpos, True), + ) + assert integrate(f, x) == F + + ap, bp = symbols('a, b', positive=True) + rep = {a: ap, b: bp} + assert integrate(f.subs(rep), x) == Fpos.subs(rep) + + +def test_issue_23566(): + i = integrate(1/sqrt(x**2-1), (x, -2, -1)) + assert i == -log(2 - sqrt(3)) + assert math.isclose(i.n(), 1.31695789692482) + + +def test_pr_23583(): + # This result from meijerg is wrong. Check whether new result is correct when this test fail. + assert integrate(1/sqrt((x - I)**2-1)) == Piecewise((acosh(x - I), Abs((x - I)**2) > 1), (-I*asin(x - I), True)) + + +def test_issue_7264(): + assert integrate(exp(x)*sqrt(1 + exp(2*x))) == sqrt(exp(2*x) + 1)*exp(x)/2 + asinh(exp(x))/2 + + +def test_issue_11254a(): + assert integrate(sech(x), (x, 0, 1)) == 2*atan(tanh(S.Half)) + + +def test_issue_11254b(): + assert integrate(csch(x), x) == log(tanh(x/2)) + assert integrate(csch(x), (x, 0, 1)) == oo + + +def test_issue_11254d(): + # (sech(x)**2).rewrite(sinh) + assert integrate(-1/sinh(x + I*pi/2, evaluate=False)**2, x) == -2/(exp(2*x) + 1) + assert integrate(cosh(x)**(-2), x) == 2*tanh(x/2)/(tanh(x/2)**2 + 1) + + +def test_issue_22863(): + i = integrate((3*x**3-x**2+2*x-4)/sqrt(x**2-3*x+2), (x, 0, 1)) + assert i == -101*sqrt(2)/8 - 135*log(3 - 2*sqrt(2))/16 + assert math.isclose(i.n(), -2.98126694400554) + + +def test_issue_9723(): + assert integrate(sqrt(x + sqrt(x))) == \ + 2*sqrt(sqrt(x) + x)*(sqrt(x)/12 + x/3 - S(1)/8) + log(2*sqrt(x) + 2*sqrt(sqrt(x) + x) + 1)/8 + assert integrate(sqrt(2*x+3+sqrt(4*x+5))**3) == \ + sqrt(2*x + sqrt(4*x + 5) + 3) * \ + (9*x/10 + 11*(4*x + 5)**(S(3)/2)/40 + sqrt(4*x + 5)/40 + (4*x + 5)**2/10 + S(11)/10)/2 + + +def test_issue_23704(): + # XXX: This is testing that an exception is not raised in risch Ideally + # manualintegrate (manual=True) would be able to compute this but + # manualintegrate is very slow for this example so we don't test that here. + assert (integrate(log(x)/x**2/(c*x**2+b*x+a),x, risch=True) + == NonElementaryIntegral(log(x)/(a*x**2 + b*x**3 + c*x**4), x)) + + +def test_exp_substitution(): + assert integrate(1/sqrt(1-exp(2*x))) == log(sqrt(1 - exp(2*x)) - 1)/2 - log(sqrt(1 - exp(2*x)) + 1)/2 + + +def test_hyperbolic(): + assert integrate(coth(x)) == x - log(tanh(x) + 1) + log(tanh(x)) + assert integrate(sech(x)) == 2*atan(tanh(x/2)) + assert integrate(csch(x)) == log(tanh(x/2)) + + +def test_nested_pow(): + assert integrate(sqrt(x**2)) == x*sqrt(x**2)/2 + assert integrate(sqrt(x**(S(5)/3))) == 6*x*sqrt(x**(S(5)/3))/11 + assert integrate(1/sqrt(x**2)) == x*log(x)/sqrt(x**2) + assert integrate(x*sqrt(x**(-4))) == x**2*sqrt(x**-4)*log(x) + + +def test_sqrt_quadratic(): + assert integrate(1/sqrt(3*x**2+4*x+5)) == sqrt(3)*asinh(3*sqrt(11)*(x + S(2)/3)/11)/3 + assert integrate(1/sqrt(-3*x**2+4*x+5)) == sqrt(3)*asin(3*sqrt(19)*(x - S(2)/3)/19)/3 + assert integrate(1/sqrt(3*x**2+4*x-5)) == sqrt(3)*log(6*x + 2*sqrt(3)*sqrt(3*x**2 + 4*x - 5) + 4)/3 + assert integrate(1/sqrt(4*x**2-4*x+1)) == (x - S.Half)*log(x - S.Half)/(2*sqrt((x - S.Half)**2)) + assert integrate(1/sqrt(a+b*x+c*x**2), x) == \ + Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(c, 0) & Ne(a - b**2/(4*c), 0)), + ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), Ne(c, 0)), + (2*sqrt(a + b*x)/b, Ne(b, 0)), (x/sqrt(a), True)) + + assert integrate((7*x+6)/sqrt(3*x**2+4*x+5)) == \ + 7*sqrt(3*x**2 + 4*x + 5)/3 + 4*sqrt(3)*asinh(3*sqrt(11)*(x + S(2)/3)/11)/9 + assert integrate((7*x+6)/sqrt(-3*x**2+4*x+5)) == \ + -7*sqrt(-3*x**2 + 4*x + 5)/3 + 32*sqrt(3)*asin(3*sqrt(19)*(x - S(2)/3)/19)/9 + assert integrate((7*x+6)/sqrt(3*x**2+4*x-5)) == \ + 7*sqrt(3*x**2 + 4*x - 5)/3 + 4*sqrt(3)*log(6*x + 2*sqrt(3)*sqrt(3*x**2 + 4*x - 5) + 4)/9 + assert integrate((d+e*x)/sqrt(a+b*x+c*x**2), x) == \ + Piecewise(((-b*e/(2*c) + d) * + Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(a - b**2/(4*c), 0)), + ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), True)) + + e*sqrt(a + b*x + c*x**2)/c, Ne(c, 0)), + ((2*d*sqrt(a + b*x) + 2*e*(-a*sqrt(a + b*x) + (a + b*x)**(S(3)/2)/3)/b)/b, Ne(b, 0)), + ((d*x + e*x**2/2)/sqrt(a), True)) + + assert integrate((3*x**3-x**2+2*x-4)/sqrt(x**2-3*x+2)) == \ + sqrt(x**2 - 3*x + 2)*(x**2 + 13*x/4 + S(101)/8) + 135*log(2*x + 2*sqrt(x**2 - 3*x + 2) - 3)/16 + + assert integrate(sqrt(53225*x**2-66732*x+23013)) == \ + (x/2 - S(16683)/53225)*sqrt(53225*x**2 - 66732*x + 23013) + \ + 111576969*sqrt(2129)*asinh(53225*x/10563 - S(11122)/3521)/1133160250 + assert integrate(sqrt(a+b*x+c*x**2), x) == \ + Piecewise(((a/2 - b**2/(8*c)) * + Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(a - b**2/(4*c), 0)), + ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), True)) + + (b/(4*c) + x/2)*sqrt(a + b*x + c*x**2), Ne(c, 0)), + (2*(a + b*x)**(S(3)/2)/(3*b), Ne(b, 0)), + (sqrt(a)*x, True)) + + assert integrate(x*sqrt(x**2+2*x+4)) == \ + (x**2/3 + x/6 + S(5)/6)*sqrt(x**2 + 2*x + 4) - 3*asinh(sqrt(3)*(x + 1)/3)/2 + + +def test_mul_pow_derivative(): + assert integrate(x*sec(x)*tan(x)) == x*sec(x) - log(tan(x) + sec(x)) + assert integrate(x*sec(x)**2, x) == x*tan(x) + log(cos(x)) + assert integrate(x**3*Derivative(f(x), (x, 4))) == \ + x**3*Derivative(f(x), (x, 3)) - 3*x**2*Derivative(f(x), (x, 2)) + 6*x*Derivative(f(x), x) - 6*f(x) + + +def test_issue_20782(): + fun1 = Piecewise((0, x < 0.0), (1, True)) + fun2 = -Piecewise((0, x < 1.0), (1, True)) + fun_sum = fun1 + fun2 + L = (x, -float('Inf'), 1) + + assert integrate(fun1, L) == 1 + assert integrate(fun2, L) == 0 + assert integrate(-fun1, L) == -1 + assert integrate(-fun2, L) == 0 + assert integrate(fun_sum, L) == 1. + assert integrate(-fun_sum, L) == -1. + + +def test_issue_20781(): + P = lambda a: Piecewise((0, x < a), (1, x >= a)) + f = lambda a: P(int(a)) + P(float(a)) + L = (x, -float('Inf'), x) + f1 = integrate(f(1), L) + assert f1 == 2*x - Min(1.0, x) - Min(x, Max(1.0, 1, evaluate=False)) + # XXX is_zero is True for S(0) and Float(0) and this is baked into + # the code more deeply than the issue of Float(0) != S(0) + assert integrate(f(0), (x, -float('Inf'), x) + ) == 2*x - 2*Min(0, x) + + +@slow +def test_issue_19427(): + # + x = Symbol("x") + + # Have always been okay: + assert integrate((x ** 4) * sqrt(1 - x ** 2), (x, -1, 1)) == pi / 16 + assert integrate((-2 * x ** 2) * sqrt(1 - x ** 2), (x, -1, 1)) == -pi / 4 + assert integrate((1) * sqrt(1 - x ** 2), (x, -1, 1)) == pi / 2 + + # Sum of the above, used to incorrectly return 0 for a while: + assert integrate((x ** 4 - 2 * x ** 2 + 1) * sqrt(1 - x ** 2), (x, -1, 1)) == 5 * pi / 16 + + +def test_issue_23942(): + I1 = Integral(1/sqrt(a*(1 + x)**3 + (1 + x)**2), (x, 0, z)) + assert I1.series(a, 1, n=1) == Integral(1/sqrt(x**3 + 4*x**2 + 5*x + 2), (x, 0, z)) + O(a - 1, (a, 1)) + I2 = Integral(1/sqrt(a*(4 - x)**4 + (5 + x)**2), (x, 0, z)) + assert I2.series(a, 2, n=1) == Integral(1/sqrt(2*x**4 - 32*x**3 + 193*x**2 - 502*x + 537), (x, 0, z)) + O(a - 2, (a, 2)) + + +def test_issue_25886(): + # https://github.com/sympy/sympy/issues/25886 + f = (1-x)*exp(0.937098661j*x) + F_exp = (1.0*(-1.0671234968289*I*y + + 1.13875255748434 + + 1.0671234968289*I)*exp(0.937098661*I*y) + - 1.13875255748434*exp(0.937098661*I)) + F = integrate(f, (x, y, 1.0)) + assert F.is_same(F_exp, math.isclose) + + +def test_old_issues(): + # https://github.com/sympy/sympy/issues/5212 + I1 = integrate(cos(log(x**2))/x) + assert I1 == sin(log(x**2))/2 + # https://github.com/sympy/sympy/issues/5462 + I2 = integrate(1/(x**2+y**2)**(Rational(3,2)),x) + assert I2 == x/(y**3*sqrt(x**2/y**2 + 1)) + # https://github.com/sympy/sympy/issues/6278 + I3 = integrate(1/(cos(x)+2),(x,0,2*pi)) + assert I3 == 2*sqrt(3)*pi/3 + + +def test_integral_issue_26566(): + # Define the symbols + x = symbols('x', real=True) + a = symbols('a', real=True, positive=True) + + # Define the integral expression + integral_expr = sin(a * (x + pi))**2 + symbolic_result = integrate(integral_expr, (x, -pi, -pi/2)) + + # Known correct result + correct_result = pi / 4 + + # Substitute a specific value for 'a' to evaluate both results + a_value = 1 + numeric_symbolic_result = symbolic_result.subs(a, a_value).evalf() + numeric_correct_result = correct_result.evalf() + + # Assert that the symbolic result matches the correct value + assert simplify(numeric_symbolic_result - numeric_correct_result) == 0 + + +def test_definite_integral_with_floats_issue_27231(): + # Define the symbol and the integral expression + x = symbols('x', real=True) + integral_expr = sqrt(1 - 0.5625 * (x + 0.333333333333333) ** 2) + + # Perform the definite integral with the known limits + result_symbolic = integrate(integral_expr, (x, -1, 1)) + result_numeric = result_symbolic.evalf() + + # Expected result with higher precision + expected_result = sqrt(3) / 6 + 4 * pi / 9 + + # Verify that the result is approximately equal within a larger tolerance + assert abs(result_numeric - expected_result.evalf()) < 1e-8 + + +def test_issue_27374(): + #https://github.com/sympy/sympy/issues/27374 + r = sqrt(x**2 + z**2) + u = erf(a*r/sqrt(2))/r + Ec = diff(u, z, z).subs([(x, sqrt(b*b-z*z))]) + expected_result = -2*sqrt(2)*b*a**3*exp(-b**2*a**2/2)/(3*sqrt(pi)) + assert simplify(integrate(Ec, (z, -b, b))) == expected_result diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_intpoly.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_intpoly.py new file mode 100644 index 0000000000000000000000000000000000000000..ddbaad1fbdeca53ccab8e8b22758a6ad2d89836e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_intpoly.py @@ -0,0 +1,627 @@ +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.miscellaneous import sqrt + +from sympy.core import S, Rational + +from sympy.integrals.intpoly import (decompose, best_origin, distance_to_side, + polytope_integrate, point_sort, + hyperplane_parameters, main_integrate3d, + main_integrate, polygon_integrate, + lineseg_integrate, integration_reduction, + integration_reduction_dynamic, is_vertex) + +from sympy.geometry.line import Segment2D +from sympy.geometry.polygon import Polygon +from sympy.geometry.point import Point, Point2D +from sympy.abc import x, y, z + +from sympy.testing.pytest import slow + + +def test_decompose(): + assert decompose(x) == {1: x} + assert decompose(x**2) == {2: x**2} + assert decompose(x*y) == {2: x*y} + assert decompose(x + y) == {1: x + y} + assert decompose(x**2 + y) == {1: y, 2: x**2} + assert decompose(8*x**2 + 4*y + 7) == {0: 7, 1: 4*y, 2: 8*x**2} + assert decompose(x**2 + 3*y*x) == {2: x**2 + 3*x*y} + assert decompose(9*x**2 + y + 4*x + x**3 + y**2*x + 3) ==\ + {0: 3, 1: 4*x + y, 2: 9*x**2, 3: x**3 + x*y**2} + + assert decompose(x, True) == {x} + assert decompose(x ** 2, True) == {x**2} + assert decompose(x * y, True) == {x * y} + assert decompose(x + y, True) == {x, y} + assert decompose(x ** 2 + y, True) == {y, x ** 2} + assert decompose(8 * x ** 2 + 4 * y + 7, True) == {7, 4*y, 8*x**2} + assert decompose(x ** 2 + 3 * y * x, True) == {x ** 2, 3 * x * y} + assert decompose(9 * x ** 2 + y + 4 * x + x ** 3 + y ** 2 * x + 3, True) == \ + {3, y, 4*x, 9*x**2, x*y**2, x**3} + + +def test_best_origin(): + expr1 = y ** 2 * x ** 5 + y ** 5 * x ** 7 + 7 * x + x ** 12 + y ** 7 * x + + l1 = Segment2D(Point(0, 3), Point(1, 1)) + l2 = Segment2D(Point(S(3) / 2, 0), Point(S(3) / 2, 3)) + l3 = Segment2D(Point(0, S(3) / 2), Point(3, S(3) / 2)) + l4 = Segment2D(Point(0, 2), Point(2, 0)) + l5 = Segment2D(Point(0, 2), Point(1, 1)) + l6 = Segment2D(Point(2, 0), Point(1, 1)) + + assert best_origin((2, 1), 3, l1, expr1) == (0, 3) + # XXX: Should these return exact Rational output? Maybe best_origin should + # sympify its arguments... + assert best_origin((2, 0), 3, l2, x ** 7) == (1.5, 0) + assert best_origin((0, 2), 3, l3, x ** 7) == (0, 1.5) + assert best_origin((1, 1), 2, l4, x ** 7 * y ** 3) == (0, 2) + assert best_origin((1, 1), 2, l4, x ** 3 * y ** 7) == (2, 0) + assert best_origin((1, 1), 2, l5, x ** 2 * y ** 9) == (0, 2) + assert best_origin((1, 1), 2, l6, x ** 9 * y ** 2) == (2, 0) + + +@slow +def test_polytope_integrate(): + # Convex 2-Polytopes + # Vertex representation + assert polytope_integrate(Polygon(Point(0, 0), Point(0, 2), + Point(4, 0)), 1) == 4 + assert polytope_integrate(Polygon(Point(0, 0), Point(0, 1), + Point(1, 1), Point(1, 0)), x * y) ==\ + Rational(1, 4) + assert polytope_integrate(Polygon(Point(0, 3), Point(5, 3), Point(1, 1)), + 6*x**2 - 40*y) == Rational(-935, 3) + + assert polytope_integrate(Polygon(Point(0, 0), Point(0, sqrt(3)), + Point(sqrt(3), sqrt(3)), + Point(sqrt(3), 0)), 1) == 3 + + hexagon = Polygon(Point(0, 0), Point(-sqrt(3) / 2, S.Half), + Point(-sqrt(3) / 2, S(3) / 2), Point(0, 2), + Point(sqrt(3) / 2, S(3) / 2), Point(sqrt(3) / 2, S.Half)) + + assert polytope_integrate(hexagon, 1) == S(3*sqrt(3)) / 2 + + # Hyperplane representation + assert polytope_integrate([((-1, 0), 0), ((1, 2), 4), + ((0, -1), 0)], 1) == 4 + assert polytope_integrate([((-1, 0), 0), ((0, 1), 1), + ((1, 0), 1), ((0, -1), 0)], x * y) == Rational(1, 4) + assert polytope_integrate([((0, 1), 3), ((1, -2), -1), + ((-2, -1), -3)], 6*x**2 - 40*y) == Rational(-935, 3) + assert polytope_integrate([((-1, 0), 0), ((0, sqrt(3)), 3), + ((sqrt(3), 0), 3), ((0, -1), 0)], 1) == 3 + + hexagon = [((Rational(-1, 2), -sqrt(3) / 2), 0), + ((-1, 0), sqrt(3) / 2), + ((Rational(-1, 2), sqrt(3) / 2), sqrt(3)), + ((S.Half, sqrt(3) / 2), sqrt(3)), + ((1, 0), sqrt(3) / 2), + ((S.Half, -sqrt(3) / 2), 0)] + assert polytope_integrate(hexagon, 1) == S(3*sqrt(3)) / 2 + + # Non-convex polytopes + # Vertex representation + assert polytope_integrate(Polygon(Point(-1, -1), Point(-1, 1), + Point(1, 1), Point(0, 0), + Point(1, -1)), 1) == 3 + assert polytope_integrate(Polygon(Point(-1, -1), Point(-1, 1), + Point(0, 0), Point(1, 1), + Point(1, -1), Point(0, 0)), 1) == 2 + # Hyperplane representation + assert polytope_integrate([((-1, 0), 1), ((0, 1), 1), ((1, -1), 0), + ((1, 1), 0), ((0, -1), 1)], 1) == 3 + assert polytope_integrate([((-1, 0), 1), ((1, 1), 0), ((-1, 1), 0), + ((1, 0), 1), ((-1, -1), 0), + ((1, -1), 0)], 1) == 2 + + # Tests for 2D polytopes mentioned in Chin et al(Page 10): + # http://dilbert.engr.ucdavis.edu/~suku/quadrature/cls-integration.pdf + fig1 = Polygon(Point(1.220, -0.827), Point(-1.490, -4.503), + Point(-3.766, -1.622), Point(-4.240, -0.091), + Point(-3.160, 4), Point(-0.981, 4.447), + Point(0.132, 4.027)) + assert polytope_integrate(fig1, x**2 + x*y + y**2) ==\ + S(2031627344735367)/(8*10**12) + + fig2 = Polygon(Point(4.561, 2.317), Point(1.491, -1.315), + Point(-3.310, -3.164), Point(-4.845, -3.110), + Point(-4.569, 1.867)) + assert polytope_integrate(fig2, x**2 + x*y + y**2) ==\ + S(517091313866043)/(16*10**11) + + fig3 = Polygon(Point(-2.740, -1.888), Point(-3.292, 4.233), + Point(-2.723, -0.697), Point(-0.643, -3.151)) + assert polytope_integrate(fig3, x**2 + x*y + y**2) ==\ + S(147449361647041)/(8*10**12) + + fig4 = Polygon(Point(0.211, -4.622), Point(-2.684, 3.851), + Point(0.468, 4.879), Point(4.630, -1.325), + Point(-0.411, -1.044)) + assert polytope_integrate(fig4, x**2 + x*y + y**2) ==\ + S(180742845225803)/(10**12) + + # Tests for many polynomials with maximum degree given(2D case). + tri = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) + polys = [] + expr1 = x**9*y + x**7*y**3 + 2*x**2*y**8 + expr2 = x**6*y**4 + x**5*y**5 + 2*y**10 + expr3 = x**10 + x**9*y + x**8*y**2 + x**5*y**5 + polys.extend((expr1, expr2, expr3)) + result_dict = polytope_integrate(tri, polys, max_degree=10) + assert result_dict[expr1] == Rational(615780107, 594) + assert result_dict[expr2] == Rational(13062161, 27) + assert result_dict[expr3] == Rational(1946257153, 924) + + tri = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) + expr1 = x**7*y**1 + 2*x**2*y**6 + expr2 = x**6*y**4 + x**5*y**5 + 2*y**10 + expr3 = x**10 + x**9*y + x**8*y**2 + x**5*y**5 + polys.extend((expr1, expr2, expr3)) + assert polytope_integrate(tri, polys, max_degree=9) == \ + {x**7*y + 2*x**2*y**6: Rational(489262, 9)} + + # Tests when all integral of all monomials up to a max_degree is to be + # calculated. + assert polytope_integrate(Polygon(Point(0, 0), Point(0, 1), + Point(1, 1), Point(1, 0)), + max_degree=4) == {0: 0, 1: 1, x: S.Half, + x ** 2 * y ** 2: S.One / 9, + x ** 4: S.One / 5, + y ** 4: S.One / 5, + y: S.Half, + x * y ** 2: S.One / 6, + y ** 2: S.One / 3, + x ** 3: S.One / 4, + x ** 2 * y: S.One / 6, + x ** 3 * y: S.One / 8, + x * y: S.One / 4, + y ** 3: S.One / 4, + x ** 2: S.One / 3, + x * y ** 3: S.One / 8} + + # Tests for 3D polytopes + cube1 = [[(0, 0, 0), (0, 6, 6), (6, 6, 6), (3, 6, 0), + (0, 6, 0), (6, 0, 6), (3, 0, 0), (0, 0, 6)], + [1, 2, 3, 4], [3, 2, 5, 6], [1, 7, 5, 2], [0, 6, 5, 7], + [1, 4, 0, 7], [0, 4, 3, 6]] + assert polytope_integrate(cube1, 1) == S(162) + + # 3D Test cases in Chin et al(2015) + cube2 = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0), + (5, 0, 5), (5, 5, 0), (5, 5, 5)], + [3, 7, 6, 2], [1, 5, 7, 3], [5, 4, 6, 7], [0, 4, 5, 1], + [2, 0, 1, 3], [2, 6, 4, 0]] + + cube3 = [[(0, 0, 0), (5, 0, 0), (5, 4, 0), (3, 2, 0), (3, 5, 0), + (0, 5, 0), (0, 0, 5), (5, 0, 5), (5, 4, 5), (3, 2, 5), + (3, 5, 5), (0, 5, 5)], + [6, 11, 5, 0], [1, 7, 6, 0], [5, 4, 3, 2, 1, 0], [11, 10, 4, 5], + [10, 9, 3, 4], [9, 8, 2, 3], [8, 7, 1, 2], [7, 8, 9, 10, 11, 6]] + + cube4 = [[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1), + (S.One / 4, S.One / 4, S.One / 4)], + [0, 2, 1], [1, 3, 0], [4, 2, 3], [4, 3, 1], + [0, 1, 2], [2, 4, 1], [0, 3, 2]] + + assert polytope_integrate(cube2, x ** 2 + y ** 2 + x * y + z ** 2) ==\ + Rational(15625, 4) + assert polytope_integrate(cube3, x ** 2 + y ** 2 + x * y + z ** 2) ==\ + S(33835) / 12 + assert polytope_integrate(cube4, x ** 2 + y ** 2 + x * y + z ** 2) ==\ + S(37) / 960 + + # Test cases from Mathematica's PolyhedronData library + octahedron = [[(S.NegativeOne / sqrt(2), 0, 0), (0, S.One / sqrt(2), 0), + (0, 0, S.NegativeOne / sqrt(2)), (0, 0, S.One / sqrt(2)), + (0, S.NegativeOne / sqrt(2), 0), (S.One / sqrt(2), 0, 0)], + [3, 4, 5], [3, 5, 1], [3, 1, 0], [3, 0, 4], [4, 0, 2], + [4, 2, 5], [2, 0, 1], [5, 2, 1]] + + assert polytope_integrate(octahedron, 1) == sqrt(2) / 3 + + great_stellated_dodecahedron =\ + [[(-0.32491969623290634095, 0, 0.42532540417601993887), + (0.32491969623290634095, 0, -0.42532540417601993887), + (-0.52573111211913359231, 0, 0.10040570794311363956), + (0.52573111211913359231, 0, -0.10040570794311363956), + (-0.10040570794311363956, -0.3090169943749474241, 0.42532540417601993887), + (-0.10040570794311363956, 0.30901699437494742410, 0.42532540417601993887), + (0.10040570794311363956, -0.3090169943749474241, -0.42532540417601993887), + (0.10040570794311363956, 0.30901699437494742410, -0.42532540417601993887), + (-0.16245984811645317047, -0.5, 0.10040570794311363956), + (-0.16245984811645317047, 0.5, 0.10040570794311363956), + (0.16245984811645317047, -0.5, -0.10040570794311363956), + (0.16245984811645317047, 0.5, -0.10040570794311363956), + (-0.42532540417601993887, -0.3090169943749474241, -0.10040570794311363956), + (-0.42532540417601993887, 0.30901699437494742410, -0.10040570794311363956), + (-0.26286555605956679615, 0.1909830056250525759, -0.42532540417601993887), + (-0.26286555605956679615, -0.1909830056250525759, -0.42532540417601993887), + (0.26286555605956679615, 0.1909830056250525759, 0.42532540417601993887), + (0.26286555605956679615, -0.1909830056250525759, 0.42532540417601993887), + (0.42532540417601993887, -0.3090169943749474241, 0.10040570794311363956), + (0.42532540417601993887, 0.30901699437494742410, 0.10040570794311363956)], + [12, 3, 0, 6, 16], [17, 7, 0, 3, 13], + [9, 6, 0, 7, 8], [18, 2, 1, 4, 14], + [15, 5, 1, 2, 19], [11, 4, 1, 5, 10], + [8, 19, 2, 18, 9], [10, 13, 3, 12, 11], + [16, 14, 4, 11, 12], [13, 10, 5, 15, 17], + [14, 16, 6, 9, 18], [19, 8, 7, 17, 15]] + # Actual volume is : 0.163118960624632 + assert Abs(polytope_integrate(great_stellated_dodecahedron, 1) -\ + 0.163118960624632) < 1e-12 + + expr = x **2 + y ** 2 + z ** 2 + octahedron_five_compound = [[(0, -0.7071067811865475244, 0), + (0, 0.70710678118654752440, 0), + (0.1148764602736805918, + -0.35355339059327376220, -0.60150095500754567366), + (0.1148764602736805918, 0.35355339059327376220, + -0.60150095500754567366), + (0.18587401723009224507, + -0.57206140281768429760, 0.37174803446018449013), + (0.18587401723009224507, 0.57206140281768429760, + 0.37174803446018449013), + (0.30075047750377283683, -0.21850801222441053540, + 0.60150095500754567366), + (0.30075047750377283683, 0.21850801222441053540, + 0.60150095500754567366), + (0.48662449473386508189, -0.35355339059327376220, + -0.37174803446018449013), + (0.48662449473386508189, 0.35355339059327376220, + -0.37174803446018449013), + (-0.60150095500754567366, 0, -0.37174803446018449013), + (-0.30075047750377283683, -0.21850801222441053540, + -0.60150095500754567366), + (-0.30075047750377283683, 0.21850801222441053540, + -0.60150095500754567366), + (0.60150095500754567366, 0, 0.37174803446018449013), + (0.4156269377774534286, -0.57206140281768429760, 0), + (0.4156269377774534286, 0.57206140281768429760, 0), + (0.37174803446018449013, 0, -0.60150095500754567366), + (-0.4156269377774534286, -0.57206140281768429760, 0), + (-0.4156269377774534286, 0.57206140281768429760, 0), + (-0.67249851196395732696, -0.21850801222441053540, 0), + (-0.67249851196395732696, 0.21850801222441053540, 0), + (0.67249851196395732696, -0.21850801222441053540, 0), + (0.67249851196395732696, 0.21850801222441053540, 0), + (-0.37174803446018449013, 0, 0.60150095500754567366), + (-0.48662449473386508189, -0.35355339059327376220, + 0.37174803446018449013), + (-0.48662449473386508189, 0.35355339059327376220, + 0.37174803446018449013), + (-0.18587401723009224507, -0.57206140281768429760, + -0.37174803446018449013), + (-0.18587401723009224507, 0.57206140281768429760, + -0.37174803446018449013), + (-0.11487646027368059176, -0.35355339059327376220, + 0.60150095500754567366), + (-0.11487646027368059176, 0.35355339059327376220, + 0.60150095500754567366)], + [0, 10, 16], [23, 10, 0], [16, 13, 0], + [0, 13, 23], [16, 10, 1], [1, 10, 23], + [1, 13, 16], [23, 13, 1], [2, 4, 19], + [22, 4, 2], [2, 19, 27], [27, 22, 2], + [20, 5, 3], [3, 5, 21], [26, 20, 3], + [3, 21, 26], [29, 19, 4], [4, 22, 29], + [5, 20, 28], [28, 21, 5], [6, 8, 15], + [17, 8, 6], [6, 15, 25], [25, 17, 6], + [14, 9, 7], [7, 9, 18], [24, 14, 7], + [7, 18, 24], [8, 12, 15], [17, 12, 8], + [14, 11, 9], [9, 11, 18], [11, 14, 24], + [24, 18, 11], [25, 15, 12], [12, 17, 25], + [29, 27, 19], [20, 26, 28], [28, 26, 21], + [22, 27, 29]] + assert Abs(polytope_integrate(octahedron_five_compound, expr)) - 0.353553\ + < 1e-6 + + cube_five_compound = [[(-0.1624598481164531631, -0.5, -0.6881909602355867691), + (-0.1624598481164531631, 0.5, -0.6881909602355867691), + (0.1624598481164531631, -0.5, 0.68819096023558676910), + (0.1624598481164531631, 0.5, 0.68819096023558676910), + (-0.52573111211913359231, 0, -0.6881909602355867691), + (0.52573111211913359231, 0, 0.68819096023558676910), + (-0.26286555605956679615, -0.8090169943749474241, + -0.1624598481164531631), + (-0.26286555605956679615, 0.8090169943749474241, + -0.1624598481164531631), + (0.26286555605956680301, -0.8090169943749474241, + 0.1624598481164531631), + (0.26286555605956680301, 0.8090169943749474241, + 0.1624598481164531631), + (-0.42532540417601993887, -0.3090169943749474241, + 0.68819096023558676910), + (-0.42532540417601993887, 0.30901699437494742410, + 0.68819096023558676910), + (0.42532540417601996609, -0.3090169943749474241, + -0.6881909602355867691), + (0.42532540417601996609, 0.30901699437494742410, + -0.6881909602355867691), + (-0.6881909602355867691, -0.5, 0.1624598481164531631), + (-0.6881909602355867691, 0.5, 0.1624598481164531631), + (0.68819096023558676910, -0.5, -0.1624598481164531631), + (0.68819096023558676910, 0.5, -0.1624598481164531631), + (-0.85065080835203998877, 0, -0.1624598481164531631), + (0.85065080835203993218, 0, 0.1624598481164531631)], + [18, 10, 3, 7], [13, 19, 8, 0], [18, 0, 8, 10], + [3, 19, 13, 7], [18, 7, 13, 0], [8, 19, 3, 10], + [6, 2, 11, 18], [1, 9, 19, 12], [11, 9, 1, 18], + [6, 12, 19, 2], [1, 12, 6, 18], [11, 2, 19, 9], + [4, 14, 11, 7], [17, 5, 8, 12], [4, 12, 8, 14], + [11, 5, 17, 7], [4, 7, 17, 12], [8, 5, 11, 14], + [6, 10, 15, 4], [13, 9, 5, 16], [15, 9, 13, 4], + [6, 16, 5, 10], [13, 16, 6, 4], [15, 10, 5, 9], + [14, 15, 1, 0], [16, 17, 3, 2], [14, 2, 3, 15], + [1, 17, 16, 0], [14, 0, 16, 2], [3, 17, 1, 15]] + assert Abs(polytope_integrate(cube_five_compound, expr) - 1.25) < 1e-12 + + echidnahedron = [[(0, 0, -2.4898982848827801995), + (0, 0, 2.4898982848827802734), + (0, -4.2360679774997896964, -2.4898982848827801995), + (0, -4.2360679774997896964, 2.4898982848827802734), + (0, 4.2360679774997896964, -2.4898982848827801995), + (0, 4.2360679774997896964, 2.4898982848827802734), + (-4.0287400534704067567, -1.3090169943749474241, -2.4898982848827801995), + (-4.0287400534704067567, -1.3090169943749474241, 2.4898982848827802734), + (-4.0287400534704067567, 1.3090169943749474241, -2.4898982848827801995), + (-4.0287400534704067567, 1.3090169943749474241, 2.4898982848827802734), + (4.0287400534704069747, -1.3090169943749474241, -2.4898982848827801995), + (4.0287400534704069747, -1.3090169943749474241, 2.4898982848827802734), + (4.0287400534704069747, 1.3090169943749474241, -2.4898982848827801995), + (4.0287400534704069747, 1.3090169943749474241, 2.4898982848827802734), + (-2.4898982848827801995, -3.4270509831248422723, -2.4898982848827801995), + (-2.4898982848827801995, -3.4270509831248422723, 2.4898982848827802734), + (-2.4898982848827801995, 3.4270509831248422723, -2.4898982848827801995), + (-2.4898982848827801995, 3.4270509831248422723, 2.4898982848827802734), + (2.4898982848827802734, -3.4270509831248422723, -2.4898982848827801995), + (2.4898982848827802734, -3.4270509831248422723, 2.4898982848827802734), + (2.4898982848827802734, 3.4270509831248422723, -2.4898982848827801995), + (2.4898982848827802734, 3.4270509831248422723, 2.4898982848827802734), + (-4.7169310137059934362, -0.8090169943749474241, -1.1135163644116066184), + (-4.7169310137059934362, 0.8090169943749474241, -1.1135163644116066184), + (4.7169310137059937438, -0.8090169943749474241, 1.11351636441160673519), + (4.7169310137059937438, 0.8090169943749474241, 1.11351636441160673519), + (-4.2916056095299737777, -2.1180339887498948482, 1.11351636441160673519), + (-4.2916056095299737777, 2.1180339887498948482, 1.11351636441160673519), + (4.2916056095299737777, -2.1180339887498948482, -1.1135163644116066184), + (4.2916056095299737777, 2.1180339887498948482, -1.1135163644116066184), + (-3.6034146492943870399, 0, -3.3405490932348205213), + (3.6034146492943870399, 0, 3.3405490932348202056), + (-3.3405490932348205213, -3.4270509831248422723, 1.11351636441160673519), + (-3.3405490932348205213, 3.4270509831248422723, 1.11351636441160673519), + (3.3405490932348202056, -3.4270509831248422723, -1.1135163644116066184), + (3.3405490932348202056, 3.4270509831248422723, -1.1135163644116066184), + (-2.9152236890588002395, -2.1180339887498948482, 3.3405490932348202056), + (-2.9152236890588002395, 2.1180339887498948482, 3.3405490932348202056), + (2.9152236890588002395, -2.1180339887498948482, -3.3405490932348205213), + (2.9152236890588002395, 2.1180339887498948482, -3.3405490932348205213), + (-2.2270327288232132368, 0, -1.1135163644116066184), + (-2.2270327288232132368, -4.2360679774997896964, -1.1135163644116066184), + (-2.2270327288232132368, 4.2360679774997896964, -1.1135163644116066184), + (2.2270327288232134704, 0, 1.11351636441160673519), + (2.2270327288232134704, -4.2360679774997896964, 1.11351636441160673519), + (2.2270327288232134704, 4.2360679774997896964, 1.11351636441160673519), + (-1.8017073246471935200, -1.3090169943749474241, 1.11351636441160673519), + (-1.8017073246471935200, 1.3090169943749474241, 1.11351636441160673519), + (1.8017073246471935043, -1.3090169943749474241, -1.1135163644116066184), + (1.8017073246471935043, 1.3090169943749474241, -1.1135163644116066184), + (-1.3763819204711735382, 0, -4.7169310137059934362), + (-1.3763819204711735382, 0, 0.26286555605956679615), + (1.37638192047117353821, 0, 4.7169310137059937438), + (1.37638192047117353821, 0, -0.26286555605956679615), + (-1.1135163644116066184, -3.4270509831248422723, -3.3405490932348205213), + (-1.1135163644116066184, -0.8090169943749474241, 4.7169310137059937438), + (-1.1135163644116066184, -0.8090169943749474241, -0.26286555605956679615), + (-1.1135163644116066184, 0.8090169943749474241, 4.7169310137059937438), + (-1.1135163644116066184, 0.8090169943749474241, -0.26286555605956679615), + (-1.1135163644116066184, 3.4270509831248422723, -3.3405490932348205213), + (1.11351636441160673519, -3.4270509831248422723, 3.3405490932348202056), + (1.11351636441160673519, -0.8090169943749474241, -4.7169310137059934362), + (1.11351636441160673519, -0.8090169943749474241, 0.26286555605956679615), + (1.11351636441160673519, 0.8090169943749474241, -4.7169310137059934362), + (1.11351636441160673519, 0.8090169943749474241, 0.26286555605956679615), + (1.11351636441160673519, 3.4270509831248422723, 3.3405490932348202056), + (-0.85065080835203998877, 0, 1.11351636441160673519), + (0.85065080835203993218, 0, -1.1135163644116066184), + (-0.6881909602355867691, -0.5, -1.1135163644116066184), + (-0.6881909602355867691, 0.5, -1.1135163644116066184), + (-0.6881909602355867691, -4.7360679774997896964, -1.1135163644116066184), + (-0.6881909602355867691, -2.1180339887498948482, -1.1135163644116066184), + (-0.6881909602355867691, 2.1180339887498948482, -1.1135163644116066184), + (-0.6881909602355867691, 4.7360679774997896964, -1.1135163644116066184), + (0.68819096023558676910, -0.5, 1.11351636441160673519), + (0.68819096023558676910, 0.5, 1.11351636441160673519), + (0.68819096023558676910, -4.7360679774997896964, 1.11351636441160673519), + (0.68819096023558676910, -2.1180339887498948482, 1.11351636441160673519), + (0.68819096023558676910, 2.1180339887498948482, 1.11351636441160673519), + (0.68819096023558676910, 4.7360679774997896964, 1.11351636441160673519), + (-0.42532540417601993887, -1.3090169943749474241, -4.7169310137059934362), + (-0.42532540417601993887, -1.3090169943749474241, 0.26286555605956679615), + (-0.42532540417601993887, 1.3090169943749474241, -4.7169310137059934362), + (-0.42532540417601993887, 1.3090169943749474241, 0.26286555605956679615), + (-0.26286555605956679615, -0.8090169943749474241, 1.11351636441160673519), + (-0.26286555605956679615, 0.8090169943749474241, 1.11351636441160673519), + (0.26286555605956679615, -0.8090169943749474241, -1.1135163644116066184), + (0.26286555605956679615, 0.8090169943749474241, -1.1135163644116066184), + (0.42532540417601996609, -1.3090169943749474241, 4.7169310137059937438), + (0.42532540417601996609, -1.3090169943749474241, -0.26286555605956679615), + (0.42532540417601996609, 1.3090169943749474241, 4.7169310137059937438), + (0.42532540417601996609, 1.3090169943749474241, -0.26286555605956679615)], + [9, 66, 47], [44, 62, 77], [20, 91, 49], [33, 47, 83], + [3, 77, 84], [12, 49, 53], [36, 84, 66], [28, 53, 62], + [73, 83, 91], [15, 84, 46], [25, 64, 43], [16, 58, 72], + [26, 46, 51], [11, 43, 74], [4, 72, 91], [60, 74, 84], + [35, 91, 64], [23, 51, 58], [19, 74, 77], [79, 83, 78], + [6, 56, 40], [76, 77, 81], [21, 78, 75], [8, 40, 58], + [31, 75, 74], [42, 58, 83], [41, 81, 56], [13, 75, 43], + [27, 51, 47], [2, 89, 71], [24, 43, 62], [17, 47, 85], + [14, 71, 56], [65, 85, 75], [22, 56, 51], [34, 62, 89], + [5, 85, 78], [32, 81, 46], [10, 53, 48], [45, 78, 64], + [7, 46, 66], [18, 48, 89], [37, 66, 85], [70, 89, 81], + [29, 64, 53], [88, 74, 1], [38, 67, 48], [42, 83, 72], + [57, 1, 85], [34, 48, 62], [59, 72, 87], [19, 62, 74], + [63, 87, 67], [17, 85, 83], [52, 75, 1], [39, 87, 49], + [22, 51, 40], [55, 1, 66], [29, 49, 64], [30, 40, 69], + [13, 64, 75], [82, 69, 87], [7, 66, 51], [90, 85, 1], + [59, 69, 72], [70, 81, 71], [88, 1, 84], [73, 72, 83], + [54, 71, 68], [5, 83, 85], [50, 68, 69], [3, 84, 81], + [57, 66, 1], [30, 68, 40], [28, 62, 48], [52, 1, 74], + [23, 40, 51], [38, 48, 86], [9, 51, 66], [80, 86, 68], + [11, 74, 62], [55, 84, 1], [54, 86, 71], [35, 64, 49], + [90, 1, 75], [41, 71, 81], [39, 49, 67], [15, 81, 84], + [61, 67, 86], [21, 75, 64], [24, 53, 43], [50, 69, 0], + [37, 85, 47], [31, 43, 75], [61, 0, 67], [27, 47, 58], + [10, 67, 53], [8, 58, 69], [90, 75, 85], [45, 91, 78], + [80, 68, 0], [36, 66, 46], [65, 78, 85], [63, 0, 87], + [32, 46, 56], [20, 87, 91], [14, 56, 68], [57, 85, 66], + [33, 58, 47], [61, 86, 0], [60, 84, 77], [37, 47, 66], + [82, 0, 69], [44, 77, 89], [16, 69, 58], [18, 89, 86], + [55, 66, 84], [26, 56, 46], [63, 67, 0], [31, 74, 43], + [36, 46, 84], [50, 0, 68], [25, 43, 53], [6, 68, 56], + [12, 53, 67], [88, 84, 74], [76, 89, 77], [82, 87, 0], + [65, 75, 78], [60, 77, 74], [80, 0, 86], [79, 78, 91], + [2, 86, 89], [4, 91, 87], [52, 74, 75], [21, 64, 78], + [18, 86, 48], [23, 58, 40], [5, 78, 83], [28, 48, 53], + [6, 40, 68], [25, 53, 64], [54, 68, 86], [33, 83, 58], + [17, 83, 47], [12, 67, 49], [41, 56, 71], [9, 47, 51], + [35, 49, 91], [2, 71, 86], [79, 91, 83], [38, 86, 67], + [26, 51, 56], [7, 51, 46], [4, 87, 72], [34, 89, 48], + [15, 46, 81], [42, 72, 58], [10, 48, 67], [27, 58, 51], + [39, 67, 87], [76, 81, 89], [3, 81, 77], [8, 69, 40], + [29, 53, 49], [19, 77, 62], [22, 40, 56], [20, 49, 87], + [32, 56, 81], [59, 87, 69], [24, 62, 53], [11, 62, 43], + [14, 68, 71], [73, 91, 72], [13, 43, 64], [70, 71, 89], + [16, 72, 69], [44, 89, 62], [30, 69, 68], [45, 64, 91]] + # Actual volume is : 51.405764746872634 + assert Abs(polytope_integrate(echidnahedron, 1) - 51.4057647468726) < 1e-12 + assert Abs(polytope_integrate(echidnahedron, expr) - 253.569603474519) <\ + 1e-12 + + # Tests for many polynomials with maximum degree given(2D case). + assert polytope_integrate(cube2, [x**2, y*z], max_degree=2) == \ + {y * z: 3125 / S(4), x ** 2: 3125 / S(3)} + + assert polytope_integrate(cube2, max_degree=2) == \ + {1: 125, x: 625 / S(2), x * z: 3125 / S(4), y: 625 / S(2), + y * z: 3125 / S(4), z ** 2: 3125 / S(3), y ** 2: 3125 / S(3), + z: 625 / S(2), x * y: 3125 / S(4), x ** 2: 3125 / S(3)} + +def test_point_sort(): + assert point_sort([Point(0, 0), Point(1, 0), Point(1, 1)]) == \ + [Point2D(1, 1), Point2D(1, 0), Point2D(0, 0)] + + fig6 = Polygon((0, 0), (1, 0), (1, 1)) + assert polytope_integrate(fig6, x*y) == Rational(-1, 8) + assert polytope_integrate(fig6, x*y, clockwise = True) == Rational(1, 8) + + +def test_polytopes_intersecting_sides(): + fig5 = Polygon(Point(-4.165, -0.832), Point(-3.668, 1.568), + Point(-3.266, 1.279), Point(-1.090, -2.080), + Point(3.313, -0.683), Point(3.033, -4.845), + Point(-4.395, 4.840), Point(-1.007, -3.328)) + assert polytope_integrate(fig5, x**2 + x*y + y**2) ==\ + S(1633405224899363)/(24*10**12) + + fig6 = Polygon(Point(-3.018, -4.473), Point(-0.103, 2.378), + Point(-1.605, -2.308), Point(4.516, -0.771), + Point(4.203, 0.478)) + assert polytope_integrate(fig6, x**2 + x*y + y**2) ==\ + S(88161333955921)/(3*10**12) + + +def test_max_degree(): + polygon = Polygon((0, 0), (0, 1), (1, 1), (1, 0)) + polys = [1, x, y, x*y, x**2*y, x*y**2] + assert polytope_integrate(polygon, polys, max_degree=3) == \ + {1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4), x**2*y: Rational(1, 6), x*y**2: Rational(1, 6)} + assert polytope_integrate(polygon, polys, max_degree=2) == \ + {1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4)} + assert polytope_integrate(polygon, polys, max_degree=1) == \ + {1: 1, x: S.Half, y: S.Half} + + +def test_main_integrate3d(): + cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ + (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ + [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ + [3, 1, 0, 2], [0, 4, 6, 2]] + vertices = cube[0] + faces = cube[1:] + hp_params = hyperplane_parameters(faces, vertices) + assert main_integrate3d(1, faces, vertices, hp_params) == -125 + assert main_integrate3d(1, faces, vertices, hp_params, max_degree=1) == \ + {1: -125, y: Rational(-625, 2), z: Rational(-625, 2), x: Rational(-625, 2)} + + +def test_main_integrate(): + triangle = Polygon((0, 3), (5, 3), (1, 1)) + facets = triangle.sides + hp_params = hyperplane_parameters(triangle) + assert main_integrate(x**2 + y**2, facets, hp_params) == Rational(325, 6) + assert main_integrate(x**2 + y**2, facets, hp_params, max_degree=1) == \ + {0: 0, 1: 5, y: Rational(35, 3), x: 10} + + +def test_polygon_integrate(): + cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ + (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ + [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ + [3, 1, 0, 2], [0, 4, 6, 2]] + facet = cube[1] + facets = cube[1:] + vertices = cube[0] + assert polygon_integrate(facet, [(0, 1, 0), 5], 0, facets, vertices, 1, 0) == -25 + + +def test_distance_to_side(): + point = (0, 0, 0) + assert distance_to_side(point, [(0, 0, 1), (0, 1, 0)], (1, 0, 0)) == -sqrt(2)/2 + + +def test_lineseg_integrate(): + polygon = [(0, 5, 0), (5, 5, 0), (5, 5, 5), (0, 5, 5)] + line_seg = [(0, 5, 0), (5, 5, 0)] + assert lineseg_integrate(polygon, 0, line_seg, 1, 0) == 5 + assert lineseg_integrate(polygon, 0, line_seg, 0, 0) == 0 + + +def test_integration_reduction(): + triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) + facets = triangle.sides + a, b = hyperplane_parameters(triangle)[0] + assert integration_reduction(facets, 0, a, b, 1, (x, y), 0) == 5 + assert integration_reduction(facets, 0, a, b, 0, (x, y), 0) == 0 + + +def test_integration_reduction_dynamic(): + triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) + facets = triangle.sides + a, b = hyperplane_parameters(triangle)[0] + x0 = facets[0].points[0] + monomial_values = [[0, 0, 0, 0], [1, 0, 0, 5],\ + [y, 0, 1, 15], [x, 1, 0, None]] + + assert integration_reduction_dynamic(facets, 0, a, b, x, 1, (x, y), 1,\ + 0, 1, x0, monomial_values, 3) == Rational(25, 2) + assert integration_reduction_dynamic(facets, 0, a, b, 0, 1, (x, y), 1,\ + 0, 1, x0, monomial_values, 3) == 0 + + +def test_is_vertex(): + assert is_vertex(2) is False + assert is_vertex((2, 3)) is True + assert is_vertex(Point(2, 3)) is True + assert is_vertex((2, 3, 4)) is True + assert is_vertex((2, 3, 4, 5)) is False + + +def test_issue_19234(): + polygon = Polygon(Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0)) + polys = [ 1, x, y, x*y, x**2*y, x*y**2] + assert polytope_integrate(polygon, polys) == \ + {1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4), x**2*y: Rational(1, 6), x*y**2: Rational(1, 6)} + polys = [ 1, x, y, x*y, 3 + x**2*y, x + x*y**2] + assert polytope_integrate(polygon, polys) == \ + {1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4), x**2*y + 3: Rational(19, 6), x*y**2 + x: Rational(2, 3)} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_laplace.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_laplace.py new file mode 100644 index 0000000000000000000000000000000000000000..cb7222d01e3dcb3e14e8d0564610ab553e637155 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_laplace.py @@ -0,0 +1,774 @@ +from sympy.integrals.laplace import ( + laplace_transform, inverse_laplace_transform, + LaplaceTransform, InverseLaplaceTransform, + _laplace_deep_collect, laplace_correspondence, + laplace_initial_conds) +from sympy.core.function import Function, expand_mul +from sympy.core import EulerGamma, Subs, Derivative, diff +from sympy.core.exprtools import factor_terms +from sympy.core.numbers import I, oo, pi +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import Symbol, symbols +from sympy.simplify.simplify import simplify +from sympy.functions.elementary.complexes import Abs, re +from sympy.functions.elementary.exponential import exp, log, exp_polar +from sympy.functions.elementary.hyperbolic import cosh, sinh, coth, asinh +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import atan, cos, sin +from sympy.logic.boolalg import And +from sympy.functions.special.gamma_functions import ( + lowergamma, gamma, uppergamma) +from sympy.functions.special.delta_functions import DiracDelta, Heaviside +from sympy.functions.special.singularity_functions import SingularityFunction +from sympy.functions.special.zeta_functions import lerchphi +from sympy.functions.special.error_functions import ( + fresnelc, fresnels, erf, erfc, Ei, Ci, expint, E1) +from sympy.functions.special.bessel import besseli, besselj, besselk, bessely +from sympy.testing.pytest import slow, warns_deprecated_sympy +from sympy.matrices import Matrix, eye +from sympy.abc import s + + +@slow +def test_laplace_transform(): + LT = laplace_transform + ILT = inverse_laplace_transform + a, b, c = symbols('a, b, c', positive=True) + np = symbols('np', integer=True, positive=True) + t, w, x = symbols('t, w, x') + f = Function('f') + F = Function('F') + g = Function('g') + y = Function('y') + Y = Function('Y') + + # Test helper functions + assert ( + _laplace_deep_collect(exp((t+a)*(t+b)) + + besselj(2, exp((t+a)*(t+b)-t**2)), t) == + exp(a*b + t**2 + t*(a + b)) + besselj(2, exp(a*b + t*(a + b)))) + L = laplace_transform(diff(y(t), t, 3), t, s, noconds=True) + L = laplace_correspondence(L, {y: Y}) + L = laplace_initial_conds(L, t, {y: [2, 4, 8, 16, 32]}) + assert L == s**3*Y(s) - 2*s**2 - 4*s - 8 + # Test whether `noconds=True` in `doit`: + assert (2*LaplaceTransform(exp(t), t, s) - 1).doit() == -1 + 2/(s - 1) + assert (LT(a*t+t**2+t**(S(5)/2), t, s) == + (a/s**2 + 2/s**3 + 15*sqrt(pi)/(8*s**(S(7)/2)), 0, True)) + assert LT(b/(t+a), t, s) == (-b*exp(-a*s)*Ei(-a*s), 0, True) + assert (LT(1/sqrt(t+a), t, s) == + (sqrt(pi)*sqrt(1/s)*exp(a*s)*erfc(sqrt(a)*sqrt(s)), 0, True)) + assert (LT(sqrt(t)/(t+a), t, s) == + (-pi*sqrt(a)*exp(a*s)*erfc(sqrt(a)*sqrt(s)) + sqrt(pi)*sqrt(1/s), + 0, True)) + assert (LT((t+a)**(-S(3)/2), t, s) == + (-2*sqrt(pi)*sqrt(s)*exp(a*s)*erfc(sqrt(a)*sqrt(s)) + 2/sqrt(a), + 0, True)) + assert (LT(t**(S(1)/2)*(t+a)**(-1), t, s) == + (-pi*sqrt(a)*exp(a*s)*erfc(sqrt(a)*sqrt(s)) + sqrt(pi)*sqrt(1/s), + 0, True)) + assert (LT(1/(a*sqrt(t) + t**(3/2)), t, s) == + (pi*sqrt(a)*exp(a*s)*erfc(sqrt(a)*sqrt(s)), 0, True)) + assert (LT((t+a)**b, t, s) == + (s**(-b - 1)*exp(-a*s)*uppergamma(b + 1, a*s), 0, True)) + assert LT(t**5/(t+a), t, s) == (120*a**5*uppergamma(-5, a*s), 0, True) + assert LT(exp(t), t, s) == (1/(s - 1), 1, True) + assert LT(exp(2*t), t, s) == (1/(s - 2), 2, True) + assert LT(exp(a*t), t, s) == (1/(s - a), a, True) + assert LT(exp(a*(t-b)), t, s) == (exp(-a*b)/(-a + s), a, True) + assert LT(t*exp(-a*(t)), t, s) == ((a + s)**(-2), -a, True) + assert LT(t*exp(-a*(t-b)), t, s) == (exp(a*b)/(a + s)**2, -a, True) + assert LT(b*t*exp(-a*t), t, s) == (b/(a + s)**2, -a, True) + assert LT(exp(-a*exp(-t)), t, s) == (lowergamma(s, a)/a**s, 0, True) + assert LT(exp(-a*exp(t)), t, s) == (a**s*uppergamma(-s, a), 0, True) + assert (LT(t**(S(7)/4)*exp(-8*t)/gamma(S(11)/4), t, s) == + ((s + 8)**(-S(11)/4), -8, True)) + assert (LT(t**(S(3)/2)*exp(-8*t), t, s) == + (3*sqrt(pi)/(4*(s + 8)**(S(5)/2)), -8, True)) + assert LT(t**a*exp(-a*t), t, s) == ((a+s)**(-a-1)*gamma(a+1), -a, True) + assert (LT(b*exp(-a*t**2), t, s) == + (sqrt(pi)*b*exp(s**2/(4*a))*erfc(s/(2*sqrt(a)))/(2*sqrt(a)), + 0, True)) + assert (LT(exp(-2*t**2), t, s) == + (sqrt(2)*sqrt(pi)*exp(s**2/8)*erfc(sqrt(2)*s/4)/4, 0, True)) + assert (LT(b*exp(2*t**2), t, s) == + (b*LaplaceTransform(exp(2*t**2), t, s), -oo, True)) + assert (LT(t*exp(-a*t**2), t, s) == + (1/(2*a) - s*erfc(s/(2*sqrt(a)))/(4*sqrt(pi)*a**(S(3)/2)), + 0, True)) + assert (LT(exp(-a/t), t, s) == + (2*sqrt(a)*sqrt(1/s)*besselk(1, 2*sqrt(a)*sqrt(s)), 0, True)) + assert LT(sqrt(t)*exp(-a/t), t, s, simplify=True) == ( + sqrt(pi)*(sqrt(a)*sqrt(s) + 1/S(2))*sqrt(s**(-3)) * + exp(-2*sqrt(a)*sqrt(s)), 0, True) + assert (LT(exp(-a/t)/sqrt(t), t, s) == + (sqrt(pi)*sqrt(1/s)*exp(-2*sqrt(a)*sqrt(s)), 0, True)) + assert (LT(exp(-a/t)/(t*sqrt(t)), t, s) == + (sqrt(pi)*sqrt(1/a)*exp(-2*sqrt(a)*sqrt(s)), 0, True)) + # TODO: rules with sqrt(a*t) and sqrt(a/t) have stopped working after + # changes to as_base_exp + # assert ( + # LT(exp(-2*sqrt(a*t)), t, s) == + # (1/s - sqrt(pi)*sqrt(a) * exp(a/s)*erfc(sqrt(a)*sqrt(1/s)) / + # s**(S(3)/2), 0, True)) + # assert LT(exp(-2*sqrt(a*t))/sqrt(t), t, s) == ( + # exp(a/s)*erfc(sqrt(a) * sqrt(1/s))*(sqrt(pi)*sqrt(1/s)), 0, True) + assert (LT(t**4*exp(-2/t), t, s) == + (8*sqrt(2)*(1/s)**(S(5)/2)*besselk(5, 2*sqrt(2)*sqrt(s)), + 0, True)) + assert LT(sinh(a*t), t, s) == (a/(-a**2 + s**2), a, True) + assert (LT(b*sinh(a*t)**2, t, s) == + (2*a**2*b/(-4*a**2*s + s**3), 2*a, True)) + assert (LT(b*sinh(a*t)**2, t, s, simplify=True) == + (2*a**2*b/(s*(-4*a**2 + s**2)), 2*a, True)) + # The following line confirms that issue #21202 is solved + assert LT(cosh(2*t), t, s) == (s/(-4 + s**2), 2, True) + assert LT(cosh(a*t), t, s) == (s/(-a**2 + s**2), a, True) + assert (LT(cosh(a*t)**2, t, s, simplify=True) == + ((2*a**2 - s**2)/(s*(4*a**2 - s**2)), 2*a, True)) + assert (LT(sinh(x+3), x, s, simplify=True) == + ((s*sinh(3) + cosh(3))/(s**2 - 1), 1, True)) + L, _, _ = LT(42*sin(w*t+x)**2, t, s) + assert ( + L - + 21*(s**2 + s*(-s*cos(2*x) + 2*w*sin(2*x)) + + 4*w**2)/(s*(s**2 + 4*w**2))).simplify() == 0 + # The following line replaces the old test test_issue_7173() + assert LT(sinh(a*t)*cosh(a*t), t, s, simplify=True) == (a/(-4*a**2 + s**2), + 2*a, True) + assert LT(sinh(a*t)/t, t, s) == (log((a + s)/(-a + s))/2, a, True) + assert (LT(t**(-S(3)/2)*sinh(a*t), t, s) == + (-sqrt(pi)*(sqrt(-a + s) - sqrt(a + s)), a, True)) + # assert (LT(sinh(2*sqrt(a*t)), t, s) == + # (sqrt(pi)*sqrt(a)*exp(a/s)/s**(S(3)/2), 0, True)) + # assert (LT(sqrt(t)*sinh(2*sqrt(a*t)), t, s, simplify=True) == + # ((-sqrt(a)*s**(S(5)/2) + sqrt(pi)*s**2*(2*a + s)*exp(a/s) * + # erf(sqrt(a)*sqrt(1/s))/2)/s**(S(9)/2), 0, True)) + # assert (LT(sinh(2*sqrt(a*t))/sqrt(t), t, s) == + # (sqrt(pi)*exp(a/s)*erf(sqrt(a)*sqrt(1/s))/sqrt(s), 0, True)) + # assert (LT(sinh(sqrt(a*t))**2/sqrt(t), t, s) == + # (sqrt(pi)*(exp(a/s) - 1)/(2*sqrt(s)), 0, True)) + assert (LT(t**(S(3)/7)*cosh(a*t), t, s) == + (((a + s)**(-S(10)/7) + (-a+s)**(-S(10)/7))*gamma(S(10)/7)/2, + a, True)) + # assert (LT(cosh(2*sqrt(a*t)), t, s) == + # (sqrt(pi)*sqrt(a)*exp(a/s)*erf(sqrt(a)*sqrt(1/s))/s**(S(3)/2) + + # 1/s, 0, True)) + # assert (LT(sqrt(t)*cosh(2*sqrt(a*t)), t, s) == + # (sqrt(pi)*(a + s/2)*exp(a/s)/s**(S(5)/2), 0, True)) + # assert (LT(cosh(2*sqrt(a*t))/sqrt(t), t, s) == + # (sqrt(pi)*exp(a/s)/sqrt(s), 0, True)) + # assert (LT(cosh(sqrt(a*t))**2/sqrt(t), t, s) == + # (sqrt(pi)*(exp(a/s) + 1)/(2*sqrt(s)), 0, True)) + assert LT(log(t), t, s, simplify=True) == ( + (-log(s) - EulerGamma)/s, 0, True) + assert (LT(-log(t/a), t, s, simplify=True) == + ((log(a) + log(s) + EulerGamma)/s, 0, True)) + assert LT(log(1+a*t), t, s) == (-exp(s/a)*Ei(-s/a)/s, 0, True) + assert (LT(log(t+a), t, s, simplify=True) == + ((s*log(a) - exp(s/a)*Ei(-s/a))/s**2, 0, True)) + assert (LT(log(t)/sqrt(t), t, s, simplify=True) == + (sqrt(pi)*(-log(s) - log(4) - EulerGamma)/sqrt(s), 0, True)) + assert (LT(t**(S(5)/2)*log(t), t, s, simplify=True) == + (sqrt(pi)*(-15*log(s) - log(1073741824) - 15*EulerGamma + 46) / + (8*s**(S(7)/2)), 0, True)) + assert (LT(t**3*log(t), t, s, noconds=True, simplify=True) - + 6*(-log(s) - S.EulerGamma + S(11)/6)/s**4).simplify() == S.Zero + assert (LT(log(t)**2, t, s, simplify=True) == + (((log(s) + EulerGamma)**2 + pi**2/6)/s, 0, True)) + assert (LT(exp(-a*t)*log(t), t, s, simplify=True) == + ((-log(a + s) - EulerGamma)/(a + s), -a, True)) + assert LT(sin(a*t), t, s) == (a/(a**2 + s**2), 0, True) + assert (LT(Abs(sin(a*t)), t, s) == + (a*coth(pi*s/(2*a))/(a**2 + s**2), 0, True)) + assert LT(sin(a*t)/t, t, s) == (atan(a/s), 0, True) + assert LT(sin(a*t)**2/t, t, s) == (log(4*a**2/s**2 + 1)/4, 0, True) + assert (LT(sin(a*t)**2/t**2, t, s) == + (a*atan(2*a/s) - s*log(4*a**2/s**2 + 1)/4, 0, True)) + # assert (LT(sin(2*sqrt(a*t)), t, s) == + # (sqrt(pi)*sqrt(a)*exp(-a/s)/s**(S(3)/2), 0, True)) + # assert LT(sin(2*sqrt(a*t))/t, t, s) == (pi*erf(sqrt(a)*sqrt(1/s)), 0, True) + assert LT(cos(a*t), t, s) == (s/(a**2 + s**2), 0, True) + assert (LT(cos(a*t)**2, t, s) == + ((2*a**2 + s**2)/(s*(4*a**2 + s**2)), 0, True)) + # assert (LT(sqrt(t)*cos(2*sqrt(a*t)), t, s, simplify=True) == + # (sqrt(pi)*(-a + s/2)*exp(-a/s)/s**(S(5)/2), 0, True)) + # assert (LT(cos(2*sqrt(a*t))/sqrt(t), t, s) == + # (sqrt(pi)*sqrt(1/s)*exp(-a/s), 0, True)) + assert (LT(sin(a*t)*sin(b*t), t, s) == + (2*a*b*s/((s**2 + (a - b)**2)*(s**2 + (a + b)**2)), 0, True)) + assert (LT(cos(a*t)*sin(b*t), t, s) == + (b*(-a**2 + b**2 + s**2)/((s**2 + (a - b)**2)*(s**2 + (a + b)**2)), + 0, True)) + assert (LT(cos(a*t)*cos(b*t), t, s) == + (s*(a**2 + b**2 + s**2)/((s**2 + (a - b)**2)*(s**2 + (a + b)**2)), + 0, True)) + assert (LT(-a*t*cos(a*t) + sin(a*t), t, s, simplify=True) == + (2*a**3/(a**4 + 2*a**2*s**2 + s**4), 0, True)) + assert LT(c*exp(-b*t)*sin(a*t), t, s) == (a * + c/(a**2 + (b + s)**2), -b, True) + assert LT(c*exp(-b*t)*cos(a*t), t, s) == (c*(b + s)/(a**2 + (b + s)**2), + -b, True) + L, plane, cond = LT(cos(x + 3), x, s, simplify=True) + assert plane == 0 + assert L - (s*cos(3) - sin(3))/(s**2 + 1) == 0 + # Error functions (laplace7.pdf) + assert LT(erf(a*t), t, s) == (exp(s**2/(4*a**2))*erfc(s/(2*a))/s, 0, True) + # assert LT(erf(sqrt(a*t)), t, s) == (sqrt(a)/(s*sqrt(a + s)), 0, True) + # assert (LT(exp(a*t)*erf(sqrt(a*t)), t, s, simplify=True) == + # (-sqrt(a)/(sqrt(s)*(a - s)), a, True)) + # assert (LT(erf(sqrt(a/t)/2), t, s, simplify=True) == + # (1/s - exp(-sqrt(a)*sqrt(s))/s, 0, True)) + # assert (LT(erfc(sqrt(a*t)), t, s, simplify=True) == + # (-sqrt(a)/(s*sqrt(a + s)) + 1/s, -a, True)) + # assert (LT(exp(a*t)*erfc(sqrt(a*t)), t, s) == + # (1/(sqrt(a)*sqrt(s) + s), 0, True)) + # assert LT(erfc(sqrt(a/t)/2), t, s) == (exp(-sqrt(a)*sqrt(s))/s, 0, True) + # Bessel functions (laplace8.pdf) + assert LT(besselj(0, a*t), t, s) == (1/sqrt(a**2 + s**2), 0, True) + assert (LT(besselj(1, a*t), t, s, simplify=True) == + (a/(a**2 + s**2 + s*sqrt(a**2 + s**2)), 0, True)) + assert (LT(besselj(2, a*t), t, s, simplify=True) == + (a**2/(sqrt(a**2 + s**2)*(s + sqrt(a**2 + s**2))**2), 0, True)) + assert (LT(t*besselj(0, a*t), t, s) == + (s/(a**2 + s**2)**(S(3)/2), 0, True)) + assert (LT(t*besselj(1, a*t), t, s) == + (a/(a**2 + s**2)**(S(3)/2), 0, True)) + assert (LT(t**2*besselj(2, a*t), t, s) == + (3*a**2/(a**2 + s**2)**(S(5)/2), 0, True)) + # assert LT(besselj(0, 2*sqrt(a*t)), t, s) == (exp(-a/s)/s, 0, True) + # assert (LT(t**(S(3)/2)*besselj(3, 2*sqrt(a*t)), t, s) == + # (a**(S(3)/2)*exp(-a/s)/s**4, 0, True)) + assert (LT(besselj(0, a*sqrt(t**2+b*t)), t, s, simplify=True) == + (exp(b*(s - sqrt(a**2 + s**2)))/sqrt(a**2 + s**2), 0, True)) + assert LT(besseli(0, a*t), t, s) == (1/sqrt(-a**2 + s**2), a, True) + assert (LT(besseli(1, a*t), t, s, simplify=True) == + (a/(-a**2 + s**2 + s*sqrt(-a**2 + s**2)), a, True)) + assert (LT(besseli(2, a*t), t, s, simplify=True) == + (a**2/(sqrt(-a**2 + s**2)*(s + sqrt(-a**2 + s**2))**2), a, True)) + assert LT(t*besseli(0, a*t), t, s) == (s/(-a**2 + s**2)**(S(3)/2), a, True) + assert LT(t*besseli(1, a*t), t, s) == (a/(-a**2 + s**2)**(S(3)/2), a, True) + assert (LT(t**2*besseli(2, a*t), t, s) == + (3*a**2/(-a**2 + s**2)**(S(5)/2), a, True)) + # assert (LT(t**(S(3)/2)*besseli(3, 2*sqrt(a*t)), t, s) == + # (a**(S(3)/2)*exp(a/s)/s**4, 0, True)) + assert (LT(bessely(0, a*t), t, s) == + (-2*asinh(s/a)/(pi*sqrt(a**2 + s**2)), 0, True)) + assert (LT(besselk(0, a*t), t, s) == + (log((s + sqrt(-a**2 + s**2))/a)/sqrt(-a**2 + s**2), -a, True)) + assert (LT(sin(a*t)**4, t, s, simplify=True) == + (24*a**4/(s*(64*a**4 + 20*a**2*s**2 + s**4)), 0, True)) + # Test general rules and unevaluated forms + # These all also test whether issue #7219 is solved. + assert LT(Heaviside(t-1)*cos(t-1), t, s) == (s*exp(-s)/(s**2 + 1), 0, True) + assert LT(a*f(t), t, w) == (a*LaplaceTransform(f(t), t, w), -oo, True) + assert (LT(a*Heaviside(t+1)*f(t+1), t, s) == + (a*LaplaceTransform(f(t + 1), t, s), -oo, True)) + assert (LT(a*Heaviside(t-1)*f(t-1), t, s) == + (a*LaplaceTransform(f(t), t, s)*exp(-s), -oo, True)) + assert (LT(b*f(t/a), t, s) == + (a*b*LaplaceTransform(f(t), t, a*s), -oo, True)) + assert LT(exp(-f(x)*t), t, s) == (1/(s + f(x)), -re(f(x)), True) + assert (LT(exp(-a*t)*f(t), t, s) == + (LaplaceTransform(f(t), t, a + s), -oo, True)) + # assert (LT(exp(-a*t)*erfc(sqrt(b/t)/2), t, s) == + # (exp(-sqrt(b)*sqrt(a + s))/(a + s), -a, True)) + assert (LT(sinh(a*t)*f(t), t, s) == + (LaplaceTransform(f(t), t, -a + s)/2 - + LaplaceTransform(f(t), t, a + s)/2, -oo, True)) + assert (LT(sinh(a*t)*t, t, s, simplify=True) == + (2*a*s/(a**4 - 2*a**2*s**2 + s**4), a, True)) + assert (LT(cosh(a*t)*f(t), t, s) == + (LaplaceTransform(f(t), t, -a + s)/2 + + LaplaceTransform(f(t), t, a + s)/2, -oo, True)) + assert (LT(cosh(a*t)*t, t, s, simplify=True) == + (1/(2*(a + s)**2) + 1/(2*(a - s)**2), a, True)) + assert (LT(sin(a*t)*f(t), t, s, simplify=True) == + (I*(-LaplaceTransform(f(t), t, -I*a + s) + + LaplaceTransform(f(t), t, I*a + s))/2, -oo, True)) + assert (LT(sin(f(t)), t, s) == + (LaplaceTransform(sin(f(t)), t, s), -oo, True)) + assert (LT(sin(a*t)*t, t, s, simplify=True) == + (2*a*s/(a**4 + 2*a**2*s**2 + s**4), 0, True)) + assert (LT(cos(a*t)*f(t), t, s) == + (LaplaceTransform(f(t), t, -I*a + s)/2 + + LaplaceTransform(f(t), t, I*a + s)/2, -oo, True)) + assert (LT(cos(a*t)*t, t, s, simplify=True) == + ((-a**2 + s**2)/(a**4 + 2*a**2*s**2 + s**4), 0, True)) + L, plane, _ = LT(sin(a*t+b)**2*f(t), t, s) + assert plane == -oo + assert ( + -L + ( + LaplaceTransform(f(t), t, s)/2 - + LaplaceTransform(f(t), t, -2*I*a + s)*exp(2*I*b)/4 - + LaplaceTransform(f(t), t, 2*I*a + s)*exp(-2*I*b)/4)) == 0 + L = LT(sin(a*t+b)**2*f(t), t, s, noconds=True) + assert ( + laplace_correspondence(L, {f: F}) == + F(s)/2 - F(-2*I*a + s)*exp(2*I*b)/4 - + F(2*I*a + s)*exp(-2*I*b)/4) + L, plane, _ = LT(sin(a*t)**3*cosh(b*t), t, s) + assert plane == b + assert ( + -L - 3*a/(8*(9*a**2 + b**2 + 2*b*s + s**2)) - + 3*a/(8*(9*a**2 + b**2 - 2*b*s + s**2)) + + 3*a/(8*(a**2 + b**2 + 2*b*s + s**2)) + + 3*a/(8*(a**2 + b**2 - 2*b*s + s**2))).simplify() == 0 + assert (LT(t**2*exp(-t**2), t, s) == + (sqrt(pi)*s**2*exp(s**2/4)*erfc(s/2)/8 - s/4 + + sqrt(pi)*exp(s**2/4)*erfc(s/2)/4, 0, True)) + assert (LT((a*t**2 + b*t + c)*f(t), t, s) == + (a*Derivative(LaplaceTransform(f(t), t, s), (s, 2)) - + b*Derivative(LaplaceTransform(f(t), t, s), s) + + c*LaplaceTransform(f(t), t, s), -oo, True)) + assert (LT(t**np*g(t), t, s) == + ((-1)**np*Derivative(LaplaceTransform(g(t), t, s), (s, np)), + -oo, True)) + # The following tests check whether _piecewise_to_heaviside works: + x1 = Piecewise((0, t <= 0), (1, t <= 1), (0, True)) + X1 = LT(x1, t, s)[0] + assert X1 == 1/s - exp(-s)/s + y1 = ILT(X1, s, t) + assert y1 == Heaviside(t) - Heaviside(t - 1) + x1 = Piecewise((0, t <= 0), (t, t <= 1), (2-t, t <= 2), (0, True)) + X1 = LT(x1, t, s)[0].simplify() + assert X1 == (exp(2*s) - 2*exp(s) + 1)*exp(-2*s)/s**2 + y1 = ILT(X1, s, t) + assert ( + -y1 + t*Heaviside(t) + (t - 2)*Heaviside(t - 2) - + 2*(t - 1)*Heaviside(t - 1)).simplify() == 0 + x1 = Piecewise((exp(t), t <= 0), (1, t <= 1), (exp(-(t)), True)) + X1 = LT(x1, t, s)[0] + assert X1 == exp(-1)*exp(-s)/(s + 1) + 1/s - exp(-s)/s + y1 = ILT(X1, s, t) + assert y1 == ( + exp(-1)*exp(1 - t)*Heaviside(t - 1) + Heaviside(t) - Heaviside(t - 1)) + x1 = Piecewise((0, x <= 0), (1, x <= 1), (0, True)) + X1 = LT(x1, t, s)[0] + assert X1 == Piecewise((0, x <= 0), (1, x <= 1), (0, True))/s + x1 = [ + a*Piecewise((1, And(t > 1, t <= 3)), (2, True)), + a*Piecewise((1, And(t >= 1, t <= 3)), (2, True)), + a*Piecewise((1, And(t >= 1, t < 3)), (2, True)), + a*Piecewise((1, And(t > 1, t < 3)), (2, True))] + for x2 in x1: + assert LT(x2, t, s)[0].expand() == 2*a/s - a*exp(-s)/s + a*exp(-3*s)/s + assert ( + LT(Piecewise((1, Eq(t, 1)), (2, True)), t, s)[0] == + LaplaceTransform(Piecewise((1, Eq(t, 1)), (2, True)), t, s)) + # The following lines test whether _laplace_transform successfully + # removes Heaviside(1) before processing espressions. It fails if + # Heaviside(t) remains because then meijerg functions will appear. + X1 = 1/sqrt(a*s**2-b) + x1 = ILT(X1, s, t) + Y1 = LT(x1, t, s)[0] + Z1 = (Y1**2/X1**2).simplify() + assert Z1 == 1 + # The following two lines test whether issues #5813 and #7176 are solved. + assert (LT(diff(f(t), (t, 1)), t, s, noconds=True) == + s*LaplaceTransform(f(t), t, s) - f(0)) + assert (LT(diff(f(t), (t, 3)), t, s, noconds=True) == + s**3*LaplaceTransform(f(t), t, s) - s**2*f(0) - + s*Subs(Derivative(f(t), t), t, 0) - + Subs(Derivative(f(t), (t, 2)), t, 0)) + # Issue #7219 + assert (LT(diff(f(x, t, w), t, 2), t, s) == + (s**2*LaplaceTransform(f(x, t, w), t, s) - s*f(x, 0, w) - + Subs(Derivative(f(x, t, w), t), t, 0), -oo, True)) + # Issue #23307 + assert (LT(10*diff(f(t), (t, 1)), t, s, noconds=True) == + 10*s*LaplaceTransform(f(t), t, s) - 10*f(0)) + assert (LT(a*f(b*t)+g(c*t), t, s, noconds=True) == + a*LaplaceTransform(f(t), t, s/b)/b + + LaplaceTransform(g(t), t, s/c)/c) + assert inverse_laplace_transform( + f(w), w, t, plane=0) == InverseLaplaceTransform(f(w), w, t, 0) + assert (LT(f(t)*g(t), t, s, noconds=True) == + LaplaceTransform(f(t)*g(t), t, s)) + # Issue #24294 + assert (LT(b*f(a*t), t, s, noconds=True) == + b*LaplaceTransform(f(t), t, s/a)/a) + assert LT(3*exp(t)*Heaviside(t), t, s) == (3/(s - 1), 1, True) + assert (LT(2*sin(t)*Heaviside(t), t, s, simplify=True) == + (2/(s**2 + 1), 0, True)) + # Issue #25293 + assert ( + LT((1/(t-1))*sin(4*pi*(t-1))*DiracDelta(t-1) * + (Heaviside(t-1/4) - Heaviside(t-2)), t, s)[0] == 4*pi*exp(-s)) + # additional basic tests from wikipedia + assert (LT((t - a)**b*exp(-c*(t - a))*Heaviside(t - a), t, s) == + ((c + s)**(-b - 1)*exp(-a*s)*gamma(b + 1), -c, True)) + assert ( + LT((exp(2*t)-1)*exp(-b-t)*Heaviside(t)/2, t, s, noconds=True, + simplify=True) == + exp(-b)/(s**2 - 1)) + # DiracDelta function: standard cases + assert LT(DiracDelta(t), t, s) == (1, -oo, True) + assert LT(DiracDelta(a*t), t, s) == (1/a, -oo, True) + assert LT(DiracDelta(t/42), t, s) == (42, -oo, True) + assert LT(DiracDelta(t+42), t, s) == (0, -oo, True) + assert (LT(DiracDelta(t)+DiracDelta(t-42), t, s) == + (1 + exp(-42*s), -oo, True)) + assert (LT(DiracDelta(t)-a*exp(-a*t), t, s, simplify=True) == + (s/(a + s), -a, True)) + assert ( + LT(exp(-t)*(DiracDelta(t)+DiracDelta(t-42)), t, s, simplify=True) == + (exp(-42*s - 42) + 1, -oo, True)) + assert LT(f(t)*DiracDelta(t-42), t, s) == (f(42)*exp(-42*s), -oo, True) + assert LT(f(t)*DiracDelta(b*t-a), t, s) == (f(a/b)*exp(-a*s/b)/b, + -oo, True) + assert LT(f(t)*DiracDelta(b*t+a), t, s) == (0, -oo, True) + # SingularityFunction + assert LT(SingularityFunction(t, a, -1), t, s)[0] == exp(-a*s) + assert LT(SingularityFunction(t, a, 1), t, s)[0] == exp(-a*s)/s**2 + assert LT(SingularityFunction(t, a, x), t, s)[0] == ( + LaplaceTransform(SingularityFunction(t, a, x), t, s)) + # Collection of cases that cannot be fully evaluated and/or would catch + # some common implementation errors + assert (LT(DiracDelta(t**2), t, s, noconds=True) == + LaplaceTransform(DiracDelta(t**2), t, s)) + assert LT(DiracDelta(t**2 - 1), t, s) == (exp(-s)/2, -oo, True) + assert LT(DiracDelta(t*(1 - t)), t, s) == (1 - exp(-s), -oo, True) + assert (LT((DiracDelta(t) + 1)*(DiracDelta(t - 1) + 1), t, s) == + (LaplaceTransform(DiracDelta(t)*DiracDelta(t - 1), t, s) + + 1 + exp(-s) + 1/s, 0, True)) + assert LT(DiracDelta(2*t-2*exp(a)), t, s) == (exp(-s*exp(a))/2, -oo, True) + assert LT(DiracDelta(-2*t+2*exp(a)), t, s) == (exp(-s*exp(a))/2, -oo, True) + # Heaviside tests + 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(Heaviside(t-1), t, s) == (exp(-s)/s, 0, True) + assert LT(Heaviside(2*t-4), t, s) == (exp(-2*s)/s, 0, True) + assert LT(Heaviside(2*t+4), t, s) == (1/s, 0, True) + assert (LT(Heaviside(-2*t+4), t, s, simplify=True) == + (1/s - exp(-2*s)/s, 0, True)) + assert (LT(g(t)*Heaviside(t - w), t, s) == + (LaplaceTransform(g(t)*Heaviside(t - w), t, s), -oo, True)) + assert ( + LT(Heaviside(t-a)*g(t), t, s) == + (LaplaceTransform(g(a + t), t, s)*exp(-a*s), -oo, True)) + assert ( + LT(Heaviside(t+a)*g(t), t, s) == + (LaplaceTransform(g(t), t, s), -oo, True)) + assert ( + LT(Heaviside(-t+a)*g(t), t, s) == + (LaplaceTransform(g(t), t, s) - + LaplaceTransform(g(a + t), t, s)*exp(-a*s), -oo, True)) + assert ( + LT(Heaviside(-t-a)*g(t), t, s) == (0, 0, True)) + # Fresnel functions + assert (laplace_transform(fresnels(t), t, s, simplify=True) == + ((-sin(s**2/(2*pi))*fresnels(s/pi) + + sqrt(2)*sin(s**2/(2*pi) + pi/4)/2 - + cos(s**2/(2*pi))*fresnelc(s/pi))/s, 0, True)) + assert (laplace_transform(fresnelc(t), t, s, simplify=True) == + ((sin(s**2/(2*pi))*fresnelc(s/pi) - + cos(s**2/(2*pi))*fresnels(s/pi) + + sqrt(2)*cos(s**2/(2*pi) + pi/4)/2)/s, 0, True)) + # Matrix tests + Mt = Matrix([[exp(t), t*exp(-t)], [t*exp(-t), exp(t)]]) + Ms = Matrix([[1/(s - 1), (s + 1)**(-2)], + [(s + 1)**(-2), 1/(s - 1)]]) + # The default behaviour for Laplace transform of a Matrix returns a Matrix + # of Tuples and is deprecated: + with warns_deprecated_sympy(): + Ms_conds = Matrix( + [[(1/(s - 1), 1, True), ((s + 1)**(-2), -1, True)], + [((s + 1)**(-2), -1, True), (1/(s - 1), 1, True)]]) + with warns_deprecated_sympy(): + assert LT(Mt, t, s) == Ms_conds + # The new behavior is to return a tuple of a Matrix and the convergence + # conditions for the matrix as a whole: + assert LT(Mt, t, s, legacy_matrix=False) == (Ms, 1, True) + # With noconds=True the transformed matrix is returned without conditions + # either way: + assert LT(Mt, t, s, noconds=True) == Ms + assert LT(Mt, t, s, legacy_matrix=False, noconds=True) == Ms + + +@slow +def test_inverse_laplace_transform(): + s = symbols('s') + k, n, t = symbols('k, n, t', real=True) + a, b, c, d = symbols('a, b, c, d', positive=True) + f = Function('f') + F = Function('F') + + def ILT(g): + return inverse_laplace_transform(g, s, t) + + def ILTS(g): + return inverse_laplace_transform(g, s, t, simplify=True) + + def ILTF(g): + return laplace_correspondence( + inverse_laplace_transform(g, s, t), {f: F}) + + # Tests for the rules in Bateman54. + + # Section 4.1: Some of the Laplace transform rules can also be used well + # in the inverse transform. + assert ILTF(exp(-a*s)*F(s)) == f(-a + t) + assert ILTF(k*F(s-a)) == k*f(t)*exp(-a*t) + assert ILTF(diff(F(s), s, 3)) == -t**3*f(t) + assert ILTF(diff(F(s), s, 4)) == t**4*f(t) + + # Section 5.1: Most rules are impractical for a computer algebra system. + + # Section 5.2: Rational functions + assert ILT(2) == 2*DiracDelta(t) + assert ILT(1/s) == Heaviside(t) + assert ILT(1/s**2) == t*Heaviside(t) + assert ILT(1/s**5) == t**4*Heaviside(t)/24 + assert ILT(1/s**n) == t**(n - 1)*Heaviside(t)/gamma(n) + assert ILT(a/(a + s)) == a*exp(-a*t)*Heaviside(t) + assert ILT(s/(a + s)) == -a*exp(-a*t)*Heaviside(t) + DiracDelta(t) + assert (ILT(b*s/(s+a)**2) == + b*(-a*t*exp(-a*t)*Heaviside(t) + exp(-a*t)*Heaviside(t))) + assert (ILTS(c/((s+a)*(s+b))) == + c*(exp(a*t) - exp(b*t))*exp(-t*(a + b))*Heaviside(t)/(a - b)) + assert (ILTS(c*s/((s+a)*(s+b))) == + c*(a*exp(b*t) - b*exp(a*t))*exp(-t*(a + b))*Heaviside(t)/(a - b)) + assert ILTS(s/(a + s)**3) == t*(-a*t + 2)*exp(-a*t)*Heaviside(t)/2 + assert ILTS(1/(s*(a + s)**3)) == ( + -a**2*t**2 - 2*a*t + 2*exp(a*t) - 2)*exp(-a*t)*Heaviside(t)/(2*a**3) + assert ILT(1/(s*(a + s)**n)) == ( + Heaviside(t)*lowergamma(n, a*t)/(a**n*gamma(n))) + assert ILT((s-a)**(-b)) == t**(b - 1)*exp(a*t)*Heaviside(t)/gamma(b) + assert ILT((a + s)**(-2)) == t*exp(-a*t)*Heaviside(t) + assert ILT((a + s)**(-5)) == t**4*exp(-a*t)*Heaviside(t)/24 + assert ILT(s**2/(s**2 + 1)) == -sin(t)*Heaviside(t) + DiracDelta(t) + assert ILT(1 - 1/(s**2 + 1)) == -sin(t)*Heaviside(t) + DiracDelta(t) + assert ILT(a/(a**2 + s**2)) == sin(a*t)*Heaviside(t) + assert ILT(s/(s**2 + a**2)) == cos(a*t)*Heaviside(t) + assert ILT(b/(b**2 + (a + s)**2)) == exp(-a*t)*sin(b*t)*Heaviside(t) + assert (ILT(b*s/(b**2 + (a + s)**2)) == + b*(-a*exp(-a*t)*sin(b*t)/b + exp(-a*t)*cos(b*t))*Heaviside(t)) + assert ILT(1/(s**2*(s**2 + 1))) == t*Heaviside(t) - sin(t)*Heaviside(t) + assert (ILTS(c*s/(d**2*(s+a)**2+b**2)) == + c*(-a*d*sin(b*t/d) + b*cos(b*t/d))*exp(-a*t)*Heaviside(t)/(b*d**2)) + assert ILTS((b*s**2 + d)/(a**2 + s**2)**2) == ( + 2*a**2*b*sin(a*t) + (a**2*b - d)*(a*t*cos(a*t) - + sin(a*t)))*Heaviside(t)/(2*a**3) + assert ILTS(b/(s**2-a**2)) == b*sinh(a*t)*Heaviside(t)/a + assert (ILT(b/(s**2-a**2)) == + b*(exp(a*t)*Heaviside(t)/(2*a) - exp(-a*t)*Heaviside(t)/(2*a))) + assert ILTS(b*s/(s**2-a**2)) == b*cosh(a*t)*Heaviside(t) + assert (ILT(b/(s*(s+a))) == + b*(Heaviside(t)/a - exp(-a*t)*Heaviside(t)/a)) + # Issue #24424 + assert (ILTS((s + 8)/((s + 2)*(s**2 + 2*s + 10))) == + ((8*sin(3*t) - 9*cos(3*t))*exp(t) + 9)*exp(-2*t)*Heaviside(t)/15) + # Issue #8514; this is not important anymore, since this function + # is not solved by integration anymore + assert (ILT(1/(a*s**2+b*s+c)) == + 2*exp(-b*t/(2*a))*sin(t*sqrt(4*a*c - b**2)/(2*a)) * + Heaviside(t)/sqrt(4*a*c - b**2)) + + # Section 5.3: Irrational algebraic functions + assert ( # (1) + ILT(1/sqrt(s)/(b*s-a)) == + exp(a*t/b)*Heaviside(t)*erf(sqrt(a)*sqrt(t)/sqrt(b))/(sqrt(a)*sqrt(b))) + assert ( # (2) + ILT(1/sqrt(k*s)/(c*s-a)/s) == + (-2*c*sqrt(t)/(sqrt(pi)*a) + + c**(S(3)/2)*exp(a*t/c)*erf(sqrt(a)*sqrt(t)/sqrt(c))/a**(S(3)/2)) * + Heaviside(t)/(c*sqrt(k))) + assert ( # (4) + ILT(1/(sqrt(c*s)+a)) == (-a*exp(a**2*t/c)*erfc(a*sqrt(t)/sqrt(c))/c + + 1/(sqrt(pi)*sqrt(c)*sqrt(t)))*Heaviside(t)) + assert ( # (5) + ILT(a/s/(b*sqrt(s)+a)) == + (-exp(a**2*t/b**2)*erfc(a*sqrt(t)/b) + 1)*Heaviside(t)) + assert ( # (6) + ILT((a-b)*sqrt(s)/(sqrt(s)+sqrt(a))/(s-b)) == + (sqrt(a)*sqrt(b)*exp(b*t)*erfc(sqrt(b)*sqrt(t)) + + a*exp(a*t)*erfc(sqrt(a)*sqrt(t)) - b*exp(b*t))*Heaviside(t)) + assert ( # (7) + ILT(1/sqrt(s)/(sqrt(b*s)+a)) == + exp(a**2*t/b)*Heaviside(t)*erfc(a*sqrt(t)/sqrt(b))/sqrt(b)) + assert ( # (8) + ILT(a**2/(sqrt(s)+a)/s**(S(3)/2)) == + (2*a*sqrt(t)/sqrt(pi) + exp(a**2*t)*erfc(a*sqrt(t)) - 1) * + Heaviside(t)) + assert ( # (9) + ILT((a-b)*sqrt(b)/(s-b)/sqrt(s)/(sqrt(s)+sqrt(a))) == + (sqrt(a)*exp(b*t)*erf(sqrt(b)*sqrt(t)) + + sqrt(b)*exp(a*t)*erfc(sqrt(a)*sqrt(t)) - + sqrt(b)*exp(b*t))*Heaviside(t)) + assert ( # (10) + ILT(1/(sqrt(s)+sqrt(a))**2) == + (-2*sqrt(a)*sqrt(t)/sqrt(pi) + + (-2*a*t + 1)*(erf(sqrt(a)*sqrt(t)) - + 1)*exp(a*t) + 1)*Heaviside(t)) + assert ( # (11) + ILT(1/(sqrt(s)+sqrt(a))**2/s) == + ((2*t - 1/a)*exp(a*t)*erfc(sqrt(a)*sqrt(t)) + 1/a - + 2*sqrt(t)/(sqrt(pi)*sqrt(a)))*Heaviside(t)) + assert ( # (12) + ILT(1/(sqrt(s)+a)**2/sqrt(s)) == + (-2*a*t*exp(a**2*t)*erfc(a*sqrt(t)) + + 2*sqrt(t)/sqrt(pi))*Heaviside(t)) + assert ( # (13) + ILT(1/(sqrt(s)+a)**3) == + (-a*t*(2*a**2*t + 3)*exp(a**2*t)*erfc(a*sqrt(t)) + + 2*sqrt(t)*(a**2*t + 1)/sqrt(pi))*Heaviside(t)) + x = ( + - ILT(sqrt(s)/(sqrt(s)+a)**3) + + 2*(sqrt(pi)*a**2*t*(-2*sqrt(pi)*erfc(a*sqrt(t)) + + 2*exp(-a**2*t)/(a*sqrt(t))) * + (-a**4*t**2 - 5*a**2*t/2 - S.Half) * exp(a**2*t)/2 + + sqrt(pi)*a*sqrt(t)*(a**2*t + 1)/2) * + Heaviside(t)/(pi*a**2*t)).simplify() + assert ( # (14) + x == 0) + x = ( + - ILT(1/sqrt(s)/(sqrt(s)+a)**3) + + Heaviside(t)*(sqrt(t)*((2*a**2*t + 1) * + (sqrt(pi)*a*sqrt(t)*exp(a**2*t) * + erfc(a*sqrt(t)) - 1) + 1) / + (sqrt(pi)*a))).simplify() + assert ( # (15) + x == 0) + assert ( # (16) + factor_terms(ILT(3/(sqrt(s)+a)**4)) == + 3*(-2*a**3*t**(S(5)/2)*(2*a**2*t + 5)/(3*sqrt(pi)) + + t*(4*a**4*t**2 + 12*a**2*t + 3)*exp(a**2*t) * + erfc(a*sqrt(t))/3)*Heaviside(t)) + assert ( # (17) + ILT((sqrt(s)-a)/(s*(sqrt(s)+a))) == + (2*exp(a**2*t)*erfc(a*sqrt(t))-1)*Heaviside(t)) + assert ( # (18) + ILT((sqrt(s)-a)**2/(s*(sqrt(s)+a)**2)) == ( + 1 + 8*a**2*t*exp(a**2*t)*erfc(a*sqrt(t)) - + 8/sqrt(pi)*a*sqrt(t))*Heaviside(t)) + assert ( # (19) + ILT((sqrt(s)-a)**3/(s*(sqrt(s)+a)**3)) == Heaviside(t)*( + 2*(8*a**4*t**2+8*a**2*t+1)*exp(a**2*t) * + erfc(a*sqrt(t))-8/sqrt(pi)*a*sqrt(t)*(2*a**2*t+1)-1)) + assert ( # (22) + ILT(sqrt(s+a)/(s+b)) == Heaviside(t)*( + exp(-a*t)/sqrt(t)/sqrt(pi) + + sqrt(a-b)*exp(-b*t)*erf(sqrt(a-b)*sqrt(t)))) + assert ( # (23) + ILT(1/sqrt(s+b)/(s+a)) == Heaviside(t)*( + 1/sqrt(b-a)*exp(-a*t)*erf(sqrt(b-a)*sqrt(t)))) + assert ( # (35) + ILT(1/sqrt(s**2+a**2)) == Heaviside(t)*( + besselj(0, a*t))) + assert ( # (44) + ILT(1/sqrt(s**2-a**2)) == Heaviside(t)*( + besseli(0, a*t))) + + # Miscellaneous tests + # Can _inverse_laplace_time_shift deal with positive exponents? + assert ( + - ILT((s**2*exp(2*s) + 4*exp(s) - 4)*exp(-2*s)/(s*(s**2 + 1))) + + cos(t)*Heaviside(t) + 4*cos(t - 2)*Heaviside(t - 2) - + 4*cos(t - 1)*Heaviside(t - 1) - 4*Heaviside(t - 2) + + 4*Heaviside(t - 1)).simplify() == 0 + + +@slow +def test_inverse_laplace_transform_old(): + from sympy.functions.special.delta_functions import DiracDelta + ILT = inverse_laplace_transform + a, b, c, d = symbols('a b c d', positive=True) + n, r = symbols('n, r', real=True) + t, z = symbols('t z') + f = Function('f') + F = Function('F') + + def simp_hyp(expr): + return factor_terms(expand_mul(expr)).rewrite(sin) + + L = ILT(F(s), s, t) + assert laplace_correspondence(L, {f: F}) == f(t) + assert ILT(exp(-a*s)/s, s, t) == Heaviside(-a + t) + assert ILT(exp(-a*s)/(b + s), s, t) == exp(-b*(-a + t))*Heaviside(-a + t) + assert (ILT((b + s)/(a**2 + (b + s)**2), s, t) == + exp(-b*t)*cos(a*t)*Heaviside(t)) + assert (ILT(exp(-a*s)/s**b, s, t) == + (-a + t)**(b - 1)*Heaviside(-a + t)/gamma(b)) + assert (ILT(exp(-a*s)/sqrt(s**2 + 1), s, t) == + Heaviside(-a + t)*besselj(0, a - t)) + assert ILT(1/(s*sqrt(s + 1)), s, t) == Heaviside(t)*erf(sqrt(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)) + assert (ILT(exp(-a*s)/sqrt(1 + s**2), s, t) == + 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, simplify=True).rewrite(exp) == + Heaviside(t)*besselj(b, a*t)) + assert ILT(1/(s*sqrt(s + 1)), s, t) == Heaviside(t)*erf(sqrt(t)) + # TODO can we make erf(t) work? + assert (ILT((s * eye(2) - Matrix([[1, 0], [0, 2]])).inv(), s, t) == + Matrix([[exp(t)*Heaviside(t), 0], [0, exp(2*t)*Heaviside(t)]])) + # Test time_diff rule + assert (ILT(s**42*f(s), s, t) == + Derivative(InverseLaplaceTransform(f(s), s, t, None), (t, 42))) + assert ILT(cos(s), s, t) == InverseLaplaceTransform(cos(s), s, t, None) + # Rules for testing different DiracDelta cases + assert ( + ILT(1 + 2*s + 3*s**2 + 5*s**3, s, t) == DiracDelta(t) + + 2*DiracDelta(t, 1) + 3*DiracDelta(t, 2) + 5*DiracDelta(t, 3)) + assert (ILT(2*exp(3*s) - 5*exp(-7*s), s, t) == + 2*InverseLaplaceTransform(exp(3*s), s, t, None) - + 5*DiracDelta(t - 7)) + a = cos(sin(7)/2) + assert ILT(a*exp(-3*s), s, t) == a*DiracDelta(t - 3) + assert ILT(exp(2*s), s, t) == InverseLaplaceTransform(exp(2*s), s, t, None) + r = Symbol('r', real=True) + assert ILT(exp(r*s), s, t) == InverseLaplaceTransform(exp(r*s), s, t, None) + # Rules for testing whether Heaviside(t) is treated properly in diff rule + assert ILT(s**2/(a**2 + s**2), s, t) == ( + -a*sin(a*t)*Heaviside(t) + DiracDelta(t)) + assert ILT(s**2*(f(s) + 1/(a**2 + s**2)), s, t) == ( + -a*sin(a*t)*Heaviside(t) + DiracDelta(t) + + Derivative(InverseLaplaceTransform(f(s), s, t, None), (t, 2))) + # Rules from the previous test_inverse_laplace_transform_delta_cond(): + assert (ILT(exp(r*s), s, t, noconds=False) == + (InverseLaplaceTransform(exp(r*s), s, t, None), True)) + # inversion does not exist: verify it doesn't evaluate to DiracDelta + for z in (Symbol('z', extended_real=False), + Symbol('z', imaginary=True, zero=False)): + f = ILT(exp(z*s), s, t, noconds=False) + f = f[0] if isinstance(f, tuple) else f + assert f.func != DiracDelta + + +@slow +def test_expint(): + x = Symbol('x') + a = Symbol('a') + u = Symbol('u', polar=True) + + # 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, simplify=True) == + (lerchphi(s*exp_polar(I*pi), 1, a), 0, re(a) > S.Zero)) + assert (laplace_transform(expint(1, x), x, s, simplify=True) == + (log(s + 1)/s, 0, True)) + assert (laplace_transform(expint(2, x), x, s, simplify=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)) + assert ( + inverse_laplace_transform(log(s + 1)/s, s, x, + simplify=True).rewrite(expint) == + Heaviside(x)*E1(x)) + assert ( + inverse_laplace_transform( + (s - log(s + 1))/s**2, s, x, + simplify=True).rewrite(expint).expand() == + (expint(2, x)*Heaviside(x)).rewrite(Ei).rewrite(expint).expand()) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_lineintegrals.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_lineintegrals.py new file mode 100644 index 0000000000000000000000000000000000000000..d0af146b52406a153d033286f3fcfa79334d2a73 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_lineintegrals.py @@ -0,0 +1,13 @@ +from sympy.core.numbers import E +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.geometry.curve import Curve +from sympy.integrals.integrals import line_integrate + +s, t, x, y, z = symbols('s,t,x,y,z') + + +def test_lineintegral(): + c = Curve([E**t + 1, E**t - 1], (t, 0, log(2))) + assert line_integrate(x + y, c, [x, y]) == 3*sqrt(2) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_manual.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_manual.py new file mode 100644 index 0000000000000000000000000000000000000000..74cae4521ec97608a21553e0203be60c210387b3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_manual.py @@ -0,0 +1,714 @@ +from sympy.core.expr import Expr +from sympy.core.mul import Mul +from sympy.core.function import (Derivative, Function, diff, expand) +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.relational import Ne +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol, symbols) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.hyperbolic import (asinh, csch, cosh, coth, sech, sinh, tanh) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold +from sympy.functions.elementary.trigonometric import (acos, acot, acsc, asec, asin, atan, cos, cot, csc, sec, sin, tan) +from sympy.functions.special.delta_functions import Heaviside, DiracDelta +from sympy.functions.special.elliptic_integrals import (elliptic_e, elliptic_f) +from sympy.functions.special.error_functions import (Chi, Ci, Ei, Shi, Si, erf, erfi, fresnelc, fresnels, li) +from sympy.functions.special.gamma_functions import uppergamma +from sympy.functions.special.polynomials import (assoc_laguerre, chebyshevt, chebyshevu, gegenbauer, hermite, jacobi, laguerre, legendre) +from sympy.functions.special.zeta_functions import polylog +from sympy.integrals.integrals import (Integral, integrate) +from sympy.logic.boolalg import And +from sympy.integrals.manualintegrate import (manualintegrate, find_substitutions, + _parts_rule, integral_steps, manual_subs) +from sympy.testing.pytest import raises, slow + +x, y, z, u, n, a, b, c, d, e = symbols('x y z u n a b c d e') +f = Function('f') + + +def assert_is_integral_of(f: Expr, F: Expr): + assert manualintegrate(f, x) == F + assert F.diff(x).equals(f) + + +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)] + assert (-x**2, Rational(-1, 2), exp(u)) in find_substitutions(x * exp(-x**2), x, u) + assert not find_substitutions(Derivative(f(x), x)**2, x, 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_is_integral_of(1/sqrt(1-exp(2*x)), + log(sqrt(1 - exp(2*x)) - 1)/2 - log(sqrt(1 - exp(2*x)) + 1)/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 + + assert_is_integral_of(x**x*(log(x)+1), x**x) + + +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) == \ + 3*x**2*exp(x) - 6*x*exp(x) + 11*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) + assert manualintegrate(sec(x)**2, x) == tan(x) + assert manualintegrate(csc(x)**2, x) == -cot(x) + + assert manualintegrate(x * sec(x**2), x) == log(tan(x**2) + sec(x**2))/2 + assert manualintegrate(cos(x)*csc(sin(x)), x) == -log(cot(sin(x)) + csc(sin(x))) + assert manualintegrate(cos(3*x)*sec(x), x) == -x + sin(2*x) + assert manualintegrate(sin(3*x)*sec(x), x) == \ + -3*log(cos(x)) + 2*log(cos(x)**2) - 2*cos(x)**2 + + assert_is_integral_of(sinh(2*x), cosh(2*x)/2) + assert_is_integral_of(x*cosh(x**2), sinh(x**2)/2) + assert_is_integral_of(tanh(x), log(cosh(x))) + assert_is_integral_of(coth(x), log(sinh(x))) + f, F = sech(x), 2*atan(tanh(x/2)) + assert manualintegrate(f, x) == F + assert (F.diff(x) - f).rewrite(exp).simplify() == 0 # todo: equals returns None + f, F = csch(x), log(tanh(x/2)) + assert manualintegrate(f, x) == F + assert (F.diff(x) - f).rewrite(exp).simplify() == 0 + + +@slow +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 + + +@slow +def test_manualintegrate_inversetrig(): + # atan + 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 + ra = Symbol('a', real=True) + rb = Symbol('b', real=True) + assert manualintegrate(1/(ra + rb*x**2), x) == \ + Piecewise((atan(x/sqrt(ra/rb))/(rb*sqrt(ra/rb)), ra/rb > 0), + ((log(x - sqrt(-ra/rb)) - log(x + sqrt(-ra/rb)))/(2*sqrt(rb)*sqrt(-ra)), True)) + assert manualintegrate(1/(4 + rb*x**2), x) == \ + Piecewise((atan(x/(2*sqrt(1/rb)))/(2*rb*sqrt(1/rb)), 1/rb > 0), + (-I*(log(x - 2*sqrt(-1/rb)) - log(x + 2*sqrt(-1/rb)))/(4*sqrt(rb)), True)) + assert manualintegrate(1/(ra + 4*x**2), x) == \ + Piecewise((atan(2*x/sqrt(ra))/(2*sqrt(ra)), ra > 0), + ((log(x - sqrt(-ra)/2) - log(x + sqrt(-ra)/2))/(4*sqrt(-ra)), True)) + assert manualintegrate(1/(4 + 4*x**2), x) == atan(x) / 4 + + assert manualintegrate(1/(a + b*x**2), x) == Piecewise((atan(x/sqrt(a/b))/(b*sqrt(a/b)), Ne(a, 0)), + (-1/(b*x), True)) + + # asin + assert manualintegrate(1/sqrt(1-x**2), x) == asin(x) + assert manualintegrate(1/sqrt(4-4*x**2), x) == asin(x)/2 + assert manualintegrate(3/sqrt(1-9*x**2), x) == asin(3*x) + assert manualintegrate(1/sqrt(4-9*x**2), x) == asin(x*Rational(3, 2))/3 + + # asinh + assert manualintegrate(1/sqrt(x**2 + 1), x) == \ + asinh(x) + assert manualintegrate(1/sqrt(x**2 + 4), x) == \ + asinh(x/2) + assert manualintegrate(1/sqrt(4*x**2 + 4), x) == \ + asinh(x)/2 + assert manualintegrate(1/sqrt(4*x**2 + 1), x) == \ + asinh(2*x)/2 + assert manualintegrate(1/sqrt(ra*x**2 + 1), x) == \ + Piecewise((asin(x*sqrt(-ra))/sqrt(-ra), ra < 0), (asinh(sqrt(ra)*x)/sqrt(ra), ra > 0), (x, True)) + assert manualintegrate(1/sqrt(ra + x**2), x) == \ + Piecewise((asinh(x*sqrt(1/ra)), ra > 0), (log(2*x + 2*sqrt(ra + x**2)), True)) + + # log + assert manualintegrate(1/sqrt(x**2 - 1), x) == log(2*x + 2*sqrt(x**2 - 1)) + assert manualintegrate(1/sqrt(x**2 - 4), x) == log(2*x + 2*sqrt(x**2 - 4)) + assert manualintegrate(1/sqrt(4*x**2 - 4), x) == log(8*x + 4*sqrt(4*x**2 - 4))/2 + assert manualintegrate(1/sqrt(9*x**2 - 1), x) == log(18*x + 6*sqrt(9*x**2 - 1))/3 + assert manualintegrate(1/sqrt(ra*x**2 - 4), x) == \ + Piecewise((log(2*sqrt(ra)*sqrt(ra*x**2 - 4) + 2*ra*x)/sqrt(ra), Ne(ra, 0)), (-I*x/2, True)) + assert manualintegrate(1/sqrt(-ra + 4*x**2), x) == \ + Piecewise((asinh(2*x*sqrt(-1/ra))/2, ra < 0), (log(8*x + 4*sqrt(-ra + 4*x**2))/2, True)) + + # From https://www.wikiwand.com/en/List_of_integrals_of_inverse_trigonometric_functions + # asin + assert manualintegrate(asin(x), x) == x*asin(x) + sqrt(1 - x**2) + assert manualintegrate(asin(a*x), x) == Piecewise(((a*x*asin(a*x) + sqrt(-a**2*x**2 + 1))/a, Ne(a, 0)), (0, True)) + assert manualintegrate(x*asin(a*x), x) == \ + -a*Piecewise((-x*sqrt(-a**2*x**2 + 1)/(2*a**2) + + log(-2*a**2*x + 2*sqrt(-a**2)*sqrt(-a**2*x**2 + 1))/(2*a**2*sqrt(-a**2)), Ne(a**2, 0)), + (x**3/3, True))/2 + x**2*asin(a*x)/2 + # acos + assert manualintegrate(acos(x), x) == x*acos(x) - sqrt(1 - x**2) + assert manualintegrate(acos(a*x), x) == Piecewise(((a*x*acos(a*x) - sqrt(-a**2*x**2 + 1))/a, Ne(a, 0)), (pi*x/2, True)) + assert manualintegrate(x*acos(a*x), x) == \ + a*Piecewise((-x*sqrt(-a**2*x**2 + 1)/(2*a**2) + + log(-2*a**2*x + 2*sqrt(-a**2)*sqrt(-a**2*x**2 + 1))/(2*a**2*sqrt(-a**2)), Ne(a**2, 0)), + (x**3/3, True))/2 + x**2*acos(a*x)/2 + # atan + assert manualintegrate(atan(x), x) == x*atan(x) - log(x**2 + 1)/2 + assert manualintegrate(atan(a*x), x) == Piecewise(((a*x*atan(a*x) - log(a**2*x**2 + 1)/2)/a, Ne(a, 0)), (0, True)) + assert manualintegrate(x*atan(a*x), x) == -a*(x/a**2 - atan(x/sqrt(a**(-2)))/(a**4*sqrt(a**(-2))))/2 + x**2*atan(a*x)/2 + # acsc + assert manualintegrate(acsc(x), x) == x*acsc(x) + Integral(1/(x*sqrt(1 - 1/x**2)), x) + assert manualintegrate(acsc(a*x), x) == x*acsc(a*x) + Integral(1/(x*sqrt(1 - 1/(a**2*x**2))), x)/a + assert manualintegrate(x*acsc(a*x), x) == x**2*acsc(a*x)/2 + Integral(1/sqrt(1 - 1/(a**2*x**2)), x)/(2*a) + # asec + assert manualintegrate(asec(x), x) == x*asec(x) - Integral(1/(x*sqrt(1 - 1/x**2)), x) + assert manualintegrate(asec(a*x), x) == x*asec(a*x) - Integral(1/(x*sqrt(1 - 1/(a**2*x**2))), x)/a + assert manualintegrate(x*asec(a*x), x) == x**2*asec(a*x)/2 - Integral(1/sqrt(1 - 1/(a**2*x**2)), x)/(2*a) + # acot + assert manualintegrate(acot(x), x) == x*acot(x) + log(x**2 + 1)/2 + assert manualintegrate(acot(a*x), x) == Piecewise(((a*x*acot(a*x) + log(a**2*x**2 + 1)/2)/a, Ne(a, 0)), (pi*x/2, True)) + assert manualintegrate(x*acot(a*x), x) == a*(x/a**2 - atan(x/sqrt(a**(-2)))/(a**4*sqrt(a**(-2))))/2 + x**2*acot(a*x)/2 + + # piecewise + assert manualintegrate(1/sqrt(ra-rb*x**2), x) == \ + Piecewise((asin(x*sqrt(rb/ra))/sqrt(rb), And(-rb < 0, ra > 0)), + (asinh(x*sqrt(-rb/ra))/sqrt(-rb), And(-rb > 0, ra > 0)), + (log(-2*rb*x + 2*sqrt(-rb)*sqrt(ra - rb*x**2))/sqrt(-rb), Ne(rb, 0)), + (x/sqrt(ra), True)) + assert manualintegrate(1/sqrt(ra + rb*x**2), x) == \ + Piecewise((asin(x*sqrt(-rb/ra))/sqrt(-rb), And(ra > 0, rb < 0)), + (asinh(x*sqrt(rb/ra))/sqrt(rb), And(ra > 0, rb > 0)), + (log(2*sqrt(rb)*sqrt(ra + rb*x**2) + 2*rb*x)/sqrt(rb), Ne(rb, 0)), + (x/sqrt(ra), True)) + + +def test_manualintegrate_trig_substitution(): + assert manualintegrate(sqrt(16*x**2 - 9)/x, x) == \ + Piecewise((sqrt(16*x**2 - 9) - 3*acos(3/(4*x)), + And(x < Rational(3, 4), x > Rational(-3, 4)))) + assert manualintegrate(1/(x**4 * sqrt(25-x**2)), x) == \ + Piecewise((-sqrt(-x**2/25 + 1)/(125*x) - + (-x**2/25 + 1)**(3*S.Half)/(15*x**3), And(x < 5, x > -5))) + assert manualintegrate(x**7/(49*x**2 + 1)**(3 * S.Half), x) == \ + ((49*x**2 + 1)**(5*S.Half)/28824005 - + (49*x**2 + 1)**(3*S.Half)/5764801 + + 3*sqrt(49*x**2 + 1)/5764801 + 1/(5764801*sqrt(49*x**2 + 1))) + +def test_manualintegrate_trivial_substitution(): + assert manualintegrate((exp(x) - exp(-x))/x, x) == -Ei(-x) + Ei(x) + f = Function('f') + assert manualintegrate((f(x) - f(-x))/x, x) == \ + -Integral(f(-x)/x, x) + Integral(f(x)/x, x) + + +def test_manualintegrate_rational(): + assert manualintegrate(1/(4 - x**2), x) == -log(x - 2)/4 + log(x + 2)/4 + assert manualintegrate(1/(-1 + x**2), x) == log(x - 1)/2 - log(x + 1)/2 + + +def test_manualintegrate_special(): + f, F = 4*exp(-x**2/3), 2*sqrt(3)*sqrt(pi)*erf(sqrt(3)*x/3) + assert_is_integral_of(f, F) + f, F = 3*exp(4*x**2), 3*sqrt(pi)*erfi(2*x)/4 + assert_is_integral_of(f, F) + f, F = x**Rational(1, 3)*exp(-x/8), -16*uppergamma(Rational(4, 3), x/8) + assert_is_integral_of(f, F) + f, F = exp(2*x)/x, Ei(2*x) + assert_is_integral_of(f, F) + f, F = exp(1 + 2*x - x**2), sqrt(pi)*exp(2)*erf(x - 1)/2 + assert_is_integral_of(f, F) + f = sin(x**2 + 4*x + 1) + F = (sqrt(2)*sqrt(pi)*(-sin(3)*fresnelc(sqrt(2)*(2*x + 4)/(2*sqrt(pi))) + + cos(3)*fresnels(sqrt(2)*(2*x + 4)/(2*sqrt(pi))))/2) + assert_is_integral_of(f, F) + f, F = cos(4*x**2), sqrt(2)*sqrt(pi)*fresnelc(2*sqrt(2)*x/sqrt(pi))/4 + assert_is_integral_of(f, F) + f, F = sin(3*x + 2)/x, sin(2)*Ci(3*x) + cos(2)*Si(3*x) + assert_is_integral_of(f, F) + f, F = sinh(3*x - 2)/x, -sinh(2)*Chi(3*x) + cosh(2)*Shi(3*x) + assert_is_integral_of(f, F) + f, F = 5*cos(2*x - 3)/x, 5*cos(3)*Ci(2*x) + 5*sin(3)*Si(2*x) + assert_is_integral_of(f, F) + f, F = cosh(x/2)/x, Chi(x/2) + assert_is_integral_of(f, F) + f, F = cos(x**2)/x, Ci(x**2)/2 + assert_is_integral_of(f, F) + f, F = 1/log(2*x + 1), li(2*x + 1)/2 + assert_is_integral_of(f, F) + f, F = polylog(2, 5*x)/x, polylog(3, 5*x) + assert_is_integral_of(f, F) + f, F = 5/sqrt(3 - 2*sin(x)**2), 5*sqrt(3)*elliptic_f(x, Rational(2, 3))/3 + assert_is_integral_of(f, F) + f, F = sqrt(4 + 9*sin(x)**2), 2*elliptic_e(x, Rational(-9, 4)) + assert_is_integral_of(f, F) + + +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) == \ + Integral(Derivative(x**2 + 2*x + 3, y)) + assert manualintegrate(Derivative(sin(x), x, x, x, y), x) == \ + Derivative(sin(x), x, x, y) + + +def test_manualintegrate_Heaviside(): + assert_is_integral_of(DiracDelta(3*x+2), Heaviside(3*x+2)/3) + assert_is_integral_of(DiracDelta(3*x, 0), Heaviside(3*x)/3) + assert manualintegrate(DiracDelta(a+b*x, 1), x) == \ + Piecewise((DiracDelta(a + b*x)/b, Ne(b, 0)), (x*DiracDelta(a, 1), True)) + assert_is_integral_of(DiracDelta(x/3-1, 2), 3*DiracDelta(x/3-1, 1)) + assert manualintegrate(Heaviside(x), x) == x*Heaviside(x) + assert manualintegrate(x*Heaviside(2), x) == x**2/2 + assert manualintegrate(x*Heaviside(-2), x) == 0 + assert manualintegrate(x*Heaviside( x), x) == x**2*Heaviside( x)/2 + assert manualintegrate(x*Heaviside(-x), x) == x**2*Heaviside(-x)/2 + assert manualintegrate(Heaviside(2*x + 4), x) == (x+2)*Heaviside(2*x + 4) + assert manualintegrate(x*Heaviside(x), x) == x**2*Heaviside(x)/2 + assert manualintegrate(Heaviside(x + 1)*Heaviside(1 - x)*x**2, x) == \ + ((x**3/3 + Rational(1, 3))*Heaviside(x + 1) - Rational(2, 3))*Heaviside(-x + 1) + + y = Symbol('y') + assert manualintegrate(sin(7 + x)*Heaviside(3*x - 7), x) == \ + (- cos(x + 7) + cos(Rational(28, 3)))*Heaviside(3*x - S(7)) + + assert manualintegrate(sin(y + x)*Heaviside(3*x - y), x) == \ + (cos(y*Rational(4, 3)) - cos(x + y))*Heaviside(3*x - y) + + +def test_manualintegrate_orthogonal_poly(): + n = symbols('n') + a, b = 7, Rational(5, 3) + polys = [jacobi(n, a, b, x), gegenbauer(n, a, x), chebyshevt(n, x), + chebyshevu(n, x), legendre(n, x), hermite(n, x), laguerre(n, x), + assoc_laguerre(n, a, x)] + for p in polys: + integral = manualintegrate(p, x) + for deg in [-2, -1, 0, 1, 3, 5, 8]: + # some accept negative "degree", some do not + try: + p_subbed = p.subs(n, deg) + except ValueError: + continue + assert (integral.subs(n, deg).diff(x) - p_subbed).expand() == 0 + + # can also integrate simple expressions with these polynomials + q = x*p.subs(x, 2*x + 1) + integral = manualintegrate(q, x) + for deg in [2, 4, 7]: + assert (integral.subs(n, deg).diff(x) - q.subs(n, deg)).expand() == 0 + + # cannot integrate with respect to any other parameter + t = symbols('t') + for i in range(len(p.args) - 1): + new_args = list(p.args) + new_args[i] = t + assert isinstance(manualintegrate(p.func(*new_args), t), Integral) + + +@slow +def test_issue_6799(): + r, x, phi = 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) == \ + ((n*x/2 + sin(2*n*x)/4)*cos(n*phi) - sin(n*phi)*cos(n*x)**2/2)/n + assert r * integrate(integrand, limits).trigsimp() / pi == r * cos(n * phi) + assert not integrate(integrand, limits).has(Dummy) + + +def test_issue_12251(): + assert manualintegrate(x**y, x) == Piecewise( + (x**(y + 1)/(y + 1), Ne(y, -1)), (log(x), True)) + + +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] + + +def test_issue_6746(): + y = Symbol('y') + n = Symbol('n') + assert manualintegrate(y**x, x) == Piecewise( + (y**x/log(y), Ne(log(y), 0)), (x, True)) + assert manualintegrate(y**(n*x), x) == Piecewise( + (Piecewise( + (y**(n*x)/log(y), Ne(log(y), 0)), + (n*x, True) + )/n, Ne(n, 0)), + (x, True)) + assert manualintegrate(exp(n*x), x) == Piecewise( + (exp(n*x)/n, Ne(n, 0)), (x, True)) + + y = Symbol('y', positive=True) + assert manualintegrate((y + 1)**x, x) == (y + 1)**x/log(y + 1) + y = Symbol('y', zero=True) + assert manualintegrate((y + 1)**x, x) == x + y = Symbol('y') + n = Symbol('n', nonzero=True) + assert manualintegrate(y**(n*x), x) == Piecewise( + (y**(n*x)/log(y), Ne(log(y), 0)), (n*x, True))/n + y = Symbol('y', positive=True) + assert manualintegrate((y + 1)**(n*x), x) == \ + (y + 1)**(n*x)/(n*log(y + 1)) + a = Symbol('a', negative=True) + b = Symbol('b') + assert manualintegrate(1/(a + b*x**2), x) == atan(x/sqrt(a/b))/(b*sqrt(a/b)) + b = Symbol('b', negative=True) + assert manualintegrate(1/(a + b*x**2), x) == \ + atan(x/(sqrt(-a)*sqrt(-1/b)))/(b*sqrt(-a)*sqrt(-1/b)) + assert manualintegrate(1/((x**a + y**b + 4)*sqrt(a*x**2 + 1)), x) == \ + y**(-b)*Integral(x**(-a)/(y**(-b)*sqrt(a*x**2 + 1) + + x**(-a)*sqrt(a*x**2 + 1) + 4*x**(-a)*y**(-b)*sqrt(a*x**2 + 1)), x) + assert manualintegrate(1/((x**2 + 4)*sqrt(4*x**2 + 1)), x) == \ + Integral(1/((x**2 + 4)*sqrt(4*x**2 + 1)), x) + assert manualintegrate(1/(x - a**x + x*b**2), x) == \ + Integral(1/(-a**x + b**2*x + x), x) + + +@slow +def test_issue_2850(): + assert manualintegrate(asin(x)*log(x), x) == -x*asin(x) - sqrt(-x**2 + 1) \ + + (x*asin(x) + sqrt(-x**2 + 1))*log(x) - Integral(sqrt(-x**2 + 1)/x, x) + assert manualintegrate(acos(x)*log(x), x) == -x*acos(x) + sqrt(-x**2 + 1) + \ + (x*acos(x) - sqrt(-x**2 + 1))*log(x) + Integral(sqrt(-x**2 + 1)/x, x) + assert manualintegrate(atan(x)*log(x), x) == -x*atan(x) + (x*atan(x) - \ + log(x**2 + 1)/2)*log(x) + log(x**2 + 1)/2 + Integral(log(x**2 + 1)/x, x)/2 + + +def test_issue_9462(): + assert manualintegrate(sin(2*x)*exp(x), x) == exp(x)*sin(2*x)/5 - 2*exp(x)*cos(2*x)/5 + assert not integral_steps(sin(2*x)*exp(x), x).contains_dont_know() + assert manualintegrate((x - 3) / (x**2 - 2*x + 2)**2, x) == \ + Integral(x/(x**4 - 4*x**3 + 8*x**2 - 8*x + 4), x) \ + - 3*Integral(1/(x**4 - 4*x**3 + 8*x**2 - 8*x + 4), x) + + +def test_cyclic_parts(): + f = cos(x)*exp(x/4) + F = 16*exp(x/4)*sin(x)/17 + 4*exp(x/4)*cos(x)/17 + assert manualintegrate(f, x) == F and F.diff(x) == f + f = x*cos(x)*exp(x/4) + F = (x*(16*exp(x/4)*sin(x)/17 + 4*exp(x/4)*cos(x)/17) - + 128*exp(x/4)*sin(x)/289 + 240*exp(x/4)*cos(x)/289) + assert manualintegrate(f, x) == F and F.diff(x) == f + + +@slow +def test_issue_10847_slow(): + assert manualintegrate((4*x**4 + 4*x**3 + 16*x**2 + 12*x + 8) + / (x**6 + 2*x**5 + 3*x**4 + 4*x**3 + 3*x**2 + 2*x + 1), x) == \ + 2*x/(x**2 + 1) + 3*atan(x) - 1/(x**2 + 1) - 3/(x + 1) + + +@slow +def test_issue_10847(): + + assert manualintegrate(x**2 / (x**2 - c), x) == \ + c*Piecewise((atan(x/sqrt(-c))/sqrt(-c), Ne(c, 0)), (-1/x, True)) + x + + rc = Symbol('c', real=True) + assert manualintegrate(x**2 / (x**2 - rc), x) == \ + rc*Piecewise((atan(x/sqrt(-rc))/sqrt(-rc), rc < 0), + ((log(-sqrt(rc) + x) - log(sqrt(rc) + x))/(2*sqrt(rc)), True)) + x + + assert manualintegrate(sqrt(x - y) * log(z / x), x) == \ + 4*y**2*Piecewise((atan(sqrt(x - y)/sqrt(y))/sqrt(y), Ne(y, 0)), + (-1/sqrt(x - y), True))/3 - 4*y*sqrt(x - y)/3 + \ + 2*(x - y)**Rational(3, 2)*log(z/x)/3 + 4*(x - y)**Rational(3, 2)/9 + ry = Symbol('y', real=True) + rz = Symbol('z', real=True) + assert manualintegrate(sqrt(x - ry) * log(rz / x), x) == \ + 4*ry**2*Piecewise((atan(sqrt(x - ry)/sqrt(ry))/sqrt(ry), ry > 0), + ((log(-sqrt(-ry) + sqrt(x - ry)) - log(sqrt(-ry) + sqrt(x - ry)))/(2*sqrt(-ry)), True))/3 \ + - 4*ry*sqrt(x - ry)/3 + 2*(x - ry)**Rational(3, 2)*log(rz/x)/3 \ + + 4*(x - ry)**Rational(3, 2)/9 + + assert manualintegrate(sqrt(x) * log(x), x) == 2*x**Rational(3, 2)*log(x)/3 - 4*x**Rational(3, 2)/9 + + result = manualintegrate(sqrt(a*x + b) / x, x) + assert result == Piecewise((-2*b*Piecewise( + (-atan(sqrt(a*x + b)/sqrt(-b))/sqrt(-b), Ne(b, 0)), + (1/sqrt(a*x + b), True)) + 2*sqrt(a*x + b), Ne(a, 0)), + (sqrt(b)*log(x), True)) + assert piecewise_fold(result) == Piecewise( + (2*b*atan(sqrt(a*x + b)/sqrt(-b))/sqrt(-b) + 2*sqrt(a*x + b), Ne(a, 0) & Ne(b, 0)), + (-2*b/sqrt(a*x + b) + 2*sqrt(a*x + b), Ne(a, 0)), + (sqrt(b)*log(x), True)) + + ra = Symbol('a', real=True) + rb = Symbol('b', real=True) + assert manualintegrate(sqrt(ra*x + rb) / x, x) == \ + Piecewise( + (-2*rb*Piecewise( + (-atan(sqrt(ra*x + rb)/sqrt(-rb))/sqrt(-rb), rb < 0), + (-I*(log(-sqrt(rb) + sqrt(ra*x + rb)) - log(sqrt(rb) + sqrt(ra*x + rb)))/(2*sqrt(-rb)), True)) + + 2*sqrt(ra*x + rb), Ne(ra, 0)), + (sqrt(rb)*log(x), True)) + + assert expand(manualintegrate(sqrt(ra*x + rb) / (x + rc), x)) == \ + Piecewise((-2*ra*rc*Piecewise((atan(sqrt(ra*x + rb)/sqrt(ra*rc - rb))/sqrt(ra*rc - rb), ra*rc - rb > 0), + (log(-sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)) - + log(sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)), True)) + + 2*rb*Piecewise((atan(sqrt(ra*x + rb)/sqrt(ra*rc - rb))/sqrt(ra*rc - rb), ra*rc - rb > 0), + (log(-sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)) - + log(sqrt(-ra*rc + rb) + sqrt(ra*x + rb))/(2*sqrt(-ra*rc + rb)), True)) + + 2*sqrt(ra*x + rb), Ne(ra, 0)), (sqrt(rb)*log(rc + x), True)) + + assert manualintegrate(sqrt(2*x + 3) / (x + 1), x) == 2*sqrt(2*x + 3) - log(sqrt(2*x + 3) + 1) + log(sqrt(2*x + 3) - 1) + assert manualintegrate(sqrt(2*x + 3) / 2 * x, x) == (2*x + 3)**Rational(5, 2)/20 - (2*x + 3)**Rational(3, 2)/4 + assert manualintegrate(x**Rational(3,2) * log(x), x) == 2*x**Rational(5,2)*log(x)/5 - 4*x**Rational(5,2)/25 + assert manualintegrate(x**(-3) * log(x), x) == -log(x)/(2*x**2) - 1/(4*x**2) + assert manualintegrate(log(y)/(y**2*(1 - 1/y)), y) == \ + log(y)*log(-1 + 1/y) - Integral(log(-1 + 1/y)/y, y) + + +def test_issue_12899(): + assert manualintegrate(f(x,y).diff(x),y) == Integral(Derivative(f(x,y),x),y) + assert manualintegrate(f(x,y).diff(y).diff(x),y) == Derivative(f(x,y),x) + + +def test_constant_independent_of_symbol(): + assert manualintegrate(Integral(y, (x, 1, 2)), x) == \ + x*Integral(y, (x, 1, 2)) + + +def test_issue_12641(): + assert manualintegrate(sin(2*x), x) == -cos(2*x)/2 + assert manualintegrate(cos(x)*sin(2*x), x) == -2*cos(x)**3/3 + assert manualintegrate((sin(2*x)*cos(x))/(1 + cos(x)), x) == \ + -2*log(cos(x) + 1) - cos(x)**2 + 2*cos(x) + + +@slow +def test_issue_13297(): + assert manualintegrate(sin(x) * cos(x)**5, x) == -cos(x)**6 / 6 + + +def test_issue_14470(): + assert_is_integral_of(1/(x*sqrt(x + 1)), log(sqrt(x + 1) - 1) - log(sqrt(x + 1) + 1)) + + +@slow +def test_issue_9858(): + assert manualintegrate(exp(x)*cos(exp(x)), x) == sin(exp(x)) + assert manualintegrate(exp(2*x)*cos(exp(x)), x) == \ + exp(x)*sin(exp(x)) + cos(exp(x)) + res = manualintegrate(exp(10*x)*sin(exp(x)), x) + assert not res.has(Integral) + assert res.diff(x) == exp(10*x)*sin(exp(x)) + # an example with many similar integrations by parts + assert manualintegrate(sum(x*exp(k*x) for k in range(1, 8)), x) == ( + x*exp(7*x)/7 + x*exp(6*x)/6 + x*exp(5*x)/5 + x*exp(4*x)/4 + + x*exp(3*x)/3 + x*exp(2*x)/2 + x*exp(x) - exp(7*x)/49 -exp(6*x)/36 - + exp(5*x)/25 - exp(4*x)/16 - exp(3*x)/9 - exp(2*x)/4 - exp(x)) + + +def test_issue_8520(): + assert manualintegrate(x/(x**4 + 1), x) == atan(x**2)/2 + assert manualintegrate(x**2/(x**6 + 25), x) == atan(x**3/5)/15 + f = x/(9*x**4 + 4)**2 + assert manualintegrate(f, x).diff(x).factor() == f + + +def test_manual_subs(): + x, y = symbols('x y') + expr = log(x) + exp(x) + # if log(x) is y, then exp(y) is x + assert manual_subs(expr, log(x), y) == y + exp(exp(y)) + # if exp(x) is y, then log(y) need not be x + assert manual_subs(expr, exp(x), y) == log(x) + y + + raises(ValueError, lambda: manual_subs(expr, x)) + raises(ValueError, lambda: manual_subs(expr, exp(x), x, y)) + + +@slow +def test_issue_15471(): + f = log(x)*cos(log(x))/x**Rational(3, 4) + F = -128*x**Rational(1, 4)*sin(log(x))/289 + 240*x**Rational(1, 4)*cos(log(x))/289 + (16*x**Rational(1, 4)*sin(log(x))/17 + 4*x**Rational(1, 4)*cos(log(x))/17)*log(x) + assert_is_integral_of(f, F) + + +def test_quadratic_denom(): + f = (5*x + 2)/(3*x**2 - 2*x + 8) + assert manualintegrate(f, x) == 5*log(3*x**2 - 2*x + 8)/6 + 11*sqrt(23)*atan(3*sqrt(23)*(x - Rational(1, 3))/23)/69 + g = 3/(2*x**2 + 3*x + 1) + assert manualintegrate(g, x) == 3*log(4*x + 2) - 3*log(4*x + 4) + +def test_issue_22757(): + assert manualintegrate(sin(x), y) == y * sin(x) + + +def test_issue_23348(): + steps = integral_steps(tan(x), x) + constant_times_step = steps.substep.substep + assert constant_times_step.integrand == constant_times_step.constant * constant_times_step.other + + +def test_issue_23566(): + i = Integral(1/sqrt(x**2 - 1), (x, -2, -1)).doit(manual=True) + assert i == -log(4 - 2*sqrt(3)) + log(2) + assert str(i.n()) == '1.31695789692482' + + +def test_issue_25093(): + ap = Symbol('ap', positive=True) + an = Symbol('an', negative=True) + assert manualintegrate(exp(a*x**2 + b), x) == sqrt(pi)*exp(b)*erfi(sqrt(a)*x)/(2*sqrt(a)) + assert manualintegrate(exp(ap*x**2 + b), x) == sqrt(pi)*exp(b)*erfi(sqrt(ap)*x)/(2*sqrt(ap)) + assert manualintegrate(exp(an*x**2 + b), x) == -sqrt(pi)*exp(b)*erf(an*x/sqrt(-an))/(2*sqrt(-an)) + assert manualintegrate(sin(a*x**2 + b), x) == ( + sqrt(2)*sqrt(pi)*(sin(b)*fresnelc(sqrt(2)*sqrt(a)*x/sqrt(pi)) + + cos(b)*fresnels(sqrt(2)*sqrt(a)*x/sqrt(pi)))/(2*sqrt(a))) + assert manualintegrate(cos(a*x**2 + b), x) == ( + sqrt(2)*sqrt(pi)*(-sin(b)*fresnels(sqrt(2)*sqrt(a)*x/sqrt(pi)) + + cos(b)*fresnelc(sqrt(2)*sqrt(a)*x/sqrt(pi)))/(2*sqrt(a))) + + +def test_nested_pow(): + assert_is_integral_of(sqrt(x**2), x*sqrt(x**2)/2) + assert_is_integral_of(sqrt(x**(S(5)/3)), 6*x*sqrt(x**(S(5)/3))/11) + assert_is_integral_of(1/sqrt(x**2), x*log(x)/sqrt(x**2)) + assert_is_integral_of(x*sqrt(x**(-4)), x**2*sqrt(x**-4)*log(x)) + f = (c*(a+b*x)**d)**e + F1 = (c*(a + b*x)**d)**e*(a/b + x)/(d*e + 1) + F2 = (c*(a + b*x)**d)**e*(a/b + x)*log(a/b + x) + assert manualintegrate(f, x) == \ + Piecewise((Piecewise((F1, Ne(d*e, -1)), (F2, True)), Ne(b, 0)), (x*(a**d*c)**e, True)) + assert F1.diff(x).equals(f) + assert F2.diff(x).subs(d*e, -1).equals(f) + + +def test_manualintegrate_sqrt_linear(): + assert_is_integral_of((5*x**3+4)/sqrt(2+3*x), + 10*(3*x + 2)**(S(7)/2)/567 - 4*(3*x + 2)**(S(5)/2)/27 + + 40*(3*x + 2)**(S(3)/2)/81 + 136*sqrt(3*x + 2)/81) + assert manualintegrate(x/sqrt(a+b*x)**3, x) == \ + Piecewise((Mul(2, b**-2, a/sqrt(a + b*x) + sqrt(a + b*x)), Ne(b, 0)), (x**2/(2*a**(S(3)/2)), True)) + assert_is_integral_of((sqrt(3*x+3)+1)/((2*x+2)**(1/S(3))+1), + 3*sqrt(6)*(2*x + 2)**(S(7)/6)/14 - 3*sqrt(6)*(2*x + 2)**(S(5)/6)/10 - + 3*sqrt(6)*(2*x + 2)**(S.One/6)/2 + 3*(2*x + 2)**(S(2)/3)/4 - 3*(2*x + 2)**(S.One/3)/2 + + sqrt(6)*sqrt(2*x + 2)/2 + 3*log((2*x + 2)**(S.One/3) + 1)/2 + + 3*sqrt(6)*atan((2*x + 2)**(S.One/6))/2) + assert_is_integral_of(sqrt(x+sqrt(x)), + 2*sqrt(sqrt(x) + x)*(sqrt(x)/12 + x/3 - S(1)/8) + log(2*sqrt(x) + 2*sqrt(sqrt(x) + x) + 1)/8) + assert_is_integral_of(sqrt(2*x+3+sqrt(4*x+5))**3, + sqrt(2*x + sqrt(4*x + 5) + 3) * + (9*x/10 + 11*(4*x + 5)**(S(3)/2)/40 + sqrt(4*x + 5)/40 + (4*x + 5)**2/10 + S(11)/10)/2) + + +def test_manualintegrate_sqrt_quadratic(): + assert_is_integral_of(1/sqrt((x - I)**2-1), log(2*x + 2*sqrt(x**2 - 2*I*x - 2) - 2*I)) + assert_is_integral_of(1/sqrt(3*x**2+4*x+5), sqrt(3)*asinh(3*sqrt(11)*(x + S(2)/3)/11)/3) + assert_is_integral_of(1/sqrt(-3*x**2+4*x+5), sqrt(3)*asin(3*sqrt(19)*(x - S(2)/3)/19)/3) + assert_is_integral_of(1/sqrt(3*x**2+4*x-5), sqrt(3)*log(6*x + 2*sqrt(3)*sqrt(3*x**2 + 4*x - 5) + 4)/3) + assert_is_integral_of(1/sqrt(4*x**2-4*x+1), (x - S.Half)*log(x - S.Half)/(2*sqrt((x - S.Half)**2))) + assert manualintegrate(1/sqrt(a+b*x+c*x**2), x) == \ + Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(c, 0) & Ne(a - b**2/(4*c), 0)), + ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), Ne(c, 0)), + (2*sqrt(a + b*x)/b, Ne(b, 0)), (x/sqrt(a), True)) + + assert_is_integral_of((7*x+6)/sqrt(3*x**2+4*x+5), + 7*sqrt(3*x**2 + 4*x + 5)/3 + 4*sqrt(3)*asinh(3*sqrt(11)*(x + S(2)/3)/11)/9) + assert_is_integral_of((7*x+6)/sqrt(-3*x**2+4*x+5), + -7*sqrt(-3*x**2 + 4*x + 5)/3 + 32*sqrt(3)*asin(3*sqrt(19)*(x - S(2)/3)/19)/9) + assert_is_integral_of((7*x+6)/sqrt(3*x**2+4*x-5), + 7*sqrt(3*x**2 + 4*x - 5)/3 + 4*sqrt(3)*log(6*x + 2*sqrt(3)*sqrt(3*x**2 + 4*x - 5) + 4)/9) + assert manualintegrate((d+e*x)/sqrt(a+b*x+c*x**2), x) == \ + Piecewise(((-b*e/(2*c) + d) * + Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(a - b**2/(4*c), 0)), + ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), True)) + + e*sqrt(a + b*x + c*x**2)/c, Ne(c, 0)), + ((2*d*sqrt(a + b*x) + 2*e*(-a*sqrt(a + b*x) + (a + b*x)**(S(3)/2)/3)/b)/b, Ne(b, 0)), + ((d*x + e*x**2/2)/sqrt(a), True)) + + assert manualintegrate((3*x**3-x**2+2*x-4)/sqrt(x**2-3*x+2), x) == \ + sqrt(x**2 - 3*x + 2)*(x**2 + 13*x/4 + S(101)/8) + 135*log(2*x + 2*sqrt(x**2 - 3*x + 2) - 3)/16 + + assert_is_integral_of(sqrt(53225*x**2-66732*x+23013), + (x/2 - S(16683)/53225)*sqrt(53225*x**2 - 66732*x + 23013) + + 111576969*sqrt(2129)*asinh(53225*x/10563 - S(11122)/3521)/1133160250) + assert manualintegrate(sqrt(a+c*x**2), x) == \ + Piecewise((a*Piecewise((log(2*sqrt(c)*sqrt(a + c*x**2) + 2*c*x)/sqrt(c), Ne(a, 0)), + (x*log(x)/sqrt(c*x**2), True))/2 + x*sqrt(a + c*x**2)/2, Ne(c, 0)), + (sqrt(a)*x, True)) + assert manualintegrate(sqrt(a+b*x+c*x**2), x) == \ + Piecewise(((a/2 - b**2/(8*c)) * + Piecewise((log(b + 2*sqrt(c)*sqrt(a + b*x + c*x**2) + 2*c*x)/sqrt(c), Ne(a - b**2/(4*c), 0)), + ((b/(2*c) + x)*log(b/(2*c) + x)/sqrt(c*(b/(2*c) + x)**2), True)) + + (b/(4*c) + x/2)*sqrt(a + b*x + c*x**2), Ne(c, 0)), + (2*(a + b*x)**(S(3)/2)/(3*b), Ne(b, 0)), + (sqrt(a)*x, True)) + + assert_is_integral_of(x*sqrt(x**2+2*x+4), + (x**2/3 + x/6 + S(5)/6)*sqrt(x**2 + 2*x + 4) - 3*asinh(sqrt(3)*(x + 1)/3)/2) + + +def test_mul_pow_derivative(): + assert_is_integral_of(x*sec(x)*tan(x), x*sec(x) - log(tan(x) + sec(x))) + assert_is_integral_of(x*sec(x)**2, x*tan(x) + log(cos(x))) + assert_is_integral_of(x**3*Derivative(f(x), (x, 4)), + x**3*Derivative(f(x), (x, 3)) - 3*x**2*Derivative(f(x), (x, 2)) + + 6*x*Derivative(f(x), x) - 6*f(x)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_meijerint.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_meijerint.py new file mode 100644 index 0000000000000000000000000000000000000000..899bc96e63d6dd5bccd52856f15d3085e87d5807 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_meijerint.py @@ -0,0 +1,774 @@ +from sympy.core.function import expand_func +from sympy.core.numbers import (I, Rational, oo, pi) +from sympy.core.singleton import S +from sympy.core.sorting import default_sort_key +from sympy.functions.elementary.complexes import Abs, arg, re, unpolarify +from sympy.functions.elementary.exponential import (exp, exp_polar, log) +from sympy.functions.elementary.hyperbolic import cosh, acosh, sinh +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold +from sympy.functions.elementary.trigonometric import (cos, sin, sinc, asin) +from sympy.functions.special.error_functions import (erf, erfc) +from sympy.functions.special.gamma_functions import (gamma, polygamma) +from sympy.functions.special.hyper import (hyper, meijerg) +from sympy.integrals.integrals import (Integral, integrate) +from sympy.simplify.hyperexpand import hyperexpand +from sympy.simplify.simplify import simplify +from sympy.integrals.meijerint import (_rewrite_single, _rewrite1, + meijerint_indefinite, _inflate_g, _create_lookup_table, + meijerint_definite, meijerint_inversion) +from sympy.testing.pytest import slow +from sympy.core.random import (verify_numerically, + 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 + + t(x, 1, x) + t(x**2, 1, x**2) + t(x**2 + y*x**2, y + 1, x**2) + tn(x**2 + x) + tn(x**y) + + def u(expr, x): + from sympy.core.add import Add + r = _rewrite_single(expr, x) + e = Add(*[res[0]*res[2] for res in r[0]]).replace( + exp_polar, exp) # XXX Hack? + assert verify_numerically(e, expr, x) + + u(exp(-x)*sin(x), x) + + # The following has stopped working because hyperexpand changed slightly. + # It is probably not worth fixing + #u(exp(-x)*sin(x)*cos(x), x) + + # This one cannot be done numerically, since it comes out as a g-function + # of argument 4*pi + # NOTE This also tests a bug in inverse mellin transform (which used to + # turn exp(4*pi*I*t) into a factor of exp(4*pi*I)**t instead of + # exp_polar). + #u(exp(x)*sin(x), x) + assert _rewrite_single(exp(x)*sin(x), x) == \ + ([(-sqrt(2)/(2*sqrt(pi)), 0, + meijerg(((Rational(-1, 2), 0, Rational(1, 4), S.Half, Rational(3, 4)), (1,)), + ((), (Rational(-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) + + +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, + c: randcplx(), d: randcplx()} + integral = meijerint_indefinite(g, x) + assert integral is not None + assert verify_numerically(g.subs(subs), integral.diff(x).subs(subs), x) + t(1, x) + t(2, x) + t(1, 2*x) + t(1, x**2) + t(5, x**S('3/2')) + t(x**3, x) + t(3*x**S('3/2'), 4*x**S('7/3')) + + +def test_meijerint_definite(): + v, b = meijerint_definite(x, x, 0, 0) + assert v.is_zero and b is True + v, b = meijerint_definite(x, x, oo, oo) + assert v.is_zero and b is True + + +def test_inflate(): + subs = {a: randcplx()/10, b: randcplx()/10 + I, c: randcplx(), + d: randcplx(), y: randcplx()/10} + + def t(a, b, arg, n): + from sympy.core.mul import Mul + m1 = meijerg(a, b, arg) + m2 = Mul(*_inflate_g(m1, n)) + # NOTE: (the random number)**9 must still be on the principal sheet. + # Thus make b&d small to create random numbers of small imaginary part. + return verify_numerically(m1.subs(subs), m2.subs(subs), x, b=0.1, d=-0.1) + assert t([[a], [b]], [[c], [d]], x, 3) + 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.core.symbol import symbols + a, b, c = symbols('a b c', positive=True) + r = exp(-(x - a)**2)*exp(-(x - b)**2) + e = integrate(r, (x, 0, oo), meijerg=True) + 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), meijerg=True) + 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), meijerg=True)) == \ + sqrt(pi)/2*(1 + erf(a + b + c)) + assert simplify(integrate(exp(-(x + a + b + c)**2), (x, 0, oo), meijerg=True)) == \ + sqrt(pi)/2*(1 - erf(a + b + c)) + + +@slow +def test_meijerint(): + from sympy.core.function import expand + from sympy.core.symbol import symbols + s, t, mu = symbols('s t mu', real=True) + assert integrate(meijerg([], [], [0], [], s*t) + *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), + meijerg=True) == gamma(s + 1) + assert isinstance(integrate(x**s*meijerg([[], []], [[0], []], x), + (x, 0, oo), meijerg=False), + Integral) + + assert meijerint_indefinite(exp(x), x) == exp(x) + + # 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) + + # This tests various conditions and expansions: + assert 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*(2 - erfc(mu/(2*sigma))) + assert c == True + + i, _ = meijerint_definite(exp(-mu*x)*exp(sigma*x), x, 0, oo) + # TODO it would be nice to test the condition + assert simplify(i) == 1/(mu - sigma) + + # Test substitutions to change limits + assert meijerint_definite(exp(x), x, -oo, 2) == (exp(2), True) + # Note: causes a NaN in _check_antecedents + 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)) + + # 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) == \ + (sqrt(pi)/2, 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) + assert meijerint_definite(sinc(x)**2, x, -oo, oo) == (pi, True) + + # Test one of the extra conditions for 2 g-functinos + assert meijerint_definite(exp(-x)*sin(x), x, 0, oo) == (S.Half, True) + + # Test a bug + 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) + + # 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) + ) == 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') + 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)), + (re(s) < 1) & (re(s) < S(1)/2) & (re(a)/2 + re(b)/2 + re(s) > 0))) + + # 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)) + + # test better hyperexpand + assert integrate(exp(-x**2)*log(x), (x, 0, oo), meijerg=True) == \ + (sqrt(pi)*polygamma(0, S.Half)/4).expand() + + # Test hyperexpand bug. + from sympy.functions.special.gamma_functions import lowergamma + n = symbols('n', integer=True) + assert simplify(integrate(exp(-x)*x**n, x, meijerg=True)) == \ + 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)*alpha*gamma(alpha + 1)*meijerg(((), (alpha/2 + S.Half, + alpha/2 + 1)), ((0, 0, S.Half), (Rational(-1, 2),)), alpha**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.Half)*((-1)**s + 1)*gamma(s/2 + S.Half)/2 + + +def test_bessel(): + from sympy.functions.special.bessel import (besseli, besselj) + 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)) + 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.Half)), + (x, 1, oo), meijerg=True, conds='none') + *2/((z/2)**y*sqrt(pi)*gamma(S.Half - y))) == \ + besselj(y, z) + + # Werner Rosenheinrich + # SOME INDEFINITE INTEGRALS OF BESSEL FUNCTIONS + + assert integrate(x*besselj(0, x), x, meijerg=True) == x*besselj(1, x) + assert integrate(x*besseli(0, x), x, meijerg=True) == x*besseli(1, x) + # TODO can do higher powers, but come out as high order ... should they be + # 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 + # 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 + assert integrate(besselj(0, x)*besselj(1, x), x, meijerg=True) == \ + -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 + assert integrate(besselj(0, x)*besselj(1, x)/x, x, meijerg=True) == \ + (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? + # TODO sin(x)*besselj(0, x) etc come out a mess + # TODO can x*log(x)*besselj(0, x) be done? + # TODO how does besselj(1, x)*besselj(0, x+a) work? + # TODO more indefinite integrals when struve functions etc are implemented + + # test a substitution + assert integrate(besselj(1, x**2)*x, x, meijerg=True) == \ + -besselj(0, x**2)/2 + + +def test_inversion(): + from sympy.functions.special.bessel import besselj + from sympy.functions.special.delta_functions import Heaviside + + 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) + assert inv(1/sqrt(1 + s**2)) == besselj(0, t)*Heaviside(t) + + # Test some antcedents checking. + assert meijerint_inversion(sqrt(s)/sqrt(1 + s**2), s, t) is None + assert inv(exp(s**2)) is None + assert meijerint_inversion(exp(-s**2), s, t) is None + + +def test_inversion_conditional_output(): + from sympy.core.symbol import Symbol + from sympy.integrals.transforms import InverseLaplaceTransform + + a = Symbol('a', positive=True) + F = sqrt(pi/a)*exp(-2*sqrt(a)*sqrt(s)) + f = meijerint_inversion(F, s, t) + assert not f.is_Piecewise + + b = Symbol('b', real=True) + F = F.subs(a, b) + f2 = meijerint_inversion(F, s, t) + assert f2.is_Piecewise + # first piece is same as f + assert f2.args[0][0] == f.subs(a, b) + # last piece is an unevaluated transform + assert f2.args[-1][1] + ILT = InverseLaplaceTransform(F, s, t, None) + assert f2.args[-1][0] == ILT or f2.args[-1][0] == ILT.as_integral + + +def test_inversion_exp_real_nonreal_shift(): + from sympy.core.symbol import Symbol + from sympy.functions.special.delta_functions import DiracDelta + r = Symbol('r', real=True) + c = Symbol('c', extended_real=False) + a = 1 + 2*I + z = Symbol('z') + assert not meijerint_inversion(exp(r*s), s, t).is_Piecewise + assert meijerint_inversion(exp(a*s), s, t) is None + assert meijerint_inversion(exp(c*s), s, t) is None + f = meijerint_inversion(exp(z*s), s, t) + assert f.is_Piecewise + assert isinstance(f.args[0][0], DiracDelta) + + +@slow +def test_lookup_table(): + from sympy.core.random import uniform, randrange + from sympy.core.add import Add + from sympy.integrals.meijerint import z as z_dummy + table = {} + _create_lookup_table(table) + for l in table.values(): + for formula, terms, cond, hint in sorted(l, key=default_sort_key): + subs = {} + for ai in list(formula.free_symbols) + [z_dummy]: + if hasattr(ai, 'properties') and ai.properties: + # these Wilds match positive integers + subs[ai] = randrange(1, 10) + else: + subs[ai] = 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) + + # Now test that the meijer g-function is indeed as advertised. + expanded = Add(*[f*x for (f, x) in terms]) + a, b = formula.n(subs=subs), expanded.n(subs=subs) + r = min(abs(a), abs(b)) + if r < 1: + assert abs(a - b).n() <= 1e-10 + else: + assert (abs(a - b)/r).n() <= 1e-10 + + +def test_branch_bug(): + from sympy.functions.special.gamma_functions import lowergamma + from sympy.simplify.powsimp import powdenest + # TODO gammasimp 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(Rational(2, 3))/3/gamma(Rational(5, 3)) + assert integrate(erf(x**3), x, meijerg=True) == \ + 2*x*erf(x**3)*gamma(Rational(2, 3))/(3*gamma(Rational(5, 3))) \ + - 2*gamma(Rational(2, 3))*lowergamma(Rational(2, 3), x**6)/(3*sqrt(pi)*gamma(Rational(5, 3))) + + +def test_linear_subs(): + from sympy.functions.special.bessel 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) + + +@slow +def test_probability(): + # various integrals from probability theory + from sympy.core.function import expand_mul + from sympy.core.symbol import (Symbol, symbols) + from sympy.simplify.gammasimp import gammasimp + from sympy.simplify.powsimp import powsimp + mu1, mu2 = symbols('mu1 mu2', nonzero=True) + sigma1, sigma2 = symbols('sigma1 sigma2', positive=True) + rate = Symbol('lambda', positive=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) + + assert integrate(normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) == 1 + 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 + assert integrate(x**3*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) \ + == 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), + (x, -oo, oo), (y, -oo, oo), meijerg=True) == mu1 + assert integrate(y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), + (x, -oo, oo), (y, -oo, oo), meijerg=True) == mu2 + assert integrate(x*y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), + (x, -oo, oo), (y, -oo, oo), meijerg=True) == mu1*mu2 + assert integrate((x + y + 1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), + (x, -oo, oo), (y, -oo, oo), meijerg=True) == 1 + mu1 + mu2 + assert integrate((x + y - 1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), + (x, -oo, oo), (y, -oo, oo), meijerg=True) == \ + -1 + mu1 + mu2 + + i = integrate(x**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), + (x, -oo, oo), (y, -oo, oo), meijerg=True) + assert not i.has(Abs) + 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 + + 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 + + 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) + 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 = 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) + assert integrate(betadist, (x, 0, oo), meijerg=True) == 1 + i = integrate(x*betadist, (x, 0, oo), meijerg=True, conds='separate') + assert (gammasimp(i[0]), i[1]) == (alpha/(beta - 1), 1 < beta) + j = integrate(x**2*betadist, (x, 0, oo), meijerg=True, conds='separate') + assert j[1] == (beta > 2) + assert gammasimp(j[0] - i[0]**2) == (alpha + beta - 1)*alpha \ + /(beta - 2)/(beta - 1)**2 + + # Beta distribution + # NOTE: this is evaluated using antiderivatives. It also tests that + # meijerint_indefinite returns the simplest possible answer. + a, b = symbols('a b', positive=True) + betadist = x**(a - 1)*(-x + 1)**(b - 1)*gamma(a + b)/(gamma(a)*gamma(b)) + assert simplify(integrate(betadist, (x, 0, 1), meijerg=True)) == 1 + 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) + assert simplify(integrate(x**y*betadist, (x, 0, 1), meijerg=True)) == \ + 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) + 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) + 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) + 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) + assert gammasimp(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) + 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') + ) == 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') + ) == 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) + 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') + ) == d2/(d2 - 2) + assert simplify(integrate(x**2*f, (x, 0, oo), meijerg=True, conds='none') + ) == d2**2*(d1 + 2)/d1/(d2 - 4)/(d2 - 2) + + # TODO gamma, rayleigh + + # inverse gaussian + lamda, mu = symbols('lamda mu', positive=True) + dist = sqrt(lamda/2/pi)*x**(Rational(-3, 2))*exp(-lamda*(x - mu)**2/x/2/mu**2) + mysimp = lambda expr: simplify(expr.rewrite(exp)) + assert mysimp(integrate(dist, (x, 0, oo))) == 1 + assert mysimp(integrate(x*dist, (x, 0, oo))) == mu + assert mysimp(integrate((x - mu)**2*dist, (x, 0, oo))) == mu**3/lamda + assert mysimp(integrate((x - mu)**3*dist, (x, 0, oo))) == 3*mu**5/lamda**2 + + # Levi + c = Symbol('c', positive=True) + assert integrate(sqrt(c/2/pi)*exp(-c/2/(x - mu))/(x - mu)**S('3/2'), + (x, mu, oo)) == 1 + # higher moments oo + + # log-logistic + alpha, beta = symbols('alpha beta', positive=True) + distn = (beta/alpha)*x**(beta - 1)/alpha**(beta - 1)/ \ + (1 + x**beta/alpha**beta)**2 + # FIXME: If alpha, beta are not declared as finite the line below hangs + # after the changes in: + # https://github.com/sympy/sympy/pull/16603 + 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) + # (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) + + # weibull + k = Symbol('k', positive=True) + n = Symbol('n', positive=True) + 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) + + # rice distribution + from sympy.functions.special.bessel 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) + assert integrate(rice, (x, 0, oo), meijerg=True) == 1 + # can someone verify higher moments? + + # Laplace distribution + mu = Symbol('mu', real=True) + b = Symbol('b', positive=True) + laplace = exp(-abs(x - mu)/b)/2/b + assert integrate(laplace, (x, -oo, oo), meijerg=True) == 1 + assert integrate(x*laplace, (x, -oo, oo), meijerg=True) == mu + assert integrate(x**2*laplace, (x, -oo, oo), meijerg=True) == \ + 2*b**2 + mu**2 + + # TODO are there other distributions supported on (-oo, oo) that we can do? + + # misc tests + k = Symbol('k', positive=True) + assert gammasimp(expand_mul(integrate(log(x)*x**(k - 1)*exp(-x)/gamma(k), + (x, 0, oo)))) == polygamma(0, k) + + +@slow +def test_expint(): + """ Test various exponential integrals. """ + from sympy.core.symbol import Symbol + from sympy.functions.elementary.hyperbolic import sinh + from sympy.functions.special.error_functions import (Chi, Ci, Ei, Shi, Si, expint) + assert simplify(unpolarify(integrate(exp(-z*x)/x**y, (x, 1, oo), + meijerg=True, conds='none' + ).rewrite(expint).expand(func=True))) == expint(y, z) + + assert integrate(exp(-z*x)/x, (x, 1, oo), meijerg=True, + conds='none').rewrite(expint).expand() == \ + 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) + 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() + + 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 + 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) + assert integrate(exp(-x)/x**2, x, meijerg=True).rewrite(expint).expand() \ + == 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) + + 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, + meijerg=True).rewrite(expint).expand(func=True))) == \ + -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) + assert integrate(Shi(x), x, meijerg=True) == x*Shi(x) - cosh(x) + assert integrate(Chi(u), u, meijerg=True).expand() == u*Chi(u) - sinh(u) + + 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.functions.elementary.hyperbolic import (acosh, acoth) + from sympy.functions.elementary.trigonometric import (asin, atan) + from sympy.functions.special.bessel import besselj + from sympy.functions.special.error_functions import (Chi, E1, Shi, Si) + from sympy.integrals.transforms import (fourier_transform, laplace_transform) + assert (laplace_transform(Si(x), x, s, simplify=True) == + ((-atan(s) + pi/2)/s, 0, True)) + + assert laplace_transform(Shi(x), x, s, simplify=True) == ( + acoth(s)/s, -oo, s**2 > 1) + + # where should the logs be simplified? + assert laplace_transform(Chi(x), x, s, simplify=True) == ( + (log(s**(-2)) - log(1 - 1/s**2))/(2*s), -oo, s**2 > 1) + + # TODO maybe simplify the inequalities? when the simplification + # allows for generators instead of symbols this will work + assert laplace_transform(besselj(a, x), x, s)[1:] == \ + (0, (re(a) > -2) & (re(a) > -1)) + + # NOTE s < 0 can be done, but argument reduction is not good enough yet + ans = fourier_transform(besselj(1, x)/x, x, s, noconds=False) + assert (ans[0].factor(deep=True).expand(), ans[1]) == \ + (Piecewise((0, (s > 1/(2*pi)) | (s < -1/(2*pi))), + (2*sqrt(-4*pi**2*s**2 + 1), True)), s > 0) + # 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.Half + sqrt(2)/2) + + assert integrate(1/x/sqrt(1 - x**2), x, meijerg=True) == \ + Piecewise((-acosh(1/x), abs(x**(-2)) > 1), (I*asin(1/x), True)) + + +def test_issue_6122(): + assert integrate(exp(-I*x**2), (x, -oo, oo), meijerg=True) == \ + -I*sqrt(pi)*exp(I*pi/4) + + +def test_issue_6252(): + expr = 1/x/(a + b*x)**Rational(1, 3) + anti = integrate(expr, x, meijerg=True) + assert not anti.has(hyper) + # XXX the expression is a mess, but actually upon differentiation and + # putting in numerical values seems to work... + + +def test_issue_6348(): + assert integrate(exp(I*x)/(1 + x**2), (x, -oo, oo)).simplify().rewrite(exp) \ + == pi*exp(-1) + + +def test_fresnel(): + from sympy.functions.special.error_functions import (fresnelc, fresnels) + + 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_issue_6860(): + assert meijerint_indefinite(x**x**x, x) is None + + +def test_issue_7337(): + f = meijerint_indefinite(x*sqrt(2*x + 3), x).together() + assert f == sqrt(2*x + 3)*(2*x**2 + x - 3)/5 + assert f._eval_interval(x, S.NegativeOne, S.One) == Rational(2, 5) + + +def test_issue_8368(): + assert meijerint_indefinite(cosh(x)*exp(-x*t), x) == ( + (-t - 1)*exp(x) + (-t + 1)*exp(-x))*exp(-t*x)/2/(t**2 - 1) + + +def test_issue_10211(): + from sympy.abc import h, w + assert integrate((1/sqrt((y-x)**2 + h**2)**3), (x,0,w), (y,0,w)) == \ + 2*sqrt(1 + w**2/h**2)/h - 2/h + + +def test_issue_11806(): + from sympy.core.symbol import symbols + y, L = symbols('y L', positive=True) + assert integrate(1/sqrt(x**2 + y**2)**3, (x, -L, L)) == \ + 2*L/(y**2*sqrt(L**2 + y**2)) + +def test_issue_10681(): + from sympy.polys.domains.realfield import RR + from sympy.abc import R, r + f = integrate(r**2*(R**2-r**2)**0.5, r, meijerg=True) + g = (1.0/3)*R**1.0*r**3*hyper((-0.5, Rational(3, 2)), (Rational(5, 2),), + r**2*exp_polar(2*I*pi)/R**2) + assert RR.almosteq((f/g).n(), 1.0, 1e-12) + +def test_issue_13536(): + from sympy.core.symbol import Symbol + a = Symbol('a', positive=True) + assert integrate(1/x**2, (x, oo, a)) == -1/a + + +def test_issue_6462(): + from sympy.core.symbol import Symbol + x = Symbol('x') + n = Symbol('n') + # Not the actual issue, still wrong answer for n = 1, but that there is no + # exception + assert integrate(cos(x**n)/x**n, x, meijerg=True).subs(n, 2).equals( + integrate(cos(x**2)/x**2, x, meijerg=True)) + + +def test_indefinite_1_bug(): + assert integrate((b + t)**(-a), t, meijerg=True) == -b*(1 + t/b)**(1 - a)/(a*b**a - b**a) + + +def test_pr_23583(): + # This result is wrong. Check whether new result is correct when this test fail. + assert integrate(1/sqrt((x - I)**2-1), meijerg=True) == \ + Piecewise((acosh(x - I), Abs((x - I)**2) > 1), (-I*asin(x - I), True)) + + +# 25786 +def test_integrate_function_of_square_over_negatives(): + assert integrate(exp(-x**2), (x,-5,0), meijerg=True) == sqrt(pi)/2 * erf(5) + + +def test_issue_25949(): + from sympy.core.symbol import symbols + y = symbols("y", nonzero=True) + assert integrate(cosh(y*(x + 1)), (x, -1, -0.25), meijerg=True) == sinh(0.75*y)/y diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_prde.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_prde.py new file mode 100644 index 0000000000000000000000000000000000000000..a7429ea8634c742eb77cdb26f99b2cb15853cd42 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_prde.py @@ -0,0 +1,322 @@ +"""Most of these tests come from the examples in Bronstein's book.""" +from sympy.integrals.risch import DifferentialExtension, derivation +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, param_poly_rischDE, param_rischDE, + prde_cancel_liouvillian) + +from sympy.polys.polymatrix import PolyMatrix as Matrix + +from sympy.core.numbers import Rational +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.polys.domains.rationalfield import QQ +from sympy.polys.polytools import Poly +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, domain='ZZ(x)'), (Poly(1, t, domain='ZZ(x)'), Poly(1, t, + domain='ZZ(x)')), [(Poly(x*t, t, domain='ZZ(x)'), + Poly(t**2 + 1, t, domain='ZZ(x)')), (Poly(1, t, domain='ZZ(x)'), + Poly(t**2 + 1, t, domain='ZZ(x)'))], Poly(1, t, domain='ZZ(x)')) + 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, domain='ZZ[x]')), [(Poly(t, t), + Poly(1, t)), (Poly(x*t, t), Poly(1, t, domain='ZZ[x]')), (Poly(x*t**2, t), + Poly(1, t, domain='ZZ[x]'))], 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, domain='ZZ[x]'), [(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, domain='ZZ[x]'), [(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, domain='ZZ[x]'), [(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, domain='QQ'), Poly(0, x, domain='QQ'), Poly(0, x, domain='QQ')), + Matrix([[1, 1, -1], [5, 1, 1]], x)) + 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, domain='QQ'), Poly(t**2, t, domain='QQ'), Poly(t**3, t, domain='QQ')), + Matrix(0, 3, [], t)) + 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)]}) + assert prde_linear_constraints(Poly(1, t), Poly(0, t), G, DE) == \ + ((Poly(0, t, domain='QQ[x]'), Poly(0, t, domain='QQ[x]')), Matrix([[2*x, -x]], t)) + + +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]], t) + u = Matrix([[(x + 1)/(x - 1)], [x + 1], [0]], t) + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + R = QQ.frac_field(x)[t] + assert constant_system(A, u, DE) == \ + (Matrix([[1, 0, 0], + [0, 1, 0], + [0, 0, 0], + [0, 0, 1]], ring=R), Matrix([0, 1, 0, 0], ring=R)) + + +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, domain='ZZ(x)'), + [Poly(2*x, t, domain='ZZ(x)'), Poly(-x, t, domain='ZZ(x)')], + [Poly(-x**2, t, domain='ZZ(x)'), Poly(0, t, domain='ZZ(x)')], 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]], x)) + 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]], x)) + assert prde_no_cancel_b_large(Poly(x, x), [Poly(x**2, x), Poly(1, x)], 1, DE) == \ + ([Poly(x, x, domain='ZZ'), Poly(0, x, domain='ZZ')], Matrix([[1, -1, 0, 0], + [1, 0, -1, 0], + [0, 1, 0, -1]], x)) + # 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)] + R = QQ.frac_field(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 + (Rational(-11, 12) - x**3/24)*t + x/24, t), + Poly(x/3*t**3 - x**2/6*t**2 + (Rational(-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, Rational(-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]], ring=R)) + + # TODO: Add test for deg(b) <= 0 with b small + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) + b = Poly(-1/x**2, t, field=True) # deg(b) == 0 + q = [Poly(x**i*t**j, t, field=True) for i in range(2) for j in range(3)] + h, A = prde_no_cancel_b_small(b, q, 3, DE) + V = A.nullspace() + R = QQ.frac_field(x)[t] + assert len(V) == 1 + assert V[0] == Matrix([Rational(-1, 2), 0, 0, 1, 0, 0]*3, ring=R) + assert (Matrix([h])*V[0][6:, :])[0] == Poly(x**2/2, t, domain='QQ(x)') + assert (Matrix([q])*V[0][:6, :])[0] == Poly(x - S.Half, t, domain='QQ(x)') + + +def test_prde_cancel_liouvillian(): + ### 1. case == 'primitive' + # used when integrating f = log(x) - log(x - 1) + # Not taken from 'the' book + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + p0 = Poly(0, t, field=True) + p1 = Poly((x - 1)*t, t, domain='ZZ(x)') + p2 = Poly(x - 1, t, domain='ZZ(x)') + p3 = Poly(-x**2 + x, t, domain='ZZ(x)') + h, A = prde_cancel_liouvillian(Poly(-1/(x - 1), t), [Poly(-x + 1, t), Poly(1, t)], 1, DE) + V = A.nullspace() + assert h == [p0, p0, p1, p0, p0, p0, p0, p0, p0, p0, p2, p3, p0, p0, p0, p0] + assert A.rank() == 16 + assert (Matrix([h])*V[0][:16, :]) == Matrix([[Poly(0, t, domain='QQ(x)')]]) + + ### 2. case == 'exp' + # used when integrating log(x/exp(x) + 1) + # Not taken from book + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t, t)]}) + assert prde_cancel_liouvillian(Poly(0, t, domain='QQ[x]'), [Poly(1, t, domain='QQ(x)')], 0, DE) == \ + ([Poly(1, t, domain='QQ'), Poly(x, t, domain='ZZ(x)')], Matrix([[-1, 0, 1]], DE.t)) + + +def test_param_poly_rischDE(): + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + a = Poly(x**2 - x, x, field=True) + b = Poly(1, x, field=True) + q = [Poly(x, x, field=True), Poly(x**2, x, field=True)] + h, A = param_poly_rischDE(a, b, q, 3, DE) + + assert A.nullspace() == [Matrix([0, 1, 1, 1], DE.t)] # c1, c2, d1, d2 + # Solution of a*Dp + b*p = c1*q1 + c2*q2 = q2 = x**2 + # is d1*h1 + d2*h2 = h1 + h2 = x. + assert h[0] + h[1] == Poly(x, x, domain='QQ') + # a*Dp + b*p = q1 = x has no solution. + + a = Poly(x**2 - x, x, field=True) + b = Poly(x**2 - 5*x + 3, x, field=True) + q = [Poly(1, x, field=True), Poly(x, x, field=True), + Poly(x**2, x, field=True)] + h, A = param_poly_rischDE(a, b, q, 3, DE) + + assert A.nullspace() == [Matrix([3, -5, 1, -5, 1, 1], DE.t)] + p = -Poly(5, DE.t)*h[0] + h[1] + h[2] # Poly(1, x) + assert a*derivation(p, DE) + b*p == Poly(x**2 - 5*x + 3, x, domain='QQ') + + +def test_param_rischDE(): + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + p1, px = Poly(1, x, field=True), Poly(x, x, field=True) + G = [(p1, px), (p1, p1), (px, p1)] # [1/x, 1, x] + h, A = param_rischDE(-p1, Poly(x**2, x, field=True), G, DE) + assert len(h) == 3 + p = [hi[0].as_expr()/hi[1].as_expr() for hi in h] + V = A.nullspace() + assert len(V) == 2 + assert V[0] == Matrix([-1, 1, 0, -1, 1, 0], DE.t) + y = -p[0] + p[1] + 0*p[2] # x + assert y.diff(x) - y/x**2 == 1 - 1/x # Dy + f*y == -G0 + G1 + 0*G2 + + # the below test computation takes place while computing the integral + # of 'f = log(log(x + exp(x)))' + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) + G = [(Poly(t + x, t, domain='ZZ(x)'), Poly(1, t, domain='QQ')), (Poly(0, t, domain='QQ'), Poly(1, t, domain='QQ'))] + h, A = param_rischDE(Poly(-t - 1, t, field=True), Poly(t + x, t, field=True), G, DE) + assert len(h) == 5 + p = [hi[0].as_expr()/hi[1].as_expr() for hi in h] + V = A.nullspace() + assert len(V) == 3 + assert V[0] == Matrix([0, 0, 0, 0, 1, 0, 0], DE.t) + y = 0*p[0] + 0*p[1] + 1*p[2] + 0*p[3] + 0*p[4] + assert y.diff(t) - y/(t + x) == 0 # Dy + f*y = 0*G0 + 0*G1 + + +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, domain='ZZ[x]')), + [(Poly(-x*t, t), Poly(1, t, domain='ZZ[x]'))]) + + +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, domain='QQ')), [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, domain='QQ')), [0]) + + +def test_is_log_deriv_k_t_radical(): + DE = DifferentialExtension(extension={'D': [Poly(1, x)], 'exts': [None], + 'extargs': [None]}) + 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)], + 'exts': [None, 'exp', 'log'], 'extargs': [None, 2*x, 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)], + 'exts': [None, 'exp', 'log'], 'extargs': [None, x, 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)], + 'exts': [None, 'log', 'log'], 'extargs': [None, x, x + 1]}) + 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)], + 'exts': [None, 'log', 'exp'], 'extargs': [None, x, 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)], + 'exts': [None, 'log'], 'extargs': [None, x**2]}) + assert is_deriv_k(Poly(x, t1), Poly(1, t1), DE) == \ + ([(t1, S.Half)], t1/2, 1) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2/(1 + x), t0)], + 'exts': [None, 'log'], 'extargs': [None, x**2 + 2*x + 1]}) + assert is_deriv_k(Poly(1 + x, t0), Poly(1, t0), DE) == \ + ([(t0, S.Half)], t0/2, 1) + + # Issue 10798 + # DE = DifferentialExtension(log(1/x), x) + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-1/x, t)], + 'exts': [None, 'log'], 'extargs': [None, 1/x]}) + assert is_deriv_k(Poly(1, t), Poly(x, t), DE) == ([(t, 1)], t, 1) + + +def test_is_log_deriv_k_t_radical_in_field(): + # NOTE: any potential constant factor 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, t*x**5) + assert is_log_deriv_k_t_radical_in_field(Poly(2 + 3*t, t), Poly(5*x*t, t), DE) == \ + (5, 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, t + 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, t*x**5) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_quadrature.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_quadrature.py new file mode 100644 index 0000000000000000000000000000000000000000..97471dbdbc13fda0bce7a8823ff2cefac4ab8802 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_quadrature.py @@ -0,0 +1,601 @@ +from sympy.core import S, Rational +from sympy.integrals.quadrature import (gauss_legendre, gauss_laguerre, + gauss_hermite, gauss_gen_laguerre, + gauss_chebyshev_t, gauss_chebyshev_u, + gauss_jacobi, gauss_lobatto) + + +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, Rational(-1, 2), 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, Rational(-1, 2), 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, Rational(-1, 2), 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, Rational(-1, 2), 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, Rational(-1, 2), 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, Rational(-1, 2), 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, Rational(-1, 2), 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, Rational(-1, 2), S.Half, 17) + assert [str(r) for r in x] == [ + '-0.30901699437494742', + '0.80901699437494742'] + assert [str(r) for r in w] == [ + '0.86831485369082398', + '2.2732777998989693'] + + x, w = gauss_jacobi(3, Rational(-1, 2), 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, Rational(-1, 2), 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, Rational(-1, 2), 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.090675770007435372', + '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.24025307335204215', + '0.46247529557426437'] + assert [str(r) for r in w] == [ + '0.48514624517838660', + '0.58152042148828007'] + + 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, Rational(-1, 2), 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'] + + +def test_lobatto(): + x, w = gauss_lobatto(2, 17) + assert [str(r) for r in x] == [ + '-1', + '1'] + assert [str(r) for r in w] == [ + '1.0000000000000000', + '1.0000000000000000'] + + x, w = gauss_lobatto(3, 17) + assert [str(r) for r in x] == [ + '-1', + '0', + '1'] + assert [str(r) for r in w] == [ + '0.33333333333333333', + '1.3333333333333333', + '0.33333333333333333'] + + x, w = gauss_lobatto(4, 17) + assert [str(r) for r in x] == [ + '-1', + '-0.44721359549995794', + '0.44721359549995794', + '1'] + assert [str(r) for r in w] == [ + '0.16666666666666667', + '0.83333333333333333', + '0.83333333333333333', + '0.16666666666666667'] + + x, w = gauss_lobatto(5, 17) + assert [str(r) for r in x] == [ + '-1', + '-0.65465367070797714', + '0', + '0.65465367070797714', + '1'] + assert [str(r) for r in w] == [ + '0.10000000000000000', + '0.54444444444444444', + '0.71111111111111111', + '0.54444444444444444', + '0.10000000000000000'] + + +def test_lobatto_precise(): + x, w = gauss_lobatto(3, 40) + assert [str(r) for r in x] == [ + '-1', + '0', + '1'] + assert [str(r) for r in w] == [ + '0.3333333333333333333333333333333333333333', + '1.333333333333333333333333333333333333333', + '0.3333333333333333333333333333333333333333'] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_rationaltools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_rationaltools.py new file mode 100644 index 0000000000000000000000000000000000000000..809bf30c1c35f80e2a0b15c1e639603eab28a250 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_rationaltools.py @@ -0,0 +1,183 @@ +from sympy.core.numbers import (I, Rational) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, symbols) +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import atan +from sympy.integrals.integrals import integrate +from sympy.polys.polytools import Poly +from sympy.simplify.simplify import simplify + +from sympy.integrals.rationaltools import ratint, ratint_logpart, log_to_atan + +from sympy.abc import a, b, x, t + +half = S.Half + + +def test_ratint(): + assert ratint(S.Zero, x) == 0 + assert ratint(S(7), x) == 7*x + + assert ratint(x, x) == x**2/2 + 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 + + f = S.One + g = 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 + + assert ratint(f/g, x) == x**3/3 + x**2/2 + + f = x + g = (x - a)*(x + a) + + assert ratint(f/g, x) == log(x**2 - a**2)/2 + + f = S.One + g = x**2 + 1 + + assert ratint(f/g, x, real=None) == atan(x) + assert ratint(f/g, x, real=True) == atan(x) + + 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 + + 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 + + assert ratint(f/g, x) == \ + atan(x) + atan(x**3) + atan(x/2 - Rational(3, 2)*x**3 + S.Half*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 + + assert ratint(f/g, x) == \ + (4 + 6*x + 8*x**2 + 3*x**3)/(4*x + 4*x**3 + x**5) + log(x) + + assert ratint((x**3*f)/(x*g), x) == \ + -(12 - 16*x + 6*x**2 - 14*x**3)/(4 + 4*x**2 + x**4) - \ + 5*sqrt(2)*atan(x*sqrt(2)/2) + S.Half*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 + + assert ratint(f/g, x) == \ + x + S.Half*x**2 + S.Half*log(2 - x + x**2) + (9 - 4*x)/(7*x**2 - 7*x + 14) + \ + 13*sqrt(7)*atan(Rational(-1, 7)*sqrt(7) + 2*x*sqrt(7)/7)/49 + + 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**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 + \ + (Rational(-1, 6) + I*3**half/6)*log(-half + x + I*3**half/2) + \ + (Rational(-1, 6) - I*3**half/6)*log(-half + x - I*3**half/2) + + # issue 4991 + 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 + # this asserts that as_dummy must return a unique symbol + # even if the symbol is already a Dummy + d = Dummy() + assert ratint(1/(d**2 + 1), d, symbol=d) == atan(d) + + +def test_ratint_logpart(): + 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) == \ + [(Poly(x**3 - 5, x), Poly(-3*t + 1, t))] + + +def test_issue_5414(): + assert ratint(1/(x**2 + 16), x) == atan(x/4)/4 + + +def test_issue_5249(): + assert ratint( + 1/(x**2 + a**2), x) == (-I*log(-I*a + x)/2 + I*log(I*a + x)/2)/a + + +def test_issue_5817(): + 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)) + + +def test_issue_5981(): + u = symbols('u') + assert integrate(1/(u**2 + 1)) == atan(u) + +def test_issue_10488(): + a,b,c,x = symbols('a b c x', positive=True) + assert integrate(x/(a*x+b),x) == x/a - b*log(a*x + b)/a**2 + + +def test_issues_8246_12050_13501_14080(): + a = symbols('a', nonzero=True) + assert integrate(a/(x**2 + a**2), x) == atan(x/a) + assert integrate(1/(x**2 + a**2), x) == atan(x/a)/a + assert integrate(1/(1 + a**2*x**2), x) == atan(a*x)/a + + +def test_issue_6308(): + k, a0 = symbols('k a0', real=True) + assert integrate((x**2 + 1 - k**2)/(x**2 + 1 + a0**2), x) == \ + x - (a0**2 + k**2)*atan(x/sqrt(a0**2 + 1))/sqrt(a0**2 + 1) + + +def test_issue_5907(): + a = symbols('a', nonzero=True) + assert integrate(1/(x**2 + a**2)**2, x) == \ + x/(2*a**4 + 2*a**2*x**2) + atan(x/a)/(2*a**3) + + +def test_log_to_atan(): + f, g = (Poly(x + S.Half, x, domain='QQ'), Poly(sqrt(3)/2, x, domain='EX')) + fg_ans = 2*atan(2*sqrt(3)*x/3 + sqrt(3)/3) + assert log_to_atan(f, g) == fg_ans + assert log_to_atan(g, f) == -fg_ans + + +def test_issue_25896(): + # for both tests, C = 0 in log_to_real + # but this only has a log result + e = (2*x + 1)/(x**2 + x + 1) + 1/x + assert ratint(e, x) == log(x**3 + x**2 + x) + # while this has more + assert ratint((4*x + 7)/(x**2 + 4*x + 6) + 2/x, x) == ( + 2*log(x) + 2*log(x**2 + 4*x + 6) - sqrt(2)*atan( + sqrt(2)*x/2 + sqrt(2))/2) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_rde.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_rde.py new file mode 100644 index 0000000000000000000000000000000000000000..3c7df5ce05846dc270756cd878870bbff78ff976 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_rde.py @@ -0,0 +1,202 @@ +"""Most of these tests come from the examples in Bronstein's book.""" +from sympy.core.numbers import (I, Rational, oo) +from sympy.core.symbol import symbols +from sympy.polys.polytools import Poly +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.testing.pytest import raises +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) + c = Poly((t**2 + 1)**6*t, t) + d = Poly((t**2 + 1)**10*t**10, t) + e = Poly((t**2 + 1)**100*t**37, 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(c, p1, t) == 1 + assert order_at(d, p1, t) == 10 + assert order_at(e, p1, t) == 37 + assert order_at(a, p2, t) == 0 + assert order_at(b, p2, t) == 3 + assert order_at(c, p2, t) == 6 + assert order_at(d, p1, t) == 10 + assert order_at(e, p2, t) == 100 + assert order_at(Poly(0, t), Poly(t, t), t) is 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) is 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, domain='ZZ[x]'), + (Poly((1 + x)*t**2 + x*t, t, domain='ZZ[x]'), + Poly(t + 1, t, domain='ZZ[x]'))) + 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 3940 + # 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, domain='ZZ'), Poly(I*k, t0, domain='ZZ_I[k,x]'), + Poly(t0, t0, domain='ZZ'), Poly(1, t0, domain='ZZ')) + + + assert special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t), + Poly(t, t), DE, case='tan') == \ + (Poly(1, t, t0, domain='ZZ'), Poly(t**2, t0, t, domain='ZZ[x]'), + Poly(t, t, t0, domain='ZZ'), Poly(1, t0, domain='ZZ')) + + raises(ValueError, lambda: special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t), + Poly(t, t), DE, case='unrecognized_case')) + + +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, domain='ZZ(x)')) + 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, domain='ZZ(x,t0)')) + 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, domain='QQ'), Poly(x/2 - Rational(1, 4), x), 2, Poly(x**2 + x + 1, x), Poly(x*Rational(5, 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, domain='QQ'), Poly(x/2 - Rational(1, 4), x), -2 + n, Poly(x**2 + x + 1, x), Poly(x*Rational(5, 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)) + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + assert spde(Poly(x**2 - x, x), Poly(1, x), Poly(9*x**4 - 10*x**3 + 2*x**2, x), 4, DE) == \ + (Poly(0, x, domain='ZZ'), Poly(0, x), 0, Poly(0, x), Poly(3*x**3 - 2*x**2, x, domain='QQ')) + assert spde(Poly(x**2 - x, x), Poly(x**2 - 5*x + 3, x), Poly(x**7 - x**6 - 2*x**4 + 3*x**3 - x**2, x), 5, DE) == \ + (Poly(1, x, domain='QQ'), Poly(x + 1, x, domain='QQ'), 1, Poly(x**4 - x**3, x), Poly(x**3 - x**2, x, domain='QQ')) + +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 - Rational(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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_risch.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_risch.py new file mode 100644 index 0000000000000000000000000000000000000000..68be260e1f3d42fb14c790afe6bda1768e777666 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_risch.py @@ -0,0 +1,763 @@ +"""Most of these tests come from the examples in Bronstein's book.""" +from sympy.core.function import (Function, Lambda, diff, expand_log) +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.relational import Ne +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (atan, sin, tan) +from sympy.polys.polytools import (Poly, cancel, factor) +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.testing.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)) + assert gcdex_diophantine(Poly(x**3 + 6*x + 7), Poly(x**2 + 3*x + 2), Poly(x + 1)) == \ + (Poly(1/13, x, domain='QQ'), Poly(-1/13*x + 3/13, x, domain='QQ')) + + +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)] + assert as_poly_1t(S.Zero, t, z) == Poly(0, t, z) + + +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 + (x*Rational(7, 2) - 25*x**2 - 12*x**3)*t**3 + + (-5 - x*Rational(15, 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, domain='ZZ(x)'), + 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, domain='ZZ[x]'), (Poly(0, t, domain='QQ[x]'), + Poly(1, t, domain='ZZ')), (Poly(-t + x, t, domain='QQ[x]'), + 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, domain='ZZ[x]'), (Poly(t**5 + t**3 + x**2*t + 1, t, domain='QQ[x]'), + Poly(t**6 + 3*t**4 + 3*t**2 + 1, t, domain='QQ')), + (Poly(0, t, domain='QQ[x]'), Poly(1, t, domain='QQ'))) + + +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, domain='QQ[x]'), Poly(t, t, domain='QQ[x]')), + (Poly(0, t, domain='QQ[x]'), Poly(1, t, domain='QQ[x]')), + (Poly(-x, t, domain='QQ[x]'), Poly(1, t, domain='QQ[x]'))) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)]}) + + 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(-x**2 - 4, t, domain='ZZ(x,nu)'), Poly(4*t**2 + 2*x**2 + 4, t, domain='ZZ(x,nu)')), + (Poly((-2*nu**2 - x**4)*t - (2*x**3 + 2*x), t, domain='ZZ(x,nu)'), + Poly(2*x**2*t**2 + x**4 + 2*x**2, t, domain='ZZ(x,nu)')), + (Poly(x*t + 1, t, domain='ZZ(x,nu)'), Poly(x, t, domain='ZZ(x,nu)'))) + + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) + + a = Poly((-2 + 3*x)*t**3 + (-1 + x)*t**2 + (-4*x + 2*x**2)*t + x**2, t) + d = Poly(x*t**6 - 4*x**2*t**5 + 6*x**3*t**4 - 4*x**4*t**3 + x**5*t**2, t) + + assert hermite_reduce(a, d, DE) == \ + ((Poly(3*t**2 + t + 3*x, t, domain='ZZ(x)'), + Poly(3*t**4 - 9*x*t**3 + 9*x**2*t**2 - 3*x**3*t, t, domain='ZZ(x)')), + (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')), + (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)'))) + + assert hermite_reduce( + Poly(-t**2 + 2*t + 2, t, domain='ZZ(x)'), + Poly(-x*t**2 + 2*x*t - x, t, domain='ZZ(x)'), DE) == \ + ((Poly(3, t, domain='ZZ(x)'), Poly(t - 1, t, domain='ZZ(x)')), + (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')), + (Poly(1, t, domain='ZZ(x)'), Poly(x, t, domain='ZZ(x)'))) + + 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, domain='ZZ(x)'), + Poly(x**4*t**6 - 2*x**2*t**3 + 1, t, domain='ZZ(x)'), DE) == \ + ((Poly(x**3*t + x**4 + 1, t, domain='ZZ(x)'), Poly(x**3*t**3 - x, t, domain='ZZ(x)')), + (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')), + (Poly(-1, t, domain='ZZ(x)'), Poly(x**2, t, domain='ZZ(x)'))) + + 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, domain='ZZ(x)'), + Poly(3*t**4 - 9*x*t**3 + 9*x**2*t**2 - 3*x**3*t, t, domain='ZZ(x)')), + (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')), + (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)'))) + + +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, domain='QQ'), Poly(2*t**6 + 6*t**5 - 8*t**3, t, domain='QQ')]) + + +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, t), DE) == True + DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) + assert recognize_log_derivative(Poly(1, x), Poly(x**2 - 2, x), DE) == False + assert recognize_log_derivative(Poly(1, x), Poly(x**2 + x, x), DE) == True + DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) + assert recognize_log_derivative(Poly(1, t), Poly(t**2 - 2, t), DE) == False + assert recognize_log_derivative(Poly(1, t), Poly(t**2 + t, t), DE) == False + + +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 - Rational(1, 4), z, domain='ZZ(x)'), + 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, domain='ZZ(z, x)'))], False) + assert residue_reduce(a, d, DE, z, invert=True) == \ + ([(Poly(z**2 - Rational(1, 4), z, domain='ZZ(x)'), 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, domain='QQ'), Poly(-2*z*t/x - 2/x, t, domain='ZZ(z,x)'))], True) + ans = residue_reduce(Poly(-2/x, t), Poly(t**2 - 1, t), DE, z, invert=True) + assert ans == ([(Poly(z**2 - 1, z, domain='QQ'), 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.Half, z, domain='QQ'), Poly(t**2 + 1 + x**2/2, t, + domain='ZZ(x,nu)'))], 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 + Rational(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, domain='QQ'), 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) + 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) + 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))]}) + + elem, nonelem, b = 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) + + assert factor(elem) == -((x - 1)*log(x)/((x + exp(x**2))*(2*x**2 - 1))) + assert (nonelem, b) == (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) + + DE = DifferentialExtension(extension={'D':[Poly(1, x), Poly(t0, t0)]}) + assert integrate_hyperexponential_polynomial(Poly(0, t0), DE, z) == ( + Poly(0, t0), Poly(1, t0), 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( + (exp(x*log(a))/log(a), Ne(log(a), 0)), (x, True)), 0, True) + DE = DifferentialExtension(a**(b*x), x) + assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( + (exp(b*x*log(a))/(b*log(a)), Ne(b*log(a), 0)), (x, True)), 0, True) + DE = DifferentialExtension(exp(a*x), x) + assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( + (exp(a*x)/a, Ne(a, 0)), (x, True)), 0, True) + DE = DifferentialExtension(x*exp(a*x), x) + assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( + ((a*x - 1)*exp(a*x)/a**2, Ne(a**2, 0)), (x**2/2, True)), 0, True) + DE = DifferentialExtension(x**2*exp(a*x), x) + assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( + ((x**2*a**2 - 2*a*x + 2)*exp(a*x)/a**3, Ne(a**3, 0)), + (x**3/3, True)), 0, True) + DE = DifferentialExtension(x**y + z, y) + assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( + (exp(log(x)*y)/log(x), Ne(log(x), 0)), (y, True)), z, True) + DE = DifferentialExtension(x**y + z + x**(2*y), y) + assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( + ((exp(2*log(x)*y)*log(x) + + 2*exp(log(x)*y)*log(x))/(2*log(x)**2), Ne(2*log(x)**2, 0)), + (2*y, True), + ), z, True) + # TODO: Add a test where two different parts of the extension use a + # Piecewise, like y**x + z**x. + + +def test_issue_13947(): + a, t, s = symbols('a t s') + assert risch_integrate(2**(-pi)/(2**t + 1), t) == \ + 2**(-pi)*t - 2**(-pi)*log(2**t + 1)/log(2) + assert risch_integrate(a**(t - s)/(a**t + 1), t) == \ + exp(-s*log(a))*log(a**t + 1)/log(a) + + +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) + 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, x*Rational(2, 3)]) == [ + (x/6, [(x, 6), (x/2, 3), (x*Rational(2, 3), 4)]), + (1 + x**2, [(1 + x**2, 1)])] + + +def test_DifferentialExtension_exp(): + assert DifferentialExtension(exp(x) + exp(x**2), x)._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))], [], [None, 'exp', 'exp'], [None, x, x**2]) + assert DifferentialExtension(exp(x) + exp(2*x), x)._important_attrs == \ + (Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0, t0)], [x, t0], + [Lambda(i, exp(i))], [], [None, 'exp'], [None, x]) + assert DifferentialExtension(exp(x) + exp(x/2), x)._important_attrs == \ + (Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], + [x, t0], [Lambda(i, exp(i/2))], [], [None, 'exp'], [None, x/2]) + assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2), x)._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))], [], [None, 'exp', 'exp'], [None, x, x**2]) + assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2 + 1), x)._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))], [], [None, 'exp', 'exp'], [None, x, x**2]) + assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2), x)._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)))], [None, 'exp', 'exp'], [None, x/2, x**2]) + assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2 + 3), x)._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)))], [None, 'exp', 'exp'], + [None, x/2, x**2]) + assert DifferentialExtension(sqrt(exp(x)), x)._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)))], [None, 'exp'], [None, x/2]) + + assert DifferentialExtension(exp(x/2), x)._important_attrs == \ + (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0], + [Lambda(i, exp(i/2))], [], [None, 'exp'], [None, x/2]) + + +def test_DifferentialExtension_log(): + assert DifferentialExtension(log(x)*log(x + 1)*log(2*x**2 + 2*x), x)._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))], [], [None, 'log', 'log'], + [None, x, x + 1]) + assert DifferentialExtension(x**x*log(x), x)._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)], [None, 'log', 'exp'], + [None, x, t0*x]) + + +def test_DifferentialExtension_symlog(): + # See comment on test_risch_integrate below + assert DifferentialExtension(log(x**x), x)._important_attrs == \ + (Poly(t0*x, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0), Poly((t0 + + 1)*t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(i*t0))], + [(exp(x*log(x)), x**x)], [None, 'log', 'exp'], [None, x, t0*x]) + assert DifferentialExtension(log(x**y), x)._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))], [None, 'log'], + [None, x]) + assert DifferentialExtension(log(sqrt(x)), x)._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)))], [None, 'log'], + [None, x]) + + +def test_DifferentialExtension_handle_first(): + assert DifferentialExtension(exp(x)*log(x), x, handle_first='log')._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))], + [], [None, 'log', 'exp'], [None, x, x]) + assert DifferentialExtension(exp(x)*log(x), x, handle_first='exp')._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))], + [], [None, 'exp', 'log'], [None, x, 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')._important_attrs == \ + DifferentialExtension(-x**x*log(x)**2 + x**x - x**x/x, x, + handle_first='log')._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)], + [None, 'log', 'exp'], [None, x, t0*x]) + + +def test_DifferentialExtension_all_attrs(): + # Test 'unimportant' attributes + DE = DifferentialExtension(exp(x)*log(x), x, 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' + + # Test methods + assert DE.indices('log') == [2] + assert DE.indices('exp') == [1] + + +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) + 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)], + 'exts': [None, 'exp'], 'extargs': [None, x]}) + assert DE._important_attrs == (None, None, [Poly(1, x), Poly(t, t)], [x, t], + None, None, [None, 'exp'], [None, x]) + raises(ValueError, lambda: DifferentialExtension()) + + +def test_DifferentialExtension_misc(): + # Odd ends + assert DifferentialExtension(sin(y)*exp(x), x)._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))], [], [None, 'exp'], [None, x]) + raises(NotImplementedError, lambda: DifferentialExtension(sin(x), x)) + assert DifferentialExtension(10**x, x)._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)], [None, 'exp'], + [None, x*log(10)]) + assert DifferentialExtension(log(x) + log(x**2), x)._important_attrs in [ + (Poly(3*t0, t0), Poly(2, t0), [Poly(1, x), Poly(2/x, t0)], [x, t0], + [Lambda(i, log(i**2))], [], [None, ], [], [1], [x**2]), + (Poly(3*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0], + [Lambda(i, log(i))], [], [None, 'log'], [None, x])] + assert DifferentialExtension(S.Zero, x)._important_attrs == \ + (Poly(0, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None]) + assert DifferentialExtension(tan(atan(x).rewrite(log)), x)._important_attrs == \ + (Poly(x, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None]) + + +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)._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))], [], + [None, 'exp', 'exp'], [None, 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) + 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 + + # also tests prde_cancel() + e1 = log(x/exp(x) + 1) + ans1 = risch_integrate(e1, x) + assert ans1 == (x*log(x*exp(-x) + 1) + NonElementaryIntegral((x**2 - x)/(x + exp(x)), x)) + assert cancel(diff(ans1, x) - e1) == 0 + + # also tests issue #10798 + e2 = (log(-1/y)/2 - log(1/y)/2)/y - (log(1 - 1/y)/2 - log(1 + 1/y)/2)/y + ans2 = risch_integrate(e2, y) + assert ans2 == log(1/y)*log(1 - 1/y)/2 - log(1/y)*log(1 + 1/y)/2 + \ + NonElementaryIntegral((I*pi*y**2 - 2*y*log(1/y) - I*pi)/(2*y**3 - 2*y), y) + assert expand_log(cancel(diff(ans2, y) - e2), force=True) == 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. + + # XXX: Unfortunately, making backsubs work on this one is a little + # trickier, because x**x is converted to exp(x*log(x)), and so log(x**x) + # is converted to x*log(x). (x**2*log(x)).subs(x*log(x), log(x**x)) is + # smart enough, the issue is that these splits happen at different places + # in the algorithm. Maybe a heuristic is in order + assert risch_integrate(log(x**x), x) == x**2*log(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_risch_integrate_float(): + assert risch_integrate((-60*exp(x) - 19.2*exp(4*x))*exp(4*x), x) == -2.4*exp(8*x) - 12.0*exp(5*x) + + +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) + + +def test_xtothex(): + a = risch_integrate(x**x, x) + assert a == NonElementaryIntegral(x**x, x) + assert isinstance(a, NonElementaryIntegral) + + +def test_DifferentialExtension_equality(): + DE1 = DE2 = DifferentialExtension(log(x), x) + assert DE1 == DE2 + + +def test_DifferentialExtension_printing(): + DE = DifferentialExtension(exp(2*x**2) + log(exp(x**2) + 1), x) + assert repr(DE) == ("DifferentialExtension(dict([('f', exp(2*x**2) + log(exp(x**2) + 1)), " + "('x', x), ('T', [x, t0, t1]), ('D', [Poly(1, x, domain='ZZ'), Poly(2*x*t0, t0, domain='ZZ[x]'), " + "Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')]), ('fa', Poly(t1 + t0**2, t1, domain='ZZ[t0]')), " + "('fd', Poly(1, t1, domain='ZZ')), ('Tfuncs', [Lambda(i, exp(i**2)), Lambda(i, log(t0 + 1))]), " + "('backsubs', []), ('exts', [None, 'exp', 'log']), ('extargs', [None, x**2, t0 + 1]), " + "('cases', ['base', 'exp', 'primitive']), ('case', 'primitive'), ('t', t1), " + "('d', Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')), ('newf', t0**2 + t1), ('level', -1), " + "('dummy', False)]))") + + assert str(DE) == ("DifferentialExtension({fa=Poly(t1 + t0**2, t1, domain='ZZ[t0]'), " + "fd=Poly(1, t1, domain='ZZ'), D=[Poly(1, x, domain='ZZ'), Poly(2*x*t0, t0, domain='ZZ[x]'), " + "Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')]})") + + +def test_issue_23948(): + f = ( + ( (-2*x**5 + 28*x**4 - 144*x**3 + 324*x**2 - 270*x)*log(x)**2 + +(-4*x**6 + 56*x**5 - 288*x**4 + 648*x**3 - 540*x**2)*log(x) + +(2*x**5 - 28*x**4 + 144*x**3 - 324*x**2 + 270*x)*exp(x) + +(2*x**5 - 28*x**4 + 144*x**3 - 324*x**2 + 270*x)*log(5) + -2*x**7 + 26*x**6 - 116*x**5 + 180*x**4 + 54*x**3 - 270*x**2 + )*log(-log(x)**2 - 2*x*log(x) + exp(x) + log(5) - x**2 - x)**2 + +( (4*x**5 - 44*x**4 + 168*x**3 - 216*x**2 - 108*x + 324)*log(x) + +(-2*x**5 + 24*x**4 - 108*x**3 + 216*x**2 - 162*x)*exp(x) + +4*x**6 - 42*x**5 + 144*x**4 - 108*x**3 - 324*x**2 + 486*x + )*log(-log(x)**2 - 2*x*log(x) + exp(x) + log(5) - x**2 - x) + )/(x*exp(x)**2*log(x)**2 + 2*x**2*exp(x)**2*log(x) - x*exp(x)**3 + +(-x*log(5) + x**3 + x**2)*exp(x)**2) + + F = ((x**4 - 12*x**3 + 54*x**2 - 108*x + 81)*exp(-2*x) + *log(-x**2 - 2*x*log(x) - x + exp(x) - log(x)**2 + log(5))**2) + + assert risch_integrate(f, x) == F diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_singularityfunctions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_singularityfunctions.py new file mode 100644 index 0000000000000000000000000000000000000000..587e5f104cbf095f851ec538601ca146377b51ae --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_singularityfunctions.py @@ -0,0 +1,22 @@ +from sympy.integrals.singularityfunctions import singularityintegrate +from sympy.core.function import Function +from sympy.core.symbol import symbols +from sympy.functions.special.singularity_functions import SingularityFunction + +x, a, n, y = symbols('x a n y') +f = Function('f') + + +def test_singularityintegrate(): + assert singularityintegrate(x, x) is None + assert singularityintegrate(x + SingularityFunction(x, 9, 1), x) is None + + assert 4*singularityintegrate(SingularityFunction(x, a, 3), x) == 4*SingularityFunction(x, a, 4)/4 + assert singularityintegrate(5*SingularityFunction(x, 5, -2), x) == 5*SingularityFunction(x, 5, -1) + assert singularityintegrate(6*SingularityFunction(x, 5, -1), x) == 6*SingularityFunction(x, 5, 0) + assert singularityintegrate(x*SingularityFunction(x, 0, -1), x) == 0 + assert singularityintegrate((x - 5)*SingularityFunction(x, 5, -1), x) == 0 + assert singularityintegrate(SingularityFunction(x, 0, -1) * f(x), x) == f(0) * SingularityFunction(x, 0, 0) + assert singularityintegrate(SingularityFunction(x, 1, -1) * f(x), x) == f(1) * SingularityFunction(x, 1, 0) + assert singularityintegrate(y*SingularityFunction(x, 0, -1)**2, x) == \ + y*SingularityFunction(0, 0, -1)*SingularityFunction(x, 0, 0) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_transforms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_transforms.py new file mode 100644 index 0000000000000000000000000000000000000000..fdf7192594bad532c93ffb31e5b2f05cfd8970f1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_transforms.py @@ -0,0 +1,637 @@ +from sympy.integrals.transforms import ( + mellin_transform, inverse_mellin_transform, + fourier_transform, inverse_fourier_transform, + sine_transform, inverse_sine_transform, + cosine_transform, inverse_cosine_transform, + hankel_transform, inverse_hankel_transform, + FourierTransform, SineTransform, CosineTransform, InverseFourierTransform, + InverseSineTransform, InverseCosineTransform, IntegralTransformError) +from sympy.integrals.laplace import ( + laplace_transform, inverse_laplace_transform) +from sympy.core.function import Function, expand_mul +from sympy.core import EulerGamma +from sympy.core.numbers import I, Rational, oo, pi +from sympy.core.singleton import S +from sympy.core.symbol import Symbol, symbols +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.complexes import re, unpolarify +from sympy.functions.elementary.exponential import exp, exp_polar, log +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import atan, cos, sin, tan +from sympy.functions.special.bessel import besseli, besselj, besselk, bessely +from sympy.functions.special.delta_functions import Heaviside +from sympy.functions.special.error_functions import erf, expint +from sympy.functions.special.gamma_functions import gamma +from sympy.functions.special.hyper import meijerg +from sympy.simplify.gammasimp import gammasimp +from sympy.simplify.hyperexpand import hyperexpand +from sympy.simplify.trigsimp import trigsimp +from sympy.testing.pytest import XFAIL, slow, skip, raises +from sympy.abc import x, s, a, b, c, d + + +nu, beta, rho = symbols('nu beta rho') + + +def test_undefined_function(): + from sympy.integrals.transforms import 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 + 1)/s, (0, oo), True) + + +def test_free_symbols(): + f = Function('f') + assert mellin_transform(f(x), x, s).free_symbols == {s} + assert mellin_transform(f(x)*a, x, s).free_symbols == {s, a} + + +def test_as_integral(): + from sympy.integrals.integrals import Integral + f = Function('f') + assert mellin_transform(f(x), x, s).rewrite('Integral') == \ + 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)) + assert laplace_transform(f(x), x, s, noconds=True).rewrite('Integral') == \ + Integral(f(x)*exp(-s*x), (x, 0, oo)) + assert str(2*pi*I*inverse_mellin_transform(f(s), s, x, (a, b)).rewrite('Integral')) \ + == "Integral(f(s)/x**s, (s, _c - oo*I, _c + oo*I))" + assert str(2*pi*I*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)) + +# NOTE this is stuck in risch because meijerint cannot handle it + + +@slow +@XFAIL +def test_mellin_transform_fail(): + skip("Risch takes forever.") + + MT = mellin_transform + + bpos = symbols('b', positive=True) + # bneg = symbols('b', negative=True) + + 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), + (-re(a), -re(a)/2 + S.Half), True) + + 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), + (-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.Half)/(2*sqrt(pi)), + (-1, Rational(-1, 2)), True) + + +def test_mellin_transform(): + from sympy.functions.elementary.miscellaneous import (Max, Min) + MT = mellin_transform + + 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, 1 - re(beta)), re(beta) > 0) + + assert MT((1 + x)**(-rho), x, s) == \ + (gamma(s)*gamma(rho - s)/gamma(rho), (0, re(rho)), True) + + assert MT(abs(1 - x)**(-rho), x, s) == ( + 2*sin(pi*rho/2)*gamma(1 - rho)* + cos(pi*(s - rho/2))*gamma(s)*gamma(rho-s)/pi, + (0, re(rho)), re(rho) < 1) + 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), re(beta) > 0) + + 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(0, -re(a)), Min(1, 1 - re(a))), True) + + 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) + assert MT(expr.subs(b, bpos), x, 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.Half), True) + + # 8.4.2 + assert MT(exp(-x), x, s) == (gamma(s), (0, oo), True) + 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 + 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) + assert MT(log(abs(1 - 1/x)), x, s) == (pi/(s*tan(pi*s)), (0, 1), True) + + # 8.4.14 + assert MT(erf(sqrt(x)), x, s) == \ + (-gamma(s + S.Half)/(sqrt(pi)*s), (Rational(-1, 2), 0), True) + + +def test_mellin_transform2(): + MT = mellin_transform + # 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) + 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) + 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) + assert mt[1:] == ((0, 2), True) + assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg) + + +@slow +def test_mellin_transform_bessel(): + from sympy.functions.elementary.miscellaneous import Max + MT = mellin_transform + + # 8.4.19 + assert MT(besselj(a, 2*sqrt(x)), x, s) == \ + (gamma(a/2 + s)/gamma(a/2 - s + 1), (-re(a)/2, Rational(3, 4)), True) + assert MT(sin(sqrt(x))*besselj(a, sqrt(x)), x, s) == \ + (2**a*gamma(-2*s + S.Half)*gamma(a/2 + s + S.Half)/( + gamma(-a/2 - s + 1)*gamma(a - 2*s + 1)), ( + -re(a)/2 - S.Half, Rational(1, 4)), True) + assert MT(cos(sqrt(x))*besselj(a, sqrt(x)), x, s) == \ + (2**a*gamma(a/2 + s)*gamma(-2*s + S.Half)/( + gamma(-a/2 - s + S.Half)*gamma(a - 2*s + 1)), ( + -re(a)/2, Rational(1, 4)), True) + assert MT(besselj(a, sqrt(x))**2, x, s) == \ + (gamma(a + s)*gamma(S.Half - s) + / (sqrt(pi)*gamma(1 - s)*gamma(1 + a - s)), + (-re(a), S.Half), True) + assert MT(besselj(a, sqrt(x))*besselj(-a, sqrt(x)), x, s) == \ + (gamma(s)*gamma(S.Half - s) + / (sqrt(pi)*gamma(1 - a - s)*gamma(1 + a - s)), + (0, S.Half), 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.Half) + / (sqrt(pi)*gamma(Rational(3, 2) - s)*gamma(a - s + S.Half)), + (S.Half - re(a), S.Half), 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)), + (-(re(a) + re(b))/2, S.Half), True) + assert MT(besselj(a, sqrt(x))**2 + besselj(-a, sqrt(x))**2, x, s)[1:] == \ + ((Max(re(a), -re(a)), S.Half), 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, + (Max(-re(a)/2, re(a)/2), Rational(3, 4)), True) + assert MT(sin(sqrt(x))*bessely(a, sqrt(x)), x, s) == \ + (-4**s*sin(pi*(a/2 - s))*gamma(S.Half - 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), Rational(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.Half - 2*s) + / (sqrt(pi)*gamma(S.Half - s - a/2)*gamma(S.Half - s + a/2)), + (Max(-re(a)/2, re(a)/2), Rational(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.Half - s) + / (pi**S('3/2')*gamma(1 + a - s)), + (Max(-re(a), 0), S.Half), 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)), + (Max((-re(a) + re(b))/2, (-re(a) - re(b))/2), S.Half), 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.Half), 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)/(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.Half)/(2*sqrt(pi)*gamma(a - s + 1)), + (Max(-re(a), 0), S.Half), True) + assert MT(besseli(b, sqrt(x))*besselk(a, sqrt(x)), x, s) == \ + (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.Half), True) + + # TODO products of besselk are a mess + + mt = MT(exp(-x/2)*besselk(a, x/2), x, s) + mt0 = gammasimp(trigsimp(gammasimp(mt[0].expand(func=True)))) + assert mt0 == 2*pi**Rational(3, 2)*cos(pi*s)*gamma(S.Half - s)/( + (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 + + +@slow +def test_expint(): + from sympy.functions.elementary.miscellaneous import Max + from sympy.functions.special.error_functions import Ci, E1, Si + from sympy.simplify.simplify import simplify + + aneg = Symbol('a', negative=True) + u = Symbol('u', polar=True) + + assert mellin_transform(E1(x), x, s) == (gamma(s)/s, (0, oo), True) + 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) + # 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) + + assert mellin_transform(Si(x), x, s) == \ + (-2**s*sqrt(pi)*gamma(s/2 + S.Half)/( + 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) + + assert mellin_transform(Ci(sqrt(x)), x, s) == \ + (-2**(2*s - 1)*sqrt(pi)*gamma(s)/(s*gamma(-s + S.Half)), (0, 1), True) + assert inverse_mellin_transform( + -4**s*sqrt(pi)*gamma(s)/(2*s*gamma(-s + S.Half)), + s, u, (0, 1)).expand() == Ci(sqrt(u)) + + +@slow +def test_inverse_mellin_transform(): + from sympy.core.function import expand + from sympy.functions.elementary.miscellaneous import (Max, Min) + from sympy.functions.elementary.trigonometric import cot + from sympy.simplify.powsimp import powsimp + from sympy.simplify.simplify import simplify + IMT = inverse_mellin_transform + + 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) + + # 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) + + # test expansion of sums + 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)) + + # test multiplicative substitution + _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) + + def simp_pows(expr): + return simplify(powsimp(expand_mul(expr, deep=False), force=True)).replace(exp_polar, exp) + + # Now test the inverses of all direct transforms tested above + + # Section 8.4.2 + nu = symbols('nu', real=True) + 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), + 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 + expr = 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))) + assert powsimp(expand_mul(expr, deep=False)).replace(exp_polar, exp).simplify() \ + == (-d**c + x**c)/(-d + x) + + 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**(a - 1)*(b**2*(sqrt(1 + x/b**2) + 1)**a + x*(sqrt(1 + x/b**2) + 1 + )**(a - 1))/(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) + 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, (Rational(-1, 2), 0)) == log(sqrt(x) + 1) + assert IMT(pi/(s*sin(pi*s)), s, x, (0, 1)) == log(1 + 1/x) + + # TODO + def mysimp(expr): + from sympy.core.function import expand + from sympy.simplify.powsimp import powsimp + from sympy.simplify.simplify import logcombine + 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(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(x)*Heaviside(-x + 1) + log(1 - 1/x)*Heaviside(x - 1) + log(-x + + 1)*Heaviside(-x + 1), ] + + # 8.4.14 + assert IMT(-gamma(s + S.Half)/(sqrt(pi)*s), s, x, (Rational(-1, 2), 0)) == \ + erf(sqrt(x)) + + # 8.4.19 + assert simplify(IMT(gamma(a/2 + s)/gamma(a/2 - s + 1), s, x, (-re(a)/2, Rational(3, 4)))) \ + == besselj(a, 2*sqrt(x)) + assert simplify(IMT(2**a*gamma(S.Half - 2*s)*gamma(s + (a + 1)/2) + / (gamma(1 - s - a/2)*gamma(1 - 2*s + a)), + s, x, (-(re(a) + 1)/2, Rational(1, 4)))) == \ + sin(sqrt(x))*besselj(a, sqrt(x)) + assert simplify(IMT(2**a*gamma(a/2 + s)*gamma(S.Half - 2*s) + / (gamma(S.Half - s - a/2)*gamma(1 - 2*s + a)), + s, x, (-re(a)/2, Rational(1, 4)))) == \ + 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.Half - s) + / (sqrt(pi)*gamma(1 - s)*gamma(1 + a - s)), + s, x, (-re(a), S.Half))) == \ + besselj(a, sqrt(x))**2 + assert simplify(IMT(gamma(s)*gamma(S.Half - s) + / (sqrt(pi)*gamma(1 - s - a)*gamma(1 + a - s)), + s, x, (0, S.Half))) == \ + 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.Half))) == \ + 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) / + (pi*gamma(a/2 - b/2 - s + 1)*gamma(a/2 + b/2 - s + 1)), + s, x, + (Max(-re(a)/2 - re(b)/2, -re(a)/2 + re(b)/2), S.Half))) == \ + besselj(a, sqrt(x))*-(besselj(-b, sqrt(x)) - + besselj(b, sqrt(x))*cos(pi*b))/sin(pi*b) + # TODO more + + # for coverage + + assert IMT(pi/cos(pi*s), s, x, (0, S.Half)) == sqrt(x)/(x + 1) + + +def test_fourier_transform(): + from sympy.core.function import (expand, expand_complex, expand_trig) + from sympy.polys.polytools import factor + from sympy.simplify.simplify import simplify + 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) + k = symbols('k', real=True) + f = Function("f") + + # TODO for this to work with real a, need to expand abs(a*x) to abs(a)*abs(x) + a = symbols('a', positive=True) + b = symbols('b', positive=True) + + posk = symbols('posk', positive=True) + + # 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) + + # 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 + # TODO IFT + + 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) + assert IFT(1/(a + 2*pi*I*x), x, -posk, + noconds=False) == (0, True) + assert IFT(1/(a + 2*pi*I*x), x, symbols('k', negative=True), + 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) == \ + 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) + assert FT(exp(-a*abs(x)), x, k) == 2*a/(a**2 + 4*pi**2*k**2) + # TODO IFT (comes out as meijer G) + + # TODO besselj(n, x), n an integer > 0 actually can be done... + + # TODO are there other common transforms (no distributions!)? + + +def test_sine_transform(): + t = symbols("t") + w = symbols("w") + a = symbols("a") + f = Function("f") + + # 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 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) == 2*sqrt(w) + + assert sine_transform(t**(-a), t, w) == 2**( + -a + S.Half)*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.Half), 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**Rational(3, 2)) + assert inverse_sine_transform( + sqrt(2)*w*exp(-w**2/(4*a))/(4*a**Rational(3, 2)), w, t) == t*exp(-a*t**2) + + +def test_cosine_transform(): + from sympy.functions.special.error_functions import (Ci, Si) + + t = symbols("t") + w = symbols("w") + a = symbols("a") + f = Function("f") + + # 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 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)*exp(-a*w)/(2*a) + + assert cosine_transform(t**( + -a), t, w) == 2**(-a + S.Half)*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.Half)/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**Rational(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.Half, 0), ()), ( + (S.Half, 0, 0), (S.Half,)), 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.Half,), ()), ((0, 0), (S.Half,)), a**2*w**2/4)/(2*sqrt(pi)) + assert inverse_cosine_transform(sqrt(2)*meijerg(((S.Half,), ()), ((0, 0), (S.Half,)), a**2*w**2/4)/(2*sqrt(pi)), w, t) == 1/(t*sqrt(a**2/t**2 + 1)) + + +def test_hankel_transform(): + r = Symbol("r") + k = Symbol("k") + nu = Symbol("nu") + m = Symbol("m") + a = symbols("a") + + 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*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 + Rational(3, 2))/sqrt(pi) + assert inverse_hankel_transform( + 2**(nu + 1)*a*k**(-nu - 3)*(a**2/k**2 + 1)**(-nu - Rational(3, 2))*gamma( + nu + Rational(3, 2))/sqrt(pi), k, r, nu) == r**nu*exp(-a*r) + + +def test_issue_7181(): + assert mellin_transform(1/(1 - x), x, s) != None + + +def test_issue_8882(): + # This is the original test. + # from sympy import diff, Integral, integrate + # r = Symbol('r') + # psi = 1/r*sin(r)*exp(-(a0*r)) + # h = -1/2*diff(psi, r, r) - 1/r*psi + # f = 4*pi*psi*h*r**2 + # assert integrate(f, (r, -oo, 3), meijerg=True).has(Integral) == True + + # To save time, only the critical part is included. + F = -a**(-s + 1)*(4 + 1/a**2)**(-s/2)*sqrt(1/a**2)*exp(-s*I*pi)* \ + sin(s*atan(sqrt(1/a**2)/2))*gamma(s) + raises(IntegralTransformError, lambda: + inverse_mellin_transform(F, s, x, (-1, oo), + **{'as_meijerg': True, 'needeval': True})) + + +def test_issue_12591(): + x, y = symbols("x y", real=True) + assert fourier_transform(exp(x), x, y) == FourierTransform(exp(x), x, y) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_trigonometry.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_trigonometry.py new file mode 100644 index 0000000000000000000000000000000000000000..857c8503c5aa690d66e9cdab49730b4ea655a52c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/integrals/tests/test_trigonometry.py @@ -0,0 +1,98 @@ +from sympy.core import Ne, Rational, Symbol +from sympy.functions import sin, cos, tan, csc, sec, cot, log, Piecewise +from sympy.integrals.trigonometry import trigintegrate + +x = Symbol('x') + + +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(sin(x), x) == -cos(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 + + y = Symbol('y') + assert trigintegrate(sin(y*x), x) == Piecewise( + (-cos(y*x)/y, Ne(y, 0)), (0, True)) + assert trigintegrate(cos(y*x), x) == Piecewise( + (sin(y*x)/y, Ne(y, 0)), (x, True)) + assert trigintegrate(sin(y*x)**2, x) == Piecewise( + ((x*y/2 - sin(x*y)*cos(x*y)/2)/y, Ne(y, 0)), (0, True)) + assert trigintegrate(sin(y*x)*cos(y*x), x) == Piecewise( + (sin(x*y)**2/(2*y), Ne(y, 0)), (0, True)) + assert trigintegrate(cos(y*x)**2, x) == Piecewise( + ((x*y/2 + sin(x*y)*cos(x*y)/2)/y, Ne(y, 0)), (x, 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) * 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 + + # both n, m are odd and -ve, and not necessarily equal + assert trigintegrate(sin(x)**-1*cos(x)**-1, x) == \ + -log(sin(x)**2 - 1)/2 + log(sin(x)) + + +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(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(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(cos(x)) + 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(sin(x)) + 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(cot(x)*cos(x)**2, x) == log(sin(x)) - sin(x)**2/2 + + +def test_trigintegrate_symbolic(): + n = Symbol('n', integer=True) + assert trigintegrate(cos(x)**n, x) is None + assert trigintegrate(sin(x)**n, x) is None + assert trigintegrate(cot(x)**n, x) is None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..97e0bfe1416c9bf1dfc308e42bafa7abf79f030f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/hydrogen.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/hydrogen.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e9bdee3efc263a7515e5d0c072bc7123a2d8cea2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/hydrogen.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/matrices.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/matrices.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca6e60e2b6b375938a53494c504248dc078beff7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/matrices.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/paulialgebra.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/paulialgebra.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c4c627bc68d00a2ccd6c662869a37a645e32d48b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/paulialgebra.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/pring.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/pring.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..79025c10698c99f74fb282da0f1bb4c850988796 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/pring.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/qho_1d.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/qho_1d.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..116d90af183ba9e87ceae3484f5baff91705d08a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/qho_1d.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/sho.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/sho.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ee0deaa1d5ccb9ab8d6f25878b8565252323ccf2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/sho.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/wigner.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/wigner.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..191e29e9512bca3eda3514fe7b8fe84d72418858 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/__pycache__/wigner.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3e0f687cc23c1862b65e55117841cfd7d2b8e3f0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__init__.py @@ -0,0 +1,53 @@ +"""Biomechanics extension for SymPy. + +Includes biomechanics-related constructs which allows users to extend multibody +models created using `sympy.physics.mechanics` into biomechanical or +musculoskeletal models involding musculotendons and activation dynamics. + +""" + +from .activation import ( + ActivationBase, + FirstOrderActivationDeGroote2016, + ZerothOrderActivation, +) +from .curve import ( + CharacteristicCurveCollection, + CharacteristicCurveFunction, + FiberForceLengthActiveDeGroote2016, + FiberForceLengthPassiveDeGroote2016, + FiberForceLengthPassiveInverseDeGroote2016, + FiberForceVelocityDeGroote2016, + FiberForceVelocityInverseDeGroote2016, + TendonForceLengthDeGroote2016, + TendonForceLengthInverseDeGroote2016, +) +from .musculotendon import ( + MusculotendonBase, + MusculotendonDeGroote2016, + MusculotendonFormulation, +) + + +__all__ = [ + # Musculotendon characteristic curve functions + 'CharacteristicCurveCollection', + 'CharacteristicCurveFunction', + 'FiberForceLengthActiveDeGroote2016', + 'FiberForceLengthPassiveDeGroote2016', + 'FiberForceLengthPassiveInverseDeGroote2016', + 'FiberForceVelocityDeGroote2016', + 'FiberForceVelocityInverseDeGroote2016', + 'TendonForceLengthDeGroote2016', + 'TendonForceLengthInverseDeGroote2016', + + # Activation dynamics classes + 'ActivationBase', + 'FirstOrderActivationDeGroote2016', + 'ZerothOrderActivation', + + # Musculotendon classes + 'MusculotendonBase', + 'MusculotendonDeGroote2016', + 'MusculotendonFormulation', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69f052f36c81968486b5ae0a1cb269192ec85221 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/_mixin.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/_mixin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e35c4ec751dd193abd63115bc128278fea37b6f6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/_mixin.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/activation.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/activation.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f017344ef46e9c684470e47552b1441bdaf493f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/activation.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/curve.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/curve.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf255d8a1d76ec1527c163e4cccb32068cac1f5a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/curve.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/musculotendon.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/musculotendon.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..288d454540b5b2ed2ece7df489563e7f444f36a4 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/__pycache__/musculotendon.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/_mixin.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/_mixin.py new file mode 100644 index 0000000000000000000000000000000000000000..f6ff905100fb4d6f346aaf717cfe9a66b4c2cc9a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/_mixin.py @@ -0,0 +1,53 @@ +"""Mixin classes for sharing functionality between unrelated classes. + +This module is named with a leading underscore to signify to users that it's +"private" and only intended for internal use by the biomechanics module. + +""" + + +__all__ = ['_NamedMixin'] + + +class _NamedMixin: + """Mixin class for adding `name` properties. + + Valid names, as will typically be used by subclasses as a suffix when + naming automatically-instantiated symbol attributes, must be nonzero length + strings. + + Attributes + ========== + + name : str + The name identifier associated with the instance. Must be a string of + length at least 1. + + """ + + @property + def name(self) -> str: + """The name associated with the class instance.""" + return self._name + + @name.setter + def name(self, name: str) -> None: + if hasattr(self, '_name'): + msg = ( + f'Can\'t set attribute `name` to {repr(name)} as it is ' + f'immutable.' + ) + raise AttributeError(msg) + if not isinstance(name, str): + msg = ( + f'Name {repr(name)} passed to `name` was of type ' + f'{type(name)}, must be {str}.' + ) + raise TypeError(msg) + if name in {''}: + msg = ( + f'Name {repr(name)} is invalid, must be a nonzero length ' + f'{type(str)}.' + ) + raise ValueError(msg) + self._name = name diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/activation.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/activation.py new file mode 100644 index 0000000000000000000000000000000000000000..908d9bd2e7b433f91ef6678426c2e4896ab82f27 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/activation.py @@ -0,0 +1,869 @@ +r"""Activation dynamics for musclotendon models. + +Musculotendon models are able to produce active force when they are activated, +which is when a chemical process has taken place within the muscle fibers +causing them to voluntarily contract. Biologically this chemical process (the +diffusion of :math:`\textrm{Ca}^{2+}` ions) is not the input in the system, +electrical signals from the nervous system are. These are termed excitations. +Activation dynamics, which relates the normalized excitation level to the +normalized activation level, can be modeled by the models present in this +module. + +""" + +from abc import ABC, abstractmethod +from functools import cached_property + +from sympy.core.symbol import Symbol +from sympy.core.numbers import Float, Integer, Rational +from sympy.functions.elementary.hyperbolic import tanh +from sympy.matrices.dense import MutableDenseMatrix as Matrix, zeros +from sympy.physics.biomechanics._mixin import _NamedMixin +from sympy.physics.mechanics import dynamicsymbols + + +__all__ = [ + 'ActivationBase', + 'FirstOrderActivationDeGroote2016', + 'ZerothOrderActivation', +] + + +class ActivationBase(ABC, _NamedMixin): + """Abstract base class for all activation dynamics classes to inherit from. + + Notes + ===== + + Instances of this class cannot be directly instantiated by users. However, + it can be used to created custom activation dynamics types through + subclassing. + + """ + + def __init__(self, name): + """Initializer for ``ActivationBase``.""" + self.name = str(name) + + # Symbols + self._e = dynamicsymbols(f"e_{name}") + self._a = dynamicsymbols(f"a_{name}") + + @classmethod + @abstractmethod + def with_defaults(cls, name): + """Alternate constructor that provides recommended defaults for + constants.""" + pass + + @property + def excitation(self): + """Dynamic symbol representing excitation. + + Explanation + =========== + + The alias ``e`` can also be used to access the same attribute. + + """ + return self._e + + @property + def e(self): + """Dynamic symbol representing excitation. + + Explanation + =========== + + The alias ``excitation`` can also be used to access the same attribute. + + """ + return self._e + + @property + def activation(self): + """Dynamic symbol representing activation. + + Explanation + =========== + + The alias ``a`` can also be used to access the same attribute. + + """ + return self._a + + @property + def a(self): + """Dynamic symbol representing activation. + + Explanation + =========== + + The alias ``activation`` can also be used to access the same attribute. + + """ + return self._a + + @property + @abstractmethod + def order(self): + """Order of the (differential) equation governing activation.""" + pass + + @property + @abstractmethod + def state_vars(self): + """Ordered column matrix of functions of time that represent the state + variables. + + Explanation + =========== + + The alias ``x`` can also be used to access the same attribute. + + """ + pass + + @property + @abstractmethod + def x(self): + """Ordered column matrix of functions of time that represent the state + variables. + + Explanation + =========== + + The alias ``state_vars`` can also be used to access the same attribute. + + """ + pass + + @property + @abstractmethod + def input_vars(self): + """Ordered column matrix of functions of time that represent the input + variables. + + Explanation + =========== + + The alias ``r`` can also be used to access the same attribute. + + """ + pass + + @property + @abstractmethod + def r(self): + """Ordered column matrix of functions of time that represent the input + variables. + + Explanation + =========== + + The alias ``input_vars`` can also be used to access the same attribute. + + """ + pass + + @property + @abstractmethod + def constants(self): + """Ordered column matrix of non-time varying symbols present in ``M`` + and ``F``. + + Only symbolic constants are returned. If a numeric type (e.g. ``Float``) + has been used instead of ``Symbol`` for a constant then that attribute + will not be included in the matrix returned by this property. This is + because the primary use of this property attribute is to provide an + ordered sequence of the still-free symbols that require numeric values + during code generation. + + Explanation + =========== + + The alias ``p`` can also be used to access the same attribute. + + """ + pass + + @property + @abstractmethod + def p(self): + """Ordered column matrix of non-time varying symbols present in ``M`` + and ``F``. + + Only symbolic constants are returned. If a numeric type (e.g. ``Float``) + has been used instead of ``Symbol`` for a constant then that attribute + will not be included in the matrix returned by this property. This is + because the primary use of this property attribute is to provide an + ordered sequence of the still-free symbols that require numeric values + during code generation. + + Explanation + =========== + + The alias ``constants`` can also be used to access the same attribute. + + """ + pass + + @property + @abstractmethod + def M(self): + """Ordered square matrix of coefficients on the LHS of ``M x' = F``. + + Explanation + =========== + + The square matrix that forms part of the LHS of the linear system of + ordinary differential equations governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + """ + pass + + @property + @abstractmethod + def F(self): + """Ordered column matrix of equations on the RHS of ``M x' = F``. + + Explanation + =========== + + The column matrix that forms the RHS of the linear system of ordinary + differential equations governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + """ + pass + + @abstractmethod + def rhs(self): + """ + + Explanation + =========== + + The solution to the linear system of ordinary differential equations + governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + """ + pass + + def __eq__(self, other): + """Equality check for activation dynamics.""" + if type(self) != type(other): + return False + if self.name != other.name: + return False + return True + + def __repr__(self): + """Default representation of activation dynamics.""" + return f'{self.__class__.__name__}({self.name!r})' + + +class ZerothOrderActivation(ActivationBase): + """Simple zeroth-order activation dynamics mapping excitation to + activation. + + Explanation + =========== + + Zeroth-order activation dynamics are useful in instances where you want to + reduce the complexity of your musculotendon dynamics as they simple map + exictation to activation. As a result, no additional state equations are + introduced to your system. They also remove a potential source of delay + between the input and dynamics of your system as no (ordinary) differential + equations are involved. + + """ + + def __init__(self, name): + """Initializer for ``ZerothOrderActivation``. + + Parameters + ========== + + name : str + The name identifier associated with the instance. Must be a string + of length at least 1. + + """ + super().__init__(name) + + # Zeroth-order activation dynamics has activation equal excitation so + # overwrite the symbol for activation with the excitation symbol. + self._a = self._e + + @classmethod + def with_defaults(cls, name): + """Alternate constructor that provides recommended defaults for + constants. + + Explanation + =========== + + As this concrete class doesn't implement any constants associated with + its dynamics, this ``classmethod`` simply creates a standard instance + of ``ZerothOrderActivation``. An implementation is provided to ensure + a consistent interface between all ``ActivationBase`` concrete classes. + + """ + return cls(name) + + @property + def order(self): + """Order of the (differential) equation governing activation.""" + return 0 + + @property + def state_vars(self): + """Ordered column matrix of functions of time that represent the state + variables. + + Explanation + =========== + + As zeroth-order activation dynamics simply maps excitation to + activation, this class has no associated state variables and so this + property return an empty column ``Matrix`` with shape (0, 1). + + The alias ``x`` can also be used to access the same attribute. + + """ + return zeros(0, 1) + + @property + def x(self): + """Ordered column matrix of functions of time that represent the state + variables. + + Explanation + =========== + + As zeroth-order activation dynamics simply maps excitation to + activation, this class has no associated state variables and so this + property return an empty column ``Matrix`` with shape (0, 1). + + The alias ``state_vars`` can also be used to access the same attribute. + + """ + return zeros(0, 1) + + @property + def input_vars(self): + """Ordered column matrix of functions of time that represent the input + variables. + + Explanation + =========== + + Excitation is the only input in zeroth-order activation dynamics and so + this property returns a column ``Matrix`` with one entry, ``e``, and + shape (1, 1). + + The alias ``r`` can also be used to access the same attribute. + + """ + return Matrix([self._e]) + + @property + def r(self): + """Ordered column matrix of functions of time that represent the input + variables. + + Explanation + =========== + + Excitation is the only input in zeroth-order activation dynamics and so + this property returns a column ``Matrix`` with one entry, ``e``, and + shape (1, 1). + + The alias ``input_vars`` can also be used to access the same attribute. + + """ + return Matrix([self._e]) + + @property + def constants(self): + """Ordered column matrix of non-time varying symbols present in ``M`` + and ``F``. + + Only symbolic constants are returned. If a numeric type (e.g. ``Float``) + has been used instead of ``Symbol`` for a constant then that attribute + will not be included in the matrix returned by this property. This is + because the primary use of this property attribute is to provide an + ordered sequence of the still-free symbols that require numeric values + during code generation. + + Explanation + =========== + + As zeroth-order activation dynamics simply maps excitation to + activation, this class has no associated constants and so this property + return an empty column ``Matrix`` with shape (0, 1). + + The alias ``p`` can also be used to access the same attribute. + + """ + return zeros(0, 1) + + @property + def p(self): + """Ordered column matrix of non-time varying symbols present in ``M`` + and ``F``. + + Only symbolic constants are returned. If a numeric type (e.g. ``Float``) + has been used instead of ``Symbol`` for a constant then that attribute + will not be included in the matrix returned by this property. This is + because the primary use of this property attribute is to provide an + ordered sequence of the still-free symbols that require numeric values + during code generation. + + Explanation + =========== + + As zeroth-order activation dynamics simply maps excitation to + activation, this class has no associated constants and so this property + return an empty column ``Matrix`` with shape (0, 1). + + The alias ``constants`` can also be used to access the same attribute. + + """ + return zeros(0, 1) + + @property + def M(self): + """Ordered square matrix of coefficients on the LHS of ``M x' = F``. + + Explanation + =========== + + The square matrix that forms part of the LHS of the linear system of + ordinary differential equations governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + As zeroth-order activation dynamics have no state variables, this + linear system has dimension 0 and therefore ``M`` is an empty square + ``Matrix`` with shape (0, 0). + + """ + return Matrix([]) + + @property + def F(self): + """Ordered column matrix of equations on the RHS of ``M x' = F``. + + Explanation + =========== + + The column matrix that forms the RHS of the linear system of ordinary + differential equations governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + As zeroth-order activation dynamics have no state variables, this + linear system has dimension 0 and therefore ``F`` is an empty column + ``Matrix`` with shape (0, 1). + + """ + return zeros(0, 1) + + def rhs(self): + """Ordered column matrix of equations for the solution of ``M x' = F``. + + Explanation + =========== + + The solution to the linear system of ordinary differential equations + governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + As zeroth-order activation dynamics have no state variables, this + linear has dimension 0 and therefore this method returns an empty + column ``Matrix`` with shape (0, 1). + + """ + return zeros(0, 1) + + +class FirstOrderActivationDeGroote2016(ActivationBase): + r"""First-order activation dynamics based on De Groote et al., 2016 [1]_. + + Explanation + =========== + + Gives the first-order activation dynamics equation for the rate of change + of activation with respect to time as a function of excitation and + activation. + + The function is defined by the equation: + + .. math:: + + \frac{da}{dt} = \left(\frac{\frac{1}{2} + a0}{\tau_a \left(\frac{1}{2} + + \frac{3a}{2}\right)} + \frac{\left(\frac{1}{2} + + \frac{3a}{2}\right) \left(\frac{1}{2} - a0\right)}{\tau_d}\right) + \left(e - a\right) + + where + + .. math:: + + a0 = \frac{\tanh{\left(b \left(e - a\right) \right)}}{2} + + with constant values of :math:`tau_a = 0.015`, :math:`tau_d = 0.060`, and + :math:`b = 10`. + + References + ========== + + .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation + of direct collocation optimal control problem formulations for + solving the muscle redundancy problem, Annals of biomedical + engineering, 44(10), (2016) pp. 2922-2936 + + """ + + def __init__(self, + name, + activation_time_constant=None, + deactivation_time_constant=None, + smoothing_rate=None, + ): + """Initializer for ``FirstOrderActivationDeGroote2016``. + + Parameters + ========== + activation time constant : Symbol | Number | None + The value of the activation time constant governing the delay + between excitation and activation when excitation exceeds + activation. + deactivation time constant : Symbol | Number | None + The value of the deactivation time constant governing the delay + between excitation and activation when activation exceeds + excitation. + smoothing_rate : Symbol | Number | None + The slope of the hyperbolic tangent function used to smooth between + the switching of the equations where excitation exceed activation + and where activation exceeds excitation. The recommended value to + use is ``10``, but values between ``0.1`` and ``100`` can be used. + + """ + super().__init__(name) + + # Symbols + self.activation_time_constant = activation_time_constant + self.deactivation_time_constant = deactivation_time_constant + self.smoothing_rate = smoothing_rate + + @classmethod + def with_defaults(cls, name): + r"""Alternate constructor that will use the published constants. + + Explanation + =========== + + Returns an instance of ``FirstOrderActivationDeGroote2016`` using the + three constant values specified in the original publication. + + These have the values: + + :math:`tau_a = 0.015` + :math:`tau_d = 0.060` + :math:`b = 10` + + """ + tau_a = Float('0.015') + tau_d = Float('0.060') + b = Float('10.0') + return cls(name, tau_a, tau_d, b) + + @property + def activation_time_constant(self): + """Delay constant for activation. + + Explanation + =========== + + The alias ```tau_a`` can also be used to access the same attribute. + + """ + return self._tau_a + + @activation_time_constant.setter + def activation_time_constant(self, tau_a): + if hasattr(self, '_tau_a'): + msg = ( + f'Can\'t set attribute `activation_time_constant` to ' + f'{repr(tau_a)} as it is immutable and already has value ' + f'{self._tau_a}.' + ) + raise AttributeError(msg) + self._tau_a = Symbol(f'tau_a_{self.name}') if tau_a is None else tau_a + + @property + def tau_a(self): + """Delay constant for activation. + + Explanation + =========== + + The alias ``activation_time_constant`` can also be used to access the + same attribute. + + """ + return self._tau_a + + @property + def deactivation_time_constant(self): + """Delay constant for deactivation. + + Explanation + =========== + + The alias ``tau_d`` can also be used to access the same attribute. + + """ + return self._tau_d + + @deactivation_time_constant.setter + def deactivation_time_constant(self, tau_d): + if hasattr(self, '_tau_d'): + msg = ( + f'Can\'t set attribute `deactivation_time_constant` to ' + f'{repr(tau_d)} as it is immutable and already has value ' + f'{self._tau_d}.' + ) + raise AttributeError(msg) + self._tau_d = Symbol(f'tau_d_{self.name}') if tau_d is None else tau_d + + @property + def tau_d(self): + """Delay constant for deactivation. + + Explanation + =========== + + The alias ``deactivation_time_constant`` can also be used to access the + same attribute. + + """ + return self._tau_d + + @property + def smoothing_rate(self): + """Smoothing constant for the hyperbolic tangent term. + + Explanation + =========== + + The alias ``b`` can also be used to access the same attribute. + + """ + return self._b + + @smoothing_rate.setter + def smoothing_rate(self, b): + if hasattr(self, '_b'): + msg = ( + f'Can\'t set attribute `smoothing_rate` to {b!r} as it is ' + f'immutable and already has value {self._b!r}.' + ) + raise AttributeError(msg) + self._b = Symbol(f'b_{self.name}') if b is None else b + + @property + def b(self): + """Smoothing constant for the hyperbolic tangent term. + + Explanation + =========== + + The alias ``smoothing_rate`` can also be used to access the same + attribute. + + """ + return self._b + + @property + def order(self): + """Order of the (differential) equation governing activation.""" + return 1 + + @property + def state_vars(self): + """Ordered column matrix of functions of time that represent the state + variables. + + Explanation + =========== + + The alias ``x`` can also be used to access the same attribute. + + """ + return Matrix([self._a]) + + @property + def x(self): + """Ordered column matrix of functions of time that represent the state + variables. + + Explanation + =========== + + The alias ``state_vars`` can also be used to access the same attribute. + + """ + return Matrix([self._a]) + + @property + def input_vars(self): + """Ordered column matrix of functions of time that represent the input + variables. + + Explanation + =========== + + The alias ``r`` can also be used to access the same attribute. + + """ + return Matrix([self._e]) + + @property + def r(self): + """Ordered column matrix of functions of time that represent the input + variables. + + Explanation + =========== + + The alias ``input_vars`` can also be used to access the same attribute. + + """ + return Matrix([self._e]) + + @property + def constants(self): + """Ordered column matrix of non-time varying symbols present in ``M`` + and ``F``. + + Only symbolic constants are returned. If a numeric type (e.g. ``Float``) + has been used instead of ``Symbol`` for a constant then that attribute + will not be included in the matrix returned by this property. This is + because the primary use of this property attribute is to provide an + ordered sequence of the still-free symbols that require numeric values + during code generation. + + Explanation + =========== + + The alias ``p`` can also be used to access the same attribute. + + """ + constants = [self._tau_a, self._tau_d, self._b] + symbolic_constants = [c for c in constants if not c.is_number] + return Matrix(symbolic_constants) if symbolic_constants else zeros(0, 1) + + @property + def p(self): + """Ordered column matrix of non-time varying symbols present in ``M`` + and ``F``. + + Explanation + =========== + + Only symbolic constants are returned. If a numeric type (e.g. ``Float``) + has been used instead of ``Symbol`` for a constant then that attribute + will not be included in the matrix returned by this property. This is + because the primary use of this property attribute is to provide an + ordered sequence of the still-free symbols that require numeric values + during code generation. + + The alias ``constants`` can also be used to access the same attribute. + + """ + constants = [self._tau_a, self._tau_d, self._b] + symbolic_constants = [c for c in constants if not c.is_number] + return Matrix(symbolic_constants) if symbolic_constants else zeros(0, 1) + + @property + def M(self): + """Ordered square matrix of coefficients on the LHS of ``M x' = F``. + + Explanation + =========== + + The square matrix that forms part of the LHS of the linear system of + ordinary differential equations governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + """ + return Matrix([Integer(1)]) + + @property + def F(self): + """Ordered column matrix of equations on the RHS of ``M x' = F``. + + Explanation + =========== + + The column matrix that forms the RHS of the linear system of ordinary + differential equations governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + """ + return Matrix([self._da_eqn]) + + def rhs(self): + """Ordered column matrix of equations for the solution of ``M x' = F``. + + Explanation + =========== + + The solution to the linear system of ordinary differential equations + governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + """ + return Matrix([self._da_eqn]) + + @cached_property + def _da_eqn(self): + HALF = Rational(1, 2) + a0 = HALF * tanh(self._b * (self._e - self._a)) + a1 = (HALF + Rational(3, 2) * self._a) + a2 = (HALF + a0) / (self._tau_a * a1) + a3 = a1 * (HALF - a0) / self._tau_d + activation_dynamics_equation = (a2 + a3) * (self._e - self._a) + return activation_dynamics_equation + + def __eq__(self, other): + """Equality check for ``FirstOrderActivationDeGroote2016``.""" + if type(self) != type(other): + return False + self_attrs = (self.name, self.tau_a, self.tau_d, self.b) + other_attrs = (other.name, other.tau_a, other.tau_d, other.b) + if self_attrs == other_attrs: + return True + return False + + def __repr__(self): + """Representation of ``FirstOrderActivationDeGroote2016``.""" + return ( + f'{self.__class__.__name__}({self.name!r}, ' + f'activation_time_constant={self.tau_a!r}, ' + f'deactivation_time_constant={self.tau_d!r}, ' + f'smoothing_rate={self.b!r})' + ) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/curve.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/curve.py new file mode 100644 index 0000000000000000000000000000000000000000..50535271f51493acc2183d257ce89ff0da4dde5e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/curve.py @@ -0,0 +1,1763 @@ +"""Implementations of characteristic curves for musculotendon models.""" + +from dataclasses import dataclass + +from sympy.core.expr import UnevaluatedExpr +from sympy.core.function import ArgumentIndexError, Function +from sympy.core.numbers import Float, Integer +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.hyperbolic import cosh, sinh +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.printing.precedence import PRECEDENCE + + +__all__ = [ + 'CharacteristicCurveCollection', + 'CharacteristicCurveFunction', + 'FiberForceLengthActiveDeGroote2016', + 'FiberForceLengthPassiveDeGroote2016', + 'FiberForceLengthPassiveInverseDeGroote2016', + 'FiberForceVelocityDeGroote2016', + 'FiberForceVelocityInverseDeGroote2016', + 'TendonForceLengthDeGroote2016', + 'TendonForceLengthInverseDeGroote2016', +] + + +class CharacteristicCurveFunction(Function): + """Base class for all musculotendon characteristic curve functions.""" + + @classmethod + def eval(cls): + msg = ( + f'Cannot directly instantiate {cls.__name__!r}, instances of ' + f'characteristic curves must be of a concrete subclass.' + + ) + raise TypeError(msg) + + def _print_code(self, printer): + """Print code for the function defining the curve using a printer. + + Explanation + =========== + + The order of operations may need to be controlled as constant folding + the numeric terms within the equations of a musculotendon + characteristic curve can sometimes results in a numerically-unstable + expression. + + Parameters + ========== + + printer : Printer + The printer to be used to print a string representation of the + characteristic curve as valid code in the target language. + + """ + return printer._print(printer.parenthesize( + self.doit(deep=False, evaluate=False), PRECEDENCE['Atom'], + )) + + _ccode = _print_code + _cupycode = _print_code + _cxxcode = _print_code + _fcode = _print_code + _jaxcode = _print_code + _lambdacode = _print_code + _mpmathcode = _print_code + _octave = _print_code + _pythoncode = _print_code + _numpycode = _print_code + _scipycode = _print_code + + +class TendonForceLengthDeGroote2016(CharacteristicCurveFunction): + r"""Tendon force-length curve based on De Groote et al., 2016 [1]_. + + Explanation + =========== + + Gives the normalized tendon force produced as a function of normalized + tendon length. + + The function is defined by the equation: + + $fl^T = c_0 \exp{c_3 \left( \tilde{l}^T - c_1 \right)} - c_2$ + + with constant values of $c_0 = 0.2$, $c_1 = 0.995$, $c_2 = 0.25$, and + $c_3 = 33.93669377311689$. + + While it is possible to change the constant values, these were carefully + selected in the original publication to give the characteristic curve + specific and required properties. For example, the function produces no + force when the tendon is in an unstrained state. It also produces a force + of 1 normalized unit when the tendon is under a 5% strain. + + Examples + ======== + + The preferred way to instantiate :class:`TendonForceLengthDeGroote2016` is using + the :meth:`~.with_defaults` constructor because this will automatically + populate the constants within the characteristic curve equation with the + floating point values from the original publication. This constructor takes + a single argument corresponding to normalized tendon length. We'll create a + :class:`~.Symbol` called ``l_T_tilde`` to represent this. + + >>> from sympy import Symbol + >>> from sympy.physics.biomechanics import TendonForceLengthDeGroote2016 + >>> l_T_tilde = Symbol('l_T_tilde') + >>> fl_T = TendonForceLengthDeGroote2016.with_defaults(l_T_tilde) + >>> fl_T + TendonForceLengthDeGroote2016(l_T_tilde, 0.2, 0.995, 0.25, + 33.93669377311689) + + It's also possible to populate the four constants with your own values too. + + >>> from sympy import symbols + >>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3') + >>> fl_T = TendonForceLengthDeGroote2016(l_T_tilde, c0, c1, c2, c3) + >>> fl_T + TendonForceLengthDeGroote2016(l_T_tilde, c0, c1, c2, c3) + + You don't just have to use symbols as the arguments, it's also possible to + use expressions. Let's create a new pair of symbols, ``l_T`` and + ``l_T_slack``, representing tendon length and tendon slack length + respectively. We can then represent ``l_T_tilde`` as an expression, the + ratio of these. + + >>> l_T, l_T_slack = symbols('l_T l_T_slack') + >>> l_T_tilde = l_T/l_T_slack + >>> fl_T = TendonForceLengthDeGroote2016.with_defaults(l_T_tilde) + >>> fl_T + TendonForceLengthDeGroote2016(l_T/l_T_slack, 0.2, 0.995, 0.25, + 33.93669377311689) + + To inspect the actual symbolic expression that this function represents, + we can call the :meth:`~.doit` method on an instance. We'll use the keyword + argument ``evaluate=False`` as this will keep the expression in its + canonical form and won't simplify any constants. + + >>> fl_T.doit(evaluate=False) + -0.25 + 0.2*exp(33.93669377311689*(l_T/l_T_slack - 0.995)) + + The function can also be differentiated. We'll differentiate with respect + to l_T using the ``diff`` method on an instance with the single positional + argument ``l_T``. + + >>> fl_T.diff(l_T) + 6.787338754623378*exp(33.93669377311689*(l_T/l_T_slack - 0.995))/l_T_slack + + References + ========== + + .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation + of direct collocation optimal control problem formulations for + solving the muscle redundancy problem, Annals of biomedical + engineering, 44(10), (2016) pp. 2922-2936 + + """ + + @classmethod + def with_defaults(cls, l_T_tilde): + r"""Recommended constructor that will use the published constants. + + Explanation + =========== + + Returns a new instance of the tendon force-length function using the + four constant values specified in the original publication. + + These have the values: + + $c_0 = 0.2$ + $c_1 = 0.995$ + $c_2 = 0.25$ + $c_3 = 33.93669377311689$ + + Parameters + ========== + + l_T_tilde : Any (sympifiable) + Normalized tendon length. + + """ + c0 = Float('0.2') + c1 = Float('0.995') + c2 = Float('0.25') + c3 = Float('33.93669377311689') + return cls(l_T_tilde, c0, c1, c2, c3) + + @classmethod + def eval(cls, l_T_tilde, c0, c1, c2, c3): + """Evaluation of basic inputs. + + Parameters + ========== + + l_T_tilde : Any (sympifiable) + Normalized tendon length. + c0 : Any (sympifiable) + The first constant in the characteristic equation. The published + value is ``0.2``. + c1 : Any (sympifiable) + The second constant in the characteristic equation. The published + value is ``0.995``. + c2 : Any (sympifiable) + The third constant in the characteristic equation. The published + value is ``0.25``. + c3 : Any (sympifiable) + The fourth constant in the characteristic equation. The published + value is ``33.93669377311689``. + + """ + pass + + def _eval_evalf(self, prec): + """Evaluate the expression numerically using ``evalf``.""" + return self.doit(deep=False, evaluate=False)._eval_evalf(prec) + + def doit(self, deep=True, evaluate=True, **hints): + """Evaluate the expression defining the function. + + Parameters + ========== + + deep : bool + Whether ``doit`` should be recursively called. Default is ``True``. + evaluate : bool. + Whether the SymPy expression should be evaluated as it is + constructed. If ``False``, then no constant folding will be + conducted which will leave the expression in a more numerically- + stable for values of ``l_T_tilde`` that correspond to a sensible + operating range for a musculotendon. Default is ``True``. + **kwargs : dict[str, Any] + Additional keyword argument pairs to be recursively passed to + ``doit``. + + """ + l_T_tilde, *constants = self.args + if deep: + hints['evaluate'] = evaluate + l_T_tilde = l_T_tilde.doit(deep=deep, **hints) + c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants] + else: + c0, c1, c2, c3 = constants + + if evaluate: + return c0*exp(c3*(l_T_tilde - c1)) - c2 + + return c0*exp(c3*UnevaluatedExpr(l_T_tilde - c1)) - c2 + + def fdiff(self, argindex=1): + """Derivative of the function with respect to a single argument. + + Parameters + ========== + + argindex : int + The index of the function's arguments with respect to which the + derivative should be taken. Argument indexes start at ``1``. + Default is ``1``. + + """ + l_T_tilde, c0, c1, c2, c3 = self.args + if argindex == 1: + return c0*c3*exp(c3*UnevaluatedExpr(l_T_tilde - c1)) + elif argindex == 2: + return exp(c3*UnevaluatedExpr(l_T_tilde - c1)) + elif argindex == 3: + return -c0*c3*exp(c3*UnevaluatedExpr(l_T_tilde - c1)) + elif argindex == 4: + return Integer(-1) + elif argindex == 5: + return c0*(l_T_tilde - c1)*exp(c3*UnevaluatedExpr(l_T_tilde - c1)) + + raise ArgumentIndexError(self, argindex) + + def inverse(self, argindex=1): + """Inverse function. + + Parameters + ========== + + argindex : int + Value to start indexing the arguments at. Default is ``1``. + + """ + return TendonForceLengthInverseDeGroote2016 + + def _latex(self, printer): + """Print a LaTeX representation of the function defining the curve. + + Parameters + ========== + + printer : Printer + The printer to be used to print the LaTeX string representation. + + """ + l_T_tilde = self.args[0] + _l_T_tilde = printer._print(l_T_tilde) + return r'\operatorname{fl}^T \left( %s \right)' % _l_T_tilde + + +class TendonForceLengthInverseDeGroote2016(CharacteristicCurveFunction): + r"""Inverse tendon force-length curve based on De Groote et al., 2016 [1]_. + + Explanation + =========== + + Gives the normalized tendon length that produces a specific normalized + tendon force. + + The function is defined by the equation: + + ${fl^T}^{-1} = frac{\log{\frac{fl^T + c_2}{c_0}}}{c_3} + c_1$ + + with constant values of $c_0 = 0.2$, $c_1 = 0.995$, $c_2 = 0.25$, and + $c_3 = 33.93669377311689$. This function is the exact analytical inverse + of the related tendon force-length curve ``TendonForceLengthDeGroote2016``. + + While it is possible to change the constant values, these were carefully + selected in the original publication to give the characteristic curve + specific and required properties. For example, the function produces no + force when the tendon is in an unstrained state. It also produces a force + of 1 normalized unit when the tendon is under a 5% strain. + + Examples + ======== + + The preferred way to instantiate :class:`TendonForceLengthInverseDeGroote2016` is + using the :meth:`~.with_defaults` constructor because this will automatically + populate the constants within the characteristic curve equation with the + floating point values from the original publication. This constructor takes + a single argument corresponding to normalized tendon force-length, which is + equal to the tendon force. We'll create a :class:`~.Symbol` called ``fl_T`` to + represent this. + + >>> from sympy import Symbol + >>> from sympy.physics.biomechanics import TendonForceLengthInverseDeGroote2016 + >>> fl_T = Symbol('fl_T') + >>> l_T_tilde = TendonForceLengthInverseDeGroote2016.with_defaults(fl_T) + >>> l_T_tilde + TendonForceLengthInverseDeGroote2016(fl_T, 0.2, 0.995, 0.25, + 33.93669377311689) + + It's also possible to populate the four constants with your own values too. + + >>> from sympy import symbols + >>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3') + >>> l_T_tilde = TendonForceLengthInverseDeGroote2016(fl_T, c0, c1, c2, c3) + >>> l_T_tilde + TendonForceLengthInverseDeGroote2016(fl_T, c0, c1, c2, c3) + + To inspect the actual symbolic expression that this function represents, + we can call the :meth:`~.doit` method on an instance. We'll use the keyword + argument ``evaluate=False`` as this will keep the expression in its + canonical form and won't simplify any constants. + + >>> l_T_tilde.doit(evaluate=False) + c1 + log((c2 + fl_T)/c0)/c3 + + The function can also be differentiated. We'll differentiate with respect + to l_T using the ``diff`` method on an instance with the single positional + argument ``l_T``. + + >>> l_T_tilde.diff(fl_T) + 1/(c3*(c2 + fl_T)) + + References + ========== + + .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation + of direct collocation optimal control problem formulations for + solving the muscle redundancy problem, Annals of biomedical + engineering, 44(10), (2016) pp. 2922-2936 + + """ + + @classmethod + def with_defaults(cls, fl_T): + r"""Recommended constructor that will use the published constants. + + Explanation + =========== + + Returns a new instance of the inverse tendon force-length function + using the four constant values specified in the original publication. + + These have the values: + + $c_0 = 0.2$ + $c_1 = 0.995$ + $c_2 = 0.25$ + $c_3 = 33.93669377311689$ + + Parameters + ========== + + fl_T : Any (sympifiable) + Normalized tendon force as a function of tendon length. + + """ + c0 = Float('0.2') + c1 = Float('0.995') + c2 = Float('0.25') + c3 = Float('33.93669377311689') + return cls(fl_T, c0, c1, c2, c3) + + @classmethod + def eval(cls, fl_T, c0, c1, c2, c3): + """Evaluation of basic inputs. + + Parameters + ========== + + fl_T : Any (sympifiable) + Normalized tendon force as a function of tendon length. + c0 : Any (sympifiable) + The first constant in the characteristic equation. The published + value is ``0.2``. + c1 : Any (sympifiable) + The second constant in the characteristic equation. The published + value is ``0.995``. + c2 : Any (sympifiable) + The third constant in the characteristic equation. The published + value is ``0.25``. + c3 : Any (sympifiable) + The fourth constant in the characteristic equation. The published + value is ``33.93669377311689``. + + """ + pass + + def _eval_evalf(self, prec): + """Evaluate the expression numerically using ``evalf``.""" + return self.doit(deep=False, evaluate=False)._eval_evalf(prec) + + def doit(self, deep=True, evaluate=True, **hints): + """Evaluate the expression defining the function. + + Parameters + ========== + + deep : bool + Whether ``doit`` should be recursively called. Default is ``True``. + evaluate : bool. + Whether the SymPy expression should be evaluated as it is + constructed. If ``False``, then no constant folding will be + conducted which will leave the expression in a more numerically- + stable for values of ``l_T_tilde`` that correspond to a sensible + operating range for a musculotendon. Default is ``True``. + **kwargs : dict[str, Any] + Additional keyword argument pairs to be recursively passed to + ``doit``. + + """ + fl_T, *constants = self.args + if deep: + hints['evaluate'] = evaluate + fl_T = fl_T.doit(deep=deep, **hints) + c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants] + else: + c0, c1, c2, c3 = constants + + if evaluate: + return log((fl_T + c2)/c0)/c3 + c1 + + return log(UnevaluatedExpr((fl_T + c2)/c0))/c3 + c1 + + def fdiff(self, argindex=1): + """Derivative of the function with respect to a single argument. + + Parameters + ========== + + argindex : int + The index of the function's arguments with respect to which the + derivative should be taken. Argument indexes start at ``1``. + Default is ``1``. + + """ + fl_T, c0, c1, c2, c3 = self.args + if argindex == 1: + return 1/(c3*(fl_T + c2)) + elif argindex == 2: + return -1/(c0*c3) + elif argindex == 3: + return Integer(1) + elif argindex == 4: + return 1/(c3*(fl_T + c2)) + elif argindex == 5: + return -log(UnevaluatedExpr((fl_T + c2)/c0))/c3**2 + + raise ArgumentIndexError(self, argindex) + + def inverse(self, argindex=1): + """Inverse function. + + Parameters + ========== + + argindex : int + Value to start indexing the arguments at. Default is ``1``. + + """ + return TendonForceLengthDeGroote2016 + + def _latex(self, printer): + """Print a LaTeX representation of the function defining the curve. + + Parameters + ========== + + printer : Printer + The printer to be used to print the LaTeX string representation. + + """ + fl_T = self.args[0] + _fl_T = printer._print(fl_T) + return r'\left( \operatorname{fl}^T \right)^{-1} \left( %s \right)' % _fl_T + + +class FiberForceLengthPassiveDeGroote2016(CharacteristicCurveFunction): + r"""Passive muscle fiber force-length curve based on De Groote et al., 2016 + [1]_. + + Explanation + =========== + + The function is defined by the equation: + + $fl^M_{pas} = \frac{\frac{\exp{c_1 \left(\tilde{l^M} - 1\right)}}{c_0} - 1}{\exp{c_1} - 1}$ + + with constant values of $c_0 = 0.6$ and $c_1 = 4.0$. + + While it is possible to change the constant values, these were carefully + selected in the original publication to give the characteristic curve + specific and required properties. For example, the function produces a + passive fiber force very close to 0 for all normalized fiber lengths + between 0 and 1. + + Examples + ======== + + The preferred way to instantiate :class:`FiberForceLengthPassiveDeGroote2016` is + using the :meth:`~.with_defaults` constructor because this will automatically + populate the constants within the characteristic curve equation with the + floating point values from the original publication. This constructor takes + a single argument corresponding to normalized muscle fiber length. We'll + create a :class:`~.Symbol` called ``l_M_tilde`` to represent this. + + >>> from sympy import Symbol + >>> from sympy.physics.biomechanics import FiberForceLengthPassiveDeGroote2016 + >>> l_M_tilde = Symbol('l_M_tilde') + >>> fl_M = FiberForceLengthPassiveDeGroote2016.with_defaults(l_M_tilde) + >>> fl_M + FiberForceLengthPassiveDeGroote2016(l_M_tilde, 0.6, 4.0) + + It's also possible to populate the two constants with your own values too. + + >>> from sympy import symbols + >>> c0, c1 = symbols('c0 c1') + >>> fl_M = FiberForceLengthPassiveDeGroote2016(l_M_tilde, c0, c1) + >>> fl_M + FiberForceLengthPassiveDeGroote2016(l_M_tilde, c0, c1) + + You don't just have to use symbols as the arguments, it's also possible to + use expressions. Let's create a new pair of symbols, ``l_M`` and + ``l_M_opt``, representing muscle fiber length and optimal muscle fiber + length respectively. We can then represent ``l_M_tilde`` as an expression, + the ratio of these. + + >>> l_M, l_M_opt = symbols('l_M l_M_opt') + >>> l_M_tilde = l_M/l_M_opt + >>> fl_M = FiberForceLengthPassiveDeGroote2016.with_defaults(l_M_tilde) + >>> fl_M + FiberForceLengthPassiveDeGroote2016(l_M/l_M_opt, 0.6, 4.0) + + To inspect the actual symbolic expression that this function represents, + we can call the :meth:`~.doit` method on an instance. We'll use the keyword + argument ``evaluate=False`` as this will keep the expression in its + canonical form and won't simplify any constants. + + >>> fl_M.doit(evaluate=False) + 0.0186573603637741*(-1 + exp(6.66666666666667*(l_M/l_M_opt - 1))) + + The function can also be differentiated. We'll differentiate with respect + to l_M using the ``diff`` method on an instance with the single positional + argument ``l_M``. + + >>> fl_M.diff(l_M) + 0.12438240242516*exp(6.66666666666667*(l_M/l_M_opt - 1))/l_M_opt + + References + ========== + + .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation + of direct collocation optimal control problem formulations for + solving the muscle redundancy problem, Annals of biomedical + engineering, 44(10), (2016) pp. 2922-2936 + + """ + + @classmethod + def with_defaults(cls, l_M_tilde): + r"""Recommended constructor that will use the published constants. + + Explanation + =========== + + Returns a new instance of the muscle fiber passive force-length + function using the four constant values specified in the original + publication. + + These have the values: + + $c_0 = 0.6$ + $c_1 = 4.0$ + + Parameters + ========== + + l_M_tilde : Any (sympifiable) + Normalized muscle fiber length. + + """ + c0 = Float('0.6') + c1 = Float('4.0') + return cls(l_M_tilde, c0, c1) + + @classmethod + def eval(cls, l_M_tilde, c0, c1): + """Evaluation of basic inputs. + + Parameters + ========== + + l_M_tilde : Any (sympifiable) + Normalized muscle fiber length. + c0 : Any (sympifiable) + The first constant in the characteristic equation. The published + value is ``0.6``. + c1 : Any (sympifiable) + The second constant in the characteristic equation. The published + value is ``4.0``. + + """ + pass + + def _eval_evalf(self, prec): + """Evaluate the expression numerically using ``evalf``.""" + return self.doit(deep=False, evaluate=False)._eval_evalf(prec) + + def doit(self, deep=True, evaluate=True, **hints): + """Evaluate the expression defining the function. + + Parameters + ========== + + deep : bool + Whether ``doit`` should be recursively called. Default is ``True``. + evaluate : bool. + Whether the SymPy expression should be evaluated as it is + constructed. If ``False``, then no constant folding will be + conducted which will leave the expression in a more numerically- + stable for values of ``l_T_tilde`` that correspond to a sensible + operating range for a musculotendon. Default is ``True``. + **kwargs : dict[str, Any] + Additional keyword argument pairs to be recursively passed to + ``doit``. + + """ + l_M_tilde, *constants = self.args + if deep: + hints['evaluate'] = evaluate + l_M_tilde = l_M_tilde.doit(deep=deep, **hints) + c0, c1 = [c.doit(deep=deep, **hints) for c in constants] + else: + c0, c1 = constants + + if evaluate: + return (exp((c1*(l_M_tilde - 1))/c0) - 1)/(exp(c1) - 1) + + return (exp((c1*UnevaluatedExpr(l_M_tilde - 1))/c0) - 1)/(exp(c1) - 1) + + def fdiff(self, argindex=1): + """Derivative of the function with respect to a single argument. + + Parameters + ========== + + argindex : int + The index of the function's arguments with respect to which the + derivative should be taken. Argument indexes start at ``1``. + Default is ``1``. + + """ + l_M_tilde, c0, c1 = self.args + if argindex == 1: + return c1*exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0)/(c0*(exp(c1) - 1)) + elif argindex == 2: + return ( + -c1*exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0) + *UnevaluatedExpr(l_M_tilde - 1)/(c0**2*(exp(c1) - 1)) + ) + elif argindex == 3: + return ( + -exp(c1)*(-1 + exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0))/(exp(c1) - 1)**2 + + exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0)*(l_M_tilde - 1)/(c0*(exp(c1) - 1)) + ) + + raise ArgumentIndexError(self, argindex) + + def inverse(self, argindex=1): + """Inverse function. + + Parameters + ========== + + argindex : int + Value to start indexing the arguments at. Default is ``1``. + + """ + return FiberForceLengthPassiveInverseDeGroote2016 + + def _latex(self, printer): + """Print a LaTeX representation of the function defining the curve. + + Parameters + ========== + + printer : Printer + The printer to be used to print the LaTeX string representation. + + """ + l_M_tilde = self.args[0] + _l_M_tilde = printer._print(l_M_tilde) + return r'\operatorname{fl}^M_{pas} \left( %s \right)' % _l_M_tilde + + +class FiberForceLengthPassiveInverseDeGroote2016(CharacteristicCurveFunction): + r"""Inverse passive muscle fiber force-length curve based on De Groote et + al., 2016 [1]_. + + Explanation + =========== + + Gives the normalized muscle fiber length that produces a specific normalized + passive muscle fiber force. + + The function is defined by the equation: + + ${fl^M_{pas}}^{-1} = \frac{c_0 \log{\left(\exp{c_1} - 1\right)fl^M_pas + 1}}{c_1} + 1$ + + with constant values of $c_0 = 0.6$ and $c_1 = 4.0$. This function is the + exact analytical inverse of the related tendon force-length curve + ``FiberForceLengthPassiveDeGroote2016``. + + While it is possible to change the constant values, these were carefully + selected in the original publication to give the characteristic curve + specific and required properties. For example, the function produces a + passive fiber force very close to 0 for all normalized fiber lengths + between 0 and 1. + + Examples + ======== + + The preferred way to instantiate + :class:`FiberForceLengthPassiveInverseDeGroote2016` is using the + :meth:`~.with_defaults` constructor because this will automatically populate the + constants within the characteristic curve equation with the floating point + values from the original publication. This constructor takes a single + argument corresponding to the normalized passive muscle fiber length-force + component of the muscle fiber force. We'll create a :class:`~.Symbol` called + ``fl_M_pas`` to represent this. + + >>> from sympy import Symbol + >>> from sympy.physics.biomechanics import FiberForceLengthPassiveInverseDeGroote2016 + >>> fl_M_pas = Symbol('fl_M_pas') + >>> l_M_tilde = FiberForceLengthPassiveInverseDeGroote2016.with_defaults(fl_M_pas) + >>> l_M_tilde + FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, 0.6, 4.0) + + It's also possible to populate the two constants with your own values too. + + >>> from sympy import symbols + >>> c0, c1 = symbols('c0 c1') + >>> l_M_tilde = FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, c0, c1) + >>> l_M_tilde + FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, c0, c1) + + To inspect the actual symbolic expression that this function represents, + we can call the :meth:`~.doit` method on an instance. We'll use the keyword + argument ``evaluate=False`` as this will keep the expression in its + canonical form and won't simplify any constants. + + >>> l_M_tilde.doit(evaluate=False) + c0*log(1 + fl_M_pas*(exp(c1) - 1))/c1 + 1 + + The function can also be differentiated. We'll differentiate with respect + to fl_M_pas using the ``diff`` method on an instance with the single positional + argument ``fl_M_pas``. + + >>> l_M_tilde.diff(fl_M_pas) + c0*(exp(c1) - 1)/(c1*(fl_M_pas*(exp(c1) - 1) + 1)) + + References + ========== + + .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation + of direct collocation optimal control problem formulations for + solving the muscle redundancy problem, Annals of biomedical + engineering, 44(10), (2016) pp. 2922-2936 + + """ + + @classmethod + def with_defaults(cls, fl_M_pas): + r"""Recommended constructor that will use the published constants. + + Explanation + =========== + + Returns a new instance of the inverse muscle fiber passive force-length + function using the four constant values specified in the original + publication. + + These have the values: + + $c_0 = 0.6$ + $c_1 = 4.0$ + + Parameters + ========== + + fl_M_pas : Any (sympifiable) + Normalized passive muscle fiber force as a function of muscle fiber + length. + + """ + c0 = Float('0.6') + c1 = Float('4.0') + return cls(fl_M_pas, c0, c1) + + @classmethod + def eval(cls, fl_M_pas, c0, c1): + """Evaluation of basic inputs. + + Parameters + ========== + + fl_M_pas : Any (sympifiable) + Normalized passive muscle fiber force. + c0 : Any (sympifiable) + The first constant in the characteristic equation. The published + value is ``0.6``. + c1 : Any (sympifiable) + The second constant in the characteristic equation. The published + value is ``4.0``. + + """ + pass + + def _eval_evalf(self, prec): + """Evaluate the expression numerically using ``evalf``.""" + return self.doit(deep=False, evaluate=False)._eval_evalf(prec) + + def doit(self, deep=True, evaluate=True, **hints): + """Evaluate the expression defining the function. + + Parameters + ========== + + deep : bool + Whether ``doit`` should be recursively called. Default is ``True``. + evaluate : bool. + Whether the SymPy expression should be evaluated as it is + constructed. If ``False``, then no constant folding will be + conducted which will leave the expression in a more numerically- + stable for values of ``l_T_tilde`` that correspond to a sensible + operating range for a musculotendon. Default is ``True``. + **kwargs : dict[str, Any] + Additional keyword argument pairs to be recursively passed to + ``doit``. + + """ + fl_M_pas, *constants = self.args + if deep: + hints['evaluate'] = evaluate + fl_M_pas = fl_M_pas.doit(deep=deep, **hints) + c0, c1 = [c.doit(deep=deep, **hints) for c in constants] + else: + c0, c1 = constants + + if evaluate: + return c0*log(fl_M_pas*(exp(c1) - 1) + 1)/c1 + 1 + + return c0*log(UnevaluatedExpr(fl_M_pas*(exp(c1) - 1)) + 1)/c1 + 1 + + def fdiff(self, argindex=1): + """Derivative of the function with respect to a single argument. + + Parameters + ========== + + argindex : int + The index of the function's arguments with respect to which the + derivative should be taken. Argument indexes start at ``1``. + Default is ``1``. + + """ + fl_M_pas, c0, c1 = self.args + if argindex == 1: + return c0*(exp(c1) - 1)/(c1*(fl_M_pas*(exp(c1) - 1) + 1)) + elif argindex == 2: + return log(fl_M_pas*(exp(c1) - 1) + 1)/c1 + elif argindex == 3: + return ( + c0*fl_M_pas*exp(c1)/(c1*(fl_M_pas*(exp(c1) - 1) + 1)) + - c0*log(fl_M_pas*(exp(c1) - 1) + 1)/c1**2 + ) + + raise ArgumentIndexError(self, argindex) + + def inverse(self, argindex=1): + """Inverse function. + + Parameters + ========== + + argindex : int + Value to start indexing the arguments at. Default is ``1``. + + """ + return FiberForceLengthPassiveDeGroote2016 + + def _latex(self, printer): + """Print a LaTeX representation of the function defining the curve. + + Parameters + ========== + + printer : Printer + The printer to be used to print the LaTeX string representation. + + """ + fl_M_pas = self.args[0] + _fl_M_pas = printer._print(fl_M_pas) + return r'\left( \operatorname{fl}^M_{pas} \right)^{-1} \left( %s \right)' % _fl_M_pas + + +class FiberForceLengthActiveDeGroote2016(CharacteristicCurveFunction): + r"""Active muscle fiber force-length curve based on De Groote et al., 2016 + [1]_. + + Explanation + =========== + + The function is defined by the equation: + + $fl_{\text{act}}^M = c_0 \exp\left(-\frac{1}{2}\left(\frac{\tilde{l}^M - c_1}{c_2 + c_3 \tilde{l}^M}\right)^2\right) + + c_4 \exp\left(-\frac{1}{2}\left(\frac{\tilde{l}^M - c_5}{c_6 + c_7 \tilde{l}^M}\right)^2\right) + + c_8 \exp\left(-\frac{1}{2}\left(\frac{\tilde{l}^M - c_9}{c_{10} + c_{11} \tilde{l}^M}\right)^2\right)$ + + with constant values of $c0 = 0.814$, $c1 = 1.06$, $c2 = 0.162$, + $c3 = 0.0633$, $c4 = 0.433$, $c5 = 0.717$, $c6 = -0.0299$, $c7 = 0.2$, + $c8 = 0.1$, $c9 = 1.0$, $c10 = 0.354$, and $c11 = 0.0$. + + While it is possible to change the constant values, these were carefully + selected in the original publication to give the characteristic curve + specific and required properties. For example, the function produces a + active fiber force of 1 at a normalized fiber length of 1, and an active + fiber force of 0 at normalized fiber lengths of 0 and 2. + + Examples + ======== + + The preferred way to instantiate :class:`FiberForceLengthActiveDeGroote2016` is + using the :meth:`~.with_defaults` constructor because this will automatically + populate the constants within the characteristic curve equation with the + floating point values from the original publication. This constructor takes + a single argument corresponding to normalized muscle fiber length. We'll + create a :class:`~.Symbol` called ``l_M_tilde`` to represent this. + + >>> from sympy import Symbol + >>> from sympy.physics.biomechanics import FiberForceLengthActiveDeGroote2016 + >>> l_M_tilde = Symbol('l_M_tilde') + >>> fl_M = FiberForceLengthActiveDeGroote2016.with_defaults(l_M_tilde) + >>> fl_M + FiberForceLengthActiveDeGroote2016(l_M_tilde, 0.814, 1.06, 0.162, 0.0633, + 0.433, 0.717, -0.0299, 0.2, 0.1, 1.0, 0.354, 0.0) + + It's also possible to populate the two constants with your own values too. + + >>> from sympy import symbols + >>> c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 = symbols('c0:12') + >>> fl_M = FiberForceLengthActiveDeGroote2016(l_M_tilde, c0, c1, c2, c3, + ... c4, c5, c6, c7, c8, c9, c10, c11) + >>> fl_M + FiberForceLengthActiveDeGroote2016(l_M_tilde, c0, c1, c2, c3, c4, c5, c6, + c7, c8, c9, c10, c11) + + You don't just have to use symbols as the arguments, it's also possible to + use expressions. Let's create a new pair of symbols, ``l_M`` and + ``l_M_opt``, representing muscle fiber length and optimal muscle fiber + length respectively. We can then represent ``l_M_tilde`` as an expression, + the ratio of these. + + >>> l_M, l_M_opt = symbols('l_M l_M_opt') + >>> l_M_tilde = l_M/l_M_opt + >>> fl_M = FiberForceLengthActiveDeGroote2016.with_defaults(l_M_tilde) + >>> fl_M + FiberForceLengthActiveDeGroote2016(l_M/l_M_opt, 0.814, 1.06, 0.162, 0.0633, + 0.433, 0.717, -0.0299, 0.2, 0.1, 1.0, 0.354, 0.0) + + To inspect the actual symbolic expression that this function represents, + we can call the :meth:`~.doit` method on an instance. We'll use the keyword + argument ``evaluate=False`` as this will keep the expression in its + canonical form and won't simplify any constants. + + >>> fl_M.doit(evaluate=False) + 0.814*exp(-(l_M/l_M_opt + - 1.06)**2/(2*(0.0633*l_M/l_M_opt + 0.162)**2)) + + 0.433*exp(-(l_M/l_M_opt - 0.717)**2/(2*(0.2*l_M/l_M_opt - 0.0299)**2)) + + 0.1*exp(-3.98991349867535*(l_M/l_M_opt - 1.0)**2) + + The function can also be differentiated. We'll differentiate with respect + to l_M using the ``diff`` method on an instance with the single positional + argument ``l_M``. + + >>> fl_M.diff(l_M) + ((-0.79798269973507*l_M/l_M_opt + + 0.79798269973507)*exp(-3.98991349867535*(l_M/l_M_opt - 1.0)**2) + + (0.433*(-l_M/l_M_opt + 0.717)/(0.2*l_M/l_M_opt - 0.0299)**2 + + 0.0866*(l_M/l_M_opt - 0.717)**2/(0.2*l_M/l_M_opt + - 0.0299)**3)*exp(-(l_M/l_M_opt - 0.717)**2/(2*(0.2*l_M/l_M_opt - 0.0299)**2)) + + (0.814*(-l_M/l_M_opt + 1.06)/(0.0633*l_M/l_M_opt + + 0.162)**2 + 0.0515262*(l_M/l_M_opt + - 1.06)**2/(0.0633*l_M/l_M_opt + + 0.162)**3)*exp(-(l_M/l_M_opt + - 1.06)**2/(2*(0.0633*l_M/l_M_opt + 0.162)**2)))/l_M_opt + + References + ========== + + .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation + of direct collocation optimal control problem formulations for + solving the muscle redundancy problem, Annals of biomedical + engineering, 44(10), (2016) pp. 2922-2936 + + """ + + @classmethod + def with_defaults(cls, l_M_tilde): + r"""Recommended constructor that will use the published constants. + + Explanation + =========== + + Returns a new instance of the inverse muscle fiber act force-length + function using the four constant values specified in the original + publication. + + These have the values: + + $c0 = 0.814$ + $c1 = 1.06$ + $c2 = 0.162$ + $c3 = 0.0633$ + $c4 = 0.433$ + $c5 = 0.717$ + $c6 = -0.0299$ + $c7 = 0.2$ + $c8 = 0.1$ + $c9 = 1.0$ + $c10 = 0.354$ + $c11 = 0.0$ + + Parameters + ========== + + fl_M_act : Any (sympifiable) + Normalized passive muscle fiber force as a function of muscle fiber + length. + + """ + c0 = Float('0.814') + c1 = Float('1.06') + c2 = Float('0.162') + c3 = Float('0.0633') + c4 = Float('0.433') + c5 = Float('0.717') + c6 = Float('-0.0299') + c7 = Float('0.2') + c8 = Float('0.1') + c9 = Float('1.0') + c10 = Float('0.354') + c11 = Float('0.0') + return cls(l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) + + @classmethod + def eval(cls, l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11): + """Evaluation of basic inputs. + + Parameters + ========== + + l_M_tilde : Any (sympifiable) + Normalized muscle fiber length. + c0 : Any (sympifiable) + The first constant in the characteristic equation. The published + value is ``0.814``. + c1 : Any (sympifiable) + The second constant in the characteristic equation. The published + value is ``1.06``. + c2 : Any (sympifiable) + The third constant in the characteristic equation. The published + value is ``0.162``. + c3 : Any (sympifiable) + The fourth constant in the characteristic equation. The published + value is ``0.0633``. + c4 : Any (sympifiable) + The fifth constant in the characteristic equation. The published + value is ``0.433``. + c5 : Any (sympifiable) + The sixth constant in the characteristic equation. The published + value is ``0.717``. + c6 : Any (sympifiable) + The seventh constant in the characteristic equation. The published + value is ``-0.0299``. + c7 : Any (sympifiable) + The eighth constant in the characteristic equation. The published + value is ``0.2``. + c8 : Any (sympifiable) + The ninth constant in the characteristic equation. The published + value is ``0.1``. + c9 : Any (sympifiable) + The tenth constant in the characteristic equation. The published + value is ``1.0``. + c10 : Any (sympifiable) + The eleventh constant in the characteristic equation. The published + value is ``0.354``. + c11 : Any (sympifiable) + The tweflth constant in the characteristic equation. The published + value is ``0.0``. + + """ + pass + + def _eval_evalf(self, prec): + """Evaluate the expression numerically using ``evalf``.""" + return self.doit(deep=False, evaluate=False)._eval_evalf(prec) + + def doit(self, deep=True, evaluate=True, **hints): + """Evaluate the expression defining the function. + + Parameters + ========== + + deep : bool + Whether ``doit`` should be recursively called. Default is ``True``. + evaluate : bool. + Whether the SymPy expression should be evaluated as it is + constructed. If ``False``, then no constant folding will be + conducted which will leave the expression in a more numerically- + stable for values of ``l_M_tilde`` that correspond to a sensible + operating range for a musculotendon. Default is ``True``. + **kwargs : dict[str, Any] + Additional keyword argument pairs to be recursively passed to + ``doit``. + + """ + l_M_tilde, *constants = self.args + if deep: + hints['evaluate'] = evaluate + l_M_tilde = l_M_tilde.doit(deep=deep, **hints) + constants = [c.doit(deep=deep, **hints) for c in constants] + c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 = constants + + if evaluate: + return ( + c0*exp(-(((l_M_tilde - c1)/(c2 + c3*l_M_tilde))**2)/2) + + c4*exp(-(((l_M_tilde - c5)/(c6 + c7*l_M_tilde))**2)/2) + + c8*exp(-(((l_M_tilde - c9)/(c10 + c11*l_M_tilde))**2)/2) + ) + + return ( + c0*exp(-((UnevaluatedExpr(l_M_tilde - c1)/(c2 + c3*l_M_tilde))**2)/2) + + c4*exp(-((UnevaluatedExpr(l_M_tilde - c5)/(c6 + c7*l_M_tilde))**2)/2) + + c8*exp(-((UnevaluatedExpr(l_M_tilde - c9)/(c10 + c11*l_M_tilde))**2)/2) + ) + + def fdiff(self, argindex=1): + """Derivative of the function with respect to a single argument. + + Parameters + ========== + + argindex : int + The index of the function's arguments with respect to which the + derivative should be taken. Argument indexes start at ``1``. + Default is ``1``. + + """ + l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 = self.args + if argindex == 1: + return ( + c0*( + c3*(l_M_tilde - c1)**2/(c2 + c3*l_M_tilde)**3 + + (c1 - l_M_tilde)/((c2 + c3*l_M_tilde)**2) + )*exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2)) + + c4*( + c7*(l_M_tilde - c5)**2/(c6 + c7*l_M_tilde)**3 + + (c5 - l_M_tilde)/((c6 + c7*l_M_tilde)**2) + )*exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2)) + + c8*( + c11*(l_M_tilde - c9)**2/(c10 + c11*l_M_tilde)**3 + + (c9 - l_M_tilde)/((c10 + c11*l_M_tilde)**2) + )*exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2)) + ) + elif argindex == 2: + return exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2)) + elif argindex == 3: + return ( + c0*(l_M_tilde - c1)/(c2 + c3*l_M_tilde)**2 + *exp(-(l_M_tilde - c1)**2 /(2*(c2 + c3*l_M_tilde)**2)) + ) + elif argindex == 4: + return ( + c0*(l_M_tilde - c1)**2/(c2 + c3*l_M_tilde)**3 + *exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2)) + ) + elif argindex == 5: + return ( + c0*l_M_tilde*(l_M_tilde - c1)**2/(c2 + c3*l_M_tilde)**3 + *exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2)) + ) + elif argindex == 6: + return exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2)) + elif argindex == 7: + return ( + c4*(l_M_tilde - c5)/(c6 + c7*l_M_tilde)**2 + *exp(-(l_M_tilde - c5)**2 /(2*(c6 + c7*l_M_tilde)**2)) + ) + elif argindex == 8: + return ( + c4*(l_M_tilde - c5)**2/(c6 + c7*l_M_tilde)**3 + *exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2)) + ) + elif argindex == 9: + return ( + c4*l_M_tilde*(l_M_tilde - c5)**2/(c6 + c7*l_M_tilde)**3 + *exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2)) + ) + elif argindex == 10: + return exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2)) + elif argindex == 11: + return ( + c8*(l_M_tilde - c9)/(c10 + c11*l_M_tilde)**2 + *exp(-(l_M_tilde - c9)**2 /(2*(c10 + c11*l_M_tilde)**2)) + ) + elif argindex == 12: + return ( + c8*(l_M_tilde - c9)**2/(c10 + c11*l_M_tilde)**3 + *exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2)) + ) + elif argindex == 13: + return ( + c8*l_M_tilde*(l_M_tilde - c9)**2/(c10 + c11*l_M_tilde)**3 + *exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2)) + ) + + raise ArgumentIndexError(self, argindex) + + def _latex(self, printer): + """Print a LaTeX representation of the function defining the curve. + + Parameters + ========== + + printer : Printer + The printer to be used to print the LaTeX string representation. + + """ + l_M_tilde = self.args[0] + _l_M_tilde = printer._print(l_M_tilde) + return r'\operatorname{fl}^M_{act} \left( %s \right)' % _l_M_tilde + + +class FiberForceVelocityDeGroote2016(CharacteristicCurveFunction): + r"""Muscle fiber force-velocity curve based on De Groote et al., 2016 [1]_. + + Explanation + =========== + + Gives the normalized muscle fiber force produced as a function of + normalized tendon velocity. + + The function is defined by the equation: + + $fv^M = c_0 \log{\left(c_1 \tilde{v}_m + c_2\right) + \sqrt{\left(c_1 \tilde{v}_m + c_2\right)^2 + 1}} + c_3$ + + with constant values of $c_0 = -0.318$, $c_1 = -8.149$, $c_2 = -0.374$, and + $c_3 = 0.886$. + + While it is possible to change the constant values, these were carefully + selected in the original publication to give the characteristic curve + specific and required properties. For example, the function produces a + normalized muscle fiber force of 1 when the muscle fibers are contracting + isometrically (they have an extension rate of 0). + + Examples + ======== + + The preferred way to instantiate :class:`FiberForceVelocityDeGroote2016` is using + the :meth:`~.with_defaults` constructor because this will automatically populate + the constants within the characteristic curve equation with the floating + point values from the original publication. This constructor takes a single + argument corresponding to normalized muscle fiber extension velocity. We'll + create a :class:`~.Symbol` called ``v_M_tilde`` to represent this. + + >>> from sympy import Symbol + >>> from sympy.physics.biomechanics import FiberForceVelocityDeGroote2016 + >>> v_M_tilde = Symbol('v_M_tilde') + >>> fv_M = FiberForceVelocityDeGroote2016.with_defaults(v_M_tilde) + >>> fv_M + FiberForceVelocityDeGroote2016(v_M_tilde, -0.318, -8.149, -0.374, 0.886) + + It's also possible to populate the four constants with your own values too. + + >>> from sympy import symbols + >>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3') + >>> fv_M = FiberForceVelocityDeGroote2016(v_M_tilde, c0, c1, c2, c3) + >>> fv_M + FiberForceVelocityDeGroote2016(v_M_tilde, c0, c1, c2, c3) + + You don't just have to use symbols as the arguments, it's also possible to + use expressions. Let's create a new pair of symbols, ``v_M`` and + ``v_M_max``, representing muscle fiber extension velocity and maximum + muscle fiber extension velocity respectively. We can then represent + ``v_M_tilde`` as an expression, the ratio of these. + + >>> v_M, v_M_max = symbols('v_M v_M_max') + >>> v_M_tilde = v_M/v_M_max + >>> fv_M = FiberForceVelocityDeGroote2016.with_defaults(v_M_tilde) + >>> fv_M + FiberForceVelocityDeGroote2016(v_M/v_M_max, -0.318, -8.149, -0.374, 0.886) + + To inspect the actual symbolic expression that this function represents, + we can call the :meth:`~.doit` method on an instance. We'll use the keyword + argument ``evaluate=False`` as this will keep the expression in its + canonical form and won't simplify any constants. + + >>> fv_M.doit(evaluate=False) + 0.886 - 0.318*log(-8.149*v_M/v_M_max - 0.374 + sqrt(1 + (-8.149*v_M/v_M_max + - 0.374)**2)) + + The function can also be differentiated. We'll differentiate with respect + to v_M using the ``diff`` method on an instance with the single positional + argument ``v_M``. + + >>> fv_M.diff(v_M) + 2.591382*(1 + (-8.149*v_M/v_M_max - 0.374)**2)**(-1/2)/v_M_max + + References + ========== + + .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation + of direct collocation optimal control problem formulations for + solving the muscle redundancy problem, Annals of biomedical + engineering, 44(10), (2016) pp. 2922-2936 + + """ + + @classmethod + def with_defaults(cls, v_M_tilde): + r"""Recommended constructor that will use the published constants. + + Explanation + =========== + + Returns a new instance of the muscle fiber force-velocity function + using the four constant values specified in the original publication. + + These have the values: + + $c_0 = -0.318$ + $c_1 = -8.149$ + $c_2 = -0.374$ + $c_3 = 0.886$ + + Parameters + ========== + + v_M_tilde : Any (sympifiable) + Normalized muscle fiber extension velocity. + + """ + c0 = Float('-0.318') + c1 = Float('-8.149') + c2 = Float('-0.374') + c3 = Float('0.886') + return cls(v_M_tilde, c0, c1, c2, c3) + + @classmethod + def eval(cls, v_M_tilde, c0, c1, c2, c3): + """Evaluation of basic inputs. + + Parameters + ========== + + v_M_tilde : Any (sympifiable) + Normalized muscle fiber extension velocity. + c0 : Any (sympifiable) + The first constant in the characteristic equation. The published + value is ``-0.318``. + c1 : Any (sympifiable) + The second constant in the characteristic equation. The published + value is ``-8.149``. + c2 : Any (sympifiable) + The third constant in the characteristic equation. The published + value is ``-0.374``. + c3 : Any (sympifiable) + The fourth constant in the characteristic equation. The published + value is ``0.886``. + + """ + pass + + def _eval_evalf(self, prec): + """Evaluate the expression numerically using ``evalf``.""" + return self.doit(deep=False, evaluate=False)._eval_evalf(prec) + + def doit(self, deep=True, evaluate=True, **hints): + """Evaluate the expression defining the function. + + Parameters + ========== + + deep : bool + Whether ``doit`` should be recursively called. Default is ``True``. + evaluate : bool. + Whether the SymPy expression should be evaluated as it is + constructed. If ``False``, then no constant folding will be + conducted which will leave the expression in a more numerically- + stable for values of ``v_M_tilde`` that correspond to a sensible + operating range for a musculotendon. Default is ``True``. + **kwargs : dict[str, Any] + Additional keyword argument pairs to be recursively passed to + ``doit``. + + """ + v_M_tilde, *constants = self.args + if deep: + hints['evaluate'] = evaluate + v_M_tilde = v_M_tilde.doit(deep=deep, **hints) + c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants] + else: + c0, c1, c2, c3 = constants + + if evaluate: + return c0*log(c1*v_M_tilde + c2 + sqrt((c1*v_M_tilde + c2)**2 + 1)) + c3 + + return c0*log(c1*v_M_tilde + c2 + sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1)) + c3 + + def fdiff(self, argindex=1): + """Derivative of the function with respect to a single argument. + + Parameters + ========== + + argindex : int + The index of the function's arguments with respect to which the + derivative should be taken. Argument indexes start at ``1``. + Default is ``1``. + + """ + v_M_tilde, c0, c1, c2, c3 = self.args + if argindex == 1: + return c0*c1/sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1) + elif argindex == 2: + return log( + c1*v_M_tilde + c2 + + sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1) + ) + elif argindex == 3: + return c0*v_M_tilde/sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1) + elif argindex == 4: + return c0/sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1) + elif argindex == 5: + return Integer(1) + + raise ArgumentIndexError(self, argindex) + + def inverse(self, argindex=1): + """Inverse function. + + Parameters + ========== + + argindex : int + Value to start indexing the arguments at. Default is ``1``. + + """ + return FiberForceVelocityInverseDeGroote2016 + + def _latex(self, printer): + """Print a LaTeX representation of the function defining the curve. + + Parameters + ========== + + printer : Printer + The printer to be used to print the LaTeX string representation. + + """ + v_M_tilde = self.args[0] + _v_M_tilde = printer._print(v_M_tilde) + return r'\operatorname{fv}^M \left( %s \right)' % _v_M_tilde + + +class FiberForceVelocityInverseDeGroote2016(CharacteristicCurveFunction): + r"""Inverse muscle fiber force-velocity curve based on De Groote et al., + 2016 [1]_. + + Explanation + =========== + + Gives the normalized muscle fiber velocity that produces a specific + normalized muscle fiber force. + + The function is defined by the equation: + + ${fv^M}^{-1} = \frac{\sinh{\frac{fv^M - c_3}{c_0}} - c_2}{c_1}$ + + with constant values of $c_0 = -0.318$, $c_1 = -8.149$, $c_2 = -0.374$, and + $c_3 = 0.886$. This function is the exact analytical inverse of the related + muscle fiber force-velocity curve ``FiberForceVelocityDeGroote2016``. + + While it is possible to change the constant values, these were carefully + selected in the original publication to give the characteristic curve + specific and required properties. For example, the function produces a + normalized muscle fiber force of 1 when the muscle fibers are contracting + isometrically (they have an extension rate of 0). + + Examples + ======== + + The preferred way to instantiate :class:`FiberForceVelocityInverseDeGroote2016` + is using the :meth:`~.with_defaults` constructor because this will automatically + populate the constants within the characteristic curve equation with the + floating point values from the original publication. This constructor takes + a single argument corresponding to normalized muscle fiber force-velocity + component of the muscle fiber force. We'll create a :class:`~.Symbol` called + ``fv_M`` to represent this. + + >>> from sympy import Symbol + >>> from sympy.physics.biomechanics import FiberForceVelocityInverseDeGroote2016 + >>> fv_M = Symbol('fv_M') + >>> v_M_tilde = FiberForceVelocityInverseDeGroote2016.with_defaults(fv_M) + >>> v_M_tilde + FiberForceVelocityInverseDeGroote2016(fv_M, -0.318, -8.149, -0.374, 0.886) + + It's also possible to populate the four constants with your own values too. + + >>> from sympy import symbols + >>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3') + >>> v_M_tilde = FiberForceVelocityInverseDeGroote2016(fv_M, c0, c1, c2, c3) + >>> v_M_tilde + FiberForceVelocityInverseDeGroote2016(fv_M, c0, c1, c2, c3) + + To inspect the actual symbolic expression that this function represents, + we can call the :meth:`~.doit` method on an instance. We'll use the keyword + argument ``evaluate=False`` as this will keep the expression in its + canonical form and won't simplify any constants. + + >>> v_M_tilde.doit(evaluate=False) + (-c2 + sinh((-c3 + fv_M)/c0))/c1 + + The function can also be differentiated. We'll differentiate with respect + to fv_M using the ``diff`` method on an instance with the single positional + argument ``fv_M``. + + >>> v_M_tilde.diff(fv_M) + cosh((-c3 + fv_M)/c0)/(c0*c1) + + References + ========== + + .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation + of direct collocation optimal control problem formulations for + solving the muscle redundancy problem, Annals of biomedical + engineering, 44(10), (2016) pp. 2922-2936 + + """ + + @classmethod + def with_defaults(cls, fv_M): + r"""Recommended constructor that will use the published constants. + + Explanation + =========== + + Returns a new instance of the inverse muscle fiber force-velocity + function using the four constant values specified in the original + publication. + + These have the values: + + $c_0 = -0.318$ + $c_1 = -8.149$ + $c_2 = -0.374$ + $c_3 = 0.886$ + + Parameters + ========== + + fv_M : Any (sympifiable) + Normalized muscle fiber extension velocity. + + """ + c0 = Float('-0.318') + c1 = Float('-8.149') + c2 = Float('-0.374') + c3 = Float('0.886') + return cls(fv_M, c0, c1, c2, c3) + + @classmethod + def eval(cls, fv_M, c0, c1, c2, c3): + """Evaluation of basic inputs. + + Parameters + ========== + + fv_M : Any (sympifiable) + Normalized muscle fiber force as a function of muscle fiber + extension velocity. + c0 : Any (sympifiable) + The first constant in the characteristic equation. The published + value is ``-0.318``. + c1 : Any (sympifiable) + The second constant in the characteristic equation. The published + value is ``-8.149``. + c2 : Any (sympifiable) + The third constant in the characteristic equation. The published + value is ``-0.374``. + c3 : Any (sympifiable) + The fourth constant in the characteristic equation. The published + value is ``0.886``. + + """ + pass + + def _eval_evalf(self, prec): + """Evaluate the expression numerically using ``evalf``.""" + return self.doit(deep=False, evaluate=False)._eval_evalf(prec) + + def doit(self, deep=True, evaluate=True, **hints): + """Evaluate the expression defining the function. + + Parameters + ========== + + deep : bool + Whether ``doit`` should be recursively called. Default is ``True``. + evaluate : bool. + Whether the SymPy expression should be evaluated as it is + constructed. If ``False``, then no constant folding will be + conducted which will leave the expression in a more numerically- + stable for values of ``fv_M`` that correspond to a sensible + operating range for a musculotendon. Default is ``True``. + **kwargs : dict[str, Any] + Additional keyword argument pairs to be recursively passed to + ``doit``. + + """ + fv_M, *constants = self.args + if deep: + hints['evaluate'] = evaluate + fv_M = fv_M.doit(deep=deep, **hints) + c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants] + else: + c0, c1, c2, c3 = constants + + if evaluate: + return (sinh((fv_M - c3)/c0) - c2)/c1 + + return (sinh(UnevaluatedExpr(fv_M - c3)/c0) - c2)/c1 + + def fdiff(self, argindex=1): + """Derivative of the function with respect to a single argument. + + Parameters + ========== + + argindex : int + The index of the function's arguments with respect to which the + derivative should be taken. Argument indexes start at ``1``. + Default is ``1``. + + """ + fv_M, c0, c1, c2, c3 = self.args + if argindex == 1: + return cosh((fv_M - c3)/c0)/(c0*c1) + elif argindex == 2: + return (c3 - fv_M)*cosh((fv_M - c3)/c0)/(c0**2*c1) + elif argindex == 3: + return (c2 - sinh((fv_M - c3)/c0))/c1**2 + elif argindex == 4: + return -1/c1 + elif argindex == 5: + return -cosh((fv_M - c3)/c0)/(c0*c1) + + raise ArgumentIndexError(self, argindex) + + def inverse(self, argindex=1): + """Inverse function. + + Parameters + ========== + + argindex : int + Value to start indexing the arguments at. Default is ``1``. + + """ + return FiberForceVelocityDeGroote2016 + + def _latex(self, printer): + """Print a LaTeX representation of the function defining the curve. + + Parameters + ========== + + printer : Printer + The printer to be used to print the LaTeX string representation. + + """ + fv_M = self.args[0] + _fv_M = printer._print(fv_M) + return r'\left( \operatorname{fv}^M \right)^{-1} \left( %s \right)' % _fv_M + + +@dataclass(frozen=True) +class CharacteristicCurveCollection: + """Simple data container to group together related characteristic curves.""" + tendon_force_length: CharacteristicCurveFunction + tendon_force_length_inverse: CharacteristicCurveFunction + fiber_force_length_passive: CharacteristicCurveFunction + fiber_force_length_passive_inverse: CharacteristicCurveFunction + fiber_force_length_active: CharacteristicCurveFunction + fiber_force_velocity: CharacteristicCurveFunction + fiber_force_velocity_inverse: CharacteristicCurveFunction + + def __iter__(self): + """Iterator support for ``CharacteristicCurveCollection``.""" + yield self.tendon_force_length + yield self.tendon_force_length_inverse + yield self.fiber_force_length_passive + yield self.fiber_force_length_passive_inverse + yield self.fiber_force_length_active + yield self.fiber_force_velocity + yield self.fiber_force_velocity_inverse diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/musculotendon.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/musculotendon.py new file mode 100644 index 0000000000000000000000000000000000000000..e16d66373da9107adee2e3b8418f657ee5879298 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/musculotendon.py @@ -0,0 +1,1424 @@ +"""Implementations of musculotendon models. + +Musculotendon models are a critical component of biomechanical models, one that +differentiates them from pure multibody systems. Musculotendon models produce a +force dependent on their level of activation, their length, and their +extension velocity. Length- and extension velocity-dependent force production +are governed by force-length and force-velocity characteristics. +These are normalized functions that are dependent on the musculotendon's state +and are specific to a given musculotendon model. + +""" + +from abc import abstractmethod +from enum import IntEnum, unique + +from sympy.core.numbers import Float, Integer +from sympy.core.symbol import Symbol, symbols +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import cos, sin +from sympy.matrices.dense import MutableDenseMatrix as Matrix, diag, eye, zeros +from sympy.physics.biomechanics.activation import ActivationBase +from sympy.physics.biomechanics.curve import ( + CharacteristicCurveCollection, + FiberForceLengthActiveDeGroote2016, + FiberForceLengthPassiveDeGroote2016, + FiberForceLengthPassiveInverseDeGroote2016, + FiberForceVelocityDeGroote2016, + FiberForceVelocityInverseDeGroote2016, + TendonForceLengthDeGroote2016, + TendonForceLengthInverseDeGroote2016, +) +from sympy.physics.biomechanics._mixin import _NamedMixin +from sympy.physics.mechanics.actuator import ForceActuator +from sympy.physics.vector.functions import dynamicsymbols + + +__all__ = [ + 'MusculotendonBase', + 'MusculotendonDeGroote2016', + 'MusculotendonFormulation', +] + + +@unique +class MusculotendonFormulation(IntEnum): + """Enumeration of types of musculotendon dynamics formulations. + + Explanation + =========== + + An (integer) enumeration is used as it allows for clearer selection of the + different formulations of musculotendon dynamics. + + Members + ======= + + RIGID_TENDON : 0 + A rigid tendon model. + FIBER_LENGTH_EXPLICIT : 1 + An explicit elastic tendon model with the muscle fiber length (l_M) as + the state variable. + TENDON_FORCE_EXPLICIT : 2 + An explicit elastic tendon model with the tendon force (F_T) as the + state variable. + FIBER_LENGTH_IMPLICIT : 3 + An implicit elastic tendon model with the muscle fiber length (l_M) as + the state variable and the muscle fiber velocity as an additional input + variable. + TENDON_FORCE_IMPLICIT : 4 + An implicit elastic tendon model with the tendon force (F_T) as the + state variable as the muscle fiber velocity as an additional input + variable. + + """ + + RIGID_TENDON = 0 + FIBER_LENGTH_EXPLICIT = 1 + TENDON_FORCE_EXPLICIT = 2 + FIBER_LENGTH_IMPLICIT = 3 + TENDON_FORCE_IMPLICIT = 4 + + def __str__(self): + """Returns a string representation of the enumeration value. + + Notes + ===== + + This hard coding is required due to an incompatibility between the + ``IntEnum`` implementations in Python 3.10 and Python 3.11 + (https://github.com/python/cpython/issues/84247). From Python 3.11 + onwards, the ``__str__`` method uses ``int.__str__``, whereas prior it + used ``Enum.__str__``. Once Python 3.11 becomes the minimum version + supported by SymPy, this method override can be removed. + + """ + return str(self.value) + + +_DEFAULT_MUSCULOTENDON_FORMULATION = MusculotendonFormulation.RIGID_TENDON + + +class MusculotendonBase(ForceActuator, _NamedMixin): + r"""Abstract base class for all musculotendon classes to inherit from. + + Explanation + =========== + + A musculotendon generates a contractile force based on its activation, + length, and shortening velocity. This abstract base class is to be inherited + by all musculotendon subclasses that implement different characteristic + musculotendon curves. Characteristic musculotendon curves are required for + the tendon force-length, passive fiber force-length, active fiber force- + length, and fiber force-velocity relationships. + + Parameters + ========== + + name : str + The name identifier associated with the musculotendon. This name is used + as a suffix when automatically generated symbols are instantiated. It + must be a string of nonzero length. + pathway : PathwayBase + The pathway that the actuator follows. This must be an instance of a + concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``. + activation_dynamics : ActivationBase + The activation dynamics that will be modeled within the musculotendon. + This must be an instance of a concrete subclass of ``ActivationBase``, + e.g. ``FirstOrderActivationDeGroote2016``. + musculotendon_dynamics : MusculotendonFormulation | int + The formulation of musculotendon dynamics that should be used + internally, i.e. rigid or elastic tendon model, the choice of + musculotendon state etc. This must be a member of the integer + enumeration ``MusculotendonFormulation`` or an integer that can be cast + to a member. To use a rigid tendon formulation, set this to + ``MusculotendonFormulation.RIGID_TENDON`` (or the integer value ``0``, + which will be cast to the enumeration member). There are four possible + formulations for an elastic tendon model. To use an explicit formulation + with the fiber length as the state, set this to + ``MusculotendonFormulation.FIBER_LENGTH_EXPLICIT`` (or the integer value + ``1``). To use an explicit formulation with the tendon force as the + state, set this to ``MusculotendonFormulation.TENDON_FORCE_EXPLICIT`` + (or the integer value ``2``). To use an implicit formulation with the + fiber length as the state, set this to + ``MusculotendonFormulation.FIBER_LENGTH_IMPLICIT`` (or the integer value + ``3``). To use an implicit formulation with the tendon force as the + state, set this to ``MusculotendonFormulation.TENDON_FORCE_IMPLICIT`` + (or the integer value ``4``). The default is + ``MusculotendonFormulation.RIGID_TENDON``, which corresponds to a rigid + tendon formulation. + tendon_slack_length : Expr | None + The length of the tendon when the musculotendon is in its unloaded + state. In a rigid tendon model the tendon length is the tendon slack + length. In all musculotendon models, tendon slack length is used to + normalize tendon length to give + :math:`\tilde{l}^T = \frac{l^T}{l^T_{slack}}`. + peak_isometric_force : Expr | None + The maximum force that the muscle fiber can produce when it is + undergoing an isometric contraction (no lengthening velocity). In all + musculotendon models, peak isometric force is used to normalized tendon + and muscle fiber force to give + :math:`\tilde{F}^T = \frac{F^T}{F^M_{max}}`. + optimal_fiber_length : Expr | None + The muscle fiber length at which the muscle fibers produce no passive + force and their maximum active force. In all musculotendon models, + optimal fiber length is used to normalize muscle fiber length to give + :math:`\tilde{l}^M = \frac{l^M}{l^M_{opt}}`. + maximal_fiber_velocity : Expr | None + The fiber velocity at which, during muscle fiber shortening, the muscle + fibers are unable to produce any active force. In all musculotendon + models, maximal fiber velocity is used to normalize muscle fiber + extension velocity to give :math:`\tilde{v}^M = \frac{v^M}{v^M_{max}}`. + optimal_pennation_angle : Expr | None + The pennation angle when muscle fiber length equals the optimal fiber + length. + fiber_damping_coefficient : Expr | None + The coefficient of damping to be used in the damping element in the + muscle fiber model. + with_defaults : bool + Whether ``with_defaults`` alternate constructors should be used when + automatically constructing child classes. Default is ``False``. + + """ + + def __init__( + self, + name, + pathway, + activation_dynamics, + *, + musculotendon_dynamics=_DEFAULT_MUSCULOTENDON_FORMULATION, + tendon_slack_length=None, + peak_isometric_force=None, + optimal_fiber_length=None, + maximal_fiber_velocity=None, + optimal_pennation_angle=None, + fiber_damping_coefficient=None, + with_defaults=False, + ): + self.name = name + + # Supply a placeholder force to the super initializer, this will be + # replaced later + super().__init__(Symbol('F'), pathway) + + # Activation dynamics + if not isinstance(activation_dynamics, ActivationBase): + msg = ( + f'Can\'t set attribute `activation_dynamics` to ' + f'{activation_dynamics} as it must be of type ' + f'`ActivationBase`, not {type(activation_dynamics)}.' + ) + raise TypeError(msg) + self._activation_dynamics = activation_dynamics + self._child_objects = (self._activation_dynamics, ) + + # Constants + if tendon_slack_length is not None: + self._l_T_slack = tendon_slack_length + else: + self._l_T_slack = Symbol(f'l_T_slack_{self.name}') + if peak_isometric_force is not None: + self._F_M_max = peak_isometric_force + else: + self._F_M_max = Symbol(f'F_M_max_{self.name}') + if optimal_fiber_length is not None: + self._l_M_opt = optimal_fiber_length + else: + self._l_M_opt = Symbol(f'l_M_opt_{self.name}') + if maximal_fiber_velocity is not None: + self._v_M_max = maximal_fiber_velocity + else: + self._v_M_max = Symbol(f'v_M_max_{self.name}') + if optimal_pennation_angle is not None: + self._alpha_opt = optimal_pennation_angle + else: + self._alpha_opt = Symbol(f'alpha_opt_{self.name}') + if fiber_damping_coefficient is not None: + self._beta = fiber_damping_coefficient + else: + self._beta = Symbol(f'beta_{self.name}') + + # Musculotendon dynamics + self._with_defaults = with_defaults + if musculotendon_dynamics == MusculotendonFormulation.RIGID_TENDON: + self._rigid_tendon_musculotendon_dynamics() + elif musculotendon_dynamics == MusculotendonFormulation.FIBER_LENGTH_EXPLICIT: + self._fiber_length_explicit_musculotendon_dynamics() + elif musculotendon_dynamics == MusculotendonFormulation.TENDON_FORCE_EXPLICIT: + self._tendon_force_explicit_musculotendon_dynamics() + elif musculotendon_dynamics == MusculotendonFormulation.FIBER_LENGTH_IMPLICIT: + self._fiber_length_implicit_musculotendon_dynamics() + elif musculotendon_dynamics == MusculotendonFormulation.TENDON_FORCE_IMPLICIT: + self._tendon_force_implicit_musculotendon_dynamics() + else: + msg = ( + f'Musculotendon dynamics {repr(musculotendon_dynamics)} ' + f'passed to `musculotendon_dynamics` was of type ' + f'{type(musculotendon_dynamics)}, must be ' + f'{MusculotendonFormulation}.' + ) + raise TypeError(msg) + self._musculotendon_dynamics = musculotendon_dynamics + + # Must override the placeholder value in `self._force` now that the + # actual force has been calculated by + # `self.__musculotendon_dynamics`. + # Note that `self._force` assumes forces are expansile, musculotendon + # forces are contractile hence the minus sign preceding `self._F_T` + # (the tendon force). + self._force = -self._F_T + + @classmethod + def with_defaults( + cls, + name, + pathway, + activation_dynamics, + *, + musculotendon_dynamics=_DEFAULT_MUSCULOTENDON_FORMULATION, + tendon_slack_length=None, + peak_isometric_force=None, + optimal_fiber_length=None, + maximal_fiber_velocity=Float('10.0'), + optimal_pennation_angle=Float('0.0'), + fiber_damping_coefficient=Float('0.1'), + ): + r"""Recommended constructor that will use the published constants. + + Explanation + =========== + + Returns a new instance of the musculotendon class using recommended + values for ``v_M_max``, ``alpha_opt``, and ``beta``. The values are: + + :math:`v^M_{max} = 10` + :math:`\alpha_{opt} = 0` + :math:`\beta = \frac{1}{10}` + + The musculotendon curves are also instantiated using the constants from + the original publication. + + Parameters + ========== + + name : str + The name identifier associated with the musculotendon. This name is + used as a suffix when automatically generated symbols are + instantiated. It must be a string of nonzero length. + pathway : PathwayBase + The pathway that the actuator follows. This must be an instance of a + concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``. + activation_dynamics : ActivationBase + The activation dynamics that will be modeled within the + musculotendon. This must be an instance of a concrete subclass of + ``ActivationBase``, e.g. ``FirstOrderActivationDeGroote2016``. + musculotendon_dynamics : MusculotendonFormulation | int + The formulation of musculotendon dynamics that should be used + internally, i.e. rigid or elastic tendon model, the choice of + musculotendon state etc. This must be a member of the integer + enumeration ``MusculotendonFormulation`` or an integer that can be + cast to a member. To use a rigid tendon formulation, set this to + ``MusculotendonFormulation.RIGID_TENDON`` (or the integer value + ``0``, which will be cast to the enumeration member). There are four + possible formulations for an elastic tendon model. To use an + explicit formulation with the fiber length as the state, set this to + ``MusculotendonFormulation.FIBER_LENGTH_EXPLICIT`` (or the integer + value ``1``). To use an explicit formulation with the tendon force + as the state, set this to + ``MusculotendonFormulation.TENDON_FORCE_EXPLICIT`` (or the integer + value ``2``). To use an implicit formulation with the fiber length + as the state, set this to + ``MusculotendonFormulation.FIBER_LENGTH_IMPLICIT`` (or the integer + value ``3``). To use an implicit formulation with the tendon force + as the state, set this to + ``MusculotendonFormulation.TENDON_FORCE_IMPLICIT`` (or the integer + value ``4``). The default is + ``MusculotendonFormulation.RIGID_TENDON``, which corresponds to a + rigid tendon formulation. + tendon_slack_length : Expr | None + The length of the tendon when the musculotendon is in its unloaded + state. In a rigid tendon model the tendon length is the tendon slack + length. In all musculotendon models, tendon slack length is used to + normalize tendon length to give + :math:`\tilde{l}^T = \frac{l^T}{l^T_{slack}}`. + peak_isometric_force : Expr | None + The maximum force that the muscle fiber can produce when it is + undergoing an isometric contraction (no lengthening velocity). In + all musculotendon models, peak isometric force is used to normalized + tendon and muscle fiber force to give + :math:`\tilde{F}^T = \frac{F^T}{F^M_{max}}`. + optimal_fiber_length : Expr | None + The muscle fiber length at which the muscle fibers produce no + passive force and their maximum active force. In all musculotendon + models, optimal fiber length is used to normalize muscle fiber + length to give :math:`\tilde{l}^M = \frac{l^M}{l^M_{opt}}`. + maximal_fiber_velocity : Expr | None + The fiber velocity at which, during muscle fiber shortening, the + muscle fibers are unable to produce any active force. In all + musculotendon models, maximal fiber velocity is used to normalize + muscle fiber extension velocity to give + :math:`\tilde{v}^M = \frac{v^M}{v^M_{max}}`. + optimal_pennation_angle : Expr | None + The pennation angle when muscle fiber length equals the optimal + fiber length. + fiber_damping_coefficient : Expr | None + The coefficient of damping to be used in the damping element in the + muscle fiber model. + + """ + return cls( + name, + pathway, + activation_dynamics=activation_dynamics, + musculotendon_dynamics=musculotendon_dynamics, + tendon_slack_length=tendon_slack_length, + peak_isometric_force=peak_isometric_force, + optimal_fiber_length=optimal_fiber_length, + maximal_fiber_velocity=maximal_fiber_velocity, + optimal_pennation_angle=optimal_pennation_angle, + fiber_damping_coefficient=fiber_damping_coefficient, + with_defaults=True, + ) + + @abstractmethod + def curves(cls): + """Return a ``CharacteristicCurveCollection`` of the curves related to + the specific model.""" + pass + + @property + def tendon_slack_length(self): + r"""Symbol or value corresponding to the tendon slack length constant. + + Explanation + =========== + + The length of the tendon when the musculotendon is in its unloaded + state. In a rigid tendon model the tendon length is the tendon slack + length. In all musculotendon models, tendon slack length is used to + normalize tendon length to give + :math:`\tilde{l}^T = \frac{l^T}{l^T_{slack}}`. + + The alias ``l_T_slack`` can also be used to access the same attribute. + + """ + return self._l_T_slack + + @property + def l_T_slack(self): + r"""Symbol or value corresponding to the tendon slack length constant. + + Explanation + =========== + + The length of the tendon when the musculotendon is in its unloaded + state. In a rigid tendon model the tendon length is the tendon slack + length. In all musculotendon models, tendon slack length is used to + normalize tendon length to give + :math:`\tilde{l}^T = \frac{l^T}{l^T_{slack}}`. + + The alias ``tendon_slack_length`` can also be used to access the same + attribute. + + """ + return self._l_T_slack + + @property + def peak_isometric_force(self): + r"""Symbol or value corresponding to the peak isometric force constant. + + Explanation + =========== + + The maximum force that the muscle fiber can produce when it is + undergoing an isometric contraction (no lengthening velocity). In all + musculotendon models, peak isometric force is used to normalized tendon + and muscle fiber force to give + :math:`\tilde{F}^T = \frac{F^T}{F^M_{max}}`. + + The alias ``F_M_max`` can also be used to access the same attribute. + + """ + return self._F_M_max + + @property + def F_M_max(self): + r"""Symbol or value corresponding to the peak isometric force constant. + + Explanation + =========== + + The maximum force that the muscle fiber can produce when it is + undergoing an isometric contraction (no lengthening velocity). In all + musculotendon models, peak isometric force is used to normalized tendon + and muscle fiber force to give + :math:`\tilde{F}^T = \frac{F^T}{F^M_{max}}`. + + The alias ``peak_isometric_force`` can also be used to access the same + attribute. + + """ + return self._F_M_max + + @property + def optimal_fiber_length(self): + r"""Symbol or value corresponding to the optimal fiber length constant. + + Explanation + =========== + + The muscle fiber length at which the muscle fibers produce no passive + force and their maximum active force. In all musculotendon models, + optimal fiber length is used to normalize muscle fiber length to give + :math:`\tilde{l}^M = \frac{l^M}{l^M_{opt}}`. + + The alias ``l_M_opt`` can also be used to access the same attribute. + + """ + return self._l_M_opt + + @property + def l_M_opt(self): + r"""Symbol or value corresponding to the optimal fiber length constant. + + Explanation + =========== + + The muscle fiber length at which the muscle fibers produce no passive + force and their maximum active force. In all musculotendon models, + optimal fiber length is used to normalize muscle fiber length to give + :math:`\tilde{l}^M = \frac{l^M}{l^M_{opt}}`. + + The alias ``optimal_fiber_length`` can also be used to access the same + attribute. + + """ + return self._l_M_opt + + @property + def maximal_fiber_velocity(self): + r"""Symbol or value corresponding to the maximal fiber velocity constant. + + Explanation + =========== + + The fiber velocity at which, during muscle fiber shortening, the muscle + fibers are unable to produce any active force. In all musculotendon + models, maximal fiber velocity is used to normalize muscle fiber + extension velocity to give :math:`\tilde{v}^M = \frac{v^M}{v^M_{max}}`. + + The alias ``v_M_max`` can also be used to access the same attribute. + + """ + return self._v_M_max + + @property + def v_M_max(self): + r"""Symbol or value corresponding to the maximal fiber velocity constant. + + Explanation + =========== + + The fiber velocity at which, during muscle fiber shortening, the muscle + fibers are unable to produce any active force. In all musculotendon + models, maximal fiber velocity is used to normalize muscle fiber + extension velocity to give :math:`\tilde{v}^M = \frac{v^M}{v^M_{max}}`. + + The alias ``maximal_fiber_velocity`` can also be used to access the same + attribute. + + """ + return self._v_M_max + + @property + def optimal_pennation_angle(self): + """Symbol or value corresponding to the optimal pennation angle + constant. + + Explanation + =========== + + The pennation angle when muscle fiber length equals the optimal fiber + length. + + The alias ``alpha_opt`` can also be used to access the same attribute. + + """ + return self._alpha_opt + + @property + def alpha_opt(self): + """Symbol or value corresponding to the optimal pennation angle + constant. + + Explanation + =========== + + The pennation angle when muscle fiber length equals the optimal fiber + length. + + The alias ``optimal_pennation_angle`` can also be used to access the + same attribute. + + """ + return self._alpha_opt + + @property + def fiber_damping_coefficient(self): + """Symbol or value corresponding to the fiber damping coefficient + constant. + + Explanation + =========== + + The coefficient of damping to be used in the damping element in the + muscle fiber model. + + The alias ``beta`` can also be used to access the same attribute. + + """ + return self._beta + + @property + def beta(self): + """Symbol or value corresponding to the fiber damping coefficient + constant. + + Explanation + =========== + + The coefficient of damping to be used in the damping element in the + muscle fiber model. + + The alias ``fiber_damping_coefficient`` can also be used to access the + same attribute. + + """ + return self._beta + + @property + def activation_dynamics(self): + """Activation dynamics model governing this musculotendon's activation. + + Explanation + =========== + + Returns the instance of a subclass of ``ActivationBase`` that governs + the relationship between excitation and activation that is used to + represent the activation dynamics of this musculotendon. + + """ + return self._activation_dynamics + + @property + def excitation(self): + """Dynamic symbol representing excitation. + + Explanation + =========== + + The alias ``e`` can also be used to access the same attribute. + + """ + return self._activation_dynamics._e + + @property + def e(self): + """Dynamic symbol representing excitation. + + Explanation + =========== + + The alias ``excitation`` can also be used to access the same attribute. + + """ + return self._activation_dynamics._e + + @property + def activation(self): + """Dynamic symbol representing activation. + + Explanation + =========== + + The alias ``a`` can also be used to access the same attribute. + + """ + return self._activation_dynamics._a + + @property + def a(self): + """Dynamic symbol representing activation. + + Explanation + =========== + + The alias ``activation`` can also be used to access the same attribute. + + """ + return self._activation_dynamics._a + + @property + def musculotendon_dynamics(self): + """The choice of rigid or type of elastic tendon musculotendon dynamics. + + Explanation + =========== + + The formulation of musculotendon dynamics that should be used + internally, i.e. rigid or elastic tendon model, the choice of + musculotendon state etc. This must be a member of the integer + enumeration ``MusculotendonFormulation`` or an integer that can be cast + to a member. To use a rigid tendon formulation, set this to + ``MusculotendonFormulation.RIGID_TENDON`` (or the integer value ``0``, + which will be cast to the enumeration member). There are four possible + formulations for an elastic tendon model. To use an explicit formulation + with the fiber length as the state, set this to + ``MusculotendonFormulation.FIBER_LENGTH_EXPLICIT`` (or the integer value + ``1``). To use an explicit formulation with the tendon force as the + state, set this to ``MusculotendonFormulation.TENDON_FORCE_EXPLICIT`` + (or the integer value ``2``). To use an implicit formulation with the + fiber length as the state, set this to + ``MusculotendonFormulation.FIBER_LENGTH_IMPLICIT`` (or the integer value + ``3``). To use an implicit formulation with the tendon force as the + state, set this to ``MusculotendonFormulation.TENDON_FORCE_IMPLICIT`` + (or the integer value ``4``). The default is + ``MusculotendonFormulation.RIGID_TENDON``, which corresponds to a rigid + tendon formulation. + + """ + return self._musculotendon_dynamics + + def _rigid_tendon_musculotendon_dynamics(self): + """Rigid tendon musculotendon.""" + self._l_MT = self.pathway.length + self._v_MT = self.pathway.extension_velocity + self._l_T = self._l_T_slack + self._l_T_tilde = Integer(1) + self._l_M = sqrt((self._l_MT - self._l_T)**2 + (self._l_M_opt*sin(self._alpha_opt))**2) + self._l_M_tilde = self._l_M/self._l_M_opt + self._v_M = self._v_MT*(self._l_MT - self._l_T_slack)/self._l_M + self._v_M_tilde = self._v_M/self._v_M_max + if self._with_defaults: + self._fl_T = self.curves.tendon_force_length.with_defaults(self._l_T_tilde) + self._fl_M_pas = self.curves.fiber_force_length_passive.with_defaults(self._l_M_tilde) + self._fl_M_act = self.curves.fiber_force_length_active.with_defaults(self._l_M_tilde) + self._fv_M = self.curves.fiber_force_velocity.with_defaults(self._v_M_tilde) + else: + fl_T_constants = symbols(f'c_0:4_fl_T_{self.name}') + self._fl_T = self.curves.tendon_force_length(self._l_T_tilde, *fl_T_constants) + fl_M_pas_constants = symbols(f'c_0:2_fl_M_pas_{self.name}') + self._fl_M_pas = self.curves.fiber_force_length_passive(self._l_M_tilde, *fl_M_pas_constants) + fl_M_act_constants = symbols(f'c_0:12_fl_M_act_{self.name}') + self._fl_M_act = self.curves.fiber_force_length_active(self._l_M_tilde, *fl_M_act_constants) + fv_M_constants = symbols(f'c_0:4_fv_M_{self.name}') + self._fv_M = self.curves.fiber_force_velocity(self._v_M_tilde, *fv_M_constants) + self._F_M_tilde = self.a*self._fl_M_act*self._fv_M + self._fl_M_pas + self._beta*self._v_M_tilde + self._F_T_tilde = self._F_M_tilde + self._F_M = self._F_M_tilde*self._F_M_max + self._cos_alpha = cos(self._alpha_opt) + self._F_T = self._F_M*self._cos_alpha + + # Containers + self._state_vars = zeros(0, 1) + self._input_vars = zeros(0, 1) + self._state_eqns = zeros(0, 1) + self._curve_constants = Matrix( + fl_T_constants + + fl_M_pas_constants + + fl_M_act_constants + + fv_M_constants + ) if not self._with_defaults else zeros(0, 1) + + def _fiber_length_explicit_musculotendon_dynamics(self): + """Elastic tendon musculotendon using `l_M_tilde` as a state.""" + self._l_M_tilde = dynamicsymbols(f'l_M_tilde_{self.name}') + self._l_MT = self.pathway.length + self._v_MT = self.pathway.extension_velocity + self._l_M = self._l_M_tilde*self._l_M_opt + self._l_T = self._l_MT - sqrt(self._l_M**2 - (self._l_M_opt*sin(self._alpha_opt))**2) + self._l_T_tilde = self._l_T/self._l_T_slack + self._cos_alpha = (self._l_MT - self._l_T)/self._l_M + if self._with_defaults: + self._fl_T = self.curves.tendon_force_length.with_defaults(self._l_T_tilde) + self._fl_M_pas = self.curves.fiber_force_length_passive.with_defaults(self._l_M_tilde) + self._fl_M_act = self.curves.fiber_force_length_active.with_defaults(self._l_M_tilde) + else: + fl_T_constants = symbols(f'c_0:4_fl_T_{self.name}') + self._fl_T = self.curves.tendon_force_length(self._l_T_tilde, *fl_T_constants) + fl_M_pas_constants = symbols(f'c_0:2_fl_M_pas_{self.name}') + self._fl_M_pas = self.curves.fiber_force_length_passive(self._l_M_tilde, *fl_M_pas_constants) + fl_M_act_constants = symbols(f'c_0:12_fl_M_act_{self.name}') + self._fl_M_act = self.curves.fiber_force_length_active(self._l_M_tilde, *fl_M_act_constants) + self._F_T_tilde = self._fl_T + self._F_T = self._F_T_tilde*self._F_M_max + self._F_M = self._F_T/self._cos_alpha + self._F_M_tilde = self._F_M/self._F_M_max + self._fv_M = (self._F_M_tilde - self._fl_M_pas)/(self.a*self._fl_M_act) + if self._with_defaults: + self._v_M_tilde = self.curves.fiber_force_velocity_inverse.with_defaults(self._fv_M) + else: + fv_M_constants = symbols(f'c_0:4_fv_M_{self.name}') + self._v_M_tilde = self.curves.fiber_force_velocity_inverse(self._fv_M, *fv_M_constants) + self._dl_M_tilde_dt = (self._v_M_max/self._l_M_opt)*self._v_M_tilde + + self._state_vars = Matrix([self._l_M_tilde]) + self._input_vars = zeros(0, 1) + self._state_eqns = Matrix([self._dl_M_tilde_dt]) + self._curve_constants = Matrix( + fl_T_constants + + fl_M_pas_constants + + fl_M_act_constants + + fv_M_constants + ) if not self._with_defaults else zeros(0, 1) + + def _tendon_force_explicit_musculotendon_dynamics(self): + """Elastic tendon musculotendon using `F_T_tilde` as a state.""" + self._F_T_tilde = dynamicsymbols(f'F_T_tilde_{self.name}') + self._l_MT = self.pathway.length + self._v_MT = self.pathway.extension_velocity + self._fl_T = self._F_T_tilde + if self._with_defaults: + self._fl_T_inv = self.curves.tendon_force_length_inverse.with_defaults(self._fl_T) + else: + fl_T_constants = symbols(f'c_0:4_fl_T_{self.name}') + self._fl_T_inv = self.curves.tendon_force_length_inverse(self._fl_T, *fl_T_constants) + self._l_T_tilde = self._fl_T_inv + self._l_T = self._l_T_tilde*self._l_T_slack + self._l_M = sqrt((self._l_MT - self._l_T)**2 + (self._l_M_opt*sin(self._alpha_opt))**2) + self._l_M_tilde = self._l_M/self._l_M_opt + if self._with_defaults: + self._fl_M_pas = self.curves.fiber_force_length_passive.with_defaults(self._l_M_tilde) + self._fl_M_act = self.curves.fiber_force_length_active.with_defaults(self._l_M_tilde) + else: + fl_M_pas_constants = symbols(f'c_0:2_fl_M_pas_{self.name}') + self._fl_M_pas = self.curves.fiber_force_length_passive(self._l_M_tilde, *fl_M_pas_constants) + fl_M_act_constants = symbols(f'c_0:12_fl_M_act_{self.name}') + self._fl_M_act = self.curves.fiber_force_length_active(self._l_M_tilde, *fl_M_act_constants) + self._cos_alpha = (self._l_MT - self._l_T)/self._l_M + self._F_T = self._F_T_tilde*self._F_M_max + self._F_M = self._F_T/self._cos_alpha + self._F_M_tilde = self._F_M/self._F_M_max + self._fv_M = (self._F_M_tilde - self._fl_M_pas)/(self.a*self._fl_M_act) + if self._with_defaults: + self._fv_M_inv = self.curves.fiber_force_velocity_inverse.with_defaults(self._fv_M) + else: + fv_M_constants = symbols(f'c_0:4_fv_M_{self.name}') + self._fv_M_inv = self.curves.fiber_force_velocity_inverse(self._fv_M, *fv_M_constants) + self._v_M_tilde = self._fv_M_inv + self._v_M = self._v_M_tilde*self._v_M_max + self._v_T = self._v_MT - (self._v_M/self._cos_alpha) + self._v_T_tilde = self._v_T/self._l_T_slack + if self._with_defaults: + self._fl_T = self.curves.tendon_force_length.with_defaults(self._l_T_tilde) + else: + self._fl_T = self.curves.tendon_force_length(self._l_T_tilde, *fl_T_constants) + self._dF_T_tilde_dt = self._fl_T.diff(dynamicsymbols._t).subs({self._l_T_tilde.diff(dynamicsymbols._t): self._v_T_tilde}) + + self._state_vars = Matrix([self._F_T_tilde]) + self._input_vars = zeros(0, 1) + self._state_eqns = Matrix([self._dF_T_tilde_dt]) + self._curve_constants = Matrix( + fl_T_constants + + fl_M_pas_constants + + fl_M_act_constants + + fv_M_constants + ) if not self._with_defaults else zeros(0, 1) + + def _fiber_length_implicit_musculotendon_dynamics(self): + raise NotImplementedError + + def _tendon_force_implicit_musculotendon_dynamics(self): + raise NotImplementedError + + @property + def state_vars(self): + """Ordered column matrix of functions of time that represent the state + variables. + + Explanation + =========== + + The alias ``x`` can also be used to access the same attribute. + + """ + state_vars = [self._state_vars] + for child in self._child_objects: + state_vars.append(child.state_vars) + return Matrix.vstack(*state_vars) + + @property + def x(self): + """Ordered column matrix of functions of time that represent the state + variables. + + Explanation + =========== + + The alias ``state_vars`` can also be used to access the same attribute. + + """ + state_vars = [self._state_vars] + for child in self._child_objects: + state_vars.append(child.state_vars) + return Matrix.vstack(*state_vars) + + @property + def input_vars(self): + """Ordered column matrix of functions of time that represent the input + variables. + + Explanation + =========== + + The alias ``r`` can also be used to access the same attribute. + + """ + input_vars = [self._input_vars] + for child in self._child_objects: + input_vars.append(child.input_vars) + return Matrix.vstack(*input_vars) + + @property + def r(self): + """Ordered column matrix of functions of time that represent the input + variables. + + Explanation + =========== + + The alias ``input_vars`` can also be used to access the same attribute. + + """ + input_vars = [self._input_vars] + for child in self._child_objects: + input_vars.append(child.input_vars) + return Matrix.vstack(*input_vars) + + @property + def constants(self): + """Ordered column matrix of non-time varying symbols present in ``M`` + and ``F``. + + Explanation + =========== + + Only symbolic constants are returned. If a numeric type (e.g. ``Float``) + has been used instead of ``Symbol`` for a constant then that attribute + will not be included in the matrix returned by this property. This is + because the primary use of this property attribute is to provide an + ordered sequence of the still-free symbols that require numeric values + during code generation. + + The alias ``p`` can also be used to access the same attribute. + + """ + musculotendon_constants = [ + self._l_T_slack, + self._F_M_max, + self._l_M_opt, + self._v_M_max, + self._alpha_opt, + self._beta, + ] + musculotendon_constants = [ + c for c in musculotendon_constants if not c.is_number + ] + constants = [ + Matrix(musculotendon_constants) + if musculotendon_constants + else zeros(0, 1) + ] + for child in self._child_objects: + constants.append(child.constants) + constants.append(self._curve_constants) + return Matrix.vstack(*constants) + + @property + def p(self): + """Ordered column matrix of non-time varying symbols present in ``M`` + and ``F``. + + Explanation + =========== + + Only symbolic constants are returned. If a numeric type (e.g. ``Float``) + has been used instead of ``Symbol`` for a constant then that attribute + will not be included in the matrix returned by this property. This is + because the primary use of this property attribute is to provide an + ordered sequence of the still-free symbols that require numeric values + during code generation. + + The alias ``constants`` can also be used to access the same attribute. + + """ + musculotendon_constants = [ + self._l_T_slack, + self._F_M_max, + self._l_M_opt, + self._v_M_max, + self._alpha_opt, + self._beta, + ] + musculotendon_constants = [ + c for c in musculotendon_constants if not c.is_number + ] + constants = [ + Matrix(musculotendon_constants) + if musculotendon_constants + else zeros(0, 1) + ] + for child in self._child_objects: + constants.append(child.constants) + constants.append(self._curve_constants) + return Matrix.vstack(*constants) + + @property + def M(self): + """Ordered square matrix of coefficients on the LHS of ``M x' = F``. + + Explanation + =========== + + The square matrix that forms part of the LHS of the linear system of + ordinary differential equations governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + As zeroth-order activation dynamics have no state variables, this + linear system has dimension 0 and therefore ``M`` is an empty square + ``Matrix`` with shape (0, 0). + + """ + M = [eye(len(self._state_vars))] + for child in self._child_objects: + M.append(child.M) + return diag(*M) + + @property + def F(self): + """Ordered column matrix of equations on the RHS of ``M x' = F``. + + Explanation + =========== + + The column matrix that forms the RHS of the linear system of ordinary + differential equations governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + As zeroth-order activation dynamics have no state variables, this + linear system has dimension 0 and therefore ``F`` is an empty column + ``Matrix`` with shape (0, 1). + + """ + F = [self._state_eqns] + for child in self._child_objects: + F.append(child.F) + return Matrix.vstack(*F) + + def rhs(self): + """Ordered column matrix of equations for the solution of ``M x' = F``. + + Explanation + =========== + + The solution to the linear system of ordinary differential equations + governing the activation dynamics: + + ``M(x, r, t, p) x' = F(x, r, t, p)``. + + As zeroth-order activation dynamics have no state variables, this + linear has dimension 0 and therefore this method returns an empty + column ``Matrix`` with shape (0, 1). + + """ + is_explicit = ( + MusculotendonFormulation.FIBER_LENGTH_EXPLICIT, + MusculotendonFormulation.TENDON_FORCE_EXPLICIT, + ) + if self.musculotendon_dynamics is MusculotendonFormulation.RIGID_TENDON: + child_rhs = [child.rhs() for child in self._child_objects] + return Matrix.vstack(*child_rhs) + elif self.musculotendon_dynamics in is_explicit: + rhs = self._state_eqns + child_rhs = [child.rhs() for child in self._child_objects] + return Matrix.vstack(rhs, *child_rhs) + return self.M.solve(self.F) + + def __repr__(self): + """Returns a string representation to reinstantiate the model.""" + return ( + f'{self.__class__.__name__}({self.name!r}, ' + f'pathway={self.pathway!r}, ' + f'activation_dynamics={self.activation_dynamics!r}, ' + f'musculotendon_dynamics={self.musculotendon_dynamics}, ' + f'tendon_slack_length={self._l_T_slack!r}, ' + f'peak_isometric_force={self._F_M_max!r}, ' + f'optimal_fiber_length={self._l_M_opt!r}, ' + f'maximal_fiber_velocity={self._v_M_max!r}, ' + f'optimal_pennation_angle={self._alpha_opt!r}, ' + f'fiber_damping_coefficient={self._beta!r})' + ) + + def __str__(self): + """Returns a string representation of the expression for musculotendon + force.""" + return str(self.force) + + +class MusculotendonDeGroote2016(MusculotendonBase): + r"""Musculotendon model using the curves of De Groote et al., 2016 [1]_. + + Examples + ======== + + This class models the musculotendon actuator parametrized by the + characteristic curves described in De Groote et al., 2016 [1]_. Like all + musculotendon models in SymPy's biomechanics module, it requires a pathway + to define its line of action. We'll begin by creating a simple + ``LinearPathway`` between two points that our musculotendon will follow. + We'll create a point ``O`` to represent the musculotendon's origin and + another ``I`` to represent its insertion. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import (LinearPathway, Point, + ... ReferenceFrame, dynamicsymbols) + + >>> N = ReferenceFrame('N') + >>> O, I = O, P = symbols('O, I', cls=Point) + >>> q, u = dynamicsymbols('q, u', real=True) + >>> I.set_pos(O, q*N.x) + >>> O.set_vel(N, 0) + >>> I.set_vel(N, u*N.x) + >>> pathway = LinearPathway(O, I) + >>> pathway.attachments + (O, I) + >>> pathway.length + Abs(q(t)) + >>> pathway.extension_velocity + sign(q(t))*Derivative(q(t), t) + + A musculotendon also takes an instance of an activation dynamics model as + this will be used to provide symbols for the activation in the formulation + of the musculotendon dynamics. We'll use an instance of + ``FirstOrderActivationDeGroote2016`` to represent first-order activation + dynamics. Note that a single name argument needs to be provided as SymPy + will use this as a suffix. + + >>> from sympy.physics.biomechanics import FirstOrderActivationDeGroote2016 + + >>> activation = FirstOrderActivationDeGroote2016('muscle') + >>> activation.x + Matrix([[a_muscle(t)]]) + >>> activation.r + Matrix([[e_muscle(t)]]) + >>> activation.p + Matrix([ + [tau_a_muscle], + [tau_d_muscle], + [ b_muscle]]) + >>> activation.rhs() + Matrix([[((1/2 - tanh(b_muscle*(-a_muscle(t) + e_muscle(t)))/2)*(3*...]]) + + The musculotendon class requires symbols or values to be passed to represent + the constants in the musculotendon dynamics. We'll use SymPy's ``symbols`` + function to create symbols for the maximum isometric force ``F_M_max``, + optimal fiber length ``l_M_opt``, tendon slack length ``l_T_slack``, maximum + fiber velocity ``v_M_max``, optimal pennation angle ``alpha_opt, and fiber + damping coefficient ``beta``. + + >>> F_M_max = symbols('F_M_max', real=True) + >>> l_M_opt = symbols('l_M_opt', real=True) + >>> l_T_slack = symbols('l_T_slack', real=True) + >>> v_M_max = symbols('v_M_max', real=True) + >>> alpha_opt = symbols('alpha_opt', real=True) + >>> beta = symbols('beta', real=True) + + We can then import the class ``MusculotendonDeGroote2016`` from the + biomechanics module and create an instance by passing in the various objects + we have previously instantiated. By default, a musculotendon model with + rigid tendon musculotendon dynamics will be created. + + >>> from sympy.physics.biomechanics import MusculotendonDeGroote2016 + + >>> rigid_tendon_muscle = MusculotendonDeGroote2016( + ... 'muscle', + ... pathway, + ... activation, + ... tendon_slack_length=l_T_slack, + ... peak_isometric_force=F_M_max, + ... optimal_fiber_length=l_M_opt, + ... maximal_fiber_velocity=v_M_max, + ... optimal_pennation_angle=alpha_opt, + ... fiber_damping_coefficient=beta, + ... ) + + We can inspect the various properties of the musculotendon, including + getting the symbolic expression describing the force it produces using its + ``force`` attribute. + + >>> rigid_tendon_muscle.force + -F_M_max*(beta*(-l_T_slack + Abs(q(t)))*sign(q(t))*Derivative(q(t), t)... + + When we created the musculotendon object, we passed in an instance of an + activation dynamics object that governs the activation within the + musculotendon. SymPy makes a design choice here that the activation dynamics + instance will be treated as a child object of the musculotendon dynamics. + Therefore, if we want to inspect the state and input variables associated + with the musculotendon model, we will also be returned the state and input + variables associated with the child object, or the activation dynamics in + this case. As the musculotendon model that we created here uses rigid tendon + dynamics, no additional states or inputs relating to the musculotendon are + introduces. Consequently, the model has a single state associated with it, + the activation, and a single input associated with it, the excitation. The + states and inputs can be inspected using the ``x`` and ``r`` attributes + respectively. Note that both ``x`` and ``r`` have the alias attributes of + ``state_vars`` and ``input_vars``. + + >>> rigid_tendon_muscle.x + Matrix([[a_muscle(t)]]) + >>> rigid_tendon_muscle.r + Matrix([[e_muscle(t)]]) + + To see which constants are symbolic in the musculotendon model, we can use + the ``p`` or ``constants`` attribute. This returns a ``Matrix`` populated + by the constants that are represented by a ``Symbol`` rather than a numeric + value. + + >>> rigid_tendon_muscle.p + Matrix([ + [ l_T_slack], + [ F_M_max], + [ l_M_opt], + [ v_M_max], + [ alpha_opt], + [ beta], + [ tau_a_muscle], + [ tau_d_muscle], + [ b_muscle], + [ c_0_fl_T_muscle], + [ c_1_fl_T_muscle], + [ c_2_fl_T_muscle], + [ c_3_fl_T_muscle], + [ c_0_fl_M_pas_muscle], + [ c_1_fl_M_pas_muscle], + [ c_0_fl_M_act_muscle], + [ c_1_fl_M_act_muscle], + [ c_2_fl_M_act_muscle], + [ c_3_fl_M_act_muscle], + [ c_4_fl_M_act_muscle], + [ c_5_fl_M_act_muscle], + [ c_6_fl_M_act_muscle], + [ c_7_fl_M_act_muscle], + [ c_8_fl_M_act_muscle], + [ c_9_fl_M_act_muscle], + [c_10_fl_M_act_muscle], + [c_11_fl_M_act_muscle], + [ c_0_fv_M_muscle], + [ c_1_fv_M_muscle], + [ c_2_fv_M_muscle], + [ c_3_fv_M_muscle]]) + + Finally, we can call the ``rhs`` method to return a ``Matrix`` that + contains as its elements the righthand side of the ordinary differential + equations corresponding to each of the musculotendon's states. Like the + method with the same name on the ``Method`` classes in SymPy's mechanics + module, this returns a column vector where the number of rows corresponds to + the number of states. For our example here, we have a single state, the + dynamic symbol ``a_muscle(t)``, so the returned value is a 1-by-1 + ``Matrix``. + + >>> rigid_tendon_muscle.rhs() + Matrix([[((1/2 - tanh(b_muscle*(-a_muscle(t) + e_muscle(t)))/2)*(3*...]]) + + The musculotendon class supports elastic tendon musculotendon models in + addition to rigid tendon ones. You can choose to either use the fiber length + or tendon force as an additional state. You can also specify whether an + explicit or implicit formulation should be used. To select a formulation, + pass a member of the ``MusculotendonFormulation`` enumeration to the + ``musculotendon_dynamics`` parameter when calling the constructor. This + enumeration is an ``IntEnum``, so you can also pass an integer, however it + is recommended to use the enumeration as it is clearer which formulation you + are actually selecting. Below, we'll use the ``FIBER_LENGTH_EXPLICIT`` + member to create a musculotendon with an elastic tendon that will use the + (normalized) muscle fiber length as an additional state and will produce + the governing ordinary differential equation in explicit form. + + >>> from sympy.physics.biomechanics import MusculotendonFormulation + + >>> elastic_tendon_muscle = MusculotendonDeGroote2016( + ... 'muscle', + ... pathway, + ... activation, + ... musculotendon_dynamics=MusculotendonFormulation.FIBER_LENGTH_EXPLICIT, + ... tendon_slack_length=l_T_slack, + ... peak_isometric_force=F_M_max, + ... optimal_fiber_length=l_M_opt, + ... maximal_fiber_velocity=v_M_max, + ... optimal_pennation_angle=alpha_opt, + ... fiber_damping_coefficient=beta, + ... ) + + >>> elastic_tendon_muscle.force + -F_M_max*TendonForceLengthDeGroote2016((-sqrt(l_M_opt**2*... + >>> elastic_tendon_muscle.x + Matrix([ + [l_M_tilde_muscle(t)], + [ a_muscle(t)]]) + >>> elastic_tendon_muscle.r + Matrix([[e_muscle(t)]]) + >>> elastic_tendon_muscle.p + Matrix([ + [ l_T_slack], + [ F_M_max], + [ l_M_opt], + [ v_M_max], + [ alpha_opt], + [ beta], + [ tau_a_muscle], + [ tau_d_muscle], + [ b_muscle], + [ c_0_fl_T_muscle], + [ c_1_fl_T_muscle], + [ c_2_fl_T_muscle], + [ c_3_fl_T_muscle], + [ c_0_fl_M_pas_muscle], + [ c_1_fl_M_pas_muscle], + [ c_0_fl_M_act_muscle], + [ c_1_fl_M_act_muscle], + [ c_2_fl_M_act_muscle], + [ c_3_fl_M_act_muscle], + [ c_4_fl_M_act_muscle], + [ c_5_fl_M_act_muscle], + [ c_6_fl_M_act_muscle], + [ c_7_fl_M_act_muscle], + [ c_8_fl_M_act_muscle], + [ c_9_fl_M_act_muscle], + [c_10_fl_M_act_muscle], + [c_11_fl_M_act_muscle], + [ c_0_fv_M_muscle], + [ c_1_fv_M_muscle], + [ c_2_fv_M_muscle], + [ c_3_fv_M_muscle]]) + >>> elastic_tendon_muscle.rhs() + Matrix([ + [v_M_max*FiberForceVelocityInverseDeGroote2016((l_M_opt*...], + [ ((1/2 - tanh(b_muscle*(-a_muscle(t) + e_muscle(t)))/2)*(3*...]]) + + It is strongly recommended to use the alternate ``with_defaults`` + constructor when creating an instance because this will ensure that the + published constants are used in the musculotendon characteristic curves. + + >>> elastic_tendon_muscle = MusculotendonDeGroote2016.with_defaults( + ... 'muscle', + ... pathway, + ... activation, + ... musculotendon_dynamics=MusculotendonFormulation.FIBER_LENGTH_EXPLICIT, + ... tendon_slack_length=l_T_slack, + ... peak_isometric_force=F_M_max, + ... optimal_fiber_length=l_M_opt, + ... ) + + >>> elastic_tendon_muscle.x + Matrix([ + [l_M_tilde_muscle(t)], + [ a_muscle(t)]]) + >>> elastic_tendon_muscle.r + Matrix([[e_muscle(t)]]) + >>> elastic_tendon_muscle.p + Matrix([ + [ l_T_slack], + [ F_M_max], + [ l_M_opt], + [tau_a_muscle], + [tau_d_muscle], + [ b_muscle]]) + + Parameters + ========== + + name : str + The name identifier associated with the musculotendon. This name is used + as a suffix when automatically generated symbols are instantiated. It + must be a string of nonzero length. + pathway : PathwayBase + The pathway that the actuator follows. This must be an instance of a + concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``. + activation_dynamics : ActivationBase + The activation dynamics that will be modeled within the musculotendon. + This must be an instance of a concrete subclass of ``ActivationBase``, + e.g. ``FirstOrderActivationDeGroote2016``. + musculotendon_dynamics : MusculotendonFormulation | int + The formulation of musculotendon dynamics that should be used + internally, i.e. rigid or elastic tendon model, the choice of + musculotendon state etc. This must be a member of the integer + enumeration ``MusculotendonFormulation`` or an integer that can be cast + to a member. To use a rigid tendon formulation, set this to + ``MusculotendonFormulation.RIGID_TENDON`` (or the integer value ``0``, + which will be cast to the enumeration member). There are four possible + formulations for an elastic tendon model. To use an explicit formulation + with the fiber length as the state, set this to + ``MusculotendonFormulation.FIBER_LENGTH_EXPLICIT`` (or the integer value + ``1``). To use an explicit formulation with the tendon force as the + state, set this to ``MusculotendonFormulation.TENDON_FORCE_EXPLICIT`` + (or the integer value ``2``). To use an implicit formulation with the + fiber length as the state, set this to + ``MusculotendonFormulation.FIBER_LENGTH_IMPLICIT`` (or the integer value + ``3``). To use an implicit formulation with the tendon force as the + state, set this to ``MusculotendonFormulation.TENDON_FORCE_IMPLICIT`` + (or the integer value ``4``). The default is + ``MusculotendonFormulation.RIGID_TENDON``, which corresponds to a rigid + tendon formulation. + tendon_slack_length : Expr | None + The length of the tendon when the musculotendon is in its unloaded + state. In a rigid tendon model the tendon length is the tendon slack + length. In all musculotendon models, tendon slack length is used to + normalize tendon length to give + :math:`\tilde{l}^T = \frac{l^T}{l^T_{slack}}`. + peak_isometric_force : Expr | None + The maximum force that the muscle fiber can produce when it is + undergoing an isometric contraction (no lengthening velocity). In all + musculotendon models, peak isometric force is used to normalized tendon + and muscle fiber force to give + :math:`\tilde{F}^T = \frac{F^T}{F^M_{max}}`. + optimal_fiber_length : Expr | None + The muscle fiber length at which the muscle fibers produce no passive + force and their maximum active force. In all musculotendon models, + optimal fiber length is used to normalize muscle fiber length to give + :math:`\tilde{l}^M = \frac{l^M}{l^M_{opt}}`. + maximal_fiber_velocity : Expr | None + The fiber velocity at which, during muscle fiber shortening, the muscle + fibers are unable to produce any active force. In all musculotendon + models, maximal fiber velocity is used to normalize muscle fiber + extension velocity to give :math:`\tilde{v}^M = \frac{v^M}{v^M_{max}}`. + optimal_pennation_angle : Expr | None + The pennation angle when muscle fiber length equals the optimal fiber + length. + fiber_damping_coefficient : Expr | None + The coefficient of damping to be used in the damping element in the + muscle fiber model. + with_defaults : bool + Whether ``with_defaults`` alternate constructors should be used when + automatically constructing child classes. Default is ``False``. + + References + ========== + + .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation + of direct collocation optimal control problem formulations for + solving the muscle redundancy problem, Annals of biomedical + engineering, 44(10), (2016) pp. 2922-2936 + + """ + + curves = CharacteristicCurveCollection( + tendon_force_length=TendonForceLengthDeGroote2016, + tendon_force_length_inverse=TendonForceLengthInverseDeGroote2016, + fiber_force_length_passive=FiberForceLengthPassiveDeGroote2016, + fiber_force_length_passive_inverse=FiberForceLengthPassiveInverseDeGroote2016, + fiber_force_length_active=FiberForceLengthActiveDeGroote2016, + fiber_force_velocity=FiberForceVelocityDeGroote2016, + fiber_force_velocity_inverse=FiberForceVelocityInverseDeGroote2016, + ) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed5db853f46e91f03ccda28fcdce0fdbc4df9d55 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_activation.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_activation.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9901eea5115f92d752b25c7731268e8f003dce30 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_activation.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_mixin.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_mixin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ce5c99121c8c81a3cb8f73ff56f3fc9712d58100 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_mixin.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_musculotendon.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_musculotendon.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9c0d70ee47cab857a8a788222473a9b9b3c5000 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_musculotendon.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_activation.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_activation.py new file mode 100644 index 0000000000000000000000000000000000000000..a38742f0d42af48dff95295eae869b2c5ef269de --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_activation.py @@ -0,0 +1,348 @@ +"""Tests for the ``sympy.physics.biomechanics.activation.py`` module.""" + +import pytest + +from sympy import Symbol +from sympy.core.numbers import Float, Integer, Rational +from sympy.functions.elementary.hyperbolic import tanh +from sympy.matrices import Matrix +from sympy.matrices.dense import zeros +from sympy.physics.mechanics import dynamicsymbols +from sympy.physics.biomechanics import ( + ActivationBase, + FirstOrderActivationDeGroote2016, + ZerothOrderActivation, +) +from sympy.physics.biomechanics._mixin import _NamedMixin +from sympy.simplify.simplify import simplify + + +class TestZerothOrderActivation: + + @staticmethod + def test_class(): + assert issubclass(ZerothOrderActivation, ActivationBase) + assert issubclass(ZerothOrderActivation, _NamedMixin) + assert ZerothOrderActivation.__name__ == 'ZerothOrderActivation' + + @pytest.fixture(autouse=True) + def _zeroth_order_activation_fixture(self): + self.name = 'name' + self.e = dynamicsymbols('e_name') + self.instance = ZerothOrderActivation(self.name) + + def test_instance(self): + instance = ZerothOrderActivation(self.name) + assert isinstance(instance, ZerothOrderActivation) + + def test_with_defaults(self): + instance = ZerothOrderActivation.with_defaults(self.name) + assert isinstance(instance, ZerothOrderActivation) + assert instance == ZerothOrderActivation(self.name) + + def test_name(self): + assert hasattr(self.instance, 'name') + assert self.instance.name == self.name + + def test_order(self): + assert hasattr(self.instance, 'order') + assert self.instance.order == 0 + + def test_excitation_attribute(self): + assert hasattr(self.instance, 'e') + assert hasattr(self.instance, 'excitation') + e_expected = dynamicsymbols('e_name') + assert self.instance.e == e_expected + assert self.instance.excitation == e_expected + assert self.instance.e is self.instance.excitation + + def test_activation_attribute(self): + assert hasattr(self.instance, 'a') + assert hasattr(self.instance, 'activation') + a_expected = dynamicsymbols('e_name') + assert self.instance.a == a_expected + assert self.instance.activation == a_expected + assert self.instance.a is self.instance.activation is self.instance.e + + def test_state_vars_attribute(self): + assert hasattr(self.instance, 'x') + assert hasattr(self.instance, 'state_vars') + assert self.instance.x == self.instance.state_vars + x_expected = zeros(0, 1) + assert self.instance.x == x_expected + assert self.instance.state_vars == x_expected + assert isinstance(self.instance.x, Matrix) + assert isinstance(self.instance.state_vars, Matrix) + assert self.instance.x.shape == (0, 1) + assert self.instance.state_vars.shape == (0, 1) + + def test_input_vars_attribute(self): + assert hasattr(self.instance, 'r') + assert hasattr(self.instance, 'input_vars') + assert self.instance.r == self.instance.input_vars + r_expected = Matrix([self.e]) + assert self.instance.r == r_expected + assert self.instance.input_vars == r_expected + assert isinstance(self.instance.r, Matrix) + assert isinstance(self.instance.input_vars, Matrix) + assert self.instance.r.shape == (1, 1) + assert self.instance.input_vars.shape == (1, 1) + + def test_constants_attribute(self): + assert hasattr(self.instance, 'p') + assert hasattr(self.instance, 'constants') + assert self.instance.p == self.instance.constants + p_expected = zeros(0, 1) + assert self.instance.p == p_expected + assert self.instance.constants == p_expected + assert isinstance(self.instance.p, Matrix) + assert isinstance(self.instance.constants, Matrix) + assert self.instance.p.shape == (0, 1) + assert self.instance.constants.shape == (0, 1) + + def test_M_attribute(self): + assert hasattr(self.instance, 'M') + M_expected = Matrix([]) + assert self.instance.M == M_expected + assert isinstance(self.instance.M, Matrix) + assert self.instance.M.shape == (0, 0) + + def test_F(self): + assert hasattr(self.instance, 'F') + F_expected = zeros(0, 1) + assert self.instance.F == F_expected + assert isinstance(self.instance.F, Matrix) + assert self.instance.F.shape == (0, 1) + + def test_rhs(self): + assert hasattr(self.instance, 'rhs') + rhs_expected = zeros(0, 1) + rhs = self.instance.rhs() + assert rhs == rhs_expected + assert isinstance(rhs, Matrix) + assert rhs.shape == (0, 1) + + def test_repr(self): + expected = 'ZerothOrderActivation(\'name\')' + assert repr(self.instance) == expected + + +class TestFirstOrderActivationDeGroote2016: + + @staticmethod + def test_class(): + assert issubclass(FirstOrderActivationDeGroote2016, ActivationBase) + assert issubclass(FirstOrderActivationDeGroote2016, _NamedMixin) + assert FirstOrderActivationDeGroote2016.__name__ == 'FirstOrderActivationDeGroote2016' + + @pytest.fixture(autouse=True) + def _first_order_activation_de_groote_2016_fixture(self): + self.name = 'name' + self.e = dynamicsymbols('e_name') + self.a = dynamicsymbols('a_name') + self.tau_a = Symbol('tau_a') + self.tau_d = Symbol('tau_d') + self.b = Symbol('b') + self.instance = FirstOrderActivationDeGroote2016( + self.name, + self.tau_a, + self.tau_d, + self.b, + ) + + def test_instance(self): + instance = FirstOrderActivationDeGroote2016(self.name) + assert isinstance(instance, FirstOrderActivationDeGroote2016) + + def test_with_defaults(self): + instance = FirstOrderActivationDeGroote2016.with_defaults(self.name) + assert isinstance(instance, FirstOrderActivationDeGroote2016) + assert instance.tau_a == Float('0.015') + assert instance.activation_time_constant == Float('0.015') + assert instance.tau_d == Float('0.060') + assert instance.deactivation_time_constant == Float('0.060') + assert instance.b == Float('10.0') + assert instance.smoothing_rate == Float('10.0') + + def test_name(self): + assert hasattr(self.instance, 'name') + assert self.instance.name == self.name + + def test_order(self): + assert hasattr(self.instance, 'order') + assert self.instance.order == 1 + + def test_excitation(self): + assert hasattr(self.instance, 'e') + assert hasattr(self.instance, 'excitation') + e_expected = dynamicsymbols('e_name') + assert self.instance.e == e_expected + assert self.instance.excitation == e_expected + assert self.instance.e is self.instance.excitation + + def test_excitation_is_immutable(self): + with pytest.raises(AttributeError): + self.instance.e = None + with pytest.raises(AttributeError): + self.instance.excitation = None + + def test_activation(self): + assert hasattr(self.instance, 'a') + assert hasattr(self.instance, 'activation') + a_expected = dynamicsymbols('a_name') + assert self.instance.a == a_expected + assert self.instance.activation == a_expected + + def test_activation_is_immutable(self): + with pytest.raises(AttributeError): + self.instance.a = None + with pytest.raises(AttributeError): + self.instance.activation = None + + @pytest.mark.parametrize( + 'tau_a, expected', + [ + (None, Symbol('tau_a_name')), + (Symbol('tau_a'), Symbol('tau_a')), + (Float('0.015'), Float('0.015')), + ] + ) + def test_activation_time_constant(self, tau_a, expected): + instance = FirstOrderActivationDeGroote2016( + 'name', activation_time_constant=tau_a, + ) + assert instance.tau_a == expected + assert instance.activation_time_constant == expected + assert instance.tau_a is instance.activation_time_constant + + def test_activation_time_constant_is_immutable(self): + with pytest.raises(AttributeError): + self.instance.tau_a = None + with pytest.raises(AttributeError): + self.instance.activation_time_constant = None + + @pytest.mark.parametrize( + 'tau_d, expected', + [ + (None, Symbol('tau_d_name')), + (Symbol('tau_d'), Symbol('tau_d')), + (Float('0.060'), Float('0.060')), + ] + ) + def test_deactivation_time_constant(self, tau_d, expected): + instance = FirstOrderActivationDeGroote2016( + 'name', deactivation_time_constant=tau_d, + ) + assert instance.tau_d == expected + assert instance.deactivation_time_constant == expected + assert instance.tau_d is instance.deactivation_time_constant + + def test_deactivation_time_constant_is_immutable(self): + with pytest.raises(AttributeError): + self.instance.tau_d = None + with pytest.raises(AttributeError): + self.instance.deactivation_time_constant = None + + @pytest.mark.parametrize( + 'b, expected', + [ + (None, Symbol('b_name')), + (Symbol('b'), Symbol('b')), + (Integer('10'), Integer('10')), + ] + ) + def test_smoothing_rate(self, b, expected): + instance = FirstOrderActivationDeGroote2016( + 'name', smoothing_rate=b, + ) + assert instance.b == expected + assert instance.smoothing_rate == expected + assert instance.b is instance.smoothing_rate + + def test_smoothing_rate_is_immutable(self): + with pytest.raises(AttributeError): + self.instance.b = None + with pytest.raises(AttributeError): + self.instance.smoothing_rate = None + + def test_state_vars(self): + assert hasattr(self.instance, 'x') + assert hasattr(self.instance, 'state_vars') + assert self.instance.x == self.instance.state_vars + x_expected = Matrix([self.a]) + assert self.instance.x == x_expected + assert self.instance.state_vars == x_expected + assert isinstance(self.instance.x, Matrix) + assert isinstance(self.instance.state_vars, Matrix) + assert self.instance.x.shape == (1, 1) + assert self.instance.state_vars.shape == (1, 1) + + def test_input_vars(self): + assert hasattr(self.instance, 'r') + assert hasattr(self.instance, 'input_vars') + assert self.instance.r == self.instance.input_vars + r_expected = Matrix([self.e]) + assert self.instance.r == r_expected + assert self.instance.input_vars == r_expected + assert isinstance(self.instance.r, Matrix) + assert isinstance(self.instance.input_vars, Matrix) + assert self.instance.r.shape == (1, 1) + assert self.instance.input_vars.shape == (1, 1) + + def test_constants(self): + assert hasattr(self.instance, 'p') + assert hasattr(self.instance, 'constants') + assert self.instance.p == self.instance.constants + p_expected = Matrix([self.tau_a, self.tau_d, self.b]) + assert self.instance.p == p_expected + assert self.instance.constants == p_expected + assert isinstance(self.instance.p, Matrix) + assert isinstance(self.instance.constants, Matrix) + assert self.instance.p.shape == (3, 1) + assert self.instance.constants.shape == (3, 1) + + def test_M(self): + assert hasattr(self.instance, 'M') + M_expected = Matrix([1]) + assert self.instance.M == M_expected + assert isinstance(self.instance.M, Matrix) + assert self.instance.M.shape == (1, 1) + + def test_F(self): + assert hasattr(self.instance, 'F') + da_expr = ( + ((1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a))) + *(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a))) + + ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d) + *(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a)))) + *(self.e - self.a) + ) + F_expected = Matrix([da_expr]) + assert self.instance.F == F_expected + assert isinstance(self.instance.F, Matrix) + assert self.instance.F.shape == (1, 1) + + def test_rhs(self): + assert hasattr(self.instance, 'rhs') + da_expr = ( + ((1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a))) + *(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a))) + + ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d) + *(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a)))) + *(self.e - self.a) + ) + rhs_expected = Matrix([da_expr]) + rhs = self.instance.rhs() + assert rhs == rhs_expected + assert isinstance(rhs, Matrix) + assert rhs.shape == (1, 1) + assert simplify(self.instance.M.solve(self.instance.F) - rhs) == zeros(1) + + def test_repr(self): + expected = ( + 'FirstOrderActivationDeGroote2016(\'name\', ' + 'activation_time_constant=tau_a, ' + 'deactivation_time_constant=tau_d, ' + 'smoothing_rate=b)' + ) + assert repr(self.instance) == expected diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_curve.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_curve.py new file mode 100644 index 0000000000000000000000000000000000000000..6a8fcbccdb8b4190376b051093b376e936d9d5d3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_curve.py @@ -0,0 +1,1695 @@ +"""Tests for the ``sympy.physics.biomechanics.characteristic.py`` module.""" + +import pytest + +from sympy.core.expr import UnevaluatedExpr +from sympy.core.function import Function +from sympy.core.numbers import Float, Integer +from sympy.core.symbol import Symbol, symbols +from sympy.external.importtools import import_module +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.hyperbolic import cosh, sinh +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.physics.biomechanics.curve import ( + CharacteristicCurveCollection, + CharacteristicCurveFunction, + FiberForceLengthActiveDeGroote2016, + FiberForceLengthPassiveDeGroote2016, + FiberForceLengthPassiveInverseDeGroote2016, + FiberForceVelocityDeGroote2016, + FiberForceVelocityInverseDeGroote2016, + TendonForceLengthDeGroote2016, + TendonForceLengthInverseDeGroote2016, +) +from sympy.printing.c import C89CodePrinter, C99CodePrinter, C11CodePrinter +from sympy.printing.cxx import ( + CXX98CodePrinter, + CXX11CodePrinter, + CXX17CodePrinter, +) +from sympy.printing.fortran import FCodePrinter +from sympy.printing.lambdarepr import LambdaPrinter +from sympy.printing.latex import LatexPrinter +from sympy.printing.octave import OctaveCodePrinter +from sympy.printing.numpy import ( + CuPyPrinter, + JaxPrinter, + NumPyPrinter, + SciPyPrinter, +) +from sympy.printing.pycode import MpmathPrinter, PythonCodePrinter +from sympy.utilities.lambdify import lambdify + +jax = import_module('jax') +numpy = import_module('numpy') + +if jax: + jax.config.update('jax_enable_x64', True) + + +class TestCharacteristicCurveFunction: + + @staticmethod + @pytest.mark.parametrize( + 'code_printer, expected', + [ + (C89CodePrinter, '(a + b)*(c + d)*(e + f)'), + (C99CodePrinter, '(a + b)*(c + d)*(e + f)'), + (C11CodePrinter, '(a + b)*(c + d)*(e + f)'), + (CXX98CodePrinter, '(a + b)*(c + d)*(e + f)'), + (CXX11CodePrinter, '(a + b)*(c + d)*(e + f)'), + (CXX17CodePrinter, '(a + b)*(c + d)*(e + f)'), + (FCodePrinter, ' (a + b)*(c + d)*(e + f)'), + (OctaveCodePrinter, '(a + b).*(c + d).*(e + f)'), + (PythonCodePrinter, '(a + b)*(c + d)*(e + f)'), + (NumPyPrinter, '(a + b)*(c + d)*(e + f)'), + (SciPyPrinter, '(a + b)*(c + d)*(e + f)'), + (CuPyPrinter, '(a + b)*(c + d)*(e + f)'), + (JaxPrinter, '(a + b)*(c + d)*(e + f)'), + (MpmathPrinter, '(a + b)*(c + d)*(e + f)'), + (LambdaPrinter, '(a + b)*(c + d)*(e + f)'), + ] + ) + def test_print_code_parenthesize(code_printer, expected): + + class ExampleFunction(CharacteristicCurveFunction): + + @classmethod + def eval(cls, a, b): + pass + + def doit(self, **kwargs): + a, b = self.args + return a + b + + a, b, c, d, e, f = symbols('a, b, c, d, e, f') + f1 = ExampleFunction(a, b) + f2 = ExampleFunction(c, d) + f3 = ExampleFunction(e, f) + assert code_printer().doprint(f1*f2*f3) == expected + + +class TestTendonForceLengthDeGroote2016: + + @pytest.fixture(autouse=True) + def _tendon_force_length_arguments_fixture(self): + self.l_T_tilde = Symbol('l_T_tilde') + self.c0 = Symbol('c_0') + self.c1 = Symbol('c_1') + self.c2 = Symbol('c_2') + self.c3 = Symbol('c_3') + self.constants = (self.c0, self.c1, self.c2, self.c3) + + @staticmethod + def test_class(): + assert issubclass(TendonForceLengthDeGroote2016, Function) + assert issubclass(TendonForceLengthDeGroote2016, CharacteristicCurveFunction) + assert TendonForceLengthDeGroote2016.__name__ == 'TendonForceLengthDeGroote2016' + + def test_instance(self): + fl_T = TendonForceLengthDeGroote2016(self.l_T_tilde, *self.constants) + assert isinstance(fl_T, TendonForceLengthDeGroote2016) + assert str(fl_T) == 'TendonForceLengthDeGroote2016(l_T_tilde, c_0, c_1, c_2, c_3)' + + def test_doit(self): + fl_T = TendonForceLengthDeGroote2016(self.l_T_tilde, *self.constants).doit() + assert fl_T == self.c0*exp(self.c3*(self.l_T_tilde - self.c1)) - self.c2 + + def test_doit_evaluate_false(self): + fl_T = TendonForceLengthDeGroote2016(self.l_T_tilde, *self.constants).doit(evaluate=False) + assert fl_T == self.c0*exp(self.c3*UnevaluatedExpr(self.l_T_tilde - self.c1)) - self.c2 + + def test_with_defaults(self): + constants = ( + Float('0.2'), + Float('0.995'), + Float('0.25'), + Float('33.93669377311689'), + ) + fl_T_manual = TendonForceLengthDeGroote2016(self.l_T_tilde, *constants) + fl_T_constants = TendonForceLengthDeGroote2016.with_defaults(self.l_T_tilde) + assert fl_T_manual == fl_T_constants + + def test_differentiate_wrt_l_T_tilde(self): + fl_T = TendonForceLengthDeGroote2016(self.l_T_tilde, *self.constants) + expected = self.c0*self.c3*exp(self.c3*UnevaluatedExpr(-self.c1 + self.l_T_tilde)) + assert fl_T.diff(self.l_T_tilde) == expected + + def test_differentiate_wrt_c0(self): + fl_T = TendonForceLengthDeGroote2016(self.l_T_tilde, *self.constants) + expected = exp(self.c3*UnevaluatedExpr(-self.c1 + self.l_T_tilde)) + assert fl_T.diff(self.c0) == expected + + def test_differentiate_wrt_c1(self): + fl_T = TendonForceLengthDeGroote2016(self.l_T_tilde, *self.constants) + expected = -self.c0*self.c3*exp(self.c3*UnevaluatedExpr(self.l_T_tilde - self.c1)) + assert fl_T.diff(self.c1) == expected + + def test_differentiate_wrt_c2(self): + fl_T = TendonForceLengthDeGroote2016(self.l_T_tilde, *self.constants) + expected = Integer(-1) + assert fl_T.diff(self.c2) == expected + + def test_differentiate_wrt_c3(self): + fl_T = TendonForceLengthDeGroote2016(self.l_T_tilde, *self.constants) + expected = self.c0*(self.l_T_tilde - self.c1)*exp(self.c3*UnevaluatedExpr(self.l_T_tilde - self.c1)) + assert fl_T.diff(self.c3) == expected + + def test_inverse(self): + fl_T = TendonForceLengthDeGroote2016(self.l_T_tilde, *self.constants) + assert fl_T.inverse() is TendonForceLengthInverseDeGroote2016 + + def test_function_print_latex(self): + fl_T = TendonForceLengthDeGroote2016(self.l_T_tilde, *self.constants) + expected = r'\operatorname{fl}^T \left( l_{T tilde} \right)' + assert LatexPrinter().doprint(fl_T) == expected + + def test_expression_print_latex(self): + fl_T = TendonForceLengthDeGroote2016(self.l_T_tilde, *self.constants) + expected = r'c_{0} e^{c_{3} \left(- c_{1} + l_{T tilde}\right)} - c_{2}' + assert LatexPrinter().doprint(fl_T.doit()) == expected + + @pytest.mark.parametrize( + 'code_printer, expected', + [ + ( + C89CodePrinter, + '(-0.25 + 0.20000000000000001*exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + C99CodePrinter, + '(-0.25 + 0.20000000000000001*exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + C11CodePrinter, + '(-0.25 + 0.20000000000000001*exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + CXX98CodePrinter, + '(-0.25 + 0.20000000000000001*exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + CXX11CodePrinter, + '(-0.25 + 0.20000000000000001*std::exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + CXX17CodePrinter, + '(-0.25 + 0.20000000000000001*std::exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + FCodePrinter, + ' (-0.25d0 + 0.2d0*exp(33.93669377311689d0*(l_T_tilde - 0.995d0)))', + ), + ( + OctaveCodePrinter, + '(-0.25 + 0.2*exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + PythonCodePrinter, + '(-0.25 + 0.2*math.exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + NumPyPrinter, + '(-0.25 + 0.2*numpy.exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + SciPyPrinter, + '(-0.25 + 0.2*numpy.exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + CuPyPrinter, + '(-0.25 + 0.2*cupy.exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + JaxPrinter, + '(-0.25 + 0.2*jax.numpy.exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ( + MpmathPrinter, + '(mpmath.mpf((1, 1, -2, 1)) + mpmath.mpf((0, 3602879701896397, -54, 52))' + '*mpmath.exp(mpmath.mpf((0, 9552330089424741, -48, 54))*(l_T_tilde + ' + 'mpmath.mpf((1, 8962163258467287, -53, 53)))))', + ), + ( + LambdaPrinter, + '(-0.25 + 0.2*math.exp(33.93669377311689*(l_T_tilde - 0.995)))', + ), + ] + ) + def test_print_code(self, code_printer, expected): + fl_T = TendonForceLengthDeGroote2016.with_defaults(self.l_T_tilde) + assert code_printer().doprint(fl_T) == expected + + def test_derivative_print_code(self): + fl_T = TendonForceLengthDeGroote2016.with_defaults(self.l_T_tilde) + dfl_T_dl_T_tilde = fl_T.diff(self.l_T_tilde) + expected = '6.787338754623378*math.exp(33.93669377311689*(l_T_tilde - 0.995))' + assert PythonCodePrinter().doprint(dfl_T_dl_T_tilde) == expected + + def test_lambdify(self): + fl_T = TendonForceLengthDeGroote2016.with_defaults(self.l_T_tilde) + fl_T_callable = lambdify(self.l_T_tilde, fl_T) + assert fl_T_callable(1.0) == pytest.approx(-0.013014055039221595) + + @pytest.mark.skipif(numpy is None, reason='NumPy not installed') + def test_lambdify_numpy(self): + fl_T = TendonForceLengthDeGroote2016.with_defaults(self.l_T_tilde) + fl_T_callable = lambdify(self.l_T_tilde, fl_T, 'numpy') + l_T_tilde = numpy.array([0.95, 1.0, 1.01, 1.05]) + expected = numpy.array([ + -0.2065693181344816, + -0.0130140550392216, + 0.0827421191989246, + 1.04314889144172, + ]) + numpy.testing.assert_allclose(fl_T_callable(l_T_tilde), expected) + + @pytest.mark.skipif(jax is None, reason='JAX not installed') + def test_lambdify_jax(self): + fl_T = TendonForceLengthDeGroote2016.with_defaults(self.l_T_tilde) + fl_T_callable = jax.jit(lambdify(self.l_T_tilde, fl_T, 'jax')) + l_T_tilde = jax.numpy.array([0.95, 1.0, 1.01, 1.05]) + expected = jax.numpy.array([ + -0.2065693181344816, + -0.0130140550392216, + 0.0827421191989246, + 1.04314889144172, + ]) + numpy.testing.assert_allclose(fl_T_callable(l_T_tilde), expected) + + +class TestTendonForceLengthInverseDeGroote2016: + + @pytest.fixture(autouse=True) + def _tendon_force_length_inverse_arguments_fixture(self): + self.fl_T = Symbol('fl_T') + self.c0 = Symbol('c_0') + self.c1 = Symbol('c_1') + self.c2 = Symbol('c_2') + self.c3 = Symbol('c_3') + self.constants = (self.c0, self.c1, self.c2, self.c3) + + @staticmethod + def test_class(): + assert issubclass(TendonForceLengthInverseDeGroote2016, Function) + assert issubclass(TendonForceLengthInverseDeGroote2016, CharacteristicCurveFunction) + assert TendonForceLengthInverseDeGroote2016.__name__ == 'TendonForceLengthInverseDeGroote2016' + + def test_instance(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016(self.fl_T, *self.constants) + assert isinstance(fl_T_inv, TendonForceLengthInverseDeGroote2016) + assert str(fl_T_inv) == 'TendonForceLengthInverseDeGroote2016(fl_T, c_0, c_1, c_2, c_3)' + + def test_doit(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016(self.fl_T, *self.constants).doit() + assert fl_T_inv == log((self.fl_T + self.c2)/self.c0)/self.c3 + self.c1 + + def test_doit_evaluate_false(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016(self.fl_T, *self.constants).doit(evaluate=False) + assert fl_T_inv == log(UnevaluatedExpr((self.fl_T + self.c2)/self.c0))/self.c3 + self.c1 + + def test_with_defaults(self): + constants = ( + Float('0.2'), + Float('0.995'), + Float('0.25'), + Float('33.93669377311689'), + ) + fl_T_inv_manual = TendonForceLengthInverseDeGroote2016(self.fl_T, *constants) + fl_T_inv_constants = TendonForceLengthInverseDeGroote2016.with_defaults(self.fl_T) + assert fl_T_inv_manual == fl_T_inv_constants + + def test_differentiate_wrt_fl_T(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016(self.fl_T, *self.constants) + expected = 1/(self.c3*(self.fl_T + self.c2)) + assert fl_T_inv.diff(self.fl_T) == expected + + def test_differentiate_wrt_c0(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016(self.fl_T, *self.constants) + expected = -1/(self.c0*self.c3) + assert fl_T_inv.diff(self.c0) == expected + + def test_differentiate_wrt_c1(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016(self.fl_T, *self.constants) + expected = Integer(1) + assert fl_T_inv.diff(self.c1) == expected + + def test_differentiate_wrt_c2(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016(self.fl_T, *self.constants) + expected = 1/(self.c3*(self.fl_T + self.c2)) + assert fl_T_inv.diff(self.c2) == expected + + def test_differentiate_wrt_c3(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016(self.fl_T, *self.constants) + expected = -log(UnevaluatedExpr((self.fl_T + self.c2)/self.c0))/self.c3**2 + assert fl_T_inv.diff(self.c3) == expected + + def test_inverse(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016(self.fl_T, *self.constants) + assert fl_T_inv.inverse() is TendonForceLengthDeGroote2016 + + def test_function_print_latex(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016(self.fl_T, *self.constants) + expected = r'\left( \operatorname{fl}^T \right)^{-1} \left( fl_{T} \right)' + assert LatexPrinter().doprint(fl_T_inv) == expected + + def test_expression_print_latex(self): + fl_T = TendonForceLengthInverseDeGroote2016(self.fl_T, *self.constants) + expected = r'c_{1} + \frac{\log{\left(\frac{c_{2} + fl_{T}}{c_{0}} \right)}}{c_{3}}' + assert LatexPrinter().doprint(fl_T.doit()) == expected + + @pytest.mark.parametrize( + 'code_printer, expected', + [ + ( + C89CodePrinter, + '(0.995 + 0.029466630034306838*log(5.0*fl_T + 1.25))', + ), + ( + C99CodePrinter, + '(0.995 + 0.029466630034306838*log(5.0*fl_T + 1.25))', + ), + ( + C11CodePrinter, + '(0.995 + 0.029466630034306838*log(5.0*fl_T + 1.25))', + ), + ( + CXX98CodePrinter, + '(0.995 + 0.029466630034306838*log(5.0*fl_T + 1.25))', + ), + ( + CXX11CodePrinter, + '(0.995 + 0.029466630034306838*std::log(5.0*fl_T + 1.25))', + ), + ( + CXX17CodePrinter, + '(0.995 + 0.029466630034306838*std::log(5.0*fl_T + 1.25))', + ), + ( + FCodePrinter, + ' (0.995d0 + 0.02946663003430684d0*log(5.0d0*fl_T + 1.25d0))', + ), + ( + OctaveCodePrinter, + '(0.995 + 0.02946663003430684*log(5.0*fl_T + 1.25))', + ), + ( + PythonCodePrinter, + '(0.995 + 0.02946663003430684*math.log(5.0*fl_T + 1.25))', + ), + ( + NumPyPrinter, + '(0.995 + 0.02946663003430684*numpy.log(5.0*fl_T + 1.25))', + ), + ( + SciPyPrinter, + '(0.995 + 0.02946663003430684*numpy.log(5.0*fl_T + 1.25))', + ), + ( + CuPyPrinter, + '(0.995 + 0.02946663003430684*cupy.log(5.0*fl_T + 1.25))', + ), + ( + JaxPrinter, + '(0.995 + 0.02946663003430684*jax.numpy.log(5.0*fl_T + 1.25))', + ), + ( + MpmathPrinter, + '(mpmath.mpf((0, 8962163258467287, -53, 53))' + ' + mpmath.mpf((0, 33972711434846347, -60, 55))' + '*mpmath.log(mpmath.mpf((0, 5, 0, 3))*fl_T + mpmath.mpf((0, 5, -2, 3))))', + ), + ( + LambdaPrinter, + '(0.995 + 0.02946663003430684*math.log(5.0*fl_T + 1.25))', + ), + ] + ) + def test_print_code(self, code_printer, expected): + fl_T_inv = TendonForceLengthInverseDeGroote2016.with_defaults(self.fl_T) + assert code_printer().doprint(fl_T_inv) == expected + + def test_derivative_print_code(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016.with_defaults(self.fl_T) + dfl_T_inv_dfl_T = fl_T_inv.diff(self.fl_T) + expected = '1/(33.93669377311689*fl_T + 8.484173443279222)' + assert PythonCodePrinter().doprint(dfl_T_inv_dfl_T) == expected + + def test_lambdify(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016.with_defaults(self.fl_T) + fl_T_inv_callable = lambdify(self.fl_T, fl_T_inv) + assert fl_T_inv_callable(0.0) == pytest.approx(1.0015752885) + + @pytest.mark.skipif(numpy is None, reason='NumPy not installed') + def test_lambdify_numpy(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016.with_defaults(self.fl_T) + fl_T_inv_callable = lambdify(self.fl_T, fl_T_inv, 'numpy') + fl_T = numpy.array([-0.2, -0.01, 0.0, 1.01, 1.02, 1.05]) + expected = numpy.array([ + 0.9541505769, + 1.0003724019, + 1.0015752885, + 1.0492347951, + 1.0494677341, + 1.0501557022, + ]) + numpy.testing.assert_allclose(fl_T_inv_callable(fl_T), expected) + + @pytest.mark.skipif(jax is None, reason='JAX not installed') + def test_lambdify_jax(self): + fl_T_inv = TendonForceLengthInverseDeGroote2016.with_defaults(self.fl_T) + fl_T_inv_callable = jax.jit(lambdify(self.fl_T, fl_T_inv, 'jax')) + fl_T = jax.numpy.array([-0.2, -0.01, 0.0, 1.01, 1.02, 1.05]) + expected = jax.numpy.array([ + 0.9541505769, + 1.0003724019, + 1.0015752885, + 1.0492347951, + 1.0494677341, + 1.0501557022, + ]) + numpy.testing.assert_allclose(fl_T_inv_callable(fl_T), expected) + + +class TestFiberForceLengthPassiveDeGroote2016: + + @pytest.fixture(autouse=True) + def _fiber_force_length_passive_arguments_fixture(self): + self.l_M_tilde = Symbol('l_M_tilde') + self.c0 = Symbol('c_0') + self.c1 = Symbol('c_1') + self.constants = (self.c0, self.c1) + + @staticmethod + def test_class(): + assert issubclass(FiberForceLengthPassiveDeGroote2016, Function) + assert issubclass(FiberForceLengthPassiveDeGroote2016, CharacteristicCurveFunction) + assert FiberForceLengthPassiveDeGroote2016.__name__ == 'FiberForceLengthPassiveDeGroote2016' + + def test_instance(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016(self.l_M_tilde, *self.constants) + assert isinstance(fl_M_pas, FiberForceLengthPassiveDeGroote2016) + assert str(fl_M_pas) == 'FiberForceLengthPassiveDeGroote2016(l_M_tilde, c_0, c_1)' + + def test_doit(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016(self.l_M_tilde, *self.constants).doit() + assert fl_M_pas == (exp((self.c1*(self.l_M_tilde - 1))/self.c0) - 1)/(exp(self.c1) - 1) + + def test_doit_evaluate_false(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016(self.l_M_tilde, *self.constants).doit(evaluate=False) + assert fl_M_pas == (exp((self.c1*UnevaluatedExpr(self.l_M_tilde - 1))/self.c0) - 1)/(exp(self.c1) - 1) + + def test_with_defaults(self): + constants = ( + Float('0.6'), + Float('4.0'), + ) + fl_M_pas_manual = FiberForceLengthPassiveDeGroote2016(self.l_M_tilde, *constants) + fl_M_pas_constants = FiberForceLengthPassiveDeGroote2016.with_defaults(self.l_M_tilde) + assert fl_M_pas_manual == fl_M_pas_constants + + def test_differentiate_wrt_l_M_tilde(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = self.c1*exp(self.c1*UnevaluatedExpr(self.l_M_tilde - 1)/self.c0)/(self.c0*(exp(self.c1) - 1)) + assert fl_M_pas.diff(self.l_M_tilde) == expected + + def test_differentiate_wrt_c0(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + -self.c1*exp(self.c1*UnevaluatedExpr(self.l_M_tilde - 1)/self.c0) + *UnevaluatedExpr(self.l_M_tilde - 1)/(self.c0**2*(exp(self.c1) - 1)) + ) + assert fl_M_pas.diff(self.c0) == expected + + def test_differentiate_wrt_c1(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + -exp(self.c1)*(-1 + exp(self.c1*UnevaluatedExpr(self.l_M_tilde - 1)/self.c0))/(exp(self.c1) - 1)**2 + + exp(self.c1*UnevaluatedExpr(self.l_M_tilde - 1)/self.c0)*(self.l_M_tilde - 1)/(self.c0*(exp(self.c1) - 1)) + ) + assert fl_M_pas.diff(self.c1) == expected + + def test_inverse(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016(self.l_M_tilde, *self.constants) + assert fl_M_pas.inverse() is FiberForceLengthPassiveInverseDeGroote2016 + + def test_function_print_latex(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = r'\operatorname{fl}^M_{pas} \left( l_{M tilde} \right)' + assert LatexPrinter().doprint(fl_M_pas) == expected + + def test_expression_print_latex(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = r'\frac{e^{\frac{c_{1} \left(l_{M tilde} - 1\right)}{c_{0}}} - 1}{e^{c_{1}} - 1}' + assert LatexPrinter().doprint(fl_M_pas.doit()) == expected + + @pytest.mark.parametrize( + 'code_printer, expected', + [ + ( + C89CodePrinter, + '(0.01865736036377405*(-1 + exp(6.666666666666667*(l_M_tilde - 1))))', + ), + ( + C99CodePrinter, + '(0.01865736036377405*(-1 + exp(6.666666666666667*(l_M_tilde - 1))))', + ), + ( + C11CodePrinter, + '(0.01865736036377405*(-1 + exp(6.666666666666667*(l_M_tilde - 1))))', + ), + ( + CXX98CodePrinter, + '(0.01865736036377405*(-1 + exp(6.666666666666667*(l_M_tilde - 1))))', + ), + ( + CXX11CodePrinter, + '(0.01865736036377405*(-1 + std::exp(6.666666666666667*(l_M_tilde - 1))))', + ), + ( + CXX17CodePrinter, + '(0.01865736036377405*(-1 + std::exp(6.666666666666667*(l_M_tilde - 1))))', + ), + ( + FCodePrinter, + ' (0.0186573603637741d0*(-1 + exp(6.666666666666667d0*(l_M_tilde - 1\n' + ' @ ))))', + ), + ( + OctaveCodePrinter, + '(0.0186573603637741*(-1 + exp(6.66666666666667*(l_M_tilde - 1))))', + ), + ( + PythonCodePrinter, + '(0.0186573603637741*(-1 + math.exp(6.66666666666667*(l_M_tilde - 1))))', + ), + ( + NumPyPrinter, + '(0.0186573603637741*(-1 + numpy.exp(6.66666666666667*(l_M_tilde - 1))))', + ), + ( + SciPyPrinter, + '(0.0186573603637741*(-1 + numpy.exp(6.66666666666667*(l_M_tilde - 1))))', + ), + ( + CuPyPrinter, + '(0.0186573603637741*(-1 + cupy.exp(6.66666666666667*(l_M_tilde - 1))))', + ), + ( + JaxPrinter, + '(0.0186573603637741*(-1 + jax.numpy.exp(6.66666666666667*(l_M_tilde - 1))))', + ), + ( + MpmathPrinter, + '(mpmath.mpf((0, 672202249456079, -55, 50))*(-1 + mpmath.exp(' + 'mpmath.mpf((0, 7505999378950827, -50, 53))*(l_M_tilde - 1))))', + ), + ( + LambdaPrinter, + '(0.0186573603637741*(-1 + math.exp(6.66666666666667*(l_M_tilde - 1))))', + ), + ] + ) + def test_print_code(self, code_printer, expected): + fl_M_pas = FiberForceLengthPassiveDeGroote2016.with_defaults(self.l_M_tilde) + assert code_printer().doprint(fl_M_pas) == expected + + def test_derivative_print_code(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016.with_defaults(self.l_M_tilde) + fl_M_pas_dl_M_tilde = fl_M_pas.diff(self.l_M_tilde) + expected = '0.12438240242516*math.exp(6.66666666666667*(l_M_tilde - 1))' + assert PythonCodePrinter().doprint(fl_M_pas_dl_M_tilde) == expected + + def test_lambdify(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016.with_defaults(self.l_M_tilde) + fl_M_pas_callable = lambdify(self.l_M_tilde, fl_M_pas) + assert fl_M_pas_callable(1.0) == pytest.approx(0.0) + + @pytest.mark.skipif(numpy is None, reason='NumPy not installed') + def test_lambdify_numpy(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016.with_defaults(self.l_M_tilde) + fl_M_pas_callable = lambdify(self.l_M_tilde, fl_M_pas, 'numpy') + l_M_tilde = numpy.array([0.5, 0.8, 0.9, 1.0, 1.1, 1.2, 1.5]) + expected = numpy.array([ + -0.0179917778, + -0.0137393336, + -0.0090783522, + 0.0, + 0.0176822155, + 0.0521224686, + 0.5043387669, + ]) + numpy.testing.assert_allclose(fl_M_pas_callable(l_M_tilde), expected) + + @pytest.mark.skipif(jax is None, reason='JAX not installed') + def test_lambdify_jax(self): + fl_M_pas = FiberForceLengthPassiveDeGroote2016.with_defaults(self.l_M_tilde) + fl_M_pas_callable = jax.jit(lambdify(self.l_M_tilde, fl_M_pas, 'jax')) + l_M_tilde = jax.numpy.array([0.5, 0.8, 0.9, 1.0, 1.1, 1.2, 1.5]) + expected = jax.numpy.array([ + -0.0179917778, + -0.0137393336, + -0.0090783522, + 0.0, + 0.0176822155, + 0.0521224686, + 0.5043387669, + ]) + numpy.testing.assert_allclose(fl_M_pas_callable(l_M_tilde), expected) + + +class TestFiberForceLengthPassiveInverseDeGroote2016: + + @pytest.fixture(autouse=True) + def _fiber_force_length_passive_arguments_fixture(self): + self.fl_M_pas = Symbol('fl_M_pas') + self.c0 = Symbol('c_0') + self.c1 = Symbol('c_1') + self.constants = (self.c0, self.c1) + + @staticmethod + def test_class(): + assert issubclass(FiberForceLengthPassiveInverseDeGroote2016, Function) + assert issubclass(FiberForceLengthPassiveInverseDeGroote2016, CharacteristicCurveFunction) + assert FiberForceLengthPassiveInverseDeGroote2016.__name__ == 'FiberForceLengthPassiveInverseDeGroote2016' + + def test_instance(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016(self.fl_M_pas, *self.constants) + assert isinstance(fl_M_pas_inv, FiberForceLengthPassiveInverseDeGroote2016) + assert str(fl_M_pas_inv) == 'FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, c_0, c_1)' + + def test_doit(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016(self.fl_M_pas, *self.constants).doit() + assert fl_M_pas_inv == self.c0*log(self.fl_M_pas*(exp(self.c1) - 1) + 1)/self.c1 + 1 + + def test_doit_evaluate_false(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016(self.fl_M_pas, *self.constants).doit(evaluate=False) + assert fl_M_pas_inv == self.c0*log(UnevaluatedExpr(self.fl_M_pas*(exp(self.c1) - 1)) + 1)/self.c1 + 1 + + def test_with_defaults(self): + constants = ( + Float('0.6'), + Float('4.0'), + ) + fl_M_pas_inv_manual = FiberForceLengthPassiveInverseDeGroote2016(self.fl_M_pas, *constants) + fl_M_pas_inv_constants = FiberForceLengthPassiveInverseDeGroote2016.with_defaults(self.fl_M_pas) + assert fl_M_pas_inv_manual == fl_M_pas_inv_constants + + def test_differentiate_wrt_fl_T(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016(self.fl_M_pas, *self.constants) + expected = self.c0*(exp(self.c1) - 1)/(self.c1*(self.fl_M_pas*(exp(self.c1) - 1) + 1)) + assert fl_M_pas_inv.diff(self.fl_M_pas) == expected + + def test_differentiate_wrt_c0(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016(self.fl_M_pas, *self.constants) + expected = log(self.fl_M_pas*(exp(self.c1) - 1) + 1)/self.c1 + assert fl_M_pas_inv.diff(self.c0) == expected + + def test_differentiate_wrt_c1(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016(self.fl_M_pas, *self.constants) + expected = ( + self.c0*self.fl_M_pas*exp(self.c1)/(self.c1*(self.fl_M_pas*(exp(self.c1) - 1) + 1)) + - self.c0*log(self.fl_M_pas*(exp(self.c1) - 1) + 1)/self.c1**2 + ) + assert fl_M_pas_inv.diff(self.c1) == expected + + def test_inverse(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016(self.fl_M_pas, *self.constants) + assert fl_M_pas_inv.inverse() is FiberForceLengthPassiveDeGroote2016 + + def test_function_print_latex(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016(self.fl_M_pas, *self.constants) + expected = r'\left( \operatorname{fl}^M_{pas} \right)^{-1} \left( fl_{M pas} \right)' + assert LatexPrinter().doprint(fl_M_pas_inv) == expected + + def test_expression_print_latex(self): + fl_T = FiberForceLengthPassiveInverseDeGroote2016(self.fl_M_pas, *self.constants) + expected = r'\frac{c_{0} \log{\left(fl_{M pas} \left(e^{c_{1}} - 1\right) + 1 \right)}}{c_{1}} + 1' + assert LatexPrinter().doprint(fl_T.doit()) == expected + + @pytest.mark.parametrize( + 'code_printer, expected', + [ + ( + C89CodePrinter, + '(1 + 0.14999999999999999*log(1 + 53.598150033144236*fl_M_pas))', + ), + ( + C99CodePrinter, + '(1 + 0.14999999999999999*log(1 + 53.598150033144236*fl_M_pas))', + ), + ( + C11CodePrinter, + '(1 + 0.14999999999999999*log(1 + 53.598150033144236*fl_M_pas))', + ), + ( + CXX98CodePrinter, + '(1 + 0.14999999999999999*log(1 + 53.598150033144236*fl_M_pas))', + ), + ( + CXX11CodePrinter, + '(1 + 0.14999999999999999*std::log(1 + 53.598150033144236*fl_M_pas))', + ), + ( + CXX17CodePrinter, + '(1 + 0.14999999999999999*std::log(1 + 53.598150033144236*fl_M_pas))', + ), + ( + FCodePrinter, + ' (1 + 0.15d0*log(1.0d0 + 53.5981500331442d0*fl_M_pas))', + ), + ( + OctaveCodePrinter, + '(1 + 0.15*log(1 + 53.5981500331442*fl_M_pas))', + ), + ( + PythonCodePrinter, + '(1 + 0.15*math.log(1 + 53.5981500331442*fl_M_pas))', + ), + ( + NumPyPrinter, + '(1 + 0.15*numpy.log(1 + 53.5981500331442*fl_M_pas))', + ), + ( + SciPyPrinter, + '(1 + 0.15*numpy.log(1 + 53.5981500331442*fl_M_pas))', + ), + ( + CuPyPrinter, + '(1 + 0.15*cupy.log(1 + 53.5981500331442*fl_M_pas))', + ), + ( + JaxPrinter, + '(1 + 0.15*jax.numpy.log(1 + 53.5981500331442*fl_M_pas))', + ), + ( + MpmathPrinter, + '(1 + mpmath.mpf((0, 5404319552844595, -55, 53))*mpmath.log(1 ' + '+ mpmath.mpf((0, 942908627019595, -44, 50))*fl_M_pas))', + ), + ( + LambdaPrinter, + '(1 + 0.15*math.log(1 + 53.5981500331442*fl_M_pas))', + ), + ] + ) + def test_print_code(self, code_printer, expected): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016.with_defaults(self.fl_M_pas) + assert code_printer().doprint(fl_M_pas_inv) == expected + + def test_derivative_print_code(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016.with_defaults(self.fl_M_pas) + dfl_M_pas_inv_dfl_T = fl_M_pas_inv.diff(self.fl_M_pas) + expected = '32.1588900198865/(214.392600132577*fl_M_pas + 4.0)' + assert PythonCodePrinter().doprint(dfl_M_pas_inv_dfl_T) == expected + + def test_lambdify(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016.with_defaults(self.fl_M_pas) + fl_M_pas_inv_callable = lambdify(self.fl_M_pas, fl_M_pas_inv) + assert fl_M_pas_inv_callable(0.0) == pytest.approx(1.0) + + @pytest.mark.skipif(numpy is None, reason='NumPy not installed') + def test_lambdify_numpy(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016.with_defaults(self.fl_M_pas) + fl_M_pas_inv_callable = lambdify(self.fl_M_pas, fl_M_pas_inv, 'numpy') + fl_M_pas = numpy.array([-0.01, 0.0, 0.01, 0.02, 0.05, 0.1]) + expected = numpy.array([ + 0.8848253714, + 1.0, + 1.0643754386, + 1.1092744701, + 1.1954331425, + 1.2774998934, + ]) + numpy.testing.assert_allclose(fl_M_pas_inv_callable(fl_M_pas), expected) + + @pytest.mark.skipif(jax is None, reason='JAX not installed') + def test_lambdify_jax(self): + fl_M_pas_inv = FiberForceLengthPassiveInverseDeGroote2016.with_defaults(self.fl_M_pas) + fl_M_pas_inv_callable = jax.jit(lambdify(self.fl_M_pas, fl_M_pas_inv, 'jax')) + fl_M_pas = jax.numpy.array([-0.01, 0.0, 0.01, 0.02, 0.05, 0.1]) + expected = jax.numpy.array([ + 0.8848253714, + 1.0, + 1.0643754386, + 1.1092744701, + 1.1954331425, + 1.2774998934, + ]) + numpy.testing.assert_allclose(fl_M_pas_inv_callable(fl_M_pas), expected) + + +class TestFiberForceLengthActiveDeGroote2016: + + @pytest.fixture(autouse=True) + def _fiber_force_length_active_arguments_fixture(self): + self.l_M_tilde = Symbol('l_M_tilde') + self.c0 = Symbol('c_0') + self.c1 = Symbol('c_1') + self.c2 = Symbol('c_2') + self.c3 = Symbol('c_3') + self.c4 = Symbol('c_4') + self.c5 = Symbol('c_5') + self.c6 = Symbol('c_6') + self.c7 = Symbol('c_7') + self.c8 = Symbol('c_8') + self.c9 = Symbol('c_9') + self.c10 = Symbol('c_10') + self.c11 = Symbol('c_11') + self.constants = ( + self.c0, self.c1, self.c2, self.c3, self.c4, self.c5, + self.c6, self.c7, self.c8, self.c9, self.c10, self.c11, + ) + + @staticmethod + def test_class(): + assert issubclass(FiberForceLengthActiveDeGroote2016, Function) + assert issubclass(FiberForceLengthActiveDeGroote2016, CharacteristicCurveFunction) + assert FiberForceLengthActiveDeGroote2016.__name__ == 'FiberForceLengthActiveDeGroote2016' + + def test_instance(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + assert isinstance(fl_M_act, FiberForceLengthActiveDeGroote2016) + assert str(fl_M_act) == ( + 'FiberForceLengthActiveDeGroote2016(l_M_tilde, c_0, c_1, c_2, c_3, ' + 'c_4, c_5, c_6, c_7, c_8, c_9, c_10, c_11)' + ) + + def test_doit(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants).doit() + assert fl_M_act == ( + self.c0*exp(-(((self.l_M_tilde - self.c1)/(self.c2 + self.c3*self.l_M_tilde))**2)/2) + + self.c4*exp(-(((self.l_M_tilde - self.c5)/(self.c6 + self.c7*self.l_M_tilde))**2)/2) + + self.c8*exp(-(((self.l_M_tilde - self.c9)/(self.c10 + self.c11*self.l_M_tilde))**2)/2) + ) + + def test_doit_evaluate_false(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants).doit(evaluate=False) + assert fl_M_act == ( + self.c0*exp(-((UnevaluatedExpr(self.l_M_tilde - self.c1)/(self.c2 + self.c3*self.l_M_tilde))**2)/2) + + self.c4*exp(-((UnevaluatedExpr(self.l_M_tilde - self.c5)/(self.c6 + self.c7*self.l_M_tilde))**2)/2) + + self.c8*exp(-((UnevaluatedExpr(self.l_M_tilde - self.c9)/(self.c10 + self.c11*self.l_M_tilde))**2)/2) + ) + + def test_with_defaults(self): + constants = ( + Float('0.814'), + Float('1.06'), + Float('0.162'), + Float('0.0633'), + Float('0.433'), + Float('0.717'), + Float('-0.0299'), + Float('0.2'), + Float('0.1'), + Float('1.0'), + Float('0.354'), + Float('0.0'), + ) + fl_M_act_manual = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *constants) + fl_M_act_constants = FiberForceLengthActiveDeGroote2016.with_defaults(self.l_M_tilde) + assert fl_M_act_manual == fl_M_act_constants + + def test_differentiate_wrt_l_M_tilde(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + self.c0*( + self.c3*(self.l_M_tilde - self.c1)**2/(self.c2 + self.c3*self.l_M_tilde)**3 + + (self.c1 - self.l_M_tilde)/((self.c2 + self.c3*self.l_M_tilde)**2) + )*exp(-(self.l_M_tilde - self.c1)**2/(2*(self.c2 + self.c3*self.l_M_tilde)**2)) + + self.c4*( + self.c7*(self.l_M_tilde - self.c5)**2/(self.c6 + self.c7*self.l_M_tilde)**3 + + (self.c5 - self.l_M_tilde)/((self.c6 + self.c7*self.l_M_tilde)**2) + )*exp(-(self.l_M_tilde - self.c5)**2/(2*(self.c6 + self.c7*self.l_M_tilde)**2)) + + self.c8*( + self.c11*(self.l_M_tilde - self.c9)**2/(self.c10 + self.c11*self.l_M_tilde)**3 + + (self.c9 - self.l_M_tilde)/((self.c10 + self.c11*self.l_M_tilde)**2) + )*exp(-(self.l_M_tilde - self.c9)**2/(2*(self.c10 + self.c11*self.l_M_tilde)**2)) + ) + assert fl_M_act.diff(self.l_M_tilde) == expected + + def test_differentiate_wrt_c0(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = exp(-(self.l_M_tilde - self.c1)**2/(2*(self.c2 + self.c3*self.l_M_tilde)**2)) + assert fl_M_act.doit().diff(self.c0) == expected + + def test_differentiate_wrt_c1(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + self.c0*(self.l_M_tilde - self.c1)/(self.c2 + self.c3*self.l_M_tilde)**2 + *exp(-(self.l_M_tilde - self.c1)**2/(2*(self.c2 + self.c3*self.l_M_tilde)**2)) + ) + assert fl_M_act.diff(self.c1) == expected + + def test_differentiate_wrt_c2(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + self.c0*(self.l_M_tilde - self.c1)**2/(self.c2 + self.c3*self.l_M_tilde)**3 + *exp(-(self.l_M_tilde - self.c1)**2/(2*(self.c2 + self.c3*self.l_M_tilde)**2)) + ) + assert fl_M_act.diff(self.c2) == expected + + def test_differentiate_wrt_c3(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + self.c0*self.l_M_tilde*(self.l_M_tilde - self.c1)**2/(self.c2 + self.c3*self.l_M_tilde)**3 + *exp(-(self.l_M_tilde - self.c1)**2/(2*(self.c2 + self.c3*self.l_M_tilde)**2)) + ) + assert fl_M_act.diff(self.c3) == expected + + def test_differentiate_wrt_c4(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = exp(-(self.l_M_tilde - self.c5)**2/(2*(self.c6 + self.c7*self.l_M_tilde)**2)) + assert fl_M_act.diff(self.c4) == expected + + def test_differentiate_wrt_c5(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + self.c4*(self.l_M_tilde - self.c5)/(self.c6 + self.c7*self.l_M_tilde)**2 + *exp(-(self.l_M_tilde - self.c5)**2/(2*(self.c6 + self.c7*self.l_M_tilde)**2)) + ) + assert fl_M_act.diff(self.c5) == expected + + def test_differentiate_wrt_c6(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + self.c4*(self.l_M_tilde - self.c5)**2/(self.c6 + self.c7*self.l_M_tilde)**3 + *exp(-(self.l_M_tilde - self.c5)**2/(2*(self.c6 + self.c7*self.l_M_tilde)**2)) + ) + assert fl_M_act.diff(self.c6) == expected + + def test_differentiate_wrt_c7(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + self.c4*self.l_M_tilde*(self.l_M_tilde - self.c5)**2/(self.c6 + self.c7*self.l_M_tilde)**3 + *exp(-(self.l_M_tilde - self.c5)**2/(2*(self.c6 + self.c7*self.l_M_tilde)**2)) + ) + assert fl_M_act.diff(self.c7) == expected + + def test_differentiate_wrt_c8(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = exp(-(self.l_M_tilde - self.c9)**2/(2*(self.c10 + self.c11*self.l_M_tilde)**2)) + assert fl_M_act.diff(self.c8) == expected + + def test_differentiate_wrt_c9(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + self.c8*(self.l_M_tilde - self.c9)/(self.c10 + self.c11*self.l_M_tilde)**2 + *exp(-(self.l_M_tilde - self.c9)**2/(2*(self.c10 + self.c11*self.l_M_tilde)**2)) + ) + assert fl_M_act.diff(self.c9) == expected + + def test_differentiate_wrt_c10(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + self.c8*(self.l_M_tilde - self.c9)**2/(self.c10 + self.c11*self.l_M_tilde)**3 + *exp(-(self.l_M_tilde - self.c9)**2/(2*(self.c10 + self.c11*self.l_M_tilde)**2)) + ) + assert fl_M_act.diff(self.c10) == expected + + def test_differentiate_wrt_c11(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + self.c8*self.l_M_tilde*(self.l_M_tilde - self.c9)**2/(self.c10 + self.c11*self.l_M_tilde)**3 + *exp(-(self.l_M_tilde - self.c9)**2/(2*(self.c10 + self.c11*self.l_M_tilde)**2)) + ) + assert fl_M_act.diff(self.c11) == expected + + def test_function_print_latex(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = r'\operatorname{fl}^M_{act} \left( l_{M tilde} \right)' + assert LatexPrinter().doprint(fl_M_act) == expected + + def test_expression_print_latex(self): + fl_M_act = FiberForceLengthActiveDeGroote2016(self.l_M_tilde, *self.constants) + expected = ( + r'c_{0} e^{- \frac{\left(- c_{1} + l_{M tilde}\right)^{2}}{2 \left(c_{2} + c_{3} l_{M tilde}\right)^{2}}} ' + r'+ c_{4} e^{- \frac{\left(- c_{5} + l_{M tilde}\right)^{2}}{2 \left(c_{6} + c_{7} l_{M tilde}\right)^{2}}} ' + r'+ c_{8} e^{- \frac{\left(- c_{9} + l_{M tilde}\right)^{2}}{2 \left(c_{10} + c_{11} l_{M tilde}\right)^{2}}}' + ) + assert LatexPrinter().doprint(fl_M_act.doit()) == expected + + @pytest.mark.parametrize( + 'code_printer, expected', + [ + ( + C89CodePrinter, + ( + '(0.81399999999999995*exp(-1.0/2.0*pow(l_M_tilde - 1.0600000000000001, 2)/pow(0.063299999999999995*l_M_tilde + 0.16200000000000001, 2)) + 0.433*exp(-1.0/2.0*pow(l_M_tilde - 0.71699999999999997, 2)/pow(0.20000000000000001*l_M_tilde - 0.029899999999999999, 2)) + 0.10000000000000001*exp(-3.9899134986753491*pow(l_M_tilde - 1.0, 2)))' + ), + ), + ( + C99CodePrinter, + ( + '(0.81399999999999995*exp(-1.0/2.0*pow(l_M_tilde - 1.0600000000000001, 2)/pow(0.063299999999999995*l_M_tilde + 0.16200000000000001, 2)) + 0.433*exp(-1.0/2.0*pow(l_M_tilde - 0.71699999999999997, 2)/pow(0.20000000000000001*l_M_tilde - 0.029899999999999999, 2)) + 0.10000000000000001*exp(-3.9899134986753491*pow(l_M_tilde - 1.0, 2)))' + ), + ), + ( + C11CodePrinter, + ( + '(0.81399999999999995*exp(-1.0/2.0*pow(l_M_tilde - 1.0600000000000001, 2)/pow(0.063299999999999995*l_M_tilde + 0.16200000000000001, 2)) + 0.433*exp(-1.0/2.0*pow(l_M_tilde - 0.71699999999999997, 2)/pow(0.20000000000000001*l_M_tilde - 0.029899999999999999, 2)) + 0.10000000000000001*exp(-3.9899134986753491*pow(l_M_tilde - 1.0, 2)))' + ), + ), + ( + CXX98CodePrinter, + ( + '(0.81399999999999995*exp(-1.0/2.0*std::pow(l_M_tilde - 1.0600000000000001, 2)/std::pow(0.063299999999999995*l_M_tilde + 0.16200000000000001, 2)) + 0.433*exp(-1.0/2.0*std::pow(l_M_tilde - 0.71699999999999997, 2)/std::pow(0.20000000000000001*l_M_tilde - 0.029899999999999999, 2)) + 0.10000000000000001*exp(-3.9899134986753491*std::pow(l_M_tilde - 1.0, 2)))' + ), + ), + ( + CXX11CodePrinter, + ( + '(0.81399999999999995*std::exp(-1.0/2.0*std::pow(l_M_tilde - 1.0600000000000001, 2)/std::pow(0.063299999999999995*l_M_tilde + 0.16200000000000001, 2)) + 0.433*std::exp(-1.0/2.0*std::pow(l_M_tilde - 0.71699999999999997, 2)/std::pow(0.20000000000000001*l_M_tilde - 0.029899999999999999, 2)) + 0.10000000000000001*std::exp(-3.9899134986753491*std::pow(l_M_tilde - 1.0, 2)))' + ), + ), + ( + CXX17CodePrinter, + ( + '(0.81399999999999995*std::exp(-1.0/2.0*std::pow(l_M_tilde - 1.0600000000000001, 2)/std::pow(0.063299999999999995*l_M_tilde + 0.16200000000000001, 2)) + 0.433*std::exp(-1.0/2.0*std::pow(l_M_tilde - 0.71699999999999997, 2)/std::pow(0.20000000000000001*l_M_tilde - 0.029899999999999999, 2)) + 0.10000000000000001*std::exp(-3.9899134986753491*std::pow(l_M_tilde - 1.0, 2)))' + ), + ), + ( + FCodePrinter, + ( + ' (0.814d0*exp(-0.5d0*(l_M_tilde - 1.06d0)**2/(\n' + ' @ 0.063299999999999995d0*l_M_tilde + 0.16200000000000001d0)**2) +\n' + ' @ 0.433d0*exp(-0.5d0*(l_M_tilde - 0.717d0)**2/(\n' + ' @ 0.20000000000000001d0*l_M_tilde - 0.029899999999999999d0)**2) +\n' + ' @ 0.1d0*exp(-3.9899134986753491d0*(l_M_tilde - 1.0d0)**2))' + ), + ), + ( + OctaveCodePrinter, + ( + '(0.814*exp(-(l_M_tilde - 1.06).^2./(2*(0.0633*l_M_tilde + 0.162).^2)) + 0.433*exp(-(l_M_tilde - 0.717).^2./(2*(0.2*l_M_tilde - 0.0299).^2)) + 0.1*exp(-3.98991349867535*(l_M_tilde - 1.0).^2))' + ), + ), + ( + PythonCodePrinter, + ( + '(0.814*math.exp(-1/2*(l_M_tilde - 1.06)**2/(0.0633*l_M_tilde + 0.162)**2) + 0.433*math.exp(-1/2*(l_M_tilde - 0.717)**2/(0.2*l_M_tilde - 0.0299)**2) + 0.1*math.exp(-3.98991349867535*(l_M_tilde - 1.0)**2))' + ), + ), + ( + NumPyPrinter, + ( + '(0.814*numpy.exp(-1/2*(l_M_tilde - 1.06)**2/(0.0633*l_M_tilde + 0.162)**2) + 0.433*numpy.exp(-1/2*(l_M_tilde - 0.717)**2/(0.2*l_M_tilde - 0.0299)**2) + 0.1*numpy.exp(-3.98991349867535*(l_M_tilde - 1.0)**2))' + ), + ), + ( + SciPyPrinter, + ( + '(0.814*numpy.exp(-1/2*(l_M_tilde - 1.06)**2/(0.0633*l_M_tilde + 0.162)**2) + 0.433*numpy.exp(-1/2*(l_M_tilde - 0.717)**2/(0.2*l_M_tilde - 0.0299)**2) + 0.1*numpy.exp(-3.98991349867535*(l_M_tilde - 1.0)**2))' + ), + ), + ( + CuPyPrinter, + ( + '(0.814*cupy.exp(-1/2*(l_M_tilde - 1.06)**2/(0.0633*l_M_tilde + 0.162)**2) + 0.433*cupy.exp(-1/2*(l_M_tilde - 0.717)**2/(0.2*l_M_tilde - 0.0299)**2) + 0.1*cupy.exp(-3.98991349867535*(l_M_tilde - 1.0)**2))' + ), + ), + ( + JaxPrinter, + ( + '(0.814*jax.numpy.exp(-1/2*(l_M_tilde - 1.06)**2/(0.0633*l_M_tilde + 0.162)**2) + 0.433*jax.numpy.exp(-1/2*(l_M_tilde - 0.717)**2/(0.2*l_M_tilde - 0.0299)**2) + 0.1*jax.numpy.exp(-3.98991349867535*(l_M_tilde - 1.0)**2))' + ), + ), + ( + MpmathPrinter, + ( + '(mpmath.mpf((0, 7331860193359167, -53, 53))*mpmath.exp(-mpmath.mpf(1)/mpmath.mpf(2)*(l_M_tilde + mpmath.mpf((1, 2386907802506363, -51, 52)))**2/(mpmath.mpf((0, 2280622851300419, -55, 52))*l_M_tilde + mpmath.mpf((0, 5836665117072163, -55, 53)))**2) + mpmath.mpf((0, 7800234554605699, -54, 53))*mpmath.exp(-mpmath.mpf(1)/mpmath.mpf(2)*(l_M_tilde + mpmath.mpf((1, 6458161865649291, -53, 53)))**2/(mpmath.mpf((0, 3602879701896397, -54, 52))*l_M_tilde + mpmath.mpf((1, 8618088246936181, -58, 53)))**2) + mpmath.mpf((0, 3602879701896397, -55, 52))*mpmath.exp(-mpmath.mpf((0, 8984486472937407, -51, 53))*(l_M_tilde + mpmath.mpf((1, 1, 0, 1)))**2))' + ), + ), + ( + LambdaPrinter, + ( + '(0.814*math.exp(-1/2*(l_M_tilde - 1.06)**2/(0.0633*l_M_tilde + 0.162)**2) + 0.433*math.exp(-1/2*(l_M_tilde - 0.717)**2/(0.2*l_M_tilde - 0.0299)**2) + 0.1*math.exp(-3.98991349867535*(l_M_tilde - 1.0)**2))' + ), + ), + ] + ) + def test_print_code(self, code_printer, expected): + fl_M_act = FiberForceLengthActiveDeGroote2016.with_defaults(self.l_M_tilde) + assert code_printer().doprint(fl_M_act) == expected + + def test_derivative_print_code(self): + fl_M_act = FiberForceLengthActiveDeGroote2016.with_defaults(self.l_M_tilde) + fl_M_act_dl_M_tilde = fl_M_act.diff(self.l_M_tilde) + expected = ( + '(0.79798269973507 - 0.79798269973507*l_M_tilde)*math.exp(-3.98991349867535*(l_M_tilde - 1.0)**2) + (0.433*(0.717 - l_M_tilde)/(0.2*l_M_tilde - 0.0299)**2 + 0.0866*(l_M_tilde - 0.717)**2/(0.2*l_M_tilde - 0.0299)**3)*math.exp(-1/2*(l_M_tilde - 0.717)**2/(0.2*l_M_tilde - 0.0299)**2) + (0.814*(1.06 - l_M_tilde)/(0.0633*l_M_tilde + 0.162)**2 + 0.0515262*(l_M_tilde - 1.06)**2/(0.0633*l_M_tilde + 0.162)**3)*math.exp(-1/2*(l_M_tilde - 1.06)**2/(0.0633*l_M_tilde + 0.162)**2)' + ) + assert PythonCodePrinter().doprint(fl_M_act_dl_M_tilde) == expected + + def test_lambdify(self): + fl_M_act = FiberForceLengthActiveDeGroote2016.with_defaults(self.l_M_tilde) + fl_M_act_callable = lambdify(self.l_M_tilde, fl_M_act) + assert fl_M_act_callable(1.0) == pytest.approx(0.9941398866) + + @pytest.mark.skipif(numpy is None, reason='NumPy not installed') + def test_lambdify_numpy(self): + fl_M_act = FiberForceLengthActiveDeGroote2016.with_defaults(self.l_M_tilde) + fl_M_act_callable = lambdify(self.l_M_tilde, fl_M_act, 'numpy') + l_M_tilde = numpy.array([0.0, 0.5, 1.0, 1.5, 2.0]) + expected = numpy.array([ + 0.0018501319, + 0.0529122812, + 0.9941398866, + 0.2312431531, + 0.0069595432, + ]) + numpy.testing.assert_allclose(fl_M_act_callable(l_M_tilde), expected) + + @pytest.mark.skipif(jax is None, reason='JAX not installed') + def test_lambdify_jax(self): + fl_M_act = FiberForceLengthActiveDeGroote2016.with_defaults(self.l_M_tilde) + fl_M_act_callable = jax.jit(lambdify(self.l_M_tilde, fl_M_act, 'jax')) + l_M_tilde = jax.numpy.array([0.0, 0.5, 1.0, 1.5, 2.0]) + expected = jax.numpy.array([ + 0.0018501319, + 0.0529122812, + 0.9941398866, + 0.2312431531, + 0.0069595432, + ]) + numpy.testing.assert_allclose(fl_M_act_callable(l_M_tilde), expected) + + +class TestFiberForceVelocityDeGroote2016: + + @pytest.fixture(autouse=True) + def _muscle_fiber_force_velocity_arguments_fixture(self): + self.v_M_tilde = Symbol('v_M_tilde') + self.c0 = Symbol('c_0') + self.c1 = Symbol('c_1') + self.c2 = Symbol('c_2') + self.c3 = Symbol('c_3') + self.constants = (self.c0, self.c1, self.c2, self.c3) + + @staticmethod + def test_class(): + assert issubclass(FiberForceVelocityDeGroote2016, Function) + assert issubclass(FiberForceVelocityDeGroote2016, CharacteristicCurveFunction) + assert FiberForceVelocityDeGroote2016.__name__ == 'FiberForceVelocityDeGroote2016' + + def test_instance(self): + fv_M = FiberForceVelocityDeGroote2016(self.v_M_tilde, *self.constants) + assert isinstance(fv_M, FiberForceVelocityDeGroote2016) + assert str(fv_M) == 'FiberForceVelocityDeGroote2016(v_M_tilde, c_0, c_1, c_2, c_3)' + + def test_doit(self): + fv_M = FiberForceVelocityDeGroote2016(self.v_M_tilde, *self.constants).doit() + expected = ( + self.c0 * log((self.c1 * self.v_M_tilde + self.c2) + + sqrt((self.c1 * self.v_M_tilde + self.c2)**2 + 1)) + self.c3 + ) + assert fv_M == expected + + def test_doit_evaluate_false(self): + fv_M = FiberForceVelocityDeGroote2016(self.v_M_tilde, *self.constants).doit(evaluate=False) + expected = ( + self.c0 * log((self.c1 * self.v_M_tilde + self.c2) + + sqrt(UnevaluatedExpr(self.c1 * self.v_M_tilde + self.c2)**2 + 1)) + self.c3 + ) + assert fv_M == expected + + def test_with_defaults(self): + constants = ( + Float('-0.318'), + Float('-8.149'), + Float('-0.374'), + Float('0.886'), + ) + fv_M_manual = FiberForceVelocityDeGroote2016(self.v_M_tilde, *constants) + fv_M_constants = FiberForceVelocityDeGroote2016.with_defaults(self.v_M_tilde) + assert fv_M_manual == fv_M_constants + + def test_differentiate_wrt_v_M_tilde(self): + fv_M = FiberForceVelocityDeGroote2016(self.v_M_tilde, *self.constants) + expected = ( + self.c0*self.c1 + /sqrt(UnevaluatedExpr(self.c1*self.v_M_tilde + self.c2)**2 + 1) + ) + assert fv_M.diff(self.v_M_tilde) == expected + + def test_differentiate_wrt_c0(self): + fv_M = FiberForceVelocityDeGroote2016(self.v_M_tilde, *self.constants) + expected = log( + self.c1*self.v_M_tilde + self.c2 + + sqrt(UnevaluatedExpr(self.c1*self.v_M_tilde + self.c2)**2 + 1) + ) + assert fv_M.diff(self.c0) == expected + + def test_differentiate_wrt_c1(self): + fv_M = FiberForceVelocityDeGroote2016(self.v_M_tilde, *self.constants) + expected = ( + self.c0*self.v_M_tilde + /sqrt(UnevaluatedExpr(self.c1*self.v_M_tilde + self.c2)**2 + 1) + ) + assert fv_M.diff(self.c1) == expected + + def test_differentiate_wrt_c2(self): + fv_M = FiberForceVelocityDeGroote2016(self.v_M_tilde, *self.constants) + expected = ( + self.c0 + /sqrt(UnevaluatedExpr(self.c1*self.v_M_tilde + self.c2)**2 + 1) + ) + assert fv_M.diff(self.c2) == expected + + def test_differentiate_wrt_c3(self): + fv_M = FiberForceVelocityDeGroote2016(self.v_M_tilde, *self.constants) + expected = Integer(1) + assert fv_M.diff(self.c3) == expected + + def test_inverse(self): + fv_M = FiberForceVelocityDeGroote2016(self.v_M_tilde, *self.constants) + assert fv_M.inverse() is FiberForceVelocityInverseDeGroote2016 + + def test_function_print_latex(self): + fv_M = FiberForceVelocityDeGroote2016(self.v_M_tilde, *self.constants) + expected = r'\operatorname{fv}^M \left( v_{M tilde} \right)' + assert LatexPrinter().doprint(fv_M) == expected + + def test_expression_print_latex(self): + fv_M = FiberForceVelocityDeGroote2016(self.v_M_tilde, *self.constants) + expected = ( + r'c_{0} \log{\left(c_{1} v_{M tilde} + c_{2} + \sqrt{\left(c_{1} ' + r'v_{M tilde} + c_{2}\right)^{2} + 1} \right)} + c_{3}' + ) + assert LatexPrinter().doprint(fv_M.doit()) == expected + + @pytest.mark.parametrize( + 'code_printer, expected', + [ + ( + C89CodePrinter, + '(0.88600000000000001 - 0.318*log(-8.1489999999999991*v_M_tilde ' + '- 0.374 + sqrt(1 + pow(-8.1489999999999991*v_M_tilde - 0.374, 2))))', + ), + ( + C99CodePrinter, + '(0.88600000000000001 - 0.318*log(-8.1489999999999991*v_M_tilde ' + '- 0.374 + sqrt(1 + pow(-8.1489999999999991*v_M_tilde - 0.374, 2))))', + ), + ( + C11CodePrinter, + '(0.88600000000000001 - 0.318*log(-8.1489999999999991*v_M_tilde ' + '- 0.374 + sqrt(1 + pow(-8.1489999999999991*v_M_tilde - 0.374, 2))))', + ), + ( + CXX98CodePrinter, + '(0.88600000000000001 - 0.318*log(-8.1489999999999991*v_M_tilde ' + '- 0.374 + std::sqrt(1 + std::pow(-8.1489999999999991*v_M_tilde - 0.374, 2))))', + ), + ( + CXX11CodePrinter, + '(0.88600000000000001 - 0.318*std::log(-8.1489999999999991*v_M_tilde ' + '- 0.374 + std::sqrt(1 + std::pow(-8.1489999999999991*v_M_tilde - 0.374, 2))))', + ), + ( + CXX17CodePrinter, + '(0.88600000000000001 - 0.318*std::log(-8.1489999999999991*v_M_tilde ' + '- 0.374 + std::sqrt(1 + std::pow(-8.1489999999999991*v_M_tilde - 0.374, 2))))', + ), + ( + FCodePrinter, + ' (0.886d0 - 0.318d0*log(-8.1489999999999991d0*v_M_tilde - 0.374d0 +\n' + ' @ sqrt(1.0d0 + (-8.149d0*v_M_tilde - 0.374d0)**2)))', + ), + ( + OctaveCodePrinter, + '(0.886 - 0.318*log(-8.149*v_M_tilde - 0.374 ' + '+ sqrt(1 + (-8.149*v_M_tilde - 0.374).^2)))', + ), + ( + PythonCodePrinter, + '(0.886 - 0.318*math.log(-8.149*v_M_tilde - 0.374 ' + '+ math.sqrt(1 + (-8.149*v_M_tilde - 0.374)**2)))', + ), + ( + NumPyPrinter, + '(0.886 - 0.318*numpy.log(-8.149*v_M_tilde - 0.374 ' + '+ numpy.sqrt(1 + (-8.149*v_M_tilde - 0.374)**2)))', + ), + ( + SciPyPrinter, + '(0.886 - 0.318*numpy.log(-8.149*v_M_tilde - 0.374 ' + '+ numpy.sqrt(1 + (-8.149*v_M_tilde - 0.374)**2)))', + ), + ( + CuPyPrinter, + '(0.886 - 0.318*cupy.log(-8.149*v_M_tilde - 0.374 ' + '+ cupy.sqrt(1 + (-8.149*v_M_tilde - 0.374)**2)))', + ), + ( + JaxPrinter, + '(0.886 - 0.318*jax.numpy.log(-8.149*v_M_tilde - 0.374 ' + '+ jax.numpy.sqrt(1 + (-8.149*v_M_tilde - 0.374)**2)))', + ), + ( + MpmathPrinter, + '(mpmath.mpf((0, 7980378539700519, -53, 53)) ' + '- mpmath.mpf((0, 5728578726015271, -54, 53))' + '*mpmath.log(-mpmath.mpf((0, 4587479170430271, -49, 53))*v_M_tilde ' + '+ mpmath.mpf((1, 3368692521273131, -53, 52)) ' + '+ mpmath.sqrt(1 + (-mpmath.mpf((0, 4587479170430271, -49, 53))*v_M_tilde ' + '+ mpmath.mpf((1, 3368692521273131, -53, 52)))**2)))', + ), + ( + LambdaPrinter, + '(0.886 - 0.318*math.log(-8.149*v_M_tilde - 0.374 ' + '+ sqrt(1 + (-8.149*v_M_tilde - 0.374)**2)))', + ), + ] + ) + def test_print_code(self, code_printer, expected): + fv_M = FiberForceVelocityDeGroote2016.with_defaults(self.v_M_tilde) + assert code_printer().doprint(fv_M) == expected + + def test_derivative_print_code(self): + fv_M = FiberForceVelocityDeGroote2016.with_defaults(self.v_M_tilde) + dfv_M_dv_M_tilde = fv_M.diff(self.v_M_tilde) + expected = '2.591382*(1 + (-8.149*v_M_tilde - 0.374)**2)**(-1/2)' + assert PythonCodePrinter().doprint(dfv_M_dv_M_tilde) == expected + + def test_lambdify(self): + fv_M = FiberForceVelocityDeGroote2016.with_defaults(self.v_M_tilde) + fv_M_callable = lambdify(self.v_M_tilde, fv_M) + assert fv_M_callable(0.0) == pytest.approx(1.002320622548512) + + @pytest.mark.skipif(numpy is None, reason='NumPy not installed') + def test_lambdify_numpy(self): + fv_M = FiberForceVelocityDeGroote2016.with_defaults(self.v_M_tilde) + fv_M_callable = lambdify(self.v_M_tilde, fv_M, 'numpy') + v_M_tilde = numpy.array([-1.0, -0.5, 0.0, 0.5]) + expected = numpy.array([ + 0.0120816781, + 0.2438336294, + 1.0023206225, + 1.5850003903, + ]) + numpy.testing.assert_allclose(fv_M_callable(v_M_tilde), expected) + + @pytest.mark.skipif(jax is None, reason='JAX not installed') + def test_lambdify_jax(self): + fv_M = FiberForceVelocityDeGroote2016.with_defaults(self.v_M_tilde) + fv_M_callable = jax.jit(lambdify(self.v_M_tilde, fv_M, 'jax')) + v_M_tilde = jax.numpy.array([-1.0, -0.5, 0.0, 0.5]) + expected = jax.numpy.array([ + 0.0120816781, + 0.2438336294, + 1.0023206225, + 1.5850003903, + ]) + numpy.testing.assert_allclose(fv_M_callable(v_M_tilde), expected) + + +class TestFiberForceVelocityInverseDeGroote2016: + + @pytest.fixture(autouse=True) + def _tendon_force_length_inverse_arguments_fixture(self): + self.fv_M = Symbol('fv_M') + self.c0 = Symbol('c_0') + self.c1 = Symbol('c_1') + self.c2 = Symbol('c_2') + self.c3 = Symbol('c_3') + self.constants = (self.c0, self.c1, self.c2, self.c3) + + @staticmethod + def test_class(): + assert issubclass(FiberForceVelocityInverseDeGroote2016, Function) + assert issubclass(FiberForceVelocityInverseDeGroote2016, CharacteristicCurveFunction) + assert FiberForceVelocityInverseDeGroote2016.__name__ == 'FiberForceVelocityInverseDeGroote2016' + + def test_instance(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016(self.fv_M, *self.constants) + assert isinstance(fv_M_inv, FiberForceVelocityInverseDeGroote2016) + assert str(fv_M_inv) == 'FiberForceVelocityInverseDeGroote2016(fv_M, c_0, c_1, c_2, c_3)' + + def test_doit(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016(self.fv_M, *self.constants).doit() + assert fv_M_inv == (sinh((self.fv_M - self.c3)/self.c0) - self.c2)/self.c1 + + def test_doit_evaluate_false(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016(self.fv_M, *self.constants).doit(evaluate=False) + assert fv_M_inv == (sinh(UnevaluatedExpr(self.fv_M - self.c3)/self.c0) - self.c2)/self.c1 + + def test_with_defaults(self): + constants = ( + Float('-0.318'), + Float('-8.149'), + Float('-0.374'), + Float('0.886'), + ) + fv_M_inv_manual = FiberForceVelocityInverseDeGroote2016(self.fv_M, *constants) + fv_M_inv_constants = FiberForceVelocityInverseDeGroote2016.with_defaults(self.fv_M) + assert fv_M_inv_manual == fv_M_inv_constants + + def test_differentiate_wrt_fv_M(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016(self.fv_M, *self.constants) + expected = cosh((self.fv_M - self.c3)/self.c0)/(self.c0*self.c1) + assert fv_M_inv.diff(self.fv_M) == expected + + def test_differentiate_wrt_c0(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016(self.fv_M, *self.constants) + expected = (self.c3 - self.fv_M)*cosh((self.fv_M - self.c3)/self.c0)/(self.c0**2*self.c1) + assert fv_M_inv.diff(self.c0) == expected + + def test_differentiate_wrt_c1(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016(self.fv_M, *self.constants) + expected = (self.c2 - sinh((self.fv_M - self.c3)/self.c0))/self.c1**2 + assert fv_M_inv.diff(self.c1) == expected + + def test_differentiate_wrt_c2(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016(self.fv_M, *self.constants) + expected = -1/self.c1 + assert fv_M_inv.diff(self.c2) == expected + + def test_differentiate_wrt_c3(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016(self.fv_M, *self.constants) + expected = -cosh((self.fv_M - self.c3)/self.c0)/(self.c0*self.c1) + assert fv_M_inv.diff(self.c3) == expected + + def test_inverse(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016(self.fv_M, *self.constants) + assert fv_M_inv.inverse() is FiberForceVelocityDeGroote2016 + + def test_function_print_latex(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016(self.fv_M, *self.constants) + expected = r'\left( \operatorname{fv}^M \right)^{-1} \left( fv_{M} \right)' + assert LatexPrinter().doprint(fv_M_inv) == expected + + def test_expression_print_latex(self): + fv_M = FiberForceVelocityInverseDeGroote2016(self.fv_M, *self.constants) + expected = r'\frac{- c_{2} + \sinh{\left(\frac{- c_{3} + fv_{M}}{c_{0}} \right)}}{c_{1}}' + assert LatexPrinter().doprint(fv_M.doit()) == expected + + @pytest.mark.parametrize( + 'code_printer, expected', + [ + ( + C89CodePrinter, + '(-0.12271444348999878*(0.374 - sinh(3.1446540880503142*(fv_M ' + '- 0.88600000000000001))))', + ), + ( + C99CodePrinter, + '(-0.12271444348999878*(0.374 - sinh(3.1446540880503142*(fv_M ' + '- 0.88600000000000001))))', + ), + ( + C11CodePrinter, + '(-0.12271444348999878*(0.374 - sinh(3.1446540880503142*(fv_M ' + '- 0.88600000000000001))))', + ), + ( + CXX98CodePrinter, + '(-0.12271444348999878*(0.374 - sinh(3.1446540880503142*(fv_M ' + '- 0.88600000000000001))))', + ), + ( + CXX11CodePrinter, + '(-0.12271444348999878*(0.374 - std::sinh(3.1446540880503142' + '*(fv_M - 0.88600000000000001))))', + ), + ( + CXX17CodePrinter, + '(-0.12271444348999878*(0.374 - std::sinh(3.1446540880503142' + '*(fv_M - 0.88600000000000001))))', + ), + ( + FCodePrinter, + ' (-0.122714443489999d0*(0.374d0 - sinh(3.1446540880503142d0*(fv_M -\n' + ' @ 0.886d0))))', + ), + ( + OctaveCodePrinter, + '(-0.122714443489999*(0.374 - sinh(3.14465408805031*(fv_M ' + '- 0.886))))', + ), + ( + PythonCodePrinter, + '(-0.122714443489999*(0.374 - math.sinh(3.14465408805031*(fv_M ' + '- 0.886))))', + ), + ( + NumPyPrinter, + '(-0.122714443489999*(0.374 - numpy.sinh(3.14465408805031' + '*(fv_M - 0.886))))', + ), + ( + SciPyPrinter, + '(-0.122714443489999*(0.374 - numpy.sinh(3.14465408805031' + '*(fv_M - 0.886))))', + ), + ( + CuPyPrinter, + '(-0.122714443489999*(0.374 - cupy.sinh(3.14465408805031*(fv_M ' + '- 0.886))))', + ), + ( + JaxPrinter, + '(-0.122714443489999*(0.374 - jax.numpy.sinh(3.14465408805031' + '*(fv_M - 0.886))))', + ), + ( + MpmathPrinter, + '(-mpmath.mpf((0, 8842507551592581, -56, 53))*(mpmath.mpf((0, ' + '3368692521273131, -53, 52)) - mpmath.sinh(mpmath.mpf((0, ' + '7081131489576251, -51, 53))*(fv_M + mpmath.mpf((1, ' + '7980378539700519, -53, 53))))))', + ), + ( + LambdaPrinter, + '(-0.122714443489999*(0.374 - math.sinh(3.14465408805031*(fv_M ' + '- 0.886))))', + ), + ] + ) + def test_print_code(self, code_printer, expected): + fv_M_inv = FiberForceVelocityInverseDeGroote2016.with_defaults(self.fv_M) + assert code_printer().doprint(fv_M_inv) == expected + + def test_derivative_print_code(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016.with_defaults(self.fv_M) + dfv_M_inv_dfv_M = fv_M_inv.diff(self.fv_M) + expected = ( + '0.385894476383644*math.cosh(3.14465408805031*fv_M ' + '- 2.78616352201258)' + ) + assert PythonCodePrinter().doprint(dfv_M_inv_dfv_M) == expected + + def test_lambdify(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016.with_defaults(self.fv_M) + fv_M_inv_callable = lambdify(self.fv_M, fv_M_inv) + assert fv_M_inv_callable(1.0) == pytest.approx(-0.0009548832444487479) + + @pytest.mark.skipif(numpy is None, reason='NumPy not installed') + def test_lambdify_numpy(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016.with_defaults(self.fv_M) + fv_M_inv_callable = lambdify(self.fv_M, fv_M_inv, 'numpy') + fv_M = numpy.array([0.8, 0.9, 1.0, 1.1, 1.2]) + expected = numpy.array([ + -0.0794881459, + -0.0404909338, + -0.0009548832, + 0.043061991, + 0.0959484397, + ]) + numpy.testing.assert_allclose(fv_M_inv_callable(fv_M), expected) + + @pytest.mark.skipif(jax is None, reason='JAX not installed') + def test_lambdify_jax(self): + fv_M_inv = FiberForceVelocityInverseDeGroote2016.with_defaults(self.fv_M) + fv_M_inv_callable = jax.jit(lambdify(self.fv_M, fv_M_inv, 'jax')) + fv_M = jax.numpy.array([0.8, 0.9, 1.0, 1.1, 1.2]) + expected = jax.numpy.array([ + -0.0794881459, + -0.0404909338, + -0.0009548832, + 0.043061991, + 0.0959484397, + ]) + numpy.testing.assert_allclose(fv_M_inv_callable(fv_M), expected) + + +class TestCharacteristicCurveCollection: + + @staticmethod + def test_valid_constructor(): + curves = CharacteristicCurveCollection( + tendon_force_length=TendonForceLengthDeGroote2016, + tendon_force_length_inverse=TendonForceLengthInverseDeGroote2016, + fiber_force_length_passive=FiberForceLengthPassiveDeGroote2016, + fiber_force_length_passive_inverse=FiberForceLengthPassiveInverseDeGroote2016, + fiber_force_length_active=FiberForceLengthActiveDeGroote2016, + fiber_force_velocity=FiberForceVelocityDeGroote2016, + fiber_force_velocity_inverse=FiberForceVelocityInverseDeGroote2016, + ) + assert curves.tendon_force_length is TendonForceLengthDeGroote2016 + assert curves.tendon_force_length_inverse is TendonForceLengthInverseDeGroote2016 + assert curves.fiber_force_length_passive is FiberForceLengthPassiveDeGroote2016 + assert curves.fiber_force_length_passive_inverse is FiberForceLengthPassiveInverseDeGroote2016 + assert curves.fiber_force_length_active is FiberForceLengthActiveDeGroote2016 + assert curves.fiber_force_velocity is FiberForceVelocityDeGroote2016 + assert curves.fiber_force_velocity_inverse is FiberForceVelocityInverseDeGroote2016 + + @staticmethod + @pytest.mark.skip(reason='kw_only dataclasses only valid in Python >3.10') + def test_invalid_constructor_keyword_only(): + with pytest.raises(TypeError): + _ = CharacteristicCurveCollection( + TendonForceLengthDeGroote2016, + TendonForceLengthInverseDeGroote2016, + FiberForceLengthPassiveDeGroote2016, + FiberForceLengthPassiveInverseDeGroote2016, + FiberForceLengthActiveDeGroote2016, + FiberForceVelocityDeGroote2016, + FiberForceVelocityInverseDeGroote2016, + ) + + @staticmethod + @pytest.mark.parametrize( + 'kwargs', + [ + {'tendon_force_length': TendonForceLengthDeGroote2016}, + { + 'tendon_force_length': TendonForceLengthDeGroote2016, + 'tendon_force_length_inverse': TendonForceLengthInverseDeGroote2016, + 'fiber_force_length_passive': FiberForceLengthPassiveDeGroote2016, + 'fiber_force_length_passive_inverse': FiberForceLengthPassiveInverseDeGroote2016, + 'fiber_force_length_active': FiberForceLengthActiveDeGroote2016, + 'fiber_force_velocity': FiberForceVelocityDeGroote2016, + 'fiber_force_velocity_inverse': FiberForceVelocityInverseDeGroote2016, + 'extra_kwarg': None, + }, + ] + ) + def test_invalid_constructor_wrong_number_args(kwargs): + with pytest.raises(TypeError): + _ = CharacteristicCurveCollection(**kwargs) + + @staticmethod + def test_instance_is_immutable(): + curves = CharacteristicCurveCollection( + tendon_force_length=TendonForceLengthDeGroote2016, + tendon_force_length_inverse=TendonForceLengthInverseDeGroote2016, + fiber_force_length_passive=FiberForceLengthPassiveDeGroote2016, + fiber_force_length_passive_inverse=FiberForceLengthPassiveInverseDeGroote2016, + fiber_force_length_active=FiberForceLengthActiveDeGroote2016, + fiber_force_velocity=FiberForceVelocityDeGroote2016, + fiber_force_velocity_inverse=FiberForceVelocityInverseDeGroote2016, + ) + with pytest.raises(AttributeError): + curves.tendon_force_length = None + with pytest.raises(AttributeError): + curves.tendon_force_length_inverse = None + with pytest.raises(AttributeError): + curves.fiber_force_length_passive = None + with pytest.raises(AttributeError): + curves.fiber_force_length_passive_inverse = None + with pytest.raises(AttributeError): + curves.fiber_force_length_active = None + with pytest.raises(AttributeError): + curves.fiber_force_velocity = None + with pytest.raises(AttributeError): + curves.fiber_force_velocity_inverse = None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_mixin.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_mixin.py new file mode 100644 index 0000000000000000000000000000000000000000..be079c195f3d961a88f52c94b695666f2a4f2bb5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_mixin.py @@ -0,0 +1,48 @@ +"""Tests for the ``sympy.physics.biomechanics._mixin.py`` module.""" + +import pytest + +from sympy.physics.biomechanics._mixin import _NamedMixin + + +class TestNamedMixin: + + @staticmethod + def test_subclass(): + + class Subclass(_NamedMixin): + + def __init__(self, name): + self.name = name + + instance = Subclass('name') + assert instance.name == 'name' + + @pytest.fixture(autouse=True) + def _named_mixin_fixture(self): + + class Subclass(_NamedMixin): + + def __init__(self, name): + self.name = name + + self.Subclass = Subclass + + @pytest.mark.parametrize('name', ['a', 'name', 'long_name']) + def test_valid_name_argument(self, name): + instance = self.Subclass(name) + assert instance.name == name + + @pytest.mark.parametrize('invalid_name', [0, 0.0, None, False]) + def test_invalid_name_argument_not_str(self, invalid_name): + with pytest.raises(TypeError): + _ = self.Subclass(invalid_name) + + def test_invalid_name_argument_zero_length_str(self): + with pytest.raises(ValueError): + _ = self.Subclass('') + + def test_name_attribute_is_immutable(self): + instance = self.Subclass('name') + with pytest.raises(AttributeError): + instance.name = 'new_name' diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_musculotendon.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_musculotendon.py new file mode 100644 index 0000000000000000000000000000000000000000..d0c5a1088214049aaaaa3666854e232d26f77786 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/biomechanics/tests/test_musculotendon.py @@ -0,0 +1,837 @@ +"""Tests for the ``sympy.physics.biomechanics.musculotendon.py`` module.""" + +import abc + +import pytest + +from sympy.core.expr import UnevaluatedExpr +from sympy.core.numbers import Float, Integer, Rational +from sympy.core.symbol import Symbol +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.hyperbolic import tanh +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin +from sympy.matrices.dense import MutableDenseMatrix as Matrix, eye, zeros +from sympy.physics.biomechanics.activation import ( + FirstOrderActivationDeGroote2016 +) +from sympy.physics.biomechanics.curve import ( + CharacteristicCurveCollection, + FiberForceLengthActiveDeGroote2016, + FiberForceLengthPassiveDeGroote2016, + FiberForceLengthPassiveInverseDeGroote2016, + FiberForceVelocityDeGroote2016, + FiberForceVelocityInverseDeGroote2016, + TendonForceLengthDeGroote2016, + TendonForceLengthInverseDeGroote2016, +) +from sympy.physics.biomechanics.musculotendon import ( + MusculotendonBase, + MusculotendonDeGroote2016, + MusculotendonFormulation, +) +from sympy.physics.biomechanics._mixin import _NamedMixin +from sympy.physics.mechanics.actuator import ForceActuator +from sympy.physics.mechanics.pathway import LinearPathway +from sympy.physics.vector.frame import ReferenceFrame +from sympy.physics.vector.functions import dynamicsymbols +from sympy.physics.vector.point import Point +from sympy.simplify.simplify import simplify + + +class TestMusculotendonFormulation: + @staticmethod + def test_rigid_tendon_member(): + assert MusculotendonFormulation(0) == 0 + assert MusculotendonFormulation.RIGID_TENDON == 0 + + @staticmethod + def test_fiber_length_explicit_member(): + assert MusculotendonFormulation(1) == 1 + assert MusculotendonFormulation.FIBER_LENGTH_EXPLICIT == 1 + + @staticmethod + def test_tendon_force_explicit_member(): + assert MusculotendonFormulation(2) == 2 + assert MusculotendonFormulation.TENDON_FORCE_EXPLICIT == 2 + + @staticmethod + def test_fiber_length_implicit_member(): + assert MusculotendonFormulation(3) == 3 + assert MusculotendonFormulation.FIBER_LENGTH_IMPLICIT == 3 + + @staticmethod + def test_tendon_force_implicit_member(): + assert MusculotendonFormulation(4) == 4 + assert MusculotendonFormulation.TENDON_FORCE_IMPLICIT == 4 + + +class TestMusculotendonBase: + + @staticmethod + def test_is_abstract_base_class(): + assert issubclass(MusculotendonBase, abc.ABC) + + @staticmethod + def test_class(): + assert issubclass(MusculotendonBase, ForceActuator) + assert issubclass(MusculotendonBase, _NamedMixin) + assert MusculotendonBase.__name__ == 'MusculotendonBase' + + @staticmethod + def test_cannot_instantiate_directly(): + with pytest.raises(TypeError): + _ = MusculotendonBase() + + +@pytest.mark.parametrize('musculotendon_concrete', [MusculotendonDeGroote2016]) +class TestMusculotendonRigidTendon: + + @pytest.fixture(autouse=True) + def _musculotendon_rigid_tendon_fixture(self, musculotendon_concrete): + self.name = 'name' + self.N = ReferenceFrame('N') + self.q = dynamicsymbols('q') + self.origin = Point('pO') + self.insertion = Point('pI') + self.insertion.set_pos(self.origin, self.q*self.N.x) + self.pathway = LinearPathway(self.origin, self.insertion) + self.activation = FirstOrderActivationDeGroote2016(self.name) + self.e = self.activation.excitation + self.a = self.activation.activation + self.tau_a = self.activation.activation_time_constant + self.tau_d = self.activation.deactivation_time_constant + self.b = self.activation.smoothing_rate + self.formulation = MusculotendonFormulation.RIGID_TENDON + self.l_T_slack = Symbol('l_T_slack') + self.F_M_max = Symbol('F_M_max') + self.l_M_opt = Symbol('l_M_opt') + self.v_M_max = Symbol('v_M_max') + self.alpha_opt = Symbol('alpha_opt') + self.beta = Symbol('beta') + self.instance = musculotendon_concrete( + self.name, + self.pathway, + self.activation, + musculotendon_dynamics=self.formulation, + tendon_slack_length=self.l_T_slack, + peak_isometric_force=self.F_M_max, + optimal_fiber_length=self.l_M_opt, + maximal_fiber_velocity=self.v_M_max, + optimal_pennation_angle=self.alpha_opt, + fiber_damping_coefficient=self.beta, + ) + self.da_expr = ( + (1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a))) + *(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a))) + + ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d) + *(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a))) + )*(self.e - self.a) + + def test_state_vars(self): + assert hasattr(self.instance, 'x') + assert hasattr(self.instance, 'state_vars') + assert self.instance.x == self.instance.state_vars + x_expected = Matrix([self.a]) + assert self.instance.x == x_expected + assert self.instance.state_vars == x_expected + assert isinstance(self.instance.x, Matrix) + assert isinstance(self.instance.state_vars, Matrix) + assert self.instance.x.shape == (1, 1) + assert self.instance.state_vars.shape == (1, 1) + + def test_input_vars(self): + assert hasattr(self.instance, 'r') + assert hasattr(self.instance, 'input_vars') + assert self.instance.r == self.instance.input_vars + r_expected = Matrix([self.e]) + assert self.instance.r == r_expected + assert self.instance.input_vars == r_expected + assert isinstance(self.instance.r, Matrix) + assert isinstance(self.instance.input_vars, Matrix) + assert self.instance.r.shape == (1, 1) + assert self.instance.input_vars.shape == (1, 1) + + def test_constants(self): + assert hasattr(self.instance, 'p') + assert hasattr(self.instance, 'constants') + assert self.instance.p == self.instance.constants + p_expected = Matrix( + [ + self.l_T_slack, + self.F_M_max, + self.l_M_opt, + self.v_M_max, + self.alpha_opt, + self.beta, + self.tau_a, + self.tau_d, + self.b, + Symbol('c_0_fl_T_name'), + Symbol('c_1_fl_T_name'), + Symbol('c_2_fl_T_name'), + Symbol('c_3_fl_T_name'), + Symbol('c_0_fl_M_pas_name'), + Symbol('c_1_fl_M_pas_name'), + Symbol('c_0_fl_M_act_name'), + Symbol('c_1_fl_M_act_name'), + Symbol('c_2_fl_M_act_name'), + Symbol('c_3_fl_M_act_name'), + Symbol('c_4_fl_M_act_name'), + Symbol('c_5_fl_M_act_name'), + Symbol('c_6_fl_M_act_name'), + Symbol('c_7_fl_M_act_name'), + Symbol('c_8_fl_M_act_name'), + Symbol('c_9_fl_M_act_name'), + Symbol('c_10_fl_M_act_name'), + Symbol('c_11_fl_M_act_name'), + Symbol('c_0_fv_M_name'), + Symbol('c_1_fv_M_name'), + Symbol('c_2_fv_M_name'), + Symbol('c_3_fv_M_name'), + ] + ) + assert self.instance.p == p_expected + assert self.instance.constants == p_expected + assert isinstance(self.instance.p, Matrix) + assert isinstance(self.instance.constants, Matrix) + assert self.instance.p.shape == (31, 1) + assert self.instance.constants.shape == (31, 1) + + def test_M(self): + assert hasattr(self.instance, 'M') + M_expected = Matrix([1]) + assert self.instance.M == M_expected + assert isinstance(self.instance.M, Matrix) + assert self.instance.M.shape == (1, 1) + + def test_F(self): + assert hasattr(self.instance, 'F') + F_expected = Matrix([self.da_expr]) + assert self.instance.F == F_expected + assert isinstance(self.instance.F, Matrix) + assert self.instance.F.shape == (1, 1) + + def test_rhs(self): + assert hasattr(self.instance, 'rhs') + rhs_expected = Matrix([self.da_expr]) + rhs = self.instance.rhs() + assert isinstance(rhs, Matrix) + assert rhs.shape == (1, 1) + assert simplify(rhs - rhs_expected) == zeros(1) + + +@pytest.mark.parametrize( + 'musculotendon_concrete, curve', + [ + ( + MusculotendonDeGroote2016, + CharacteristicCurveCollection( + tendon_force_length=TendonForceLengthDeGroote2016, + tendon_force_length_inverse=TendonForceLengthInverseDeGroote2016, + fiber_force_length_passive=FiberForceLengthPassiveDeGroote2016, + fiber_force_length_passive_inverse=FiberForceLengthPassiveInverseDeGroote2016, + fiber_force_length_active=FiberForceLengthActiveDeGroote2016, + fiber_force_velocity=FiberForceVelocityDeGroote2016, + fiber_force_velocity_inverse=FiberForceVelocityInverseDeGroote2016, + ), + ) + ], +) +class TestFiberLengthExplicit: + + @pytest.fixture(autouse=True) + def _musculotendon_fiber_length_explicit_fixture( + self, + musculotendon_concrete, + curve, + ): + self.name = 'name' + self.N = ReferenceFrame('N') + self.q = dynamicsymbols('q') + self.origin = Point('pO') + self.insertion = Point('pI') + self.insertion.set_pos(self.origin, self.q*self.N.x) + self.pathway = LinearPathway(self.origin, self.insertion) + self.activation = FirstOrderActivationDeGroote2016(self.name) + self.e = self.activation.excitation + self.a = self.activation.activation + self.tau_a = self.activation.activation_time_constant + self.tau_d = self.activation.deactivation_time_constant + self.b = self.activation.smoothing_rate + self.formulation = MusculotendonFormulation.FIBER_LENGTH_EXPLICIT + self.l_T_slack = Symbol('l_T_slack') + self.F_M_max = Symbol('F_M_max') + self.l_M_opt = Symbol('l_M_opt') + self.v_M_max = Symbol('v_M_max') + self.alpha_opt = Symbol('alpha_opt') + self.beta = Symbol('beta') + self.instance = musculotendon_concrete( + self.name, + self.pathway, + self.activation, + musculotendon_dynamics=self.formulation, + tendon_slack_length=self.l_T_slack, + peak_isometric_force=self.F_M_max, + optimal_fiber_length=self.l_M_opt, + maximal_fiber_velocity=self.v_M_max, + optimal_pennation_angle=self.alpha_opt, + fiber_damping_coefficient=self.beta, + with_defaults=True, + ) + self.l_M_tilde = dynamicsymbols('l_M_tilde_name') + l_MT = self.pathway.length + l_M = self.l_M_tilde*self.l_M_opt + l_T = l_MT - sqrt(l_M**2 - (self.l_M_opt*sin(self.alpha_opt))**2) + fl_T = curve.tendon_force_length.with_defaults(l_T/self.l_T_slack) + fl_M_pas = curve.fiber_force_length_passive.with_defaults(self.l_M_tilde) + fl_M_act = curve.fiber_force_length_active.with_defaults(self.l_M_tilde) + v_M_tilde = curve.fiber_force_velocity_inverse.with_defaults( + ((((fl_T*self.F_M_max)/((l_MT - l_T)/l_M))/self.F_M_max) - fl_M_pas) + /(self.a*fl_M_act) + ) + self.dl_M_tilde_expr = (self.v_M_max/self.l_M_opt)*v_M_tilde + self.da_expr = ( + (1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a))) + *(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a))) + + ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d) + *(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a))) + )*(self.e - self.a) + + def test_state_vars(self): + assert hasattr(self.instance, 'x') + assert hasattr(self.instance, 'state_vars') + assert self.instance.x == self.instance.state_vars + x_expected = Matrix([self.l_M_tilde, self.a]) + assert self.instance.x == x_expected + assert self.instance.state_vars == x_expected + assert isinstance(self.instance.x, Matrix) + assert isinstance(self.instance.state_vars, Matrix) + assert self.instance.x.shape == (2, 1) + assert self.instance.state_vars.shape == (2, 1) + + def test_input_vars(self): + assert hasattr(self.instance, 'r') + assert hasattr(self.instance, 'input_vars') + assert self.instance.r == self.instance.input_vars + r_expected = Matrix([self.e]) + assert self.instance.r == r_expected + assert self.instance.input_vars == r_expected + assert isinstance(self.instance.r, Matrix) + assert isinstance(self.instance.input_vars, Matrix) + assert self.instance.r.shape == (1, 1) + assert self.instance.input_vars.shape == (1, 1) + + def test_constants(self): + assert hasattr(self.instance, 'p') + assert hasattr(self.instance, 'constants') + assert self.instance.p == self.instance.constants + p_expected = Matrix( + [ + self.l_T_slack, + self.F_M_max, + self.l_M_opt, + self.v_M_max, + self.alpha_opt, + self.beta, + self.tau_a, + self.tau_d, + self.b, + ] + ) + assert self.instance.p == p_expected + assert self.instance.constants == p_expected + assert isinstance(self.instance.p, Matrix) + assert isinstance(self.instance.constants, Matrix) + assert self.instance.p.shape == (9, 1) + assert self.instance.constants.shape == (9, 1) + + def test_M(self): + assert hasattr(self.instance, 'M') + M_expected = eye(2) + assert self.instance.M == M_expected + assert isinstance(self.instance.M, Matrix) + assert self.instance.M.shape == (2, 2) + + def test_F(self): + assert hasattr(self.instance, 'F') + F_expected = Matrix([self.dl_M_tilde_expr, self.da_expr]) + assert self.instance.F == F_expected + assert isinstance(self.instance.F, Matrix) + assert self.instance.F.shape == (2, 1) + + def test_rhs(self): + assert hasattr(self.instance, 'rhs') + rhs_expected = Matrix([self.dl_M_tilde_expr, self.da_expr]) + rhs = self.instance.rhs() + assert isinstance(rhs, Matrix) + assert rhs.shape == (2, 1) + assert simplify(rhs - rhs_expected) == zeros(2, 1) + + +@pytest.mark.parametrize( + 'musculotendon_concrete, curve', + [ + ( + MusculotendonDeGroote2016, + CharacteristicCurveCollection( + tendon_force_length=TendonForceLengthDeGroote2016, + tendon_force_length_inverse=TendonForceLengthInverseDeGroote2016, + fiber_force_length_passive=FiberForceLengthPassiveDeGroote2016, + fiber_force_length_passive_inverse=FiberForceLengthPassiveInverseDeGroote2016, + fiber_force_length_active=FiberForceLengthActiveDeGroote2016, + fiber_force_velocity=FiberForceVelocityDeGroote2016, + fiber_force_velocity_inverse=FiberForceVelocityInverseDeGroote2016, + ), + ) + ], +) +class TestTendonForceExplicit: + + @pytest.fixture(autouse=True) + def _musculotendon_tendon_force_explicit_fixture( + self, + musculotendon_concrete, + curve, + ): + self.name = 'name' + self.N = ReferenceFrame('N') + self.q = dynamicsymbols('q') + self.origin = Point('pO') + self.insertion = Point('pI') + self.insertion.set_pos(self.origin, self.q*self.N.x) + self.pathway = LinearPathway(self.origin, self.insertion) + self.activation = FirstOrderActivationDeGroote2016(self.name) + self.e = self.activation.excitation + self.a = self.activation.activation + self.tau_a = self.activation.activation_time_constant + self.tau_d = self.activation.deactivation_time_constant + self.b = self.activation.smoothing_rate + self.formulation = MusculotendonFormulation.TENDON_FORCE_EXPLICIT + self.l_T_slack = Symbol('l_T_slack') + self.F_M_max = Symbol('F_M_max') + self.l_M_opt = Symbol('l_M_opt') + self.v_M_max = Symbol('v_M_max') + self.alpha_opt = Symbol('alpha_opt') + self.beta = Symbol('beta') + self.instance = musculotendon_concrete( + self.name, + self.pathway, + self.activation, + musculotendon_dynamics=self.formulation, + tendon_slack_length=self.l_T_slack, + peak_isometric_force=self.F_M_max, + optimal_fiber_length=self.l_M_opt, + maximal_fiber_velocity=self.v_M_max, + optimal_pennation_angle=self.alpha_opt, + fiber_damping_coefficient=self.beta, + with_defaults=True, + ) + self.F_T_tilde = dynamicsymbols('F_T_tilde_name') + l_T_tilde = curve.tendon_force_length_inverse.with_defaults(self.F_T_tilde) + l_MT = self.pathway.length + v_MT = self.pathway.extension_velocity + l_T = l_T_tilde*self.l_T_slack + l_M = sqrt((l_MT - l_T)**2 + (self.l_M_opt*sin(self.alpha_opt))**2) + l_M_tilde = l_M/self.l_M_opt + cos_alpha = (l_MT - l_T)/l_M + F_T = self.F_T_tilde*self.F_M_max + F_M = F_T/cos_alpha + F_M_tilde = F_M/self.F_M_max + fl_M_pas = curve.fiber_force_length_passive.with_defaults(l_M_tilde) + fl_M_act = curve.fiber_force_length_active.with_defaults(l_M_tilde) + fv_M = (F_M_tilde - fl_M_pas)/(self.a*fl_M_act) + v_M_tilde = curve.fiber_force_velocity_inverse.with_defaults(fv_M) + v_M = v_M_tilde*self.v_M_max + v_T = v_MT - v_M/cos_alpha + v_T_tilde = v_T/self.l_T_slack + self.dF_T_tilde_expr = ( + Float('0.2')*Float('33.93669377311689')*exp( + Float('33.93669377311689')*UnevaluatedExpr(l_T_tilde - Float('0.995')) + )*v_T_tilde + ) + self.da_expr = ( + (1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a))) + *(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a))) + + ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d) + *(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a))) + )*(self.e - self.a) + + def test_state_vars(self): + assert hasattr(self.instance, 'x') + assert hasattr(self.instance, 'state_vars') + assert self.instance.x == self.instance.state_vars + x_expected = Matrix([self.F_T_tilde, self.a]) + assert self.instance.x == x_expected + assert self.instance.state_vars == x_expected + assert isinstance(self.instance.x, Matrix) + assert isinstance(self.instance.state_vars, Matrix) + assert self.instance.x.shape == (2, 1) + assert self.instance.state_vars.shape == (2, 1) + + def test_input_vars(self): + assert hasattr(self.instance, 'r') + assert hasattr(self.instance, 'input_vars') + assert self.instance.r == self.instance.input_vars + r_expected = Matrix([self.e]) + assert self.instance.r == r_expected + assert self.instance.input_vars == r_expected + assert isinstance(self.instance.r, Matrix) + assert isinstance(self.instance.input_vars, Matrix) + assert self.instance.r.shape == (1, 1) + assert self.instance.input_vars.shape == (1, 1) + + def test_constants(self): + assert hasattr(self.instance, 'p') + assert hasattr(self.instance, 'constants') + assert self.instance.p == self.instance.constants + p_expected = Matrix( + [ + self.l_T_slack, + self.F_M_max, + self.l_M_opt, + self.v_M_max, + self.alpha_opt, + self.beta, + self.tau_a, + self.tau_d, + self.b, + ] + ) + assert self.instance.p == p_expected + assert self.instance.constants == p_expected + assert isinstance(self.instance.p, Matrix) + assert isinstance(self.instance.constants, Matrix) + assert self.instance.p.shape == (9, 1) + assert self.instance.constants.shape == (9, 1) + + def test_M(self): + assert hasattr(self.instance, 'M') + M_expected = eye(2) + assert self.instance.M == M_expected + assert isinstance(self.instance.M, Matrix) + assert self.instance.M.shape == (2, 2) + + def test_F(self): + assert hasattr(self.instance, 'F') + F_expected = Matrix([self.dF_T_tilde_expr, self.da_expr]) + assert self.instance.F == F_expected + assert isinstance(self.instance.F, Matrix) + assert self.instance.F.shape == (2, 1) + + def test_rhs(self): + assert hasattr(self.instance, 'rhs') + rhs_expected = Matrix([self.dF_T_tilde_expr, self.da_expr]) + rhs = self.instance.rhs() + assert isinstance(rhs, Matrix) + assert rhs.shape == (2, 1) + assert simplify(rhs - rhs_expected) == zeros(2, 1) + + +class TestMusculotendonDeGroote2016: + + @staticmethod + def test_class(): + assert issubclass(MusculotendonDeGroote2016, ForceActuator) + assert issubclass(MusculotendonDeGroote2016, _NamedMixin) + assert MusculotendonDeGroote2016.__name__ == 'MusculotendonDeGroote2016' + + @staticmethod + def test_instance(): + origin = Point('pO') + insertion = Point('pI') + insertion.set_pos(origin, dynamicsymbols('q')*ReferenceFrame('N').x) + pathway = LinearPathway(origin, insertion) + activation = FirstOrderActivationDeGroote2016('name') + l_T_slack = Symbol('l_T_slack') + F_M_max = Symbol('F_M_max') + l_M_opt = Symbol('l_M_opt') + v_M_max = Symbol('v_M_max') + alpha_opt = Symbol('alpha_opt') + beta = Symbol('beta') + instance = MusculotendonDeGroote2016( + 'name', + pathway, + activation, + musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON, + tendon_slack_length=l_T_slack, + peak_isometric_force=F_M_max, + optimal_fiber_length=l_M_opt, + maximal_fiber_velocity=v_M_max, + optimal_pennation_angle=alpha_opt, + fiber_damping_coefficient=beta, + ) + assert isinstance(instance, MusculotendonDeGroote2016) + + @pytest.fixture(autouse=True) + def _musculotendon_fixture(self): + self.name = 'name' + self.N = ReferenceFrame('N') + self.q = dynamicsymbols('q') + self.origin = Point('pO') + self.insertion = Point('pI') + self.insertion.set_pos(self.origin, self.q*self.N.x) + self.pathway = LinearPathway(self.origin, self.insertion) + self.activation = FirstOrderActivationDeGroote2016(self.name) + self.l_T_slack = Symbol('l_T_slack') + self.F_M_max = Symbol('F_M_max') + self.l_M_opt = Symbol('l_M_opt') + self.v_M_max = Symbol('v_M_max') + self.alpha_opt = Symbol('alpha_opt') + self.beta = Symbol('beta') + + def test_with_defaults(self): + origin = Point('pO') + insertion = Point('pI') + insertion.set_pos(origin, dynamicsymbols('q')*ReferenceFrame('N').x) + pathway = LinearPathway(origin, insertion) + activation = FirstOrderActivationDeGroote2016('name') + l_T_slack = Symbol('l_T_slack') + F_M_max = Symbol('F_M_max') + l_M_opt = Symbol('l_M_opt') + v_M_max = Float('10.0') + alpha_opt = Float('0.0') + beta = Float('0.1') + instance = MusculotendonDeGroote2016.with_defaults( + 'name', + pathway, + activation, + musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON, + tendon_slack_length=l_T_slack, + peak_isometric_force=F_M_max, + optimal_fiber_length=l_M_opt, + ) + assert instance.tendon_slack_length == l_T_slack + assert instance.peak_isometric_force == F_M_max + assert instance.optimal_fiber_length == l_M_opt + assert instance.maximal_fiber_velocity == v_M_max + assert instance.optimal_pennation_angle == alpha_opt + assert instance.fiber_damping_coefficient == beta + + @pytest.mark.parametrize( + 'l_T_slack, expected', + [ + (None, Symbol('l_T_slack_name')), + (Symbol('l_T_slack'), Symbol('l_T_slack')), + (Rational(1, 2), Rational(1, 2)), + (Float('0.5'), Float('0.5')), + ], + ) + def test_tendon_slack_length(self, l_T_slack, expected): + instance = MusculotendonDeGroote2016( + self.name, + self.pathway, + self.activation, + musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON, + tendon_slack_length=l_T_slack, + peak_isometric_force=self.F_M_max, + optimal_fiber_length=self.l_M_opt, + maximal_fiber_velocity=self.v_M_max, + optimal_pennation_angle=self.alpha_opt, + fiber_damping_coefficient=self.beta, + ) + assert instance.l_T_slack == expected + assert instance.tendon_slack_length == expected + + @pytest.mark.parametrize( + 'F_M_max, expected', + [ + (None, Symbol('F_M_max_name')), + (Symbol('F_M_max'), Symbol('F_M_max')), + (Integer(1000), Integer(1000)), + (Float('1000.0'), Float('1000.0')), + ], + ) + def test_peak_isometric_force(self, F_M_max, expected): + instance = MusculotendonDeGroote2016( + self.name, + self.pathway, + self.activation, + musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON, + tendon_slack_length=self.l_T_slack, + peak_isometric_force=F_M_max, + optimal_fiber_length=self.l_M_opt, + maximal_fiber_velocity=self.v_M_max, + optimal_pennation_angle=self.alpha_opt, + fiber_damping_coefficient=self.beta, + ) + assert instance.F_M_max == expected + assert instance.peak_isometric_force == expected + + @pytest.mark.parametrize( + 'l_M_opt, expected', + [ + (None, Symbol('l_M_opt_name')), + (Symbol('l_M_opt'), Symbol('l_M_opt')), + (Rational(1, 2), Rational(1, 2)), + (Float('0.5'), Float('0.5')), + ], + ) + def test_optimal_fiber_length(self, l_M_opt, expected): + instance = MusculotendonDeGroote2016( + self.name, + self.pathway, + self.activation, + musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON, + tendon_slack_length=self.l_T_slack, + peak_isometric_force=self.F_M_max, + optimal_fiber_length=l_M_opt, + maximal_fiber_velocity=self.v_M_max, + optimal_pennation_angle=self.alpha_opt, + fiber_damping_coefficient=self.beta, + ) + assert instance.l_M_opt == expected + assert instance.optimal_fiber_length == expected + + @pytest.mark.parametrize( + 'v_M_max, expected', + [ + (None, Symbol('v_M_max_name')), + (Symbol('v_M_max'), Symbol('v_M_max')), + (Integer(10), Integer(10)), + (Float('10.0'), Float('10.0')), + ], + ) + def test_maximal_fiber_velocity(self, v_M_max, expected): + instance = MusculotendonDeGroote2016( + self.name, + self.pathway, + self.activation, + musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON, + tendon_slack_length=self.l_T_slack, + peak_isometric_force=self.F_M_max, + optimal_fiber_length=self.l_M_opt, + maximal_fiber_velocity=v_M_max, + optimal_pennation_angle=self.alpha_opt, + fiber_damping_coefficient=self.beta, + ) + assert instance.v_M_max == expected + assert instance.maximal_fiber_velocity == expected + + @pytest.mark.parametrize( + 'alpha_opt, expected', + [ + (None, Symbol('alpha_opt_name')), + (Symbol('alpha_opt'), Symbol('alpha_opt')), + (Integer(0), Integer(0)), + (Float('0.1'), Float('0.1')), + ], + ) + def test_optimal_pennation_angle(self, alpha_opt, expected): + instance = MusculotendonDeGroote2016( + self.name, + self.pathway, + self.activation, + musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON, + tendon_slack_length=self.l_T_slack, + peak_isometric_force=self.F_M_max, + optimal_fiber_length=self.l_M_opt, + maximal_fiber_velocity=self.v_M_max, + optimal_pennation_angle=alpha_opt, + fiber_damping_coefficient=self.beta, + ) + assert instance.alpha_opt == expected + assert instance.optimal_pennation_angle == expected + + @pytest.mark.parametrize( + 'beta, expected', + [ + (None, Symbol('beta_name')), + (Symbol('beta'), Symbol('beta')), + (Integer(0), Integer(0)), + (Rational(1, 10), Rational(1, 10)), + (Float('0.1'), Float('0.1')), + ], + ) + def test_fiber_damping_coefficient(self, beta, expected): + instance = MusculotendonDeGroote2016( + self.name, + self.pathway, + self.activation, + musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON, + tendon_slack_length=self.l_T_slack, + peak_isometric_force=self.F_M_max, + optimal_fiber_length=self.l_M_opt, + maximal_fiber_velocity=self.v_M_max, + optimal_pennation_angle=self.alpha_opt, + fiber_damping_coefficient=beta, + ) + assert instance.beta == expected + assert instance.fiber_damping_coefficient == expected + + def test_excitation(self): + instance = MusculotendonDeGroote2016( + self.name, + self.pathway, + self.activation, + ) + assert hasattr(instance, 'e') + assert hasattr(instance, 'excitation') + e_expected = dynamicsymbols('e_name') + assert instance.e == e_expected + assert instance.excitation == e_expected + assert instance.e is instance.excitation + + def test_excitation_is_immutable(self): + instance = MusculotendonDeGroote2016( + self.name, + self.pathway, + self.activation, + ) + with pytest.raises(AttributeError): + instance.e = None + with pytest.raises(AttributeError): + instance.excitation = None + + def test_activation(self): + instance = MusculotendonDeGroote2016( + self.name, + self.pathway, + self.activation, + ) + assert hasattr(instance, 'a') + assert hasattr(instance, 'activation') + a_expected = dynamicsymbols('a_name') + assert instance.a == a_expected + assert instance.activation == a_expected + + def test_activation_is_immutable(self): + instance = MusculotendonDeGroote2016( + self.name, + self.pathway, + self.activation, + ) + with pytest.raises(AttributeError): + instance.a = None + with pytest.raises(AttributeError): + instance.activation = None + + def test_repr(self): + instance = MusculotendonDeGroote2016( + self.name, + self.pathway, + self.activation, + musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON, + tendon_slack_length=self.l_T_slack, + peak_isometric_force=self.F_M_max, + optimal_fiber_length=self.l_M_opt, + maximal_fiber_velocity=self.v_M_max, + optimal_pennation_angle=self.alpha_opt, + fiber_damping_coefficient=self.beta, + ) + expected = ( + 'MusculotendonDeGroote2016(\'name\', ' + 'pathway=LinearPathway(pO, pI), ' + 'activation_dynamics=FirstOrderActivationDeGroote2016(\'name\', ' + 'activation_time_constant=tau_a_name, ' + 'deactivation_time_constant=tau_d_name, ' + 'smoothing_rate=b_name), ' + 'musculotendon_dynamics=0, ' + 'tendon_slack_length=l_T_slack, ' + 'peak_isometric_force=F_M_max, ' + 'optimal_fiber_length=l_M_opt, ' + 'maximal_fiber_velocity=v_M_max, ' + 'optimal_pennation_angle=alpha_opt, ' + 'fiber_damping_coefficient=beta)' + ) + assert repr(instance) == expected diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1df459eea15ff90f2a4d6be388f968db874ddd5e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/arch.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/arch.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4912ee22687e8299143683945bd8f46a638b5815 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/arch.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/cable.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/cable.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d33137ded64ac6dc75cd54d114420a38f05d343e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/cable.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/truss.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/truss.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c020aa792c4bc46a1f822be22c9a221f8474f0d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/__pycache__/truss.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfc652d4409f58907f9baa3f94bba1b3240e90d4 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_arch.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_arch.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35f9f7bc297c68281f5a5f908e980ee53aa756bc Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_arch.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_beam.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_beam.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6cde91c3a48ad40116b7e473e3d07849dabe9992 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_beam.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_cable.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_cable.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b4928d6ffea7b216e525cf292c5faf8d5cc9d91 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_cable.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_truss.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_truss.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2e9f626b78a6a65a160709892df584a4d4a78f7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/__pycache__/test_truss.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_arch.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_arch.py new file mode 100644 index 0000000000000000000000000000000000000000..3d77062702222d7381a89450e8230b52bac4028c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_arch.py @@ -0,0 +1,61 @@ +from sympy.physics.continuum_mechanics.arch import Arch +from sympy import Symbol, simplify + +x = Symbol('x') +t = Symbol('t') + +def test_arch_init(): + a = Arch((0,0),(10,0),crown_x=5,crown_y=5) + assert a.get_loads == {'distributed': {}, 'concentrated': {}} + assert a.reaction_force == {Symbol('R_A_x'):0, Symbol('R_A_y'):0, Symbol('R_B_x'):0, Symbol('R_B_y'):0} + assert a.supports == {'left':'hinge', 'right':'hinge'} + assert a.left_support == (0,0) + assert a.right_support == (10,0) + assert a.get_shape_eqn == 5 - ((x-5)**2)/5 + + a = Arch((0,0),(10,1),crown_x=6) + a.change_support_type(left_support='roller') + a.add_member(0.5) + assert a.supports == {'left':'roller', 'right':'hinge'} + assert simplify(a.get_shape_eqn) == simplify(9/5 - (x - 6)**2/20) + +def test_arch_support(): + a = Arch((0,0),(40,0),crown_x=20,crown_y=12) + a.apply_load(-1,'C',8,150,angle=270) + a.apply_load(0,'D',start=20,end=40,mag=-4) + a.solve() + assert abs(a.reaction_force[Symbol("R_A_x")] - 83.33333333333333) < 10e-12 + assert abs(a.reaction_force[Symbol("R_B_y")] - 90.00000000000000) < 10e-12 + assert abs(a.reaction_force[Symbol("R_B_x")] + 83.33333333333333) < 10e-12 + assert abs(a.reaction_force[Symbol("R_A_y")] - 140.00000000000000) < 10e-12 + +def test_arch_member(): + a = Arch((0,0),(40,0),crown_x=20,crown_y=15) + a.change_support_type(right_support='roller') + a.add_member(0) + a.apply_load(-1,'D',start=12,mag=3,angle=270) + a.apply_load(-1,'E',start=6,mag=4,angle=270) + a.apply_load(-1,'C',start=30,mag=5,angle=270) + a.solve() + assert a.reaction_force[Symbol("R_A_x")] == 0 + assert abs(a.reaction_force[Symbol("R_A_y")] - 6.750000000000000) < 10e-12 + assert a.reaction_force[Symbol("R_B_x")] == 0 + assert abs(a.reaction_force[Symbol("R_B_y")] - 5.250000000000000) < 10e-12 + +def test_symbol_magnitude(): + a = Arch((0,0),(16,0),crown_x=8,crown_y=5) + a.apply_load(0,'C',start=3,end=5,mag=t) + a.solve() + assert a.reaction_force[Symbol("R_A_x")] == -(4*t)/5 + assert a.reaction_force[Symbol("R_A_y")] == -(3*t)/2 + assert a.reaction_force[Symbol("R_B_x")] == (4*t)/5 + assert a.reaction_force[Symbol("R_B_y")] == -t/2 + assert a.bending_moment_at(4) == -5*t/2 + +def test_forces(): + a = Arch((0,0),(40,0),crown_x=20,crown_y=12) + a.apply_load(-1,'C',8,150,angle=270) + a.apply_load(0,'D',start=20,end=40,mag=-4) + a.solve() + assert abs(a.axial_force_at(7.999999999999999)-149.430523405935) < 1e-12 + assert abs(a.shear_force_at(7.999999999999999)-64.9227473161196) < 1e-12 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_beam.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_beam.py new file mode 100644 index 0000000000000000000000000000000000000000..a6a36fb030f99d9d384e52d4a239351688c7626b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_beam.py @@ -0,0 +1,1118 @@ +from sympy.core.function import expand +from sympy.core.numbers import (Rational, pi) +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.sets.sets import Interval +from sympy.simplify.simplify import simplify +from sympy.physics.continuum_mechanics.beam import Beam +from sympy.functions import SingularityFunction, Piecewise, meijerg, Abs, log +from sympy.testing.pytest import raises +from sympy.physics.units import meter, newton, kilo, giga, milli +from sympy.physics.continuum_mechanics.beam import Beam3D +from sympy.geometry import Circle, Polygon, Point2D, Triangle +from sympy.core.sympify import sympify + +x = Symbol('x') +y = Symbol('y') +R1, R2 = symbols('R1, R2') + + +def test_Beam(): + E = Symbol('E') + E_1 = Symbol('E_1') + I = Symbol('I') + I_1 = Symbol('I_1') + A = Symbol('A') + + b = Beam(1, E, I) + assert b.length == 1 + assert b.elastic_modulus == E + assert b.second_moment == I + assert b.variable == x + + # Test the length setter + b.length = 4 + assert b.length == 4 + + # Test the E setter + b.elastic_modulus = E_1 + assert b.elastic_modulus == E_1 + + # Test the I setter + b.second_moment = I_1 + assert b.second_moment is I_1 + + # Test the variable setter + b.variable = y + assert b.variable is y + + # Test for all boundary conditions. + b.bc_deflection = [(0, 2)] + b.bc_slope = [(0, 1)] + b.bc_bending_moment = [(0, 5)] + b.bc_shear_force = [(2, 1)] + assert b.boundary_conditions == {'deflection': [(0, 2)], 'slope': [(0, 1)], + 'bending_moment': [(0, 5)], 'shear_force': [(2, 1)]} + + # Test for shear force boundary condition method + b.bc_shear_force.extend([(1, 1), (2, 3)]) + sf_bcs = b.bc_shear_force + assert sf_bcs == [(2, 1), (1, 1), (2, 3)] + + # Test for slope boundary condition method + b.bc_bending_moment.extend([(1, 3), (5, 3)]) + bm_bcs = b.bc_bending_moment + assert bm_bcs == [(0, 5), (1, 3), (5, 3)] + + # Test for slope boundary condition method + b.bc_slope.extend([(4, 3), (5, 0)]) + s_bcs = b.bc_slope + assert s_bcs == [(0, 1), (4, 3), (5, 0)] + + # Test for deflection boundary condition method + b.bc_deflection.extend([(4, 3), (5, 0)]) + d_bcs = b.bc_deflection + assert d_bcs == [(0, 2), (4, 3), (5, 0)] + + # Test for updated boundary conditions + bcs_new = b.boundary_conditions + assert bcs_new == { + 'deflection': [(0, 2), (4, 3), (5, 0)], + 'slope': [(0, 1), (4, 3), (5, 0)], + 'bending_moment': [(0, 5), (1, 3), (5, 3)], + 'shear_force': [(2, 1), (1, 1), (2, 3)]} + + b1 = Beam(30, E, I) + b1.apply_load(-8, 0, -1) + b1.apply_load(R1, 10, -1) + b1.apply_load(R2, 30, -1) + b1.apply_load(120, 30, -2) + b1.bc_deflection = [(10, 0), (30, 0)] + b1.solve_for_reaction_loads(R1, R2) + + # Test for finding reaction forces + p = b1.reaction_loads + q = {R1: 6, R2: 2} + assert p == q + + # Test for load distribution function. + p = b1.load + q = -8*SingularityFunction(x, 0, -1) + 6*SingularityFunction(x, 10, -1) \ + + 120*SingularityFunction(x, 30, -2) + 2*SingularityFunction(x, 30, -1) + assert p == q + + # Test for shear force distribution function + p = b1.shear_force() + q = 8*SingularityFunction(x, 0, 0) - 6*SingularityFunction(x, 10, 0) \ + - 120*SingularityFunction(x, 30, -1) - 2*SingularityFunction(x, 30, 0) + assert p == q + + # Test for shear stress distribution function + p = b1.shear_stress() + q = (8*SingularityFunction(x, 0, 0) - 6*SingularityFunction(x, 10, 0) \ + - 120*SingularityFunction(x, 30, -1) \ + - 2*SingularityFunction(x, 30, 0))/A + assert p==q + + # Test for bending moment distribution function + p = b1.bending_moment() + q = 8*SingularityFunction(x, 0, 1) - 6*SingularityFunction(x, 10, 1) \ + - 120*SingularityFunction(x, 30, 0) - 2*SingularityFunction(x, 30, 1) + assert p == q + + # Test for slope distribution function + p = b1.slope() + q = -4*SingularityFunction(x, 0, 2) + 3*SingularityFunction(x, 10, 2) \ + + 120*SingularityFunction(x, 30, 1) + SingularityFunction(x, 30, 2) \ + + Rational(4000, 3) + assert p == q/(E*I) + + # Test for deflection distribution function + p = b1.deflection() + q = x*Rational(4000, 3) - 4*SingularityFunction(x, 0, 3)/3 \ + + SingularityFunction(x, 10, 3) + 60*SingularityFunction(x, 30, 2) \ + + SingularityFunction(x, 30, 3)/3 - 12000 + assert p == q/(E*I) + + # Test using symbols + l = Symbol('l') + w0 = Symbol('w0') + w2 = Symbol('w2') + a1 = Symbol('a1') + c = Symbol('c') + c1 = Symbol('c1') + d = Symbol('d') + e = Symbol('e') + f = Symbol('f') + + b2 = Beam(l, E, I) + + b2.apply_load(w0, a1, 1) + b2.apply_load(w2, c1, -1) + + b2.bc_deflection = [(c, d)] + b2.bc_slope = [(e, f)] + + # Test for load distribution function. + p = b2.load + q = w0*SingularityFunction(x, a1, 1) + w2*SingularityFunction(x, c1, -1) + assert p == q + + # Test for shear force distribution function + p = b2.shear_force() + q = -w0*SingularityFunction(x, a1, 2)/2 \ + - w2*SingularityFunction(x, c1, 0) + assert p == q + + # Test for shear stress distribution function + p = b2.shear_stress() + q = (-w0*SingularityFunction(x, a1, 2)/2 \ + - w2*SingularityFunction(x, c1, 0))/A + assert p == q + + # Test for bending moment distribution function + p = b2.bending_moment() + q = -w0*SingularityFunction(x, a1, 3)/6 - w2*SingularityFunction(x, c1, 1) + assert p == q + + # Test for slope distribution function + p = b2.slope() + q = (w0*SingularityFunction(x, a1, 4)/24 + w2*SingularityFunction(x, c1, 2)/2)/(E*I) + (E*I*f - w0*SingularityFunction(e, a1, 4)/24 - w2*SingularityFunction(e, c1, 2)/2)/(E*I) + assert expand(p) == expand(q) + + # Test for deflection distribution function + p = b2.deflection() + q = x*(E*I*f - w0*SingularityFunction(e, a1, 4)/24 \ + - w2*SingularityFunction(e, c1, 2)/2)/(E*I) \ + + (w0*SingularityFunction(x, a1, 5)/120 \ + + w2*SingularityFunction(x, c1, 3)/6)/(E*I) \ + + (E*I*(-c*f + d) + c*w0*SingularityFunction(e, a1, 4)/24 \ + + c*w2*SingularityFunction(e, c1, 2)/2 \ + - w0*SingularityFunction(c, a1, 5)/120 \ + - w2*SingularityFunction(c, c1, 3)/6)/(E*I) + assert simplify(p - q) == 0 + + b3 = Beam(9, E, I, 2) + b3.apply_load(value=-2, start=2, order=2, end=3) + b3.bc_slope.append((0, 2)) + C3 = symbols('C3') + C4 = symbols('C4') + + p = b3.load + q = -2*SingularityFunction(x, 2, 2) + 2*SingularityFunction(x, 3, 0) \ + + 4*SingularityFunction(x, 3, 1) + 2*SingularityFunction(x, 3, 2) + assert p == q + + p = b3.shear_force() + q = 2*SingularityFunction(x, 2, 3)/3 - 2*SingularityFunction(x, 3, 1) \ + - 2*SingularityFunction(x, 3, 2) - 2*SingularityFunction(x, 3, 3)/3 + assert p == q + + p = b3.shear_stress() + q = SingularityFunction(x, 2, 3)/3 - 1*SingularityFunction(x, 3, 1) \ + - 1*SingularityFunction(x, 3, 2) - 1*SingularityFunction(x, 3, 3)/3 + assert p == q + + p = b3.slope() + q = 2 - (SingularityFunction(x, 2, 5)/30 - SingularityFunction(x, 3, 3)/3 \ + - SingularityFunction(x, 3, 4)/6 - SingularityFunction(x, 3, 5)/30)/(E*I) + assert p == q + + p = b3.deflection() + q = 2*x - (SingularityFunction(x, 2, 6)/180 \ + - SingularityFunction(x, 3, 4)/12 - SingularityFunction(x, 3, 5)/30 \ + - SingularityFunction(x, 3, 6)/180)/(E*I) + assert p == q + C4 + + b4 = Beam(4, E, I, 3) + b4.apply_load(-3, 0, 0, end=3) + + p = b4.load + q = -3*SingularityFunction(x, 0, 0) + 3*SingularityFunction(x, 3, 0) + assert p == q + + p = b4.shear_force() + q = 3*SingularityFunction(x, 0, 1) \ + - 3*SingularityFunction(x, 3, 1) + assert p == q + + p = b4.shear_stress() + q = SingularityFunction(x, 0, 1) - SingularityFunction(x, 3, 1) + assert p == q + + p = b4.slope() + q = -3*SingularityFunction(x, 0, 3)/6 + 3*SingularityFunction(x, 3, 3)/6 + assert p == q/(E*I) + C3 + + p = b4.deflection() + q = -3*SingularityFunction(x, 0, 4)/24 + 3*SingularityFunction(x, 3, 4)/24 + assert p == q/(E*I) + C3*x + C4 + + # can't use end with point loads + raises(ValueError, lambda: b4.apply_load(-3, 0, -1, end=3)) + with raises(TypeError): + b4.variable = 1 + + +def test_insufficient_bconditions(): + # Test cases when required number of boundary conditions + # are not provided to solve the integration constants. + L = symbols('L', positive=True) + E, I, P, a3, a4 = symbols('E I P a3 a4') + + b = Beam(L, E, I, base_char='a') + b.apply_load(R2, L, -1) + b.apply_load(R1, 0, -1) + b.apply_load(-P, L/2, -1) + b.solve_for_reaction_loads(R1, R2) + + p = b.slope() + q = P*SingularityFunction(x, 0, 2)/4 - P*SingularityFunction(x, L/2, 2)/2 + P*SingularityFunction(x, L, 2)/4 + assert p == q/(E*I) + a3 + + p = b.deflection() + q = P*SingularityFunction(x, 0, 3)/12 - P*SingularityFunction(x, L/2, 3)/6 + P*SingularityFunction(x, L, 3)/12 + assert p == q/(E*I) + a3*x + a4 + + b.bc_deflection = [(0, 0)] + p = b.deflection() + q = a3*x + P*SingularityFunction(x, 0, 3)/12 - P*SingularityFunction(x, L/2, 3)/6 + P*SingularityFunction(x, L, 3)/12 + assert p == q/(E*I) + + b.bc_deflection = [(0, 0), (L, 0)] + p = b.deflection() + q = -L**2*P*x/16 + P*SingularityFunction(x, 0, 3)/12 - P*SingularityFunction(x, L/2, 3)/6 + P*SingularityFunction(x, L, 3)/12 + assert p == q/(E*I) + + +def test_statically_indeterminate(): + E = Symbol('E') + I = Symbol('I') + M1, M2 = symbols('M1, M2') + F = Symbol('F') + l = Symbol('l', positive=True) + + b5 = Beam(l, E, I) + b5.bc_deflection = [(0, 0),(l, 0)] + b5.bc_slope = [(0, 0),(l, 0)] + + b5.apply_load(R1, 0, -1) + b5.apply_load(M1, 0, -2) + b5.apply_load(R2, l, -1) + b5.apply_load(M2, l, -2) + b5.apply_load(-F, l/2, -1) + + b5.solve_for_reaction_loads(R1, R2, M1, M2) + p = b5.reaction_loads + q = {R1: F/2, R2: F/2, M1: -F*l/8, M2: F*l/8} + assert p == q + + +def test_beam_units(): + E = Symbol('E') + I = Symbol('I') + R1, R2 = symbols('R1, R2') + + kN = kilo*newton + gN = giga*newton + + b = Beam(8*meter, 200*gN/meter**2, 400*1000000*(milli*meter)**4) + b.apply_load(5*kN, 2*meter, -1) + b.apply_load(R1, 0*meter, -1) + b.apply_load(R2, 8*meter, -1) + b.apply_load(10*kN/meter, 4*meter, 0, end=8*meter) + b.bc_deflection = [(0*meter, 0*meter), (8*meter, 0*meter)] + b.solve_for_reaction_loads(R1, R2) + assert b.reaction_loads == {R1: -13750*newton, R2: -31250*newton} + + b = Beam(3*meter, E*newton/meter**2, I*meter**4) + b.apply_load(8*kN, 1*meter, -1) + b.apply_load(R1, 0*meter, -1) + b.apply_load(R2, 3*meter, -1) + b.apply_load(12*kN*meter, 2*meter, -2) + b.bc_deflection = [(0*meter, 0*meter), (3*meter, 0*meter)] + b.solve_for_reaction_loads(R1, R2) + assert b.reaction_loads == {R1: newton*Rational(-28000, 3), R2: newton*Rational(4000, 3)} + assert b.deflection().subs(x, 1*meter) == 62000*meter/(9*E*I) + + +def test_variable_moment(): + E = Symbol('E') + I = Symbol('I') + + b = Beam(4, E, 2*(4 - x)) + b.apply_load(20, 4, -1) + R, M = symbols('R, M') + b.apply_load(R, 0, -1) + b.apply_load(M, 0, -2) + b.bc_deflection = [(0, 0)] + b.bc_slope = [(0, 0)] + b.solve_for_reaction_loads(R, M) + assert b.slope().expand() == ((10*x*SingularityFunction(x, 0, 0) + - 10*(x - 4)*SingularityFunction(x, 4, 0))/E).expand() + assert b.deflection().expand() == ((5*x**2*SingularityFunction(x, 0, 0) + - 10*Piecewise((0, Abs(x)/4 < 1), (x**2*meijerg(((-1, 1), ()), ((), (-2, 0)), x/4), True)) + + 40*SingularityFunction(x, 4, 1))/E).expand() + + b = Beam(4, E - x, I) + b.apply_load(20, 4, -1) + R, M = symbols('R, M') + b.apply_load(R, 0, -1) + b.apply_load(M, 0, -2) + b.bc_deflection = [(0, 0)] + b.bc_slope = [(0, 0)] + b.solve_for_reaction_loads(R, M) + assert b.slope().expand() == ((-80*(-log(-E) + log(-E + x))*SingularityFunction(x, 0, 0) + + 80*(-log(-E + 4) + log(-E + x))*SingularityFunction(x, 4, 0) + 20*(-E*log(-E) + + E*log(-E + x) + x)*SingularityFunction(x, 0, 0) - 20*(-E*log(-E + 4) + E*log(-E + x) + + x - 4)*SingularityFunction(x, 4, 0))/I).expand() + + +def test_composite_beam(): + E = Symbol('E') + I = Symbol('I') + b1 = Beam(2, E, 1.5*I) + b2 = Beam(2, E, I) + b = b1.join(b2, "fixed") + b.apply_load(-20, 0, -1) + b.apply_load(80, 0, -2) + b.apply_load(20, 4, -1) + b.bc_slope = [(0, 0)] + b.bc_deflection = [(0, 0)] + assert b.length == 4 + assert b.second_moment == Piecewise((1.5*I, x <= 2), (I, x <= 4)) + assert b.slope().subs(x, 4) == 120.0/(E*I) + assert b.slope().subs(x, 2) == 80.0/(E*I) + assert int(b.deflection().subs(x, 4).args[0]) == -302 # Coefficient of 1/(E*I) + + l = symbols('l', positive=True) + R1, M1, R2, R3, P = symbols('R1 M1 R2 R3 P') + b1 = Beam(2*l, E, I) + b2 = Beam(2*l, E, I) + b = b1.join(b2,"hinge") + b.apply_load(M1, 0, -2) + b.apply_load(R1, 0, -1) + b.apply_load(R2, l, -1) + b.apply_load(R3, 4*l, -1) + b.apply_load(P, 3*l, -1) + b.bc_slope = [(0, 0)] + b.bc_deflection = [(0, 0), (l, 0), (4*l, 0)] + b.solve_for_reaction_loads(M1, R1, R2, R3) + assert b.reaction_loads == {R3: -P/2, R2: P*Rational(-5, 4), M1: -P*l/4, R1: P*Rational(3, 4)} + assert b.slope().subs(x, 3*l) == -7*P*l**2/(48*E*I) + assert b.deflection().subs(x, 2*l) == 7*P*l**3/(24*E*I) + assert b.deflection().subs(x, 3*l) == 5*P*l**3/(16*E*I) + + # When beams having same second moment are joined. + b1 = Beam(2, 500, 10) + b2 = Beam(2, 500, 10) + b = b1.join(b2, "fixed") + b.apply_load(M1, 0, -2) + b.apply_load(R1, 0, -1) + b.apply_load(R2, 1, -1) + b.apply_load(R3, 4, -1) + b.apply_load(10, 3, -1) + b.bc_slope = [(0, 0)] + b.bc_deflection = [(0, 0), (1, 0), (4, 0)] + b.solve_for_reaction_loads(M1, R1, R2, R3) + assert b.slope() == -2*SingularityFunction(x, 0, 1)/5625 + SingularityFunction(x, 0, 2)/1875\ + - 133*SingularityFunction(x, 1, 2)/135000 + SingularityFunction(x, 3, 2)/1000\ + - 37*SingularityFunction(x, 4, 2)/67500 + assert b.deflection() == -SingularityFunction(x, 0, 2)/5625 + SingularityFunction(x, 0, 3)/5625\ + - 133*SingularityFunction(x, 1, 3)/405000 + SingularityFunction(x, 3, 3)/3000\ + - 37*SingularityFunction(x, 4, 3)/202500 + + +def test_point_cflexure(): + E = Symbol('E') + I = Symbol('I') + b = Beam(10, E, I) + b.apply_load(-4, 0, -1) + b.apply_load(-46, 6, -1) + b.apply_load(10, 2, -1) + b.apply_load(20, 4, -1) + b.apply_load(3, 6, 0) + assert b.point_cflexure() == [Rational(10, 3)] + + E = Symbol('E') + I = Symbol('I') + b = Beam(15, E, I) + r0 = b.apply_support(0, type='pin') + r10 = b.apply_support(10, type='pin') + r15, m15 = b.apply_support(15, type='fixed') + b.apply_rotation_hinge(12) + b.apply_load(-10, 5, -1) + b.apply_load(-5, 10, 0, 15) + b.solve_for_reaction_loads(r0, r10, r15, m15) + assert b.point_cflexure() == [Rational(1200, 163), 12, Rational(163, 12)] + + E = Symbol('E') + I = Symbol('I') + b = Beam(15, E, I) + r0 = b.apply_support(0, type='pin') + r10 = b.apply_support(10, type='pin') + r15, m15 = b.apply_support(15, type='fixed') + b.apply_rotation_hinge(5) + b.apply_rotation_hinge(12) + b.apply_load(-10, 5, -1) + b.apply_load(-5, 10, 0, 15) + b.solve_for_reaction_loads(r0, r10, r15, m15) + with raises(NotImplementedError): + b.point_cflexure() + +def test_remove_load(): + E = Symbol('E') + I = Symbol('I') + b = Beam(4, E, I) + + try: + b.remove_load(2, 1, -1) + # As no load is applied on beam, ValueError should be returned. + except ValueError: + assert True + else: + assert False + + b.apply_load(-3, 0, -2) + b.apply_load(4, 2, -1) + b.apply_load(-2, 2, 2, end = 3) + b.remove_load(-2, 2, 2, end = 3) + assert b.load == -3*SingularityFunction(x, 0, -2) + 4*SingularityFunction(x, 2, -1) + assert b.applied_loads == [(-3, 0, -2, None), (4, 2, -1, None)] + + try: + b.remove_load(1, 2, -1) + # As load of this magnitude was never applied at + # this position, method should return a ValueError. + except ValueError: + assert True + else: + assert False + + b.remove_load(-3, 0, -2) + b.remove_load(4, 2, -1) + assert b.load == 0 + assert b.applied_loads == [] + + +def test_apply_support(): + E = Symbol('E') + I = Symbol('I') + + b = Beam(4, E, I) + b.apply_support(0, "cantilever") + b.apply_load(20, 4, -1) + M_0, R_0 = symbols('M_0, R_0') + b.solve_for_reaction_loads(R_0, M_0) + assert simplify(b.slope()) == simplify((80*SingularityFunction(x, 0, 1) - 10*SingularityFunction(x, 0, 2) + + 10*SingularityFunction(x, 4, 2))/(E*I)) + assert simplify(b.deflection()) == simplify((40*SingularityFunction(x, 0, 2) - 10*SingularityFunction(x, 0, 3)/3 + + 10*SingularityFunction(x, 4, 3)/3)/(E*I)) + + b = Beam(30, E, I) + p0 = b.apply_support(10, "pin") + p1 = b.apply_support(30, "roller") + b.apply_load(-8, 0, -1) + b.apply_load(120, 30, -2) + b.solve_for_reaction_loads(p0, p1) + assert b.slope() == (-4*SingularityFunction(x, 0, 2) + 3*SingularityFunction(x, 10, 2) + + 120*SingularityFunction(x, 30, 1) + SingularityFunction(x, 30, 2) + Rational(4000, 3))/(E*I) + assert b.deflection() == (x*Rational(4000, 3) - 4*SingularityFunction(x, 0, 3)/3 + SingularityFunction(x, 10, 3) + + 60*SingularityFunction(x, 30, 2) + SingularityFunction(x, 30, 3)/3 - 12000)/(E*I) + R_10 = Symbol('R_10') + R_30 = Symbol('R_30') + assert p0 == R_10 + assert b.reaction_loads == {R_10: 6, R_30: 2} + assert b.reaction_loads[p0] == 6 + + b = Beam(8, E, I) + p0, m0 = b.apply_support(0, "fixed") + p1 = b.apply_support(8, "roller") + b.apply_load(-5, 0, 0, 8) + b.solve_for_reaction_loads(p0, m0, p1) + R_0 = Symbol('R_0') + M_0 = Symbol('M_0') + R_8 = Symbol('R_8') + assert p0 == R_0 + assert m0 == M_0 + assert p1 == R_8 + assert b.reaction_loads == {R_0: 25, M_0: -40, R_8: 15} + assert b.reaction_loads[m0] == -40 + + P = Symbol('P', positive=True) + L = Symbol('L', positive=True) + b = Beam(L, E, I) + b.apply_support(0, type='fixed') + b.apply_support(L, type='fixed') + b.apply_load(-P, L/2, -1) + R_0, R_L, M_0, M_L = symbols('R_0, R_L, M_0, M_L') + b.solve_for_reaction_loads(R_0, R_L, M_0, M_L) + assert b.reaction_loads == {R_0: P/2, R_L: P/2, M_0: -L*P/8, M_L: L*P/8} + +def test_apply_rotation_hinge(): + b = Beam(15, 20, 20) + r0, m0 = b.apply_support(0, type='fixed') + r10 = b.apply_support(10, type='pin') + r15 = b.apply_support(15, type='pin') + p7 = b.apply_rotation_hinge(7) + p12 = b.apply_rotation_hinge(12) + b.apply_load(-10, 7, -1) + b.apply_load(-2, 10, 0, 15) + b.solve_for_reaction_loads(r0, m0, r10, r15) + R_0, M_0, R_10, R_15, P_7, P_12 = symbols('R_0, M_0, R_10, R_15, P_7, P_12') + expected_reactions = {R_0: 20/3, M_0: -140/3, R_10: 31/3, R_15: 3} + expected_rotations = {P_7: 2281/2160, P_12: -5137/5184} + reaction_symbols = [r0, m0, r10, r15] + rotation_symbols = [p7, p12] + tolerance = 1e-6 + assert all(abs(b.reaction_loads[r] - expected_reactions[r]) < tolerance for r in reaction_symbols) + assert all(abs(b.rotation_jumps[r] - expected_rotations[r]) < tolerance for r in rotation_symbols) + expected_bending_moment = (140 * SingularityFunction(x, 0, 0) / 3 - 20 * SingularityFunction(x, 0, 1) / 3 + - 11405 * SingularityFunction(x, 7, -1) / 27 + 10 * SingularityFunction(x, 7, 1) + - 31 * SingularityFunction(x, 10, 1) / 3 + SingularityFunction(x, 10, 2) + + 128425 * SingularityFunction(x, 12, -1) / 324 - 3 * SingularityFunction(x, 15, 1) + - SingularityFunction(x, 15, 2)) + assert b.bending_moment().expand() == expected_bending_moment.expand() + expected_slope = (-7*SingularityFunction(x, 0, 1)/60 + SingularityFunction(x, 0, 2)/120 + + 2281*SingularityFunction(x, 7, 0)/2160 - SingularityFunction(x, 7, 2)/80 + + 31*SingularityFunction(x, 10, 2)/2400 - SingularityFunction(x, 10, 3)/1200 + - 5137*SingularityFunction(x, 12, 0)/5184 + 3*SingularityFunction(x, 15, 2)/800 + + SingularityFunction(x, 15, 3)/1200) + assert b.slope().expand() == expected_slope.expand() + expected_deflection = (-7 * SingularityFunction(x, 0, 2) / 120 + SingularityFunction(x, 0, 3) / 360 + + 2281 * SingularityFunction(x, 7, 1) / 2160 - SingularityFunction(x, 7, 3) / 240 + + 31 * SingularityFunction(x, 10, 3) / 7200 - SingularityFunction(x, 10, 4) / 4800 + - 5137 * SingularityFunction(x, 12, 1) / 5184 + SingularityFunction(x, 15, 3) / 800 + + SingularityFunction(x, 15, 4) / 4800) + assert b.deflection().expand() == expected_deflection.expand() + + E = Symbol('E') + I = Symbol('I') + F = Symbol('F') + b = Beam(10, E, I) + r0, m0 = b.apply_support(0, type="fixed") + r10 = b.apply_support(10, type="pin") + b.apply_rotation_hinge(6) + b.apply_load(F, 8, -1) + b.solve_for_reaction_loads(r0, m0, r10) + assert b.reaction_loads == {R_0: -F/2, M_0: 3*F, R_10: -F/2} + assert (b.bending_moment() == -3*F*SingularityFunction(x, 0, 0) + F*SingularityFunction(x, 0, 1)/2 + + 17*F*SingularityFunction(x, 6, -1) - F*SingularityFunction(x, 8, 1) + + F*SingularityFunction(x, 10, 1)/2) + expected_deflection = -(-3*F*SingularityFunction(x, 0, 2)/2 + F*SingularityFunction(x, 0, 3)/12 + + 17*F*SingularityFunction(x, 6, 1) - F*SingularityFunction(x, 8, 3)/6 + + F*SingularityFunction(x, 10, 3)/12)/(E*I) + assert b.deflection().expand() == expected_deflection.expand() + + E = Symbol('E') + I = Symbol('I') + F = Symbol('F') + l1 = Symbol('l1', positive=True) + l2 = Symbol('l2', positive=True) + l3 = Symbol('l3', positive=True) + L = l1 + l2 + l3 + b = Beam(L, E, I) + r0, m0 = b.apply_support(0, type="fixed") + r1 = b.apply_support(L, type="pin") + b.apply_rotation_hinge(l1) + b.apply_load(F, l1+l2, -1) + b.solve_for_reaction_loads(r0, m0, r1) + assert b.reaction_loads[r0] == -F*l3/(l2 + l3) + assert b.reaction_loads[m0] == F*l1*l3/(l2 + l3) + assert b.reaction_loads[r1] == -F*l2/(l2 + l3) + expected_bending_moment = (-F*l1*l3*SingularityFunction(x, 0, 0)/(l2 + l3) + + F*l2*SingularityFunction(x, l1 + l2 + l3, 1)/(l2 + l3) + + F*l3*SingularityFunction(x, 0, 1)/(l2 + l3) - F*SingularityFunction(x, l1 + l2, 1) + - (-2*F*l1**3*l3 - 3*F*l1**2*l2*l3 - 3*F*l1**2*l3**2 + F*l2**3*l3 + 3*F*l2**2*l3**2 + 2*F*l2*l3**3) + *SingularityFunction(x, l1, -1)/(6*l2**2 + 12*l2*l3 + 6*l3**2)) + assert simplify(b.bending_moment().expand()) == simplify(expected_bending_moment.expand()) + +def test_apply_sliding_hinge(): + b = Beam(13, 20, 20) + r0, m0 = b.apply_support(0, type="fixed") + w8 = b.apply_sliding_hinge(8) + r13 = b.apply_support(13, type="pin") + b.apply_load(-10, 5, -1) + b.solve_for_reaction_loads(r0, m0, r13) + R_0, M_0, R_13, W_8 = symbols('R_0, M_0, R_13 W_8') + assert b.reaction_loads == {R_0: 10, M_0: -50, R_13: 0} + tolerance = 1e-6 + assert abs(b.deflection_jumps[w8] - 85/24) < tolerance + assert (b.bending_moment() == 50*SingularityFunction(x, 0, 0) - 10*SingularityFunction(x, 0, 1) + + 10*SingularityFunction(x, 5, 1) - 4250*SingularityFunction(x, 8, -2)/3) + assert (b.deflection() == -SingularityFunction(x, 0, 2)/16 + SingularityFunction(x, 0, 3)/240 + - SingularityFunction(x, 5, 3)/240 + 85*SingularityFunction(x, 8, 0)/24) + + E = Symbol('E') + I = Symbol('I') + I2 = Symbol('I2') + b1 = Beam(5, E, I) + b2 = Beam(8, E, I2) + b = b1.join(b2) + r0, m0 = b.apply_support(0, type="fixed") + b.apply_sliding_hinge(8) + r13 = b.apply_support(13, type="pin") + b.apply_load(-10, 5, -1) + b.solve_for_reaction_loads(r0, m0, r13) + W_8 = Symbol('W_8') + assert b.deflection_jumps == {W_8: 4250/(3*E*I2)} + + E = Symbol('E') + I = Symbol('I') + q = Symbol('q') + l1 = Symbol('l1', positive=True) + l2 = Symbol('l2', positive=True) + l3 = Symbol('l3', positive=True) + L = l1 + l2 + l3 + b = Beam(L, E, I) + r0 = b.apply_support(0, type="pin") + r3 = b.apply_support(l1, type="pin") + b.apply_sliding_hinge(l1 + l2) + r10 = b.apply_support(L, type="pin") + b.apply_load(q, 0, 0, l1) + b.solve_for_reaction_loads(r0, r3, r10) + assert (b.bending_moment() == l1*q*SingularityFunction(x, 0, 1)/2 + l1*q*SingularityFunction(x, l1, 1)/2 + - q*SingularityFunction(x, 0, 2)/2 + q*SingularityFunction(x, l1, 2)/2 + + (-l1**3*l2*q/24 - l1**3*l3*q/24)*SingularityFunction(x, l1 + l2, -2)) + assert b.deflection() ==(l1**3*q*x/24 - l1*q*SingularityFunction(x, 0, 3)/12 + - l1*q*SingularityFunction(x, l1, 3)/12 + q*SingularityFunction(x, 0, 4)/24 + - q*SingularityFunction(x, l1, 4)/24 + + (l1**3*l2*q/24 + l1**3*l3*q/24)*SingularityFunction(x, l1 + l2, 0))/(E*I) + +def test_max_shear_force(): + E = Symbol('E') + I = Symbol('I') + + b = Beam(3, E, I) + R, M = symbols('R, M') + b.apply_load(R, 0, -1) + b.apply_load(M, 0, -2) + b.apply_load(2, 3, -1) + b.apply_load(4, 2, -1) + b.apply_load(2, 2, 0, end=3) + b.solve_for_reaction_loads(R, M) + assert b.max_shear_force() == (Interval(0, 2), 8) + + l = symbols('l', positive=True) + P = Symbol('P') + b = Beam(l, E, I) + R1, R2 = symbols('R1, R2') + b.apply_load(R1, 0, -1) + b.apply_load(R2, l, -1) + b.apply_load(P, 0, 0, end=l) + b.solve_for_reaction_loads(R1, R2) + max_shear = b.max_shear_force() + assert max_shear[0] == 0 + assert simplify(max_shear[1] - (l*Abs(P)/2)) == 0 + + +def test_max_bmoment(): + E = Symbol('E') + I = Symbol('I') + l, P = symbols('l, P', positive=True) + + b = Beam(l, E, I) + R1, R2 = symbols('R1, R2') + b.apply_load(R1, 0, -1) + b.apply_load(R2, l, -1) + b.apply_load(P, l/2, -1) + b.solve_for_reaction_loads(R1, R2) + b.reaction_loads + assert b.max_bmoment() == (l/2, P*l/4) + + b = Beam(l, E, I) + R1, R2 = symbols('R1, R2') + b.apply_load(R1, 0, -1) + b.apply_load(R2, l, -1) + b.apply_load(P, 0, 0, end=l) + b.solve_for_reaction_loads(R1, R2) + assert b.max_bmoment() == (l/2, P*l**2/8) + + +def test_max_deflection(): + E, I, l, F = symbols('E, I, l, F', positive=True) + b = Beam(l, E, I) + b.bc_deflection = [(0, 0),(l, 0)] + b.bc_slope = [(0, 0),(l, 0)] + b.apply_load(F/2, 0, -1) + b.apply_load(-F*l/8, 0, -2) + b.apply_load(F/2, l, -1) + b.apply_load(F*l/8, l, -2) + b.apply_load(-F, l/2, -1) + assert b.max_deflection() == (l/2, F*l**3/(192*E*I)) + +def test_solve_for_ild_reactions(): + E = Symbol('E') + I = Symbol('I') + b = Beam(10, E, I) + b.apply_support(0, type="pin") + b.apply_support(10, type="pin") + R_0, R_10 = symbols('R_0, R_10') + b.solve_for_ild_reactions(1, R_0, R_10) + a = b.ild_variable + assert b.ild_reactions == {R_0: -SingularityFunction(a, 0, 0) + SingularityFunction(a, 0, 1)/10 + - SingularityFunction(a, 10, 1)/10, + R_10: -SingularityFunction(a, 0, 1)/10 + SingularityFunction(a, 10, 0) + + SingularityFunction(a, 10, 1)/10} + + E = Symbol('E') + I = Symbol('I') + F = Symbol('F') + L = Symbol('L', positive=True) + b = Beam(L, E, I) + b.apply_support(L, type="fixed") + b.apply_load(F, 0, -1) + R_L, M_L = symbols('R_L, M_L') + b.solve_for_ild_reactions(F, R_L, M_L) + a = b.ild_variable + assert b.ild_reactions == {R_L: -F*SingularityFunction(a, 0, 0) + F*SingularityFunction(a, L, 0) - F, + M_L: -F*L*SingularityFunction(a, 0, 0) - F*L + F*SingularityFunction(a, 0, 1) + - F*SingularityFunction(a, L, 1)} + + E = Symbol('E') + I = Symbol('I') + b = Beam(20, E, I) + r0 = b.apply_support(0, type="pin") + r5 = b.apply_support(5, type="pin") + r10 = b.apply_support(10, type="pin") + r20, m20 = b.apply_support(20, type="fixed") + b.solve_for_ild_reactions(1, r0, r5, r10, r20, m20) + a = b.ild_variable + assert b.ild_reactions[r0].subs(a, 4) == -Rational(59, 475) + assert b.ild_reactions[r5].subs(a, 4) == -Rational(2296, 2375) + assert b.ild_reactions[r10].subs(a, 4) == Rational(243, 2375) + assert b.ild_reactions[r20].subs(a, 12) == -Rational(83, 475) + assert b.ild_reactions[m20].subs(a, 12) == -Rational(264, 475) + +def test_solve_for_ild_shear(): + E = Symbol('E') + I = Symbol('I') + F = Symbol('F') + L1 = Symbol('L1', positive=True) + L2 = Symbol('L2', positive=True) + b = Beam(L1 + L2, E, I) + r0 = b.apply_support(0, type="pin") + rL = b.apply_support(L1 + L2, type="pin") + b.solve_for_ild_reactions(F, r0, rL) + b.solve_for_ild_shear(L1, F, r0, rL) + a = b.ild_variable + expected_shear = (-F*L1*SingularityFunction(a, 0, 0)/(L1 + L2) - F*L2*SingularityFunction(a, 0, 0)/(L1 + L2) + - F*SingularityFunction(-a, 0, 0) + F*SingularityFunction(a, L1 + L2, 0) + F + + F*SingularityFunction(a, 0, 1)/(L1 + L2) - F*SingularityFunction(a, L1 + L2, 1)/(L1 + L2) + - (-F*L1*SingularityFunction(a, 0, 0)/(L1 + L2) + F*L1*SingularityFunction(a, L1 + L2, 0)/(L1 + L2) + - F*L2*SingularityFunction(a, 0, 0)/(L1 + L2) + F*L2*SingularityFunction(a, L1 + L2, 0)/(L1 + L2) + + 2*F)*SingularityFunction(a, L1, 0)) + assert b.ild_shear.expand() == expected_shear.expand() + + E = Symbol('E') + I = Symbol('I') + b = Beam(20, E, I) + r0 = b.apply_support(0, type="pin") + r5 = b.apply_support(5, type="pin") + r10 = b.apply_support(10, type="pin") + r20, m20 = b.apply_support(20, type="fixed") + b.solve_for_ild_reactions(1, r0, r5, r10, r20, m20) + b.solve_for_ild_shear(6, 1, r0, r5, r10, r20, m20) + a = b.ild_variable + assert b.ild_shear.subs(a, 12) == Rational(96, 475) + assert b.ild_shear.subs(a, 4) == -Rational(216, 2375) + +def test_solve_for_ild_moment(): + E = Symbol('E') + I = Symbol('I') + F = Symbol('F') + L1 = Symbol('L1', positive=True) + L2 = Symbol('L2', positive=True) + b = Beam(L1 + L2, E, I) + r0 = b.apply_support(0, type="pin") + rL = b.apply_support(L1 + L2, type="pin") + a = b.ild_variable + b.solve_for_ild_reactions(F, r0, rL) + b.solve_for_ild_moment(L1, F, r0, rL) + assert b.ild_moment.subs(a, 3).subs(L1, 5).subs(L2, 5) == -3*F/2 + + E = Symbol('E') + I = Symbol('I') + b = Beam(20, E, I) + r0 = b.apply_support(0, type="pin") + r5 = b.apply_support(5, type="pin") + r10 = b.apply_support(10, type="pin") + r20, m20 = b.apply_support(20, type="fixed") + b.solve_for_ild_reactions(1, r0, r5, r10, r20, m20) + b.solve_for_ild_moment(5, 1, r0, r5, r10, r20, m20) + assert b.ild_moment.subs(a, 12) == -Rational(96, 475) + assert b.ild_moment.subs(a, 4) == Rational(36, 95) + +def test_ild_with_rotation_hinge(): + E = Symbol('E') + I = Symbol('I') + F = Symbol('F') + L1 = Symbol('L1', positive=True) + L2 = Symbol('L2', positive=True) + L3 = Symbol('L3', positive=True) + b = Beam(L1 + L2 + L3, E, I) + r0 = b.apply_support(0, type="pin") + r1 = b.apply_support(L1 + L2, type="pin") + r2 = b.apply_support(L1 + L2 + L3, type="pin") + b.apply_rotation_hinge(L1 + L2) + b.solve_for_ild_reactions(F, r0, r1, r2) + a = b.ild_variable + assert b.ild_reactions[r0].subs(a, 4).subs(L1, 5).subs(L2, 5).subs(L3, 10) == -3*F/5 + assert b.ild_reactions[r0].subs(a, -10).subs(L1, 5).subs(L2, 5).subs(L3, 10) == 0 + assert b.ild_reactions[r0].subs(a, 25).subs(L1, 5).subs(L2, 5).subs(L3, 10) == 0 + assert b.ild_reactions[r1].subs(a, 4).subs(L1, 5).subs(L2, 5).subs(L3, 10) == -2*F/5 + assert b.ild_reactions[r2].subs(a, 18).subs(L1, 5).subs(L2, 5).subs(L3, 10) == -4*F/5 + b.solve_for_ild_shear(L1, F, r0, r1, r2) + assert b.ild_shear.subs(a, 7).subs(L1, 5).subs(L2, 5).subs(L3, 10) == -3*F/10 + assert b.ild_shear.subs(a, 70).subs(L1, 5).subs(L2, 5).subs(L3, 10) == 0 + b.solve_for_ild_moment(L1, F, r0, r1, r2) + assert b.ild_moment.subs(a, 1).subs(L1, 5).subs(L2, 5).subs(L3, 10) == -F/2 + assert b.ild_moment.subs(a, 8).subs(L1, 5).subs(L2, 5).subs(L3, 10) == -F + +def test_ild_with_sliding_hinge(): + b = Beam(13, 200, 200) + r0 = b.apply_support(0, type="pin") + r6 = b.apply_support(6, type="pin") + r13, m13 = b.apply_support(13, type="fixed") + w3 = b.apply_sliding_hinge(3) + b.solve_for_ild_reactions(1, r0, r6, r13, m13) + a = b.ild_variable + assert b.ild_reactions[r0].subs(a, 3) == -1 + assert b.ild_reactions[r6].subs(a, 3) == Rational(9, 14) + assert b.ild_reactions[r13].subs(a, 9) == -Rational(207, 343) + assert b.ild_reactions[m13].subs(a, 9) == -Rational(60, 49) + assert b.ild_reactions[m13].subs(a, 15) == 0 + assert b.ild_reactions[m13].subs(a, -3) == 0 + assert b.ild_deflection_jumps[w3].subs(a, 9) == -Rational(9, 35000) + b.solve_for_ild_shear(7, 1, r0, r6, r13, m13) + assert b.ild_shear.subs(a, 8) == -Rational(200, 343) + b.solve_for_ild_moment(8, 1, r0, r6, r13, m13) + assert b.ild_moment.subs(a, 3) == -Rational(12, 7) + +def test_Beam3D(): + l, E, G, I, A = symbols('l, E, G, I, A') + R1, R2, R3, R4 = symbols('R1, R2, R3, R4') + + b = Beam3D(l, E, G, I, A) + m, q = symbols('m, q') + b.apply_load(q, 0, 0, dir="y") + b.apply_moment_load(m, 0, 0, dir="z") + b.bc_slope = [(0, [0, 0, 0]), (l, [0, 0, 0])] + b.bc_deflection = [(0, [0, 0, 0]), (l, [0, 0, 0])] + b.solve_slope_deflection() + + assert b.polar_moment() == 2*I + assert b.shear_force() == [0, -q*x, 0] + assert b.shear_stress() == [0, -q*x/A, 0] + assert b.axial_stress() == 0 + assert b.bending_moment() == [0, 0, -m*x + q*x**2/2] + expected_deflection = (x*(A*G*q*x**3/4 + A*G*x**2*(-l*(A*G*l*(l*q - 2*m) + + 12*E*I*q)/(A*G*l**2 + 12*E*I)/2 - m) + 3*E*I*l*(A*G*l*(l*q - 2*m) + + 12*E*I*q)/(A*G*l**2 + 12*E*I) + x*(-A*G*l**2*q/2 + + 3*A*G*l**2*(A*G*l*(l*q - 2*m) + 12*E*I*q)/(A*G*l**2 + 12*E*I)/4 + + A*G*l*m*Rational(3, 2) - 3*E*I*q))/(6*A*E*G*I)) + dx, dy, dz = b.deflection() + assert dx == dz == 0 + assert simplify(dy - expected_deflection) == 0 + + b2 = Beam3D(30, E, G, I, A, x) + b2.apply_load(50, start=0, order=0, dir="y") + b2.bc_deflection = [(0, [0, 0, 0]), (30, [0, 0, 0])] + b2.apply_load(R1, start=0, order=-1, dir="y") + b2.apply_load(R2, start=30, order=-1, dir="y") + b2.solve_for_reaction_loads(R1, R2) + assert b2.reaction_loads == {R1: -750, R2: -750} + + b2.solve_slope_deflection() + assert b2.slope() == [0, 0, 25*x**3/(3*E*I) - 375*x**2/(E*I) + 3750*x/(E*I)] + expected_deflection = 25*x**4/(12*E*I) - 125*x**3/(E*I) + 1875*x**2/(E*I) - \ + 25*x**2/(A*G) + 750*x/(A*G) + dx, dy, dz = b2.deflection() + assert dx == dz == 0 + assert dy == expected_deflection + + # Test for solve_for_reaction_loads + b3 = Beam3D(30, E, G, I, A, x) + b3.apply_load(8, start=0, order=0, dir="y") + b3.apply_load(9*x, start=0, order=0, dir="z") + b3.apply_load(R1, start=0, order=-1, dir="y") + b3.apply_load(R2, start=30, order=-1, dir="y") + b3.apply_load(R3, start=0, order=-1, dir="z") + b3.apply_load(R4, start=30, order=-1, dir="z") + b3.solve_for_reaction_loads(R1, R2, R3, R4) + assert b3.reaction_loads == {R1: -120, R2: -120, R3: -1350, R4: -2700} + + +def test_polar_moment_Beam3D(): + l, E, G, A, I1, I2 = symbols('l, E, G, A, I1, I2') + I = [I1, I2] + + b = Beam3D(l, E, G, I, A) + assert b.polar_moment() == I1 + I2 + + +def test_parabolic_loads(): + + E, I, L = symbols('E, I, L', positive=True, real=True) + R, M, P = symbols('R, M, P', real=True) + + # cantilever beam fixed at x=0 and parabolic distributed loading across + # length of beam + beam = Beam(L, E, I) + + beam.bc_deflection.append((0, 0)) + beam.bc_slope.append((0, 0)) + beam.apply_load(R, 0, -1) + beam.apply_load(M, 0, -2) + + # parabolic load + beam.apply_load(1, 0, 2) + + beam.solve_for_reaction_loads(R, M) + + assert beam.reaction_loads[R] == -L**3/3 + + # cantilever beam fixed at x=0 and parabolic distributed loading across + # first half of beam + beam = Beam(2*L, E, I) + + beam.bc_deflection.append((0, 0)) + beam.bc_slope.append((0, 0)) + beam.apply_load(R, 0, -1) + beam.apply_load(M, 0, -2) + + # parabolic load from x=0 to x=L + beam.apply_load(1, 0, 2, end=L) + + beam.solve_for_reaction_loads(R, M) + + # result should be the same as the prior example + assert beam.reaction_loads[R] == -L**3/3 + + # check constant load + beam = Beam(2*L, E, I) + beam.apply_load(P, 0, 0, end=L) + loading = beam.load.xreplace({L: 10, E: 20, I: 30, P: 40}) + assert loading.xreplace({x: 5}) == 40 + assert loading.xreplace({x: 15}) == 0 + + # check ramp load + beam = Beam(2*L, E, I) + beam.apply_load(P, 0, 1, end=L) + assert beam.load == (P*SingularityFunction(x, 0, 1) - + P*SingularityFunction(x, L, 1) - + P*L*SingularityFunction(x, L, 0)) + + # check higher order load: x**8 load from x=0 to x=L + beam = Beam(2*L, E, I) + beam.apply_load(P, 0, 8, end=L) + loading = beam.load.xreplace({L: 10, E: 20, I: 30, P: 40}) + assert loading.xreplace({x: 5}) == 40*5**8 + assert loading.xreplace({x: 15}) == 0 + + +def test_cross_section(): + I = Symbol('I') + l = Symbol('l') + E = Symbol('E') + C3, C4 = symbols('C3, C4') + a, c, g, h, r, n = symbols('a, c, g, h, r, n') + + # test for second_moment and cross_section setter + b0 = Beam(l, E, I) + assert b0.second_moment == I + assert b0.cross_section == None + b0.cross_section = Circle((0, 0), 5) + assert b0.second_moment == pi*Rational(625, 4) + assert b0.cross_section == Circle((0, 0), 5) + b0.second_moment = 2*n - 6 + assert b0.second_moment == 2*n-6 + assert b0.cross_section == None + with raises(ValueError): + b0.second_moment = Circle((0, 0), 5) + + # beam with a circular cross-section + b1 = Beam(50, E, Circle((0, 0), r)) + assert b1.cross_section == Circle((0, 0), r) + assert b1.second_moment == pi*r*Abs(r)**3/4 + + b1.apply_load(-10, 0, -1) + b1.apply_load(R1, 5, -1) + b1.apply_load(R2, 50, -1) + b1.apply_load(90, 45, -2) + b1.solve_for_reaction_loads(R1, R2) + assert b1.load == (-10*SingularityFunction(x, 0, -1) + 82*SingularityFunction(x, 5, -1)/S(9) + + 90*SingularityFunction(x, 45, -2) + 8*SingularityFunction(x, 50, -1)/9) + assert b1.bending_moment() == (10*SingularityFunction(x, 0, 1) - 82*SingularityFunction(x, 5, 1)/9 + - 90*SingularityFunction(x, 45, 0) - 8*SingularityFunction(x, 50, 1)/9) + q = (-5*SingularityFunction(x, 0, 2) + 41*SingularityFunction(x, 5, 2)/S(9) + + 90*SingularityFunction(x, 45, 1) + 4*SingularityFunction(x, 50, 2)/S(9))/(pi*E*r*Abs(r)**3) + assert b1.slope() == C3 + 4*q + q = (-5*SingularityFunction(x, 0, 3)/3 + 41*SingularityFunction(x, 5, 3)/27 + 45*SingularityFunction(x, 45, 2) + + 4*SingularityFunction(x, 50, 3)/27)/(pi*E*r*Abs(r)**3) + assert b1.deflection() == C3*x + C4 + 4*q + + # beam with a recatangular cross-section + b2 = Beam(20, E, Polygon((0, 0), (a, 0), (a, c), (0, c))) + assert b2.cross_section == Polygon((0, 0), (a, 0), (a, c), (0, c)) + assert b2.second_moment == a*c**3/12 + # beam with a triangular cross-section + b3 = Beam(15, E, Triangle((0, 0), (g, 0), (g/2, h))) + assert b3.cross_section == Triangle(Point2D(0, 0), Point2D(g, 0), Point2D(g/2, h)) + assert b3.second_moment == g*h**3/36 + + # composite beam + b = b2.join(b3, "fixed") + b.apply_load(-30, 0, -1) + b.apply_load(65, 0, -2) + b.apply_load(40, 0, -1) + b.bc_slope = [(0, 0)] + b.bc_deflection = [(0, 0)] + + assert b.second_moment == Piecewise((a*c**3/12, x <= 20), (g*h**3/36, x <= 35)) + assert b.cross_section == None + assert b.length == 35 + assert b.slope().subs(x, 7) == 8400/(E*a*c**3) + assert b.slope().subs(x, 25) == 52200/(E*g*h**3) + 39600/(E*a*c**3) + assert b.deflection().subs(x, 30) == -537000/(E*g*h**3) - 712000/(E*a*c**3) + +def test_max_shear_force_Beam3D(): + x = symbols('x') + b = Beam3D(20, 40, 21, 100, 25) + b.apply_load(15, start=0, order=0, dir="z") + b.apply_load(12*x, start=0, order=0, dir="y") + b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + assert b.max_shear_force() == [(0, 0), (20, 2400), (20, 300)] + +def test_max_bending_moment_Beam3D(): + x = symbols('x') + b = Beam3D(20, 40, 21, 100, 25) + b.apply_load(15, start=0, order=0, dir="z") + b.apply_load(12*x, start=0, order=0, dir="y") + b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + assert b.max_bmoment() == [(0, 0), (20, 3000), (20, 16000)] + +def test_max_deflection_Beam3D(): + x = symbols('x') + b = Beam3D(20, 40, 21, 100, 25) + b.apply_load(15, start=0, order=0, dir="z") + b.apply_load(12*x, start=0, order=0, dir="y") + b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] + b.solve_slope_deflection() + c = sympify("495/14") + p = sympify("-10 + 10*sqrt(10793)/43") + q = sympify("(10 - 10*sqrt(10793)/43)**3/160 - 20/7 + (10 - 10*sqrt(10793)/43)**4/6400 + 20*sqrt(10793)/301 + 27*(10 - 10*sqrt(10793)/43)**2/560") + assert b.max_deflection() == [(0, 0), (10, c), (p, q)] + +def test_torsion_Beam3D(): + x = symbols('x') + b = Beam3D(20, 40, 21, 100, 25) + b.apply_moment_load(15, 5, -2, dir='x') + b.apply_moment_load(25, 10, -2, dir='x') + b.apply_moment_load(-5, 20, -2, dir='x') + b.solve_for_torsion() + assert b.angular_deflection().subs(x, 3) == sympify("1/40") + assert b.angular_deflection().subs(x, 9) == sympify("17/280") + assert b.angular_deflection().subs(x, 12) == sympify("53/840") + assert b.angular_deflection().subs(x, 17) == sympify("2/35") + assert b.angular_deflection().subs(x, 20) == sympify("3/56") diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_cable.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_cable.py new file mode 100644 index 0000000000000000000000000000000000000000..95ae7997af20f31cbd1b36df4a494f66968ecf53 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_cable.py @@ -0,0 +1,83 @@ +from sympy.physics.continuum_mechanics.cable import Cable +from sympy.core.symbol import Symbol + + +def test_cable(): + c = Cable(('A', 0, 10), ('B', 10, 10)) + assert c.supports == {'A': [0, 10], 'B': [10, 10]} + assert c.left_support == [0, 10] + assert c.right_support == [10, 10] + assert c.loads == {'distributed': {}, 'point_load': {}} + assert c.loads_position == {} + assert c.length == 0 + assert c.reaction_loads == {Symbol("R_A_x"): 0, Symbol("R_A_y"): 0, Symbol("R_B_x"): 0, Symbol("R_B_y"): 0} + + # tests for change_support method + c.change_support('A', ('C', 12, 3)) + assert c.supports == {'B': [10, 10], 'C': [12, 3]} + assert c.left_support == [10, 10] + assert c.right_support == [12, 3] + assert c.reaction_loads == {Symbol("R_B_x"): 0, Symbol("R_B_y"): 0, Symbol("R_C_x"): 0, Symbol("R_C_y"): 0} + + c.change_support('C', ('A', 0, 10)) + + # tests for apply_load method for point loads + c.apply_load(-1, ('X', 2, 5, 3, 30)) + c.apply_load(-1, ('Y', 5, 8, 5, 60)) + assert c.loads == {'distributed': {}, 'point_load': {'X': [3, 30], 'Y': [5, 60]}} + assert c.loads_position == {'X': [2, 5], 'Y': [5, 8]} + assert c.length == 0 + assert c.reaction_loads == {Symbol("R_A_x"): 0, Symbol("R_A_y"): 0, Symbol("R_B_x"): 0, Symbol("R_B_y"): 0} + + # tests for remove_loads method + c.remove_loads('X') + assert c.loads == {'distributed': {}, 'point_load': {'Y': [5, 60]}} + assert c.loads_position == {'Y': [5, 8]} + assert c.length == 0 + assert c.reaction_loads == {Symbol("R_A_x"): 0, Symbol("R_A_y"): 0, Symbol("R_B_x"): 0, Symbol("R_B_y"): 0} + + c.remove_loads('Y') + + #tests for apply_load method for distributed load + c.apply_load(0, ('Z', 9)) + assert c.loads == {'distributed': {'Z': 9}, 'point_load': {}} + assert c.loads_position == {} + assert c.length == 0 + assert c.reaction_loads == {Symbol("R_A_x"): 0, Symbol("R_A_y"): 0, Symbol("R_B_x"): 0, Symbol("R_B_y"): 0} + + # tests for apply_length method + c.apply_length(20) + assert c.length == 20 + + del c + # tests for solve method + # for point loads + c = Cable(("A", 0, 10), ("B", 5.5, 8)) + c.apply_load(-1, ('Z', 2, 7.26, 3, 270)) + c.apply_load(-1, ('X', 4, 6, 8, 270)) + c.solve() + #assert c.tension == {Symbol("Z_X"): 4.79150773600774, Symbol("X_B"): 6.78571428571429, Symbol("A_Z"): 6.89488895397307} + assert abs(c.tension[Symbol("A_Z")] - 6.89488895397307) < 10e-12 + assert abs(c.tension[Symbol("Z_X")] - 4.79150773600774) < 10e-12 + assert abs(c.tension[Symbol("X_B")] - 6.78571428571429) < 10e-12 + #assert c.reaction_loads == {Symbol("R_A_x"): -4.06504065040650, Symbol("R_A_y"): 5.56910569105691, Symbol("R_B_x"): 4.06504065040650, Symbol("R_B_y"): 5.43089430894309} + assert abs(c.reaction_loads[Symbol("R_A_x")] + 4.06504065040650) < 10e-12 + assert abs(c.reaction_loads[Symbol("R_A_y")] - 5.56910569105691) < 10e-12 + assert abs(c.reaction_loads[Symbol("R_B_x")] - 4.06504065040650) < 10e-12 + assert abs(c.reaction_loads[Symbol("R_B_y")] - 5.43089430894309) < 10e-12 + assert abs(c.length - 8.25609584845190) < 10e-12 + + del c + # tests for solve method + # for distributed loads + c=Cable(("A", 0, 40),("B", 100, 20)) + c.apply_load(0, ("X", 850)) + c.solve(58.58, 0) + + # assert c.tension['distributed'] == 36456.8485*sqrt(0.000543529004799705*(X + 0.00135624381275735)**2 + 1) + assert abs(c.tension_at(0) - 61717.4130533677) < 10e-11 + assert abs(c.tension_at(40) - 39738.0809048449) < 10e-11 + assert abs(c.reaction_loads[Symbol("R_A_x")] - 36465.0000000000) < 10e-11 + assert abs(c.reaction_loads[Symbol("R_A_y")] + 49793.0000000000) < 10e-11 + assert abs(c.reaction_loads[Symbol("R_B_x")] - 44399.9537590861) < 10e-11 + assert abs(c.reaction_loads[Symbol("R_B_y")] - 42868.2071025955 ) < 10e-11 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_truss.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_truss.py new file mode 100644 index 0000000000000000000000000000000000000000..61c89c9e09386257c7c69909dfdb0f37cda8627d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/continuum_mechanics/tests/test_truss.py @@ -0,0 +1,100 @@ +from sympy.core.symbol import Symbol, symbols +from sympy.physics.continuum_mechanics.truss import Truss +from sympy import sqrt + + +def test_truss(): + A = Symbol('A') + B = Symbol('B') + C = Symbol('C') + AB, BC, AC = symbols('AB, BC, AC') + P = Symbol('P') + + t = Truss() + assert t.nodes == [] + assert t.node_labels == [] + assert t.node_positions == [] + assert t.members == {} + assert t.loads == {} + assert t.supports == {} + assert t.reaction_loads == {} + assert t.internal_forces == {} + + # testing the add_node method + t.add_node((A, 0, 0), (B, 2, 2), (C, 3, 0)) + assert t.nodes == [(A, 0, 0), (B, 2, 2), (C, 3, 0)] + assert t.node_labels == [A, B, C] + assert t.node_positions == [(0, 0), (2, 2), (3, 0)] + assert t.loads == {} + assert t.supports == {} + assert t.reaction_loads == {} + + # testing the remove_node method + t.remove_node(C) + assert t.nodes == [(A, 0, 0), (B, 2, 2)] + assert t.node_labels == [A, B] + assert t.node_positions == [(0, 0), (2, 2)] + assert t.loads == {} + assert t.supports == {} + + t.add_node((C, 3, 0)) + + # testing the add_member method + t.add_member((AB, A, B), (BC, B, C), (AC, A, C)) + assert t.members == {AB: [A, B], BC: [B, C], AC: [A, C]} + assert t.internal_forces == {AB: 0, BC: 0, AC: 0} + + # testing the remove_member method + t.remove_member(BC) + assert t.members == {AB: [A, B], AC: [A, C]} + assert t.internal_forces == {AB: 0, AC: 0} + + t.add_member((BC, B, C)) + + D, CD = symbols('D, CD') + + # testing the change_label methods + t.change_node_label((B, D)) + assert t.nodes == [(A, 0, 0), (D, 2, 2), (C, 3, 0)] + assert t.node_labels == [A, D, C] + assert t.loads == {} + assert t.supports == {} + assert t.members == {AB: [A, D], BC: [D, C], AC: [A, C]} + + t.change_member_label((BC, CD)) + assert t.members == {AB: [A, D], CD: [D, C], AC: [A, C]} + assert t.internal_forces == {AB: 0, CD: 0, AC: 0} + + + # testing the apply_load method + t.apply_load((A, P, 90), (A, P/4, 90), (A, 2*P,45), (D, P/2, 90)) + assert t.loads == {A: [[P, 90], [P/4, 90], [2*P, 45]], D: [[P/2, 90]]} + assert t.loads[A] == [[P, 90], [P/4, 90], [2*P, 45]] + + # testing the remove_load method + t.remove_load((A, P/4, 90)) + assert t.loads == {A: [[P, 90], [2*P, 45]], D: [[P/2, 90]]} + assert t.loads[A] == [[P, 90], [2*P, 45]] + + # testing the apply_support method + t.apply_support((A, "pinned"), (D, "roller")) + assert t.supports == {A: 'pinned', D: 'roller'} + assert t.reaction_loads == {} + assert t.loads == {A: [[P, 90], [2*P, 45], [Symbol('R_A_x'), 0], [Symbol('R_A_y'), 90]], D: [[P/2, 90], [Symbol('R_D_y'), 90]]} + + # testing the remove_support method + t.remove_support(A) + assert t.supports == {D: 'roller'} + assert t.reaction_loads == {} + assert t.loads == {A: [[P, 90], [2*P, 45]], D: [[P/2, 90], [Symbol('R_D_y'), 90]]} + + t.apply_support((A, "pinned")) + + # testing the solve method + t.solve() + assert t.reaction_loads['R_A_x'] == -sqrt(2)*P + assert t.reaction_loads['R_A_y'] == -sqrt(2)*P - P + assert t.reaction_loads['R_D_y'] == -P/2 + assert t.internal_forces[AB]/P == 0 + assert t.internal_forces[CD] == 0 + assert t.internal_forces[AC] == 0 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a43a7f4a74d83229bbf9da55fe031e3b1c8ebd5c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/__pycache__/control_plots.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/__pycache__/control_plots.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6ee52ffce51341adeedfc5b41e93b8232872f4d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/__pycache__/control_plots.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6226cea201b18ac07ea943485789104acad52afc Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/__pycache__/test_control_plots.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/__pycache__/test_control_plots.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa13d408c69a303d4e0a7f4157694a58cb9325d6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/__pycache__/test_control_plots.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/test_control_plots.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/test_control_plots.py new file mode 100644 index 0000000000000000000000000000000000000000..05836c806f93c4a8ff375efe2b8bd5f993db7502 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/test_control_plots.py @@ -0,0 +1,332 @@ +from math import isclose +from sympy.core.numbers import I, all_close +from sympy.core.symbol import Dummy +from sympy.functions.elementary.complexes import (Abs, arg) +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.abc import s, p, a +from sympy import pi +from sympy.external import import_module +from sympy.physics.control.control_plots import \ + (pole_zero_numerical_data, pole_zero_plot, step_response_numerical_data, + step_response_plot, impulse_response_numerical_data, + impulse_response_plot, ramp_response_numerical_data, + ramp_response_plot, bode_magnitude_numerical_data, + bode_phase_numerical_data, bode_plot, nyquist_plot_expr, + nichols_plot_expr) + +from sympy.physics.control.lti import (TransferFunction, + Series, Parallel, TransferFunctionMatrix) +from sympy.testing.pytest import raises, skip + +matplotlib = import_module( + 'matplotlib', import_kwargs={'fromlist': ['pyplot']}, + catch=(RuntimeError,)) + +numpy = import_module('numpy') + +tf1 = TransferFunction(1, p**2 + 0.5*p + 2, p) +tf2 = TransferFunction(p, 6*p**2 + 3*p + 1, p) +tf3 = TransferFunction(p, p**3 - 1, p) +tf4 = TransferFunction(10, p**3, p) +tf5 = TransferFunction(5, s**2 + 2*s + 10, s) +tf6 = TransferFunction(1, 1, s) +tf7 = TransferFunction(4*s*3 + 9*s**2 + 0.1*s + 11, 8*s**6 + 9*s**4 + 11, s) +tf8 = TransferFunction(5, s**2 + (2+I)*s + 10, s) + +ser1 = Series(tf4, TransferFunction(1, p - 5, p)) +ser2 = Series(tf3, TransferFunction(p, p + 2, p)) + +par1 = Parallel(tf1, tf2) + + +def _to_tuple(a, b): + return tuple(a), tuple(b) + +def _trim_tuple(a, b): + a, b = _to_tuple(a, b) + return tuple(a[0: 2] + a[len(a)//2 : len(a)//2 + 1] + a[-2:]), \ + tuple(b[0: 2] + b[len(b)//2 : len(b)//2 + 1] + b[-2:]) + +def y_coordinate_equality(plot_data_func, evalf_func, system): + """Checks whether the y-coordinate value of the plotted + data point is equal to the value of the function at a + particular x.""" + x, y = plot_data_func(system) + x, y = _trim_tuple(x, y) + y_exp = tuple(evalf_func(system, x_i) for x_i in x) + return all(Abs(y_exp_i - y_i) < 1e-8 for y_exp_i, y_i in zip(y_exp, y)) + + +def test_errors(): + if not matplotlib: + skip("Matplotlib not the default backend") + + # Invalid `system` check + tfm = TransferFunctionMatrix([[tf6, tf5], [tf5, tf6]]) + expr = 1/(s**2 - 1) + raises(NotImplementedError, lambda: pole_zero_plot(tfm)) + raises(NotImplementedError, lambda: pole_zero_numerical_data(expr)) + raises(NotImplementedError, lambda: impulse_response_plot(expr)) + raises(NotImplementedError, lambda: impulse_response_numerical_data(tfm)) + raises(NotImplementedError, lambda: step_response_plot(tfm)) + raises(NotImplementedError, lambda: step_response_numerical_data(expr)) + raises(NotImplementedError, lambda: ramp_response_plot(expr)) + raises(NotImplementedError, lambda: ramp_response_numerical_data(tfm)) + raises(NotImplementedError, lambda: bode_plot(tfm)) + + # More than 1 variables + tf_a = TransferFunction(a, s + 1, s) + raises(ValueError, lambda: pole_zero_plot(tf_a)) + raises(ValueError, lambda: pole_zero_numerical_data(tf_a)) + raises(ValueError, lambda: impulse_response_plot(tf_a)) + raises(ValueError, lambda: impulse_response_numerical_data(tf_a)) + raises(ValueError, lambda: step_response_plot(tf_a)) + raises(ValueError, lambda: step_response_numerical_data(tf_a)) + raises(ValueError, lambda: ramp_response_plot(tf_a)) + raises(ValueError, lambda: ramp_response_numerical_data(tf_a)) + raises(ValueError, lambda: bode_plot(tf_a)) + + # lower_limit > 0 for response plots + raises(ValueError, lambda: impulse_response_plot(tf1, lower_limit=-1)) + raises(ValueError, lambda: step_response_plot(tf1, lower_limit=-0.1)) + raises(ValueError, lambda: ramp_response_plot(tf1, lower_limit=-4/3)) + + # slope in ramp_response_plot() is negative + raises(ValueError, lambda: ramp_response_plot(tf1, slope=-0.1)) + + # incorrect frequency or phase unit + raises(ValueError, lambda: bode_plot(tf1,freq_unit = 'hz')) + raises(ValueError, lambda: bode_plot(tf1,phase_unit = 'degree')) + + +def test_pole_zero(): + + def pz_tester(sys, expected_value): + _z, _p = pole_zero_numerical_data(sys) + z_check = all_close(_z, expected_value[0]) + p_check = all_close(_p, expected_value[1]) + return p_check and z_check + + exp1 = [[], [-0.24999999999999994-1.3919410907075054j, -0.24999999999999994+1.3919410907075054j]] + exp2 = [[0.0], [-0.25-0.3227486121839514j, -0.25+0.3227486121839514j]] + exp3 = [[0.0], [0.9999999999999998+0j, -0.5000000000000004-0.8660254037844395j, + -0.5000000000000004+0.8660254037844395j]] + exp4 = [[], [0.0, 0.0, 0.0, 5.0]] + exp5 = [[-5.645751311064592, -0.5000000000000008, -0.3542486889354093], + [-0.24999999999999986-0.322748612183951348j, + -0.2499999999999998+0.32274861218395134j, + -0.24999999999999986-1.3919410907075052j, + -0.2499999999999998+1.3919410907075052j]] + exp6 = [[], [-1.1641600331447917-3.545808351896439j, + -0.8358399668552097+2.5458083518964383j]] + + assert pz_tester(tf1, exp1) + assert pz_tester(tf2, exp2) + assert pz_tester(tf3, exp3) + assert pz_tester(ser1, exp4) + assert pz_tester(par1, exp5) + assert pz_tester(tf8, exp6) + + +def test_bode(): + if not numpy: + skip("NumPy is required for this test") + + def bode_phase_evalf(system, point): + expr = system.to_expr() + _w = Dummy("w", real=True) + w_expr = expr.subs({system.var: I*_w}) + return arg(w_expr).subs({_w: point}).evalf() + + def bode_mag_evalf(system, point): + expr = system.to_expr() + _w = Dummy("w", real=True) + w_expr = expr.subs({system.var: I*_w}) + return 20*log(Abs(w_expr), 10).subs({_w: point}).evalf() + + def test_bode_data(sys): + return y_coordinate_equality(bode_magnitude_numerical_data, bode_mag_evalf, sys) \ + and y_coordinate_equality(bode_phase_numerical_data, bode_phase_evalf, sys) + + assert test_bode_data(tf1) + assert test_bode_data(tf2) + assert test_bode_data(tf3) + assert test_bode_data(tf4) + assert test_bode_data(tf5) + + +def check_point_accuracy(a, b): + return all(isclose(*_, rel_tol=1e-1, abs_tol=1e-6 + ) for _ in zip(a, b)) + + +def test_impulse_response(): + if not numpy: + skip("NumPy is required for this test") + + def impulse_res_tester(sys, expected_value): + x, y = _to_tuple(*impulse_response_numerical_data(sys, + adaptive=False, n=10)) + x_check = check_point_accuracy(x, expected_value[0]) + y_check = check_point_accuracy(y, expected_value[1]) + return x_check and y_check + + exp1 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, + 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), + (0.0, 0.544019738507865, 0.01993849743234938, -0.31140243360893216, -0.022852779906491996, 0.1778306498155759, + 0.01962941084328499, -0.1013115194573652, -0.014975541213105696, 0.0575789724730714)) + exp2 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, + 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.1666666675, 0.08389223412935855, + 0.02338051973475047, -0.014966807776379383, -0.034645954223054234, -0.040560075735512804, + -0.037658628907103885, -0.030149507719590022, -0.021162090730736834, -0.012721292737437523)) + exp3 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, + 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (4.369893391586999e-09, 1.1750333000630964, + 3.2922404058312473, 9.432290008148343, 28.37098083007151, 86.18577464367974, 261.90356653762115, + 795.6538758627842, 2416.9920942096983, 7342.159505206647)) + exp4 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, + 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 6.17283950617284, 24.69135802469136, + 55.555555555555564, 98.76543209876544, 154.320987654321, 222.22222222222226, 302.46913580246917, + 395.0617283950618, 500.0)) + exp5 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, + 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, -0.10455606138085417, + 0.06757671513476461, -0.03234567568833768, 0.013582514927757873, -0.005273419510705473, + 0.0019364083003354075, -0.000680070134067832, 0.00022969845960406913, -7.476094359583917e-05)) + exp6 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, + 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), + (-6.016699583000218e-09, 0.35039802056107394, 3.3728423827689884, 12.119846079276684, + 25.86101014293389, 29.352480635282088, -30.49475907497664, -273.8717189554019, -863.2381702029659, + -1747.0262164682233)) + exp7 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, + 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, + 8.88888888888889, 10.0), (0.0, 18.934638095560974, 5346.93244680907, 1384609.8718249386, + 358161126.65801865, 92645770015.70108, 23964739753087.42, 6198974342083139.0, 1.603492601616059e+18, + 4.147764422869658e+20)) + + assert impulse_res_tester(tf1, exp1) + assert impulse_res_tester(tf2, exp2) + assert impulse_res_tester(tf3, exp3) + assert impulse_res_tester(tf4, exp4) + assert impulse_res_tester(tf5, exp5) + assert impulse_res_tester(tf7, exp6) + assert impulse_res_tester(ser1, exp7) + + +def test_step_response(): + if not numpy: + skip("NumPy is required for this test") + + def step_res_tester(sys, expected_value): + x, y = _to_tuple(*step_response_numerical_data(sys, + adaptive=False, n=10)) + x_check = check_point_accuracy(x, expected_value[0]) + y_check = check_point_accuracy(y, expected_value[1]) + return x_check and y_check + + exp1 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, + 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), + (-1.9193285738516863e-08, 0.42283495488246126, 0.7840485977945262, 0.5546841805655717, + 0.33903033806932087, 0.4627251747410237, 0.5909907598988051, 0.5247213989553071, + 0.4486997874319281, 0.4839358435839171)) + exp2 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, + 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), + (0.0, 0.13728409095645816, 0.19474559355325086, 0.1974909129243011, 0.16841657696573073, + 0.12559777736159378, 0.08153828016664713, 0.04360471317348958, 0.015072994568868221, + -0.003636420058445484)) + exp3 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, + 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), + (0.0, 0.6314542141914303, 2.9356520038101035, 9.37731009663807, 28.452300356688376, + 86.25721933273988, 261.9236645044672, 795.6435410577224, 2416.9786984578764, 7342.154119725917)) + exp4 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, + 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), + (0.0, 2.286236899862826, 18.28989519890261, 61.72839629629631, 146.31916159122088, 285.7796124828532, + 493.8271703703705, 784.1792566529494, 1170.553292729767, 1666.6667)) + exp5 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, + 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), + (-3.999999997894577e-09, 0.6720357068882895, 0.4429938256137113, 0.5182010838004518, + 0.4944139147159695, 0.5016379853883338, 0.4995466896527733, 0.5001154784851325, + 0.49997448824584123, 0.5000039745919259)) + exp6 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, + 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), + (-1.5433688493882158e-09, 0.3428705539937336, 1.1253619102202777, 3.1849962651016517, + 9.47532757182671, 28.727231099148135, 87.29426924860557, 265.2138681048606, 805.6636260007757, + 2447.387582370878)) + + assert step_res_tester(tf1, exp1) + assert step_res_tester(tf2, exp2) + assert step_res_tester(tf3, exp3) + assert step_res_tester(tf4, exp4) + assert step_res_tester(tf5, exp5) + assert step_res_tester(ser2, exp6) + + +def test_ramp_response(): + if not numpy: + skip("NumPy is required for this test") + + def ramp_res_tester(sys, num_points, expected_value, slope=1): + x, y = _to_tuple(*ramp_response_numerical_data(sys, + slope=slope, adaptive=False, n=num_points)) + x_check = check_point_accuracy(x, expected_value[0]) + y_check = check_point_accuracy(y, expected_value[1]) + return x_check and y_check + + exp1 = ((0.0, 2.0, 4.0, 6.0, 8.0, 10.0), (0.0, 0.7324667795033895, 1.9909720978650398, + 2.7956587704217783, 3.9224897567931514, 4.85022655284895)) + exp2 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, + 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), + (2.4360213402019326e-08, 0.10175320182493253, 0.33057612497658406, 0.5967937263298935, + 0.8431511866718248, 1.0398805391471613, 1.1776043125035738, 1.2600994825747305, 1.2981042689274653, + 1.304684417610106)) + exp3 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, + 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (-3.9329040468771836e-08, + 0.34686634635794555, 2.9998828170537903, 12.33303690737476, 40.993913948137795, 127.84145222317912, + 391.41713691996, 1192.0006858708389, 3623.9808672503405, 11011.728034546572)) + exp4 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, + 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 1.9051973784484078, 30.483158055174524, + 154.32098765432104, 487.7305288827924, 1190.7483615302544, 2469.1358024691367, 4574.3789056546275, + 7803.688462124678, 12500.0)) + exp5 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, + 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 3.8844361856975635, 9.141792069209865, + 14.096349157657231, 19.09783068994694, 24.10179770390321, 29.09907319114121, 34.10040420185154, + 39.09983919254265, 44.10006013058409)) + exp6 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, + 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 1.1111111111111112, 2.2222222222222223, + 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0)) + + assert ramp_res_tester(tf1, 6, exp1) + assert ramp_res_tester(tf2, 10, exp2, 1.2) + assert ramp_res_tester(tf3, 10, exp3, 1.5) + assert ramp_res_tester(tf4, 10, exp4, 3) + assert ramp_res_tester(tf5, 10, exp5, 9) + assert ramp_res_tester(tf6, 10, exp6) + + +def test_nyquist_plot_expr(): + r1, i1, w1 = nyquist_plot_expr(tf1) + r2, i2, w2 = nyquist_plot_expr(tf2) + r3, i3, w3 = nyquist_plot_expr(tf3) + r4, i4, w4 = nyquist_plot_expr(tf4) + assert r1 == (2 - w1**2)/(0.25*w1**2 + (2 - w1**2)**2) + assert i1 == -0.5*w1/(0.25*w1**2 + (2 - w1**2)**2) + assert r2 == 3*w2**2/(9*w2**2 + (1 - 6*w2**2)**2) + assert i2 == w2*(1 - 6*w2**2)/(9*w2**2 + (1 - 6*w2**2)**2) + assert r3 == -w3**4/(w3**6 + 1) + assert i3 == -w3/(w3**6 + 1) + assert r4 == 0 + assert i4 == 10/w4**3 + + +def test_nichols_expr(): + m1, p1, w1 = nichols_plot_expr(tf1) + m2, p2, w2 = nichols_plot_expr(tf2) + m3, p3, w3 = nichols_plot_expr(tf3) + m4, p4, w4 = nichols_plot_expr(tf4) + assert m1 == 20*log(1/sqrt(w1**4 - 3.75*w1**2 + 4))/log(10) + assert p1 == 180*arg(1/(-w1**2 + 0.5*w1*I + 2))/pi + assert m2 == 20*log(Abs(w2)/sqrt(36*w2**4 - 3*w2**2 + 1))/log(10) + assert p2 == 180*arg(w2*I/(-6*w2**2 + 3*w2*I + 1))/pi + assert m3 == 20*log(Abs(w3)/sqrt(w3**6 + 1))/log(10) + assert p3 == 180*arg(-w3*I/(w3**3*I + 1))/pi + assert m4 == 20*log(10/(w4**2*Abs(w4)))/log(10) + assert p4 == 180*arg(I/w4**3)/pi diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/test_lti.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/test_lti.py new file mode 100644 index 0000000000000000000000000000000000000000..a78a4c9b893d11f5e9e94705637080e2a722796a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/control/tests/test_lti.py @@ -0,0 +1,2273 @@ +from sympy.core.add import Add +from sympy.core.function import Function +from sympy.core.mul import Mul +from sympy.core.numbers import (I, pi, Rational, oo) +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.special.delta_functions import Heaviside +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import atan +from sympy.matrices.dense import eye +from sympy.physics.control.lti import SISOLinearTimeInvariant +from sympy.polys.polytools import factor +from sympy.polys.rootoftools import CRootOf +from sympy.simplify.simplify import simplify +from sympy.core.containers import Tuple +from sympy.matrices import ImmutableMatrix, Matrix, ShapeError +from sympy.functions.elementary.trigonometric import sin, cos +from sympy.physics.control import (TransferFunction, PIDController, Series, Parallel, + Feedback, TransferFunctionMatrix, MIMOSeries, MIMOParallel, MIMOFeedback, + StateSpace, gbt, bilinear, forward_diff, backward_diff, phase_margin, gain_margin) +from sympy.testing.pytest import raises + +a, x, b, c, s, g, d, p, k, tau, zeta, wn, T = symbols('a, x, b, c, s, g, d, p, k,\ + tau, zeta, wn, T') +a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3, d0, d1, d2, d3 = symbols('a0:4,\ + b0:4, c0:4, d0:4') +TF1 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) +TF2 = TransferFunction(k, 1, s) +TF3 = TransferFunction(a2*p - s, a2*s + p, s) + + +def test_TransferFunction_construction(): + tf = TransferFunction(s + 1, s**2 + s + 1, s) + assert tf.num == (s + 1) + assert tf.den == (s**2 + s + 1) + assert tf.args == (s + 1, s**2 + s + 1, s) + + tf1 = TransferFunction(s + 4, s - 5, s) + assert tf1.num == (s + 4) + assert tf1.den == (s - 5) + assert tf1.args == (s + 4, s - 5, s) + + # using different polynomial variables. + tf2 = TransferFunction(p + 3, p**2 - 9, p) + assert tf2.num == (p + 3) + assert tf2.den == (p**2 - 9) + assert tf2.args == (p + 3, p**2 - 9, p) + + tf3 = TransferFunction(p**3 + 5*p**2 + 4, p**4 + 3*p + 1, p) + assert tf3.args == (p**3 + 5*p**2 + 4, p**4 + 3*p + 1, p) + + # no pole-zero cancellation on its own. + tf4 = TransferFunction((s + 3)*(s - 1), (s - 1)*(s + 5), s) + assert tf4.den == (s - 1)*(s + 5) + assert tf4.args == ((s + 3)*(s - 1), (s - 1)*(s + 5), s) + + tf4_ = TransferFunction(p + 2, p + 2, p) + assert tf4_.args == (p + 2, p + 2, p) + + tf5 = TransferFunction(s - 1, 4 - p, s) + assert tf5.args == (s - 1, 4 - p, s) + + tf5_ = TransferFunction(s - 1, s - 1, s) + assert tf5_.args == (s - 1, s - 1, s) + + tf6 = TransferFunction(5, 6, s) + assert tf6.num == 5 + assert tf6.den == 6 + assert tf6.args == (5, 6, s) + + tf6_ = TransferFunction(1/2, 4, s) + assert tf6_.num == 0.5 + assert tf6_.den == 4 + assert tf6_.args == (0.500000000000000, 4, s) + + tf7 = TransferFunction(3*s**2 + 2*p + 4*s, 8*p**2 + 7*s, s) + tf8 = TransferFunction(3*s**2 + 2*p + 4*s, 8*p**2 + 7*s, p) + assert not tf7 == tf8 + + tf7_ = TransferFunction(a0*s + a1*s**2 + a2*s**3, b0*p - b1*s, s) + tf8_ = TransferFunction(a0*s + a1*s**2 + a2*s**3, b0*p - b1*s, s) + assert tf7_ == tf8_ + assert -(-tf7_) == tf7_ == -(-(-(-tf7_))) + + tf9 = TransferFunction(a*s**3 + b*s**2 + g*s + d, d*p + g*p**2 + g*s, s) + assert tf9.args == (a*s**3 + b*s**2 + d + g*s, d*p + g*p**2 + g*s, s) + + tf10 = TransferFunction(p**3 + d, g*s**2 + d*s + a, p) + tf10_ = TransferFunction(p**3 + d, g*s**2 + d*s + a, p) + assert tf10.args == (d + p**3, a + d*s + g*s**2, p) + assert tf10_ == tf10 + + tf11 = TransferFunction(a1*s + a0, b2*s**2 + b1*s + b0, s) + assert tf11.num == (a0 + a1*s) + assert tf11.den == (b0 + b1*s + b2*s**2) + assert tf11.args == (a0 + a1*s, b0 + b1*s + b2*s**2, s) + + # when just the numerator is 0, leave the denominator alone. + tf12 = TransferFunction(0, p**2 - p + 1, p) + assert tf12.args == (0, p**2 - p + 1, p) + + tf13 = TransferFunction(0, 1, s) + assert tf13.args == (0, 1, s) + + # float exponents + tf14 = TransferFunction(a0*s**0.5 + a2*s**0.6 - a1, a1*p**(-8.7), s) + assert tf14.args == (a0*s**0.5 - a1 + a2*s**0.6, a1*p**(-8.7), s) + + tf15 = TransferFunction(a2**2*p**(1/4) + a1*s**(-4/5), a0*s - p, p) + assert tf15.args == (a1*s**(-0.8) + a2**2*p**0.25, a0*s - p, p) + + omega_o, k_p, k_o, k_i = symbols('omega_o, k_p, k_o, k_i') + tf18 = TransferFunction((k_p + k_o*s + k_i/s), s**2 + 2*omega_o*s + omega_o**2, s) + assert tf18.num == k_i/s + k_o*s + k_p + assert tf18.args == (k_i/s + k_o*s + k_p, omega_o**2 + 2*omega_o*s + s**2, s) + + # ValueError when denominator is zero. + raises(ValueError, lambda: TransferFunction(4, 0, s)) + raises(ValueError, lambda: TransferFunction(s, 0, s)) + raises(ValueError, lambda: TransferFunction(0, 0, s)) + + raises(TypeError, lambda: TransferFunction(Matrix([1, 2, 3]), s, s)) + + raises(TypeError, lambda: TransferFunction(s**2 + 2*s - 1, s + 3, 3)) + raises(TypeError, lambda: TransferFunction(p + 1, 5 - p, 4)) + raises(TypeError, lambda: TransferFunction(3, 4, 8)) + + +def test_TransferFunction_functions(): + # classmethod from_rational_expression + expr_1 = Mul(0, Pow(s, -1, evaluate=False), evaluate=False) + expr_2 = s/0 + expr_3 = (p*s**2 + 5*s)/(s + 1)**3 + expr_4 = 6 + expr_5 = ((2 + 3*s)*(5 + 2*s))/((9 + 3*s)*(5 + 2*s**2)) + expr_6 = (9*s**4 + 4*s**2 + 8)/((s + 1)*(s + 9)) + tf = TransferFunction(s + 1, s**2 + 2, s) + delay = exp(-s/tau) + expr_7 = delay*tf.to_expr() + H1 = TransferFunction.from_rational_expression(expr_7, s) + H2 = TransferFunction(s + 1, (s**2 + 2)*exp(s/tau), s) + expr_8 = Add(2, 3*s/(s**2 + 1), evaluate=False) + + assert TransferFunction.from_rational_expression(expr_1) == TransferFunction(0, s, s) + raises(ZeroDivisionError, lambda: TransferFunction.from_rational_expression(expr_2)) + raises(ValueError, lambda: TransferFunction.from_rational_expression(expr_3)) + assert TransferFunction.from_rational_expression(expr_3, s) == TransferFunction((p*s**2 + 5*s), (s + 1)**3, s) + assert TransferFunction.from_rational_expression(expr_3, p) == TransferFunction((p*s**2 + 5*s), (s + 1)**3, p) + raises(ValueError, lambda: TransferFunction.from_rational_expression(expr_4)) + assert TransferFunction.from_rational_expression(expr_4, s) == TransferFunction(6, 1, s) + assert TransferFunction.from_rational_expression(expr_5, s) == \ + TransferFunction((2 + 3*s)*(5 + 2*s), (9 + 3*s)*(5 + 2*s**2), s) + assert TransferFunction.from_rational_expression(expr_6, s) == \ + TransferFunction((9*s**4 + 4*s**2 + 8), (s + 1)*(s + 9), s) + assert H1 == H2 + assert TransferFunction.from_rational_expression(expr_8, s) == \ + TransferFunction(2*s**2 + 3*s + 2, s**2 + 1, s) + + # classmethod from_coeff_lists + tf1 = TransferFunction.from_coeff_lists([1, 2], [3, 4, 5], s) + num2 = [p**2, 2*p] + den2 = [p**3, p + 1, 4] + tf2 = TransferFunction.from_coeff_lists(num2, den2, s) + num3 = [1, 2, 3] + den3 = [0, 0] + + assert tf1 == TransferFunction(s + 2, 3*s**2 + 4*s + 5, s) + assert tf2 == TransferFunction(p**2*s + 2*p, p**3*s**2 + s*(p + 1) + 4, s) + raises(ZeroDivisionError, lambda: TransferFunction.from_coeff_lists(num3, den3, s)) + + # classmethod from_zpk + zeros = [4] + poles = [-1+2j, -1-2j] + gain = 3 + tf1 = TransferFunction.from_zpk(zeros, poles, gain, s) + + assert tf1 == TransferFunction(3*s - 12, (s + 1.0 - 2.0*I)*(s + 1.0 + 2.0*I), s) + + # explicitly cancel poles and zeros. + tf0 = TransferFunction(s**5 + s**3 + s, s - s**2, s) + a = TransferFunction(-(s**4 + s**2 + 1), s - 1, s) + assert tf0.simplify() == simplify(tf0) == a + + tf1 = TransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p) + b = TransferFunction(p + 3, p + 5, p) + assert tf1.simplify() == simplify(tf1) == b + + # expand the numerator and the denominator. + G1 = TransferFunction((1 - s)**2, (s**2 + 1)**2, s) + G2 = TransferFunction(1, -3, p) + c = (a2*s**p + a1*s**s + a0*p**p)*(p**s + s**p) + d = (b0*s**s + b1*p**s)*(b2*s*p + p**p) + e = a0*p**p*p**s + a0*p**p*s**p + a1*p**s*s**s + a1*s**p*s**s + a2*p**s*s**p + a2*s**(2*p) + f = b0*b2*p*s*s**s + b0*p**p*s**s + b1*b2*p*p**s*s + b1*p**p*p**s + g = a1*a2*s*s**p + a1*p*s + a2*b1*p*s*s**p + b1*p**2*s + G3 = TransferFunction(c, d, s) + G4 = TransferFunction(a0*s**s - b0*p**p, (a1*s + b1*s*p)*(a2*s**p + p), p) + + assert G1.expand() == TransferFunction(s**2 - 2*s + 1, s**4 + 2*s**2 + 1, s) + assert tf1.expand() == TransferFunction(p**2 + 2*p - 3, p**2 + 4*p - 5, p) + assert G2.expand() == G2 + assert G3.expand() == TransferFunction(e, f, s) + assert G4.expand() == TransferFunction(a0*s**s - b0*p**p, g, p) + + # purely symbolic polynomials. + p1 = a1*s + a0 + p2 = b2*s**2 + b1*s + b0 + SP1 = TransferFunction(p1, p2, s) + expect1 = TransferFunction(2.0*s + 1.0, 5.0*s**2 + 4.0*s + 3.0, s) + expect1_ = TransferFunction(2*s + 1, 5*s**2 + 4*s + 3, s) + assert SP1.subs({a0: 1, a1: 2, b0: 3, b1: 4, b2: 5}) == expect1_ + assert SP1.subs({a0: 1, a1: 2, b0: 3, b1: 4, b2: 5}).evalf() == expect1 + assert expect1_.evalf() == expect1 + + c1, d0, d1, d2 = symbols('c1, d0:3') + p3, p4 = c1*p, d2*p**3 + d1*p**2 - d0 + SP2 = TransferFunction(p3, p4, p) + expect2 = TransferFunction(2.0*p, 5.0*p**3 + 2.0*p**2 - 3.0, p) + expect2_ = TransferFunction(2*p, 5*p**3 + 2*p**2 - 3, p) + assert SP2.subs({c1: 2, d0: 3, d1: 2, d2: 5}) == expect2_ + assert SP2.subs({c1: 2, d0: 3, d1: 2, d2: 5}).evalf() == expect2 + assert expect2_.evalf() == expect2 + + SP3 = TransferFunction(a0*p**3 + a1*s**2 - b0*s + b1, a1*s + p, s) + expect3 = TransferFunction(2.0*p**3 + 4.0*s**2 - s + 5.0, p + 4.0*s, s) + expect3_ = TransferFunction(2*p**3 + 4*s**2 - s + 5, p + 4*s, s) + assert SP3.subs({a0: 2, a1: 4, b0: 1, b1: 5}) == expect3_ + assert SP3.subs({a0: 2, a1: 4, b0: 1, b1: 5}).evalf() == expect3 + assert expect3_.evalf() == expect3 + + SP4 = TransferFunction(s - a1*p**3, a0*s + p, p) + expect4 = TransferFunction(7.0*p**3 + s, p - s, p) + expect4_ = TransferFunction(7*p**3 + s, p - s, p) + assert SP4.subs({a0: -1, a1: -7}) == expect4_ + assert SP4.subs({a0: -1, a1: -7}).evalf() == expect4 + assert expect4_.evalf() == expect4 + + # evaluate the transfer function at particular frequencies. + assert tf1.eval_frequency(wn) == wn**2/(wn**2 + 4*wn - 5) + 2*wn/(wn**2 + 4*wn - 5) - 3/(wn**2 + 4*wn - 5) + assert G1.eval_frequency(1 + I) == S(3)/25 + S(4)*I/25 + assert G4.eval_frequency(S(5)/3) == \ + a0*s**s/(a1*a2*s**(S(8)/3) + S(5)*a1*s/3 + 5*a2*b1*s**(S(8)/3)/3 + S(25)*b1*s/9) - 5*3**(S(1)/3)*5**(S(2)/3)*b0/(9*a1*a2*s**(S(8)/3) + 15*a1*s + 15*a2*b1*s**(S(8)/3) + 25*b1*s) + + # Low-frequency (or DC) gain. + assert tf0.dc_gain() == 1 + assert tf1.dc_gain() == Rational(3, 5) + assert SP2.dc_gain() == 0 + assert expect4.dc_gain() == -1 + assert expect2_.dc_gain() == 0 + assert TransferFunction(1, s, s).dc_gain() == oo + + # Poles of a transfer function. + tf_ = TransferFunction(x**3 - k, k, x) + _tf = TransferFunction(k, x**4 - k, x) + TF_ = TransferFunction(x**2, x**10 + x + x**2, x) + _TF = TransferFunction(x**10 + x + x**2, x**2, x) + assert G1.poles() == [I, I, -I, -I] + assert G2.poles() == [] + assert tf1.poles() == [-5, 1] + assert expect4_.poles() == [s] + assert SP4.poles() == [-a0*s] + assert expect3.poles() == [-0.25*p] + assert str(expect2.poles()) == str([0.729001428685125, -0.564500714342563 - 0.710198984796332*I, -0.564500714342563 + 0.710198984796332*I]) + assert str(expect1.poles()) == str([-0.4 - 0.66332495807108*I, -0.4 + 0.66332495807108*I]) + assert _tf.poles() == [k**(Rational(1, 4)), -k**(Rational(1, 4)), I*k**(Rational(1, 4)), -I*k**(Rational(1, 4))] + assert TF_.poles() == [CRootOf(x**9 + x + 1, 0), 0, CRootOf(x**9 + x + 1, 1), CRootOf(x**9 + x + 1, 2), + CRootOf(x**9 + x + 1, 3), CRootOf(x**9 + x + 1, 4), CRootOf(x**9 + x + 1, 5), CRootOf(x**9 + x + 1, 6), + CRootOf(x**9 + x + 1, 7), CRootOf(x**9 + x + 1, 8)] + raises(NotImplementedError, lambda: TransferFunction(x**2, a0*x**10 + x + x**2, x).poles()) + + # Stability of a transfer function. + q, r = symbols('q, r', negative=True) + t = symbols('t', positive=True) + TF_ = TransferFunction(s**2 + a0 - a1*p, q*s - r, s) + stable_tf = TransferFunction(s**2 + a0 - a1*p, q*s - 1, s) + stable_tf_ = TransferFunction(s**2 + a0 - a1*p, q*s - t, s) + + assert G1.is_stable() is False + assert G2.is_stable() is True + assert tf1.is_stable() is False # as one pole is +ve, and the other is -ve. + assert expect2.is_stable() is False + assert expect1.is_stable() is True + assert stable_tf.is_stable() is True + assert stable_tf_.is_stable() is True + assert TF_.is_stable() is False + assert expect4_.is_stable() is None # no assumption provided for the only pole 's'. + assert SP4.is_stable() is None + + # Zeros of a transfer function. + assert G1.zeros() == [1, 1] + assert G2.zeros() == [] + assert tf1.zeros() == [-3, 1] + assert expect4_.zeros() == [7**(Rational(2, 3))*(-s)**(Rational(1, 3))/7, -7**(Rational(2, 3))*(-s)**(Rational(1, 3))/14 - + sqrt(3)*7**(Rational(2, 3))*I*(-s)**(Rational(1, 3))/14, -7**(Rational(2, 3))*(-s)**(Rational(1, 3))/14 + sqrt(3)*7**(Rational(2, 3))*I*(-s)**(Rational(1, 3))/14] + assert SP4.zeros() == [(s/a1)**(Rational(1, 3)), -(s/a1)**(Rational(1, 3))/2 - sqrt(3)*I*(s/a1)**(Rational(1, 3))/2, + -(s/a1)**(Rational(1, 3))/2 + sqrt(3)*I*(s/a1)**(Rational(1, 3))/2] + assert str(expect3.zeros()) == str([0.125 - 1.11102430216445*sqrt(-0.405063291139241*p**3 - 1.0), + 1.11102430216445*sqrt(-0.405063291139241*p**3 - 1.0) + 0.125]) + assert tf_.zeros() == [k**(Rational(1, 3)), -k**(Rational(1, 3))/2 - sqrt(3)*I*k**(Rational(1, 3))/2, + -k**(Rational(1, 3))/2 + sqrt(3)*I*k**(Rational(1, 3))/2] + assert _TF.zeros() == [CRootOf(x**9 + x + 1, 0), 0, CRootOf(x**9 + x + 1, 1), CRootOf(x**9 + x + 1, 2), + CRootOf(x**9 + x + 1, 3), CRootOf(x**9 + x + 1, 4), CRootOf(x**9 + x + 1, 5), CRootOf(x**9 + x + 1, 6), + CRootOf(x**9 + x + 1, 7), CRootOf(x**9 + x + 1, 8)] + raises(NotImplementedError, lambda: TransferFunction(a0*x**10 + x + x**2, x**2, x).zeros()) + + # negation of TF. + tf2 = TransferFunction(s + 3, s**2 - s**3 + 9, s) + tf3 = TransferFunction(-3*p + 3, 1 - p, p) + assert -tf2 == TransferFunction(-s - 3, s**2 - s**3 + 9, s) + assert -tf3 == TransferFunction(3*p - 3, 1 - p, p) + + # taking power of a TF. + tf4 = TransferFunction(p + 4, p - 3, p) + tf5 = TransferFunction(s**2 + 1, 1 - s, s) + expect2 = TransferFunction((s**2 + 1)**3, (1 - s)**3, s) + expect1 = TransferFunction((p + 4)**2, (p - 3)**2, p) + assert (tf4*tf4).doit() == tf4**2 == pow(tf4, 2) == expect1 + assert (tf5*tf5*tf5).doit() == tf5**3 == pow(tf5, 3) == expect2 + assert tf5**0 == pow(tf5, 0) == TransferFunction(1, 1, s) + assert Series(tf4).doit()**-1 == tf4**-1 == pow(tf4, -1) == TransferFunction(p - 3, p + 4, p) + assert (tf5*tf5).doit()**-1 == tf5**-2 == pow(tf5, -2) == TransferFunction((1 - s)**2, (s**2 + 1)**2, s) + + raises(ValueError, lambda: tf4**(s**2 + s - 1)) + raises(ValueError, lambda: tf5**s) + raises(ValueError, lambda: tf4**tf5) + + # SymPy's own functions. + tf = TransferFunction(s - 1, s**2 - 2*s + 1, s) + tf6 = TransferFunction(s + p, p**2 - 5, s) + assert factor(tf) == TransferFunction(s - 1, (s - 1)**2, s) + assert tf.num.subs(s, 2) == tf.den.subs(s, 2) == 1 + # subs & xreplace + assert tf.subs(s, 2) == TransferFunction(s - 1, s**2 - 2*s + 1, s) + assert tf6.subs(p, 3) == TransferFunction(s + 3, 4, s) + assert tf3.xreplace({p: s}) == TransferFunction(-3*s + 3, 1 - s, s) + raises(TypeError, lambda: tf3.xreplace({p: exp(2)})) + assert tf3.subs(p, exp(2)) == tf3 + + tf7 = TransferFunction(a0*s**p + a1*p**s, a2*p - s, s) + assert tf7.xreplace({s: k}) == TransferFunction(a0*k**p + a1*p**k, a2*p - k, k) + assert tf7.subs(s, k) == TransferFunction(a0*s**p + a1*p**s, a2*p - s, s) + + # Conversion to Expr with to_expr() + tf8 = TransferFunction(a0*s**5 + 5*s**2 + 3, s**6 - 3, s) + tf9 = TransferFunction((5 + s), (5 + s)*(6 + s), s) + tf10 = TransferFunction(0, 1, s) + tf11 = TransferFunction(1, 1, s) + assert tf8.to_expr() == Mul((a0*s**5 + 5*s**2 + 3), Pow((s**6 - 3), -1, evaluate=False), evaluate=False) + assert tf9.to_expr() == Mul((s + 5), Pow((5 + s)*(6 + s), -1, evaluate=False), evaluate=False) + assert tf10.to_expr() == Mul(S(0), Pow(1, -1, evaluate=False), evaluate=False) + assert tf11.to_expr() == Pow(1, -1, evaluate=False) + + +def test_TransferFunction_addition_and_subtraction(): + tf1 = TransferFunction(s + 6, s - 5, s) + tf2 = TransferFunction(s + 3, s + 1, s) + tf3 = TransferFunction(s + 1, s**2 + s + 1, s) + tf4 = TransferFunction(p, 2 - p, p) + + # addition + assert tf1 + tf2 == Parallel(tf1, tf2) + assert tf3 + tf1 == Parallel(tf3, tf1) + assert -tf1 + tf2 + tf3 == Parallel(-tf1, tf2, tf3) + assert tf1 + (tf2 + tf3) == Parallel(tf1, tf2, tf3) + + c = symbols("c", commutative=False) + raises(ValueError, lambda: tf1 + Matrix([1, 2, 3])) + raises(ValueError, lambda: tf2 + c) + raises(ValueError, lambda: tf3 + tf4) + raises(ValueError, lambda: tf1 + (s - 1)) + raises(ValueError, lambda: tf1 + 8) + raises(ValueError, lambda: (1 - p**3) + tf1) + + # subtraction + assert tf1 - tf2 == Parallel(tf1, -tf2) + assert tf3 - tf2 == Parallel(tf3, -tf2) + assert -tf1 - tf3 == Parallel(-tf1, -tf3) + assert tf1 - tf2 + tf3 == Parallel(tf1, -tf2, tf3) + + raises(ValueError, lambda: tf1 - Matrix([1, 2, 3])) + raises(ValueError, lambda: tf3 - tf4) + raises(ValueError, lambda: tf1 - (s - 1)) + raises(ValueError, lambda: tf1 - 8) + raises(ValueError, lambda: (s + 5) - tf2) + raises(ValueError, lambda: (1 + p**4) - tf1) + + +def test_TransferFunction_multiplication_and_division(): + G1 = TransferFunction(s + 3, -s**3 + 9, s) + G2 = TransferFunction(s + 1, s - 5, s) + G3 = TransferFunction(p, p**4 - 6, p) + G4 = TransferFunction(p + 4, p - 5, p) + G5 = TransferFunction(s + 6, s - 5, s) + G6 = TransferFunction(s + 3, s + 1, s) + G7 = TransferFunction(1, 1, s) + + # multiplication + assert G1*G2 == Series(G1, G2) + assert -G1*G5 == Series(-G1, G5) + assert -G2*G5*-G6 == Series(-G2, G5, -G6) + assert -G1*-G2*-G5*-G6 == Series(-G1, -G2, -G5, -G6) + assert G3*G4 == Series(G3, G4) + assert (G1*G2)*-(G5*G6) == \ + Series(G1, G2, TransferFunction(-1, 1, s), Series(G5, G6)) + assert G1*G2*(G5 + G6) == Series(G1, G2, Parallel(G5, G6)) + + # division - See ``test_Feedback_functions()`` for division by Parallel objects. + assert G5/G6 == Series(G5, pow(G6, -1)) + assert -G3/G4 == Series(-G3, pow(G4, -1)) + assert (G5*G6)/G7 == Series(G5, G6, pow(G7, -1)) + + c = symbols("c", commutative=False) + raises(ValueError, lambda: G3 * Matrix([1, 2, 3])) + raises(ValueError, lambda: G1 * c) + raises(ValueError, lambda: G3 * G5) + raises(ValueError, lambda: G5 * (s - 1)) + raises(ValueError, lambda: 9 * G5) + + raises(ValueError, lambda: G3 / Matrix([1, 2, 3])) + raises(ValueError, lambda: G6 / 0) + raises(ValueError, lambda: G3 / G5) + raises(ValueError, lambda: G5 / 2) + raises(ValueError, lambda: G5 / s**2) + raises(ValueError, lambda: (s - 4*s**2) / G2) + raises(ValueError, lambda: 0 / G4) + raises(ValueError, lambda: G7 / (1 + G6)) + raises(ValueError, lambda: G7 / (G5 * G6)) + raises(ValueError, lambda: G7 / (G7 + (G5 + G6))) + + +def test_TransferFunction_is_proper(): + omega_o, zeta, tau = symbols('omega_o, zeta, tau') + G1 = TransferFunction(omega_o**2, s**2 + p*omega_o*zeta*s + omega_o**2, omega_o) + G2 = TransferFunction(tau - s**3, tau + p**4, tau) + G3 = TransferFunction(a*b*s**3 + s**2 - a*p + s, b - s*p**2, p) + G4 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) + assert G1.is_proper + assert G2.is_proper + assert G3.is_proper + assert not G4.is_proper + + +def test_TransferFunction_is_strictly_proper(): + omega_o, zeta, tau = symbols('omega_o, zeta, tau') + tf1 = TransferFunction(omega_o**2, s**2 + p*omega_o*zeta*s + omega_o**2, omega_o) + tf2 = TransferFunction(tau - s**3, tau + p**4, tau) + tf3 = TransferFunction(a*b*s**3 + s**2 - a*p + s, b - s*p**2, p) + tf4 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) + assert not tf1.is_strictly_proper + assert not tf2.is_strictly_proper + assert tf3.is_strictly_proper + assert not tf4.is_strictly_proper + + +def test_TransferFunction_is_biproper(): + tau, omega_o, zeta = symbols('tau, omega_o, zeta') + tf1 = TransferFunction(omega_o**2, s**2 + p*omega_o*zeta*s + omega_o**2, omega_o) + tf2 = TransferFunction(tau - s**3, tau + p**4, tau) + tf3 = TransferFunction(a*b*s**3 + s**2 - a*p + s, b - s*p**2, p) + tf4 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) + assert tf1.is_biproper + assert tf2.is_biproper + assert not tf3.is_biproper + assert not tf4.is_biproper + + +def test_PIDController(): + kp, ki, kd, tf = symbols("kp ki kd tf") + p1 = PIDController(kp, ki, kd, tf) + p2 = PIDController() + + # Type Checking + assert isinstance(p1, PIDController) + assert isinstance(p1, TransferFunction) + + # Properties checking + assert p1 == PIDController(kp, ki, kd, tf, s) + assert p2 == PIDController(kp, ki, kd, 0, s) + assert p1.num == kd*s**2 + ki*s*tf + ki + kp*s**2*tf + kp*s + assert p1.den == s**2*tf + s + assert p1.var == s + assert p1.kp == kp + assert p1.ki == ki + assert p1.kd == kd + assert p1.tf == tf + + # Functionality checking + assert p1.doit() == TransferFunction(kd*s**2 + ki*s*tf + ki + kp*s**2*tf + kp*s, s**2*tf + s, s) + assert p1.is_proper == True + assert p1.is_biproper == True + assert p1.is_strictly_proper == False + assert p2.doit() == TransferFunction(kd*s**2 + ki + kp*s, s, s) + + # Using PIDController with TransferFunction + tf1 = TransferFunction(s, s + 1, s) + par1 = Parallel(p1, tf1) + ser1 = Series(p1, tf1) + fed1 = Feedback(p1, tf1) + assert par1 == Parallel(PIDController(kp, ki, kd, tf, s), TransferFunction(s, s + 1, s)) + assert ser1 == Series(PIDController(kp, ki, kd, tf, s), TransferFunction(s, s + 1, s)) + assert fed1 == Feedback(PIDController(kp, ki, kd, tf, s), TransferFunction(s, s + 1, s)) + assert par1.doit() == TransferFunction(s*(s**2*tf + s) + (s + 1)*(kd*s**2 + ki*s*tf + ki + kp*s**2*tf + kp*s), + (s + 1)*(s**2*tf + s), s) + assert ser1.doit() == TransferFunction(s*(kd*s**2 + ki*s*tf + ki + kp*s**2*tf + kp*s), + (s + 1)*(s**2*tf + s), s) + assert fed1.doit() == TransferFunction((s + 1)*(s**2*tf + s)*(kd*s**2 + ki*s*tf + ki + kp*s**2*tf + kp*s), + (s*(kd*s**2 + ki*s*tf + ki + kp*s**2*tf + kp*s) + (s + 1)*(s**2*tf + s))*(s**2*tf + s), s) + + +def test_Series_construction(): + tf = TransferFunction(a0*s**3 + a1*s**2 - a2*s, b0*p**4 + b1*p**3 - b2*s*p, s) + tf2 = TransferFunction(a2*p - s, a2*s + p, s) + tf3 = TransferFunction(a0*p + p**a1 - s, p, p) + tf4 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) + inp = Function('X_d')(s) + out = Function('X')(s) + + s0 = Series(tf, tf2) + assert s0.args == (tf, tf2) + assert s0.var == s + + s1 = Series(Parallel(tf, -tf2), tf2) + assert s1.args == (Parallel(tf, -tf2), tf2) + assert s1.var == s + + tf3_ = TransferFunction(inp, 1, s) + tf4_ = TransferFunction(-out, 1, s) + s2 = Series(tf, Parallel(tf3_, tf4_), tf2) + assert s2.args == (tf, Parallel(tf3_, tf4_), tf2) + + s3 = Series(tf, tf2, tf4) + assert s3.args == (tf, tf2, tf4) + + s4 = Series(tf3_, tf4_) + assert s4.args == (tf3_, tf4_) + assert s4.var == s + + s6 = Series(tf2, tf4, Parallel(tf2, -tf), tf4) + assert s6.args == (tf2, tf4, Parallel(tf2, -tf), tf4) + + s7 = Series(tf, tf2) + assert s0 == s7 + assert not s0 == s2 + + raises(ValueError, lambda: Series(tf, tf3)) + raises(ValueError, lambda: Series(tf, tf2, tf3, tf4)) + raises(ValueError, lambda: Series(-tf3, tf2)) + raises(TypeError, lambda: Series(2, tf, tf4)) + raises(TypeError, lambda: Series(s**2 + p*s, tf3, tf2)) + raises(TypeError, lambda: Series(tf3, Matrix([1, 2, 3, 4]))) + + +def test_MIMOSeries_construction(): + tf_1 = TransferFunction(a0*s**3 + a1*s**2 - a2*s, b0*p**4 + b1*p**3 - b2*s*p, s) + tf_2 = TransferFunction(a2*p - s, a2*s + p, s) + tf_3 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) + + tfm_1 = TransferFunctionMatrix([[tf_1, tf_2, tf_3], [-tf_3, -tf_2, tf_1]]) + tfm_2 = TransferFunctionMatrix([[-tf_2], [-tf_2], [-tf_3]]) + tfm_3 = TransferFunctionMatrix([[-tf_3]]) + tfm_4 = TransferFunctionMatrix([[TF3], [TF2], [-TF1]]) + tfm_5 = TransferFunctionMatrix.from_Matrix(Matrix([1/p]), p) + + s8 = MIMOSeries(tfm_2, tfm_1) + assert s8.args == (tfm_2, tfm_1) + assert s8.var == s + assert s8.shape == (s8.num_outputs, s8.num_inputs) == (2, 1) + + s9 = MIMOSeries(tfm_3, tfm_2, tfm_1) + assert s9.args == (tfm_3, tfm_2, tfm_1) + assert s9.var == s + assert s9.shape == (s9.num_outputs, s9.num_inputs) == (2, 1) + + s11 = MIMOSeries(tfm_3, MIMOParallel(-tfm_2, -tfm_4), tfm_1) + assert s11.args == (tfm_3, MIMOParallel(-tfm_2, -tfm_4), tfm_1) + assert s11.shape == (s11.num_outputs, s11.num_inputs) == (2, 1) + + # arg cannot be empty tuple. + raises(ValueError, lambda: MIMOSeries()) + + # arg cannot contain SISO as well as MIMO systems. + raises(TypeError, lambda: MIMOSeries(tfm_1, tf_1)) + + # for all the adjacent transfer function matrices: + # no. of inputs of first TFM must be equal to the no. of outputs of the second TFM. + raises(ValueError, lambda: MIMOSeries(tfm_1, tfm_2, -tfm_1)) + + # all the TFMs must use the same complex variable. + raises(ValueError, lambda: MIMOSeries(tfm_3, tfm_5)) + + # Number or expression not allowed in the arguments. + raises(TypeError, lambda: MIMOSeries(2, tfm_2, tfm_3)) + raises(TypeError, lambda: MIMOSeries(s**2 + p*s, -tfm_2, tfm_3)) + raises(TypeError, lambda: MIMOSeries(Matrix([1/p]), tfm_3)) + + +def test_Series_functions(): + tf1 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) + tf2 = TransferFunction(k, 1, s) + tf3 = TransferFunction(a2*p - s, a2*s + p, s) + tf4 = TransferFunction(a0*p + p**a1 - s, p, p) + tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) + + assert tf1*tf2*tf3 == Series(tf1, tf2, tf3) == Series(Series(tf1, tf2), tf3) \ + == Series(tf1, Series(tf2, tf3)) + assert tf1*(tf2 + tf3) == Series(tf1, Parallel(tf2, tf3)) + assert tf1*tf2 + tf5 == Parallel(Series(tf1, tf2), tf5) + assert tf1*tf2 - tf5 == Parallel(Series(tf1, tf2), -tf5) + assert tf1*tf2 + tf3 + tf5 == Parallel(Series(tf1, tf2), tf3, tf5) + assert tf1*tf2 - tf3 - tf5 == Parallel(Series(tf1, tf2), -tf3, -tf5) + assert tf1*tf2 - tf3 + tf5 == Parallel(Series(tf1, tf2), -tf3, tf5) + assert tf1*tf2 + tf3*tf5 == Parallel(Series(tf1, tf2), Series(tf3, tf5)) + assert tf1*tf2 - tf3*tf5 == Parallel(Series(tf1, tf2), Series(TransferFunction(-1, 1, s), Series(tf3, tf5))) + assert tf2*tf3*(tf2 - tf1)*tf3 == Series(tf2, tf3, Parallel(tf2, -tf1), tf3) + assert -tf1*tf2 == Series(-tf1, tf2) + assert -(tf1*tf2) == Series(TransferFunction(-1, 1, s), Series(tf1, tf2)) + raises(ValueError, lambda: tf1*tf2*tf4) + raises(ValueError, lambda: tf1*(tf2 - tf4)) + raises(ValueError, lambda: tf3*Matrix([1, 2, 3])) + + # evaluate=True -> doit() + assert Series(tf1, tf2, evaluate=True) == Series(tf1, tf2).doit() == \ + TransferFunction(k, s**2 + 2*s*wn*zeta + wn**2, s) + assert Series(tf1, tf2, Parallel(tf1, -tf3), evaluate=True) == Series(tf1, tf2, Parallel(tf1, -tf3)).doit() == \ + TransferFunction(k*(a2*s + p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2)), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2)**2, s) + assert Series(tf2, tf1, -tf3, evaluate=True) == Series(tf2, tf1, -tf3).doit() == \ + TransferFunction(k*(-a2*p + s), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + assert not Series(tf1, -tf2, evaluate=False) == Series(tf1, -tf2).doit() + + assert Series(Parallel(tf1, tf2), Parallel(tf2, -tf3)).doit() == \ + TransferFunction((k*(s**2 + 2*s*wn*zeta + wn**2) + 1)*(-a2*p + k*(a2*s + p) + s), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + assert Series(-tf1, -tf2, -tf3).doit() == \ + TransferFunction(k*(-a2*p + s), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + assert -Series(tf1, tf2, tf3).doit() == \ + TransferFunction(-k*(a2*p - s), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + assert Series(tf2, tf3, Parallel(tf2, -tf1), tf3).doit() == \ + TransferFunction(k*(a2*p - s)**2*(k*(s**2 + 2*s*wn*zeta + wn**2) - 1), (a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2), s) + + assert Series(tf1, tf2).rewrite(TransferFunction) == TransferFunction(k, s**2 + 2*s*wn*zeta + wn**2, s) + assert Series(tf2, tf1, -tf3).rewrite(TransferFunction) == \ + TransferFunction(k*(-a2*p + s), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + + S1 = Series(Parallel(tf1, tf2), Parallel(tf2, -tf3)) + assert S1.is_proper + assert not S1.is_strictly_proper + assert S1.is_biproper + + S2 = Series(tf1, tf2, tf3) + assert S2.is_proper + assert S2.is_strictly_proper + assert not S2.is_biproper + + S3 = Series(tf1, -tf2, Parallel(tf1, -tf3)) + assert S3.is_proper + assert S3.is_strictly_proper + assert not S3.is_biproper + + +def test_MIMOSeries_functions(): + tfm1 = TransferFunctionMatrix([[TF1, TF2, TF3], [-TF3, -TF2, TF1]]) + tfm2 = TransferFunctionMatrix([[-TF1], [-TF2], [-TF3]]) + tfm3 = TransferFunctionMatrix([[-TF1]]) + tfm4 = TransferFunctionMatrix([[-TF2, -TF3], [-TF1, TF2]]) + tfm5 = TransferFunctionMatrix([[TF2, -TF2], [-TF3, -TF2]]) + tfm6 = TransferFunctionMatrix([[-TF3], [TF1]]) + tfm7 = TransferFunctionMatrix([[TF1], [-TF2]]) + + assert tfm1*tfm2 + tfm6 == MIMOParallel(MIMOSeries(tfm2, tfm1), tfm6) + assert tfm1*tfm2 + tfm7 + tfm6 == MIMOParallel(MIMOSeries(tfm2, tfm1), tfm7, tfm6) + assert tfm1*tfm2 - tfm6 - tfm7 == MIMOParallel(MIMOSeries(tfm2, tfm1), -tfm6, -tfm7) + assert tfm4*tfm5 + (tfm4 - tfm5) == MIMOParallel(MIMOSeries(tfm5, tfm4), tfm4, -tfm5) + assert tfm4*-tfm6 + (-tfm4*tfm6) == MIMOParallel(MIMOSeries(-tfm6, tfm4), MIMOSeries(tfm6, -tfm4)) + + raises(ValueError, lambda: tfm1*tfm2 + TF1) + raises(TypeError, lambda: tfm1*tfm2 + a0) + raises(TypeError, lambda: tfm4*tfm6 - (s - 1)) + raises(TypeError, lambda: tfm4*-tfm6 - 8) + raises(TypeError, lambda: (-1 + p**5) + tfm1*tfm2) + + # Shape criteria. + + raises(TypeError, lambda: -tfm1*tfm2 + tfm4) + raises(TypeError, lambda: tfm1*tfm2 - tfm4 + tfm5) + raises(TypeError, lambda: tfm1*tfm2 - tfm4*tfm5) + + assert tfm1*tfm2*-tfm3 == MIMOSeries(-tfm3, tfm2, tfm1) + assert (tfm1*-tfm2)*tfm3 == MIMOSeries(tfm3, -tfm2, tfm1) + + # Multiplication of a Series object with a SISO TF not allowed. + + raises(ValueError, lambda: tfm4*tfm5*TF1) + raises(TypeError, lambda: tfm4*tfm5*a1) + raises(TypeError, lambda: tfm4*-tfm5*(s - 2)) + raises(TypeError, lambda: tfm5*tfm4*9) + raises(TypeError, lambda: (-p**3 + 1)*tfm5*tfm4) + + # Transfer function matrix in the arguments. + assert (MIMOSeries(tfm2, tfm1, evaluate=True) == MIMOSeries(tfm2, tfm1).doit() + == TransferFunctionMatrix(((TransferFunction(-k**2*(a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2 + (-a2*p + s)*(a2*p - s)*(s**2 + 2*s*wn*zeta + wn**2)**2 - (a2*s + p)**2, + (a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2, s),), + (TransferFunction(k**2*(a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2 + (-a2*p + s)*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) + (a2*p - s)*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), + (a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2, s),)))) + + # doit() should not cancel poles and zeros. + mat_1 = Matrix([[1/(1+s), (1+s)/(1+s**2+2*s)**3]]) + mat_2 = Matrix([[(1+s)], [(1+s**2+2*s)**3/(1+s)]]) + tm_1, tm_2 = TransferFunctionMatrix.from_Matrix(mat_1, s), TransferFunctionMatrix.from_Matrix(mat_2, s) + assert (MIMOSeries(tm_2, tm_1).doit() + == TransferFunctionMatrix(((TransferFunction(2*(s + 1)**2*(s**2 + 2*s + 1)**3, (s + 1)**2*(s**2 + 2*s + 1)**3, s),),))) + assert MIMOSeries(tm_2, tm_1).doit().simplify() == TransferFunctionMatrix(((TransferFunction(2, 1, s),),)) + + # calling doit() will expand the internal Series and Parallel objects. + assert (MIMOSeries(-tfm3, -tfm2, tfm1, evaluate=True) + == MIMOSeries(-tfm3, -tfm2, tfm1).doit() + == TransferFunctionMatrix(((TransferFunction(k**2*(a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2 + (a2*p - s)**2*(s**2 + 2*s*wn*zeta + wn**2)**2 + (a2*s + p)**2, + (a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**3, s),), + (TransferFunction(-k**2*(a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2 + (-a2*p + s)*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) + (a2*p - s)*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), + (a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**3, s),)))) + assert (MIMOSeries(MIMOParallel(tfm4, tfm5), tfm5, evaluate=True) + == MIMOSeries(MIMOParallel(tfm4, tfm5), tfm5).doit() + == TransferFunctionMatrix(((TransferFunction(-k*(-a2*s - p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2)), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s), TransferFunction(k*(-a2*p - \ + k*(a2*s + p) + s), a2*s + p, s)), (TransferFunction(-k*(-a2*s - p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2)), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s), \ + TransferFunction((-a2*p + s)*(-a2*p - k*(a2*s + p) + s), (a2*s + p)**2, s)))) == MIMOSeries(MIMOParallel(tfm4, tfm5), tfm5).rewrite(TransferFunctionMatrix)) + + +def test_Parallel_construction(): + tf = TransferFunction(a0*s**3 + a1*s**2 - a2*s, b0*p**4 + b1*p**3 - b2*s*p, s) + tf2 = TransferFunction(a2*p - s, a2*s + p, s) + tf3 = TransferFunction(a0*p + p**a1 - s, p, p) + tf4 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) + inp = Function('X_d')(s) + out = Function('X')(s) + + p0 = Parallel(tf, tf2) + assert p0.args == (tf, tf2) + assert p0.var == s + + p1 = Parallel(Series(tf, -tf2), tf2) + assert p1.args == (Series(tf, -tf2), tf2) + assert p1.var == s + + tf3_ = TransferFunction(inp, 1, s) + tf4_ = TransferFunction(-out, 1, s) + p2 = Parallel(tf, Series(tf3_, -tf4_), tf2) + assert p2.args == (tf, Series(tf3_, -tf4_), tf2) + + p3 = Parallel(tf, tf2, tf4) + assert p3.args == (tf, tf2, tf4) + + p4 = Parallel(tf3_, tf4_) + assert p4.args == (tf3_, tf4_) + assert p4.var == s + + p5 = Parallel(tf, tf2) + assert p0 == p5 + assert not p0 == p1 + + p6 = Parallel(tf2, tf4, Series(tf2, -tf4)) + assert p6.args == (tf2, tf4, Series(tf2, -tf4)) + + p7 = Parallel(tf2, tf4, Series(tf2, -tf), tf4) + assert p7.args == (tf2, tf4, Series(tf2, -tf), tf4) + + raises(ValueError, lambda: Parallel(tf, tf3)) + raises(ValueError, lambda: Parallel(tf, tf2, tf3, tf4)) + raises(ValueError, lambda: Parallel(-tf3, tf4)) + raises(TypeError, lambda: Parallel(2, tf, tf4)) + raises(TypeError, lambda: Parallel(s**2 + p*s, tf3, tf2)) + raises(TypeError, lambda: Parallel(tf3, Matrix([1, 2, 3, 4]))) + + +def test_MIMOParallel_construction(): + tfm1 = TransferFunctionMatrix([[TF1], [TF2], [TF3]]) + tfm2 = TransferFunctionMatrix([[-TF3], [TF2], [TF1]]) + tfm3 = TransferFunctionMatrix([[TF1]]) + tfm4 = TransferFunctionMatrix([[TF2], [TF1], [TF3]]) + tfm5 = TransferFunctionMatrix([[TF1, TF2], [TF2, TF1]]) + tfm6 = TransferFunctionMatrix([[TF2, TF1], [TF1, TF2]]) + tfm7 = TransferFunctionMatrix.from_Matrix(Matrix([[1/p]]), p) + + p8 = MIMOParallel(tfm1, tfm2) + assert p8.args == (tfm1, tfm2) + assert p8.var == s + assert p8.shape == (p8.num_outputs, p8.num_inputs) == (3, 1) + + p9 = MIMOParallel(MIMOSeries(tfm3, tfm1), tfm2) + assert p9.args == (MIMOSeries(tfm3, tfm1), tfm2) + assert p9.var == s + assert p9.shape == (p9.num_outputs, p9.num_inputs) == (3, 1) + + p10 = MIMOParallel(tfm1, MIMOSeries(tfm3, tfm4), tfm2) + assert p10.args == (tfm1, MIMOSeries(tfm3, tfm4), tfm2) + assert p10.var == s + assert p10.shape == (p10.num_outputs, p10.num_inputs) == (3, 1) + + p11 = MIMOParallel(tfm2, tfm1, tfm4) + assert p11.args == (tfm2, tfm1, tfm4) + assert p11.shape == (p11.num_outputs, p11.num_inputs) == (3, 1) + + p12 = MIMOParallel(tfm6, tfm5) + assert p12.args == (tfm6, tfm5) + assert p12.shape == (p12.num_outputs, p12.num_inputs) == (2, 2) + + p13 = MIMOParallel(tfm2, tfm4, MIMOSeries(-tfm3, tfm4), -tfm4) + assert p13.args == (tfm2, tfm4, MIMOSeries(-tfm3, tfm4), -tfm4) + assert p13.shape == (p13.num_outputs, p13.num_inputs) == (3, 1) + + # arg cannot be empty tuple. + raises(TypeError, lambda: MIMOParallel(())) + + # arg cannot contain SISO as well as MIMO systems. + raises(TypeError, lambda: MIMOParallel(tfm1, tfm2, TF1)) + + # all TFMs must have same shapes. + raises(TypeError, lambda: MIMOParallel(tfm1, tfm3, tfm4)) + + # all TFMs must be using the same complex variable. + raises(ValueError, lambda: MIMOParallel(tfm3, tfm7)) + + # Number or expression not allowed in the arguments. + raises(TypeError, lambda: MIMOParallel(2, tfm1, tfm4)) + raises(TypeError, lambda: MIMOParallel(s**2 + p*s, -tfm4, tfm2)) + + +def test_Parallel_functions(): + tf1 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) + tf2 = TransferFunction(k, 1, s) + tf3 = TransferFunction(a2*p - s, a2*s + p, s) + tf4 = TransferFunction(a0*p + p**a1 - s, p, p) + tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) + + assert tf1 + tf2 + tf3 == Parallel(tf1, tf2, tf3) + assert tf1 + tf2 + tf3 + tf5 == Parallel(tf1, tf2, tf3, tf5) + assert tf1 + tf2 - tf3 - tf5 == Parallel(tf1, tf2, -tf3, -tf5) + assert tf1 + tf2*tf3 == Parallel(tf1, Series(tf2, tf3)) + assert tf1 - tf2*tf3 == Parallel(tf1, -Series(tf2,tf3)) + assert -tf1 - tf2 == Parallel(-tf1, -tf2) + assert -(tf1 + tf2) == Series(TransferFunction(-1, 1, s), Parallel(tf1, tf2)) + assert (tf2 + tf3)*tf1 == Series(Parallel(tf2, tf3), tf1) + assert (tf1 + tf2)*(tf3*tf5) == Series(Parallel(tf1, tf2), tf3, tf5) + assert -(tf2 + tf3)*-tf5 == Series(TransferFunction(-1, 1, s), Parallel(tf2, tf3), -tf5) + assert tf2 + tf3 + tf2*tf1 + tf5 == Parallel(tf2, tf3, Series(tf2, tf1), tf5) + assert tf2 + tf3 + tf2*tf1 - tf3 == Parallel(tf2, tf3, Series(tf2, tf1), -tf3) + assert (tf1 + tf2 + tf5)*(tf3 + tf5) == Series(Parallel(tf1, tf2, tf5), Parallel(tf3, tf5)) + raises(ValueError, lambda: tf1 + tf2 + tf4) + raises(ValueError, lambda: tf1 - tf2*tf4) + raises(ValueError, lambda: tf3 + Matrix([1, 2, 3])) + + # evaluate=True -> doit() + assert Parallel(tf1, tf2, evaluate=True) == Parallel(tf1, tf2).doit() == \ + TransferFunction(k*(s**2 + 2*s*wn*zeta + wn**2) + 1, s**2 + 2*s*wn*zeta + wn**2, s) + assert Parallel(tf1, tf2, Series(-tf1, tf3), evaluate=True) == \ + Parallel(tf1, tf2, Series(-tf1, tf3)).doit() == TransferFunction(k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2)**2 + \ + (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2) + (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), (a2*s + p)*(s**2 + \ + 2*s*wn*zeta + wn**2)**2, s) + assert Parallel(tf2, tf1, -tf3, evaluate=True) == Parallel(tf2, tf1, -tf3).doit() == \ + TransferFunction(a2*s + k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) + p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2) \ + , (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + assert not Parallel(tf1, -tf2, evaluate=False) == Parallel(tf1, -tf2).doit() + + assert Parallel(Series(tf1, tf2), Series(tf2, tf3)).doit() == \ + TransferFunction(k*(a2*p - s)*(s**2 + 2*s*wn*zeta + wn**2) + k*(a2*s + p), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + assert Parallel(-tf1, -tf2, -tf3).doit() == \ + TransferFunction(-a2*s - k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) - p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2), \ + (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + assert -Parallel(tf1, tf2, tf3).doit() == \ + TransferFunction(-a2*s - k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) - p - (a2*p - s)*(s**2 + 2*s*wn*zeta + wn**2), \ + (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + assert Parallel(tf2, tf3, Series(tf2, -tf1), tf3).doit() == \ + TransferFunction(k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) - k*(a2*s + p) + (2*a2*p - 2*s)*(s**2 + 2*s*wn*zeta \ + + wn**2), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + + assert Parallel(tf1, tf2).rewrite(TransferFunction) == \ + TransferFunction(k*(s**2 + 2*s*wn*zeta + wn**2) + 1, s**2 + 2*s*wn*zeta + wn**2, s) + assert Parallel(tf2, tf1, -tf3).rewrite(TransferFunction) == \ + TransferFunction(a2*s + k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) + p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + \ + wn**2), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + + assert Parallel(tf1, Parallel(tf2, tf3)) == Parallel(tf1, tf2, tf3) == Parallel(Parallel(tf1, tf2), tf3) + + P1 = Parallel(Series(tf1, tf2), Series(tf2, tf3)) + assert P1.is_proper + assert not P1.is_strictly_proper + assert P1.is_biproper + + P2 = Parallel(tf1, -tf2, -tf3) + assert P2.is_proper + assert not P2.is_strictly_proper + assert P2.is_biproper + + P3 = Parallel(tf1, -tf2, Series(tf1, tf3)) + assert P3.is_proper + assert not P3.is_strictly_proper + assert P3.is_biproper + + +def test_MIMOParallel_functions(): + tf4 = TransferFunction(a0*p + p**a1 - s, p, p) + tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) + + tfm1 = TransferFunctionMatrix([[TF1], [TF2], [TF3]]) + tfm2 = TransferFunctionMatrix([[-TF2], [tf5], [-TF1]]) + tfm3 = TransferFunctionMatrix([[tf5], [-tf5], [TF2]]) + tfm4 = TransferFunctionMatrix([[TF2, -tf5], [TF1, tf5]]) + tfm5 = TransferFunctionMatrix([[TF1, TF2], [TF3, -tf5]]) + tfm6 = TransferFunctionMatrix([[-TF2]]) + tfm7 = TransferFunctionMatrix([[tf4], [-tf4], [tf4]]) + + assert tfm1 + tfm2 + tfm3 == MIMOParallel(tfm1, tfm2, tfm3) == MIMOParallel(MIMOParallel(tfm1, tfm2), tfm3) + assert tfm2 - tfm1 - tfm3 == MIMOParallel(tfm2, -tfm1, -tfm3) + assert tfm2 - tfm3 + (-tfm1*tfm6*-tfm6) == MIMOParallel(tfm2, -tfm3, MIMOSeries(-tfm6, tfm6, -tfm1)) + assert tfm1 + tfm1 - (-tfm1*tfm6) == MIMOParallel(tfm1, tfm1, -MIMOSeries(tfm6, -tfm1)) + assert tfm2 - tfm3 - tfm1 + tfm2 == MIMOParallel(tfm2, -tfm3, -tfm1, tfm2) + assert tfm1 + tfm2 - tfm3 - tfm1 == MIMOParallel(tfm1, tfm2, -tfm3, -tfm1) + raises(ValueError, lambda: tfm1 + tfm2 + TF2) + raises(TypeError, lambda: tfm1 - tfm2 - a1) + raises(TypeError, lambda: tfm2 - tfm3 - (s - 1)) + raises(TypeError, lambda: -tfm3 - tfm2 - 9) + raises(TypeError, lambda: (1 - p**3) - tfm3 - tfm2) + # All TFMs must use the same complex var. tfm7 uses 'p'. + raises(ValueError, lambda: tfm3 - tfm2 - tfm7) + raises(ValueError, lambda: tfm2 - tfm1 + tfm7) + # (tfm1 +/- tfm2) has (3, 1) shape while tfm4 has (2, 2) shape. + raises(TypeError, lambda: tfm1 + tfm2 + tfm4) + raises(TypeError, lambda: (tfm1 - tfm2) - tfm4) + + assert (tfm1 + tfm2)*tfm6 == MIMOSeries(tfm6, MIMOParallel(tfm1, tfm2)) + assert (tfm2 - tfm3)*tfm6*-tfm6 == MIMOSeries(-tfm6, tfm6, MIMOParallel(tfm2, -tfm3)) + assert (tfm2 - tfm1 - tfm3)*(tfm6 + tfm6) == MIMOSeries(MIMOParallel(tfm6, tfm6), MIMOParallel(tfm2, -tfm1, -tfm3)) + raises(ValueError, lambda: (tfm4 + tfm5)*TF1) + raises(TypeError, lambda: (tfm2 - tfm3)*a2) + raises(TypeError, lambda: (tfm3 + tfm2)*(s - 6)) + raises(TypeError, lambda: (tfm1 + tfm2 + tfm3)*0) + raises(TypeError, lambda: (1 - p**3)*(tfm1 + tfm3)) + + # (tfm3 - tfm2) has (3, 1) shape while tfm4*tfm5 has (2, 2) shape. + raises(ValueError, lambda: (tfm3 - tfm2)*tfm4*tfm5) + # (tfm1 - tfm2) has (3, 1) shape while tfm5 has (2, 2) shape. + raises(ValueError, lambda: (tfm1 - tfm2)*tfm5) + + # TFM in the arguments. + assert (MIMOParallel(tfm1, tfm2, evaluate=True) == MIMOParallel(tfm1, tfm2).doit() + == MIMOParallel(tfm1, tfm2).rewrite(TransferFunctionMatrix) + == TransferFunctionMatrix(((TransferFunction(-k*(s**2 + 2*s*wn*zeta + wn**2) + 1, s**2 + 2*s*wn*zeta + wn**2, s),), \ + (TransferFunction(-a0 + a1*s**2 + a2*s + k*(a0 + s), a0 + s, s),), (TransferFunction(-a2*s - p + (a2*p - s)* \ + (s**2 + 2*s*wn*zeta + wn**2), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s),)))) + + +def test_Feedback_construction(): + tf1 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) + tf2 = TransferFunction(k, 1, s) + tf3 = TransferFunction(a2*p - s, a2*s + p, s) + tf4 = TransferFunction(a0*p + p**a1 - s, p, p) + tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) + tf6 = TransferFunction(s - p, p + s, p) + + f1 = Feedback(TransferFunction(1, 1, s), tf1*tf2*tf3) + assert f1.args == (TransferFunction(1, 1, s), Series(tf1, tf2, tf3), -1) + assert f1.sys1 == TransferFunction(1, 1, s) + assert f1.sys2 == Series(tf1, tf2, tf3) + assert f1.var == s + + f2 = Feedback(tf1, tf2*tf3) + assert f2.args == (tf1, Series(tf2, tf3), -1) + assert f2.sys1 == tf1 + assert f2.sys2 == Series(tf2, tf3) + assert f2.var == s + + f3 = Feedback(tf1*tf2, tf5) + assert f3.args == (Series(tf1, tf2), tf5, -1) + assert f3.sys1 == Series(tf1, tf2) + + f4 = Feedback(tf4, tf6) + assert f4.args == (tf4, tf6, -1) + assert f4.sys1 == tf4 + assert f4.var == p + + f5 = Feedback(tf5, TransferFunction(1, 1, s)) + assert f5.args == (tf5, TransferFunction(1, 1, s), -1) + assert f5.var == s + assert f5 == Feedback(tf5) # When sys2 is not passed explicitly, it is assumed to be unit tf. + + f6 = Feedback(TransferFunction(1, 1, p), tf4) + assert f6.args == (TransferFunction(1, 1, p), tf4, -1) + assert f6.var == p + + f7 = -Feedback(tf4*tf6, TransferFunction(1, 1, p)) + assert f7.args == (Series(TransferFunction(-1, 1, p), Series(tf4, tf6)), -TransferFunction(1, 1, p), -1) + assert f7.sys1 == Series(TransferFunction(-1, 1, p), Series(tf4, tf6)) + + # denominator can't be a Parallel instance + raises(TypeError, lambda: Feedback(tf1, tf2 + tf3)) + raises(TypeError, lambda: Feedback(tf1, Matrix([1, 2, 3]))) + raises(TypeError, lambda: Feedback(TransferFunction(1, 1, s), s - 1)) + raises(TypeError, lambda: Feedback(1, 1)) + # raises(ValueError, lambda: Feedback(TransferFunction(1, 1, s), TransferFunction(1, 1, s))) + raises(ValueError, lambda: Feedback(tf2, tf4*tf5)) + raises(ValueError, lambda: Feedback(tf2, tf1, 1.5)) # `sign` can only be -1 or 1 + raises(ValueError, lambda: Feedback(tf1, -tf1**-1)) # denominator can't be zero + raises(ValueError, lambda: Feedback(tf4, tf5)) # Both systems should use the same `var` + + +def test_Feedback_functions(): + tf = TransferFunction(1, 1, s) + tf1 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) + tf2 = TransferFunction(k, 1, s) + tf3 = TransferFunction(a2*p - s, a2*s + p, s) + tf4 = TransferFunction(a0*p + p**a1 - s, p, p) + tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) + tf6 = TransferFunction(s - p, p + s, p) + + assert (tf1*tf2*tf3 / tf3*tf5) == Series(tf1, tf2, tf3, pow(tf3, -1), tf5) + assert (tf1*tf2*tf3) / (tf3*tf5) == Series((tf1*tf2*tf3).doit(), pow((tf3*tf5).doit(),-1)) + assert tf / (tf + tf1) == Feedback(tf, tf1) + assert tf / (tf + tf1*tf2*tf3) == Feedback(tf, tf1*tf2*tf3) + assert tf1 / (tf + tf1*tf2*tf3) == Feedback(tf1, tf2*tf3) + assert (tf1*tf2) / (tf + tf1*tf2) == Feedback(tf1*tf2, tf) + assert (tf1*tf2) / (tf + tf1*tf2*tf5) == Feedback(tf1*tf2, tf5) + assert (tf1*tf2) / (tf + tf1*tf2*tf5*tf3) in (Feedback(tf1*tf2, tf5*tf3), Feedback(tf1*tf2, tf3*tf5)) + assert tf4 / (TransferFunction(1, 1, p) + tf4*tf6) == Feedback(tf4, tf6) + assert tf5 / (tf + tf5) == Feedback(tf5, tf) + + raises(TypeError, lambda: tf1*tf2*tf3 / (1 + tf1*tf2*tf3)) + raises(ValueError, lambda: tf2*tf3 / (tf + tf2*tf3*tf4)) + + assert Feedback(tf, tf1*tf2*tf3).doit() == \ + TransferFunction((a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), k*(a2*p - s) + \ + (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) + assert Feedback(tf, tf1*tf2*tf3).sensitivity == \ + 1/(k*(a2*p - s)/((a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2)) + 1) + assert Feedback(tf1, tf2*tf3).doit() == \ + TransferFunction((a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), (k*(a2*p - s) + \ + (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2))*(s**2 + 2*s*wn*zeta + wn**2), s) + assert Feedback(tf1, tf2*tf3).sensitivity == \ + 1/(k*(a2*p - s)/((a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2)) + 1) + assert Feedback(tf1*tf2, tf5).doit() == \ + TransferFunction(k*(a0 + s)*(s**2 + 2*s*wn*zeta + wn**2), (k*(-a0 + a1*s**2 + a2*s) + \ + (a0 + s)*(s**2 + 2*s*wn*zeta + wn**2))*(s**2 + 2*s*wn*zeta + wn**2), s) + assert Feedback(tf1*tf2, tf5, 1).sensitivity == \ + 1/(-k*(-a0 + a1*s**2 + a2*s)/((a0 + s)*(s**2 + 2*s*wn*zeta + wn**2)) + 1) + assert Feedback(tf4, tf6).doit() == \ + TransferFunction(p*(p + s)*(a0*p + p**a1 - s), p*(p*(p + s) + (-p + s)*(a0*p + p**a1 - s)), p) + assert -Feedback(tf4*tf6, TransferFunction(1, 1, p)).doit() == \ + TransferFunction(-p*(-p + s)*(p + s)*(a0*p + p**a1 - s), p*(p + s)*(p*(p + s) + (-p + s)*(a0*p + p**a1 - s)), p) + assert Feedback(tf, tf).doit() == TransferFunction(1, 2, s) + + assert Feedback(tf1, tf2*tf5).rewrite(TransferFunction) == \ + TransferFunction((a0 + s)*(s**2 + 2*s*wn*zeta + wn**2), (k*(-a0 + a1*s**2 + a2*s) + \ + (a0 + s)*(s**2 + 2*s*wn*zeta + wn**2))*(s**2 + 2*s*wn*zeta + wn**2), s) + assert Feedback(TransferFunction(1, 1, p), tf4).rewrite(TransferFunction) == \ + TransferFunction(p, a0*p + p + p**a1 - s, p) + + +def test_Feedback_with_Series(): + # Solves issue https://github.com/sympy/sympy/issues/26161 + tf1 = TransferFunction(s+1, 1, s) + tf2 = TransferFunction(s+2, 1, s) + fd1 = Feedback(tf1, tf2, -1) # Negative Feedback system + fd2 = Feedback(tf1, tf2, 1) # Positive Feedback system + unit = TransferFunction(1, 1, s) + + # Checking the type + assert isinstance(fd1, SISOLinearTimeInvariant) + assert isinstance(fd1, Feedback) + + # Testing the numerator and denominator + assert fd1.num == tf1 + assert fd2.num == tf1 + assert fd1.den == Parallel(unit, Series(tf2, tf1)) + assert fd2.den == Parallel(unit, -Series(tf2, tf1)) + + # Testing the Series and Parallel Combination with Feedback and TransferFunction + s1 = Series(tf1, fd1) + p1 = Parallel(tf1, fd1) + assert tf1 * fd1 == s1 + assert tf1 + fd1 == p1 + assert s1.doit() == TransferFunction((s + 1)**2, (s + 1)*(s + 2) + 1, s) + assert p1.doit() == TransferFunction(s + (s + 1)*((s + 1)*(s + 2) + 1) + 1, (s + 1)*(s + 2) + 1, s) + + # Testing the use of Feedback and TransferFunction with Feedback + fd3 = Feedback(tf1*fd1, tf2, -1) + assert fd3 == Feedback(Series(tf1, fd1), tf2) + assert fd3.num == tf1 * fd1 + assert fd3.den == Parallel(unit, Series(tf2, Series(tf1, fd1))) + + # Testing the use of Feedback and TransferFunction with TransferFunction + tf3 = TransferFunction(tf1*fd1, tf2, s) + assert tf3 == TransferFunction(Series(tf1, fd1), tf2, s) + assert tf3.num == tf1*fd1 + + +def test_issue_26161(): + # Issue https://github.com/sympy/sympy/issues/26161 + Ib, Is, m, h, l2, l1 = symbols('I_b, I_s, m, h, l2, l1', + real=True, nonnegative=True) + KD, KP, v = symbols('K_D, K_P, v', real=True) + + tau1_sq = (Ib + m * h ** 2) / m / g / h + tau2 = l2 / v + tau3 = v / (l1 + l2) + K = v ** 2 / g / (l1 + l2) + + Gtheta = TransferFunction(-K * (tau2 * s + 1), tau1_sq * s ** 2 - 1, s) + Gdelta = TransferFunction(1, Is * s ** 2 + c * s, s) + Gpsi = TransferFunction(1, tau3 * s, s) + Dcont = TransferFunction(KD * s, 1, s) + PIcont = TransferFunction(KP, s, s) + Gunity = TransferFunction(1, 1, s) + + Ginner = Feedback(Dcont * Gdelta, Gtheta) + Gouter = Feedback(PIcont * Ginner * Gpsi, Gunity) + assert Gouter == Feedback(Series(PIcont, Series(Ginner, Gpsi)), Gunity) + assert Gouter.num == Series(PIcont, Series(Ginner, Gpsi)) + assert Gouter.den == Parallel(Gunity, Series(Gunity, Series(PIcont, Series(Ginner, Gpsi)))) + expr = (KD*KP*g*s**3*v**2*(l1 + l2)*(Is*s**2 + c*s)**2*(-g*h*m + s**2*(Ib + h**2*m))*(-KD*g*h*m*s*v**2*(l2*s + v) + \ + g*v*(l1 + l2)*(Is*s**2 + c*s)*(-g*h*m + s**2*(Ib + h**2*m))))/((s**2*v*(Is*s**2 + c*s)*(-KD*g*h*m*s*v**2* \ + (l2*s + v) + g*v*(l1 + l2)*(Is*s**2 + c*s)*(-g*h*m + s**2*(Ib + h**2*m)))*(KD*KP*g*s*v*(l1 + l2)**2* \ + (Is*s**2 + c*s)*(-g*h*m + s**2*(Ib + h**2*m)) + s**2*v*(Is*s**2 + c*s)*(-KD*g*h*m*s*v**2*(l2*s + v) + \ + g*v*(l1 + l2)*(Is*s**2 + c*s)*(-g*h*m + s**2*(Ib + h**2*m))))/(l1 + l2))) + + assert (Gouter.to_expr() - expr).simplify() == 0 + + +def test_MIMOFeedback_construction(): + tf1 = TransferFunction(1, s, s) + tf2 = TransferFunction(s, s**3 - 1, s) + tf3 = TransferFunction(s, s + 1, s) + tf4 = TransferFunction(s, s**2 + 1, s) + + tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf3, tf4]]) + tfm_2 = TransferFunctionMatrix([[tf2, tf3], [tf4, tf1]]) + tfm_3 = TransferFunctionMatrix([[tf3, tf4], [tf1, tf2]]) + + f1 = MIMOFeedback(tfm_1, tfm_2) + assert f1.args == (tfm_1, tfm_2, -1) + assert f1.sys1 == tfm_1 + assert f1.sys2 == tfm_2 + assert f1.var == s + assert f1.sign == -1 + assert -(-f1) == f1 + + f2 = MIMOFeedback(tfm_2, tfm_1, 1) + assert f2.args == (tfm_2, tfm_1, 1) + assert f2.sys1 == tfm_2 + assert f2.sys2 == tfm_1 + assert f2.var == s + assert f2.sign == 1 + + f3 = MIMOFeedback(tfm_1, MIMOSeries(tfm_3, tfm_2)) + assert f3.args == (tfm_1, MIMOSeries(tfm_3, tfm_2), -1) + assert f3.sys1 == tfm_1 + assert f3.sys2 == MIMOSeries(tfm_3, tfm_2) + assert f3.var == s + assert f3.sign == -1 + + mat = Matrix([[1, 1/s], [0, 1]]) + sys1 = controller = TransferFunctionMatrix.from_Matrix(mat, s) + f4 = MIMOFeedback(sys1, controller) + assert f4.args == (sys1, controller, -1) + assert f4.sys1 == f4.sys2 == sys1 + + +def test_MIMOFeedback_errors(): + tf1 = TransferFunction(1, s, s) + tf2 = TransferFunction(s, s**3 - 1, s) + tf3 = TransferFunction(s, s - 1, s) + tf4 = TransferFunction(s, s**2 + 1, s) + tf5 = TransferFunction(1, 1, s) + tf6 = TransferFunction(-1, s - 1, s) + + tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf3, tf4]]) + tfm_2 = TransferFunctionMatrix([[tf2, tf3], [tf4, tf1]]) + tfm_3 = TransferFunctionMatrix.from_Matrix(eye(2), var=s) + tfm_4 = TransferFunctionMatrix([[tf1, tf5], [tf5, tf5]]) + tfm_5 = TransferFunctionMatrix([[-tf3, tf3], [tf3, tf6]]) + # tfm_4 is inverse of tfm_5. Therefore tfm_5*tfm_4 = I + tfm_6 = TransferFunctionMatrix([[-tf3]]) + tfm_7 = TransferFunctionMatrix([[tf3, tf4]]) + + # Unsupported Types + raises(TypeError, lambda: MIMOFeedback(tf1, tf2)) + raises(TypeError, lambda: MIMOFeedback(MIMOParallel(tfm_1, tfm_2), tfm_3)) + # Shape Errors + raises(ValueError, lambda: MIMOFeedback(tfm_1, tfm_6, 1)) + raises(ValueError, lambda: MIMOFeedback(tfm_7, tfm_7)) + # sign not 1/-1 + raises(ValueError, lambda: MIMOFeedback(tfm_1, tfm_2, -2)) + # Non-Invertible Systems + raises(ValueError, lambda: MIMOFeedback(tfm_5, tfm_4, 1)) + raises(ValueError, lambda: MIMOFeedback(tfm_4, -tfm_5)) + raises(ValueError, lambda: MIMOFeedback(tfm_3, tfm_3, 1)) + # Variable not same in both the systems + tfm_8 = TransferFunctionMatrix.from_Matrix(eye(2), var=p) + raises(ValueError, lambda: MIMOFeedback(tfm_1, tfm_8, 1)) + + +def test_MIMOFeedback_functions(): + tf1 = TransferFunction(1, s, s) + tf2 = TransferFunction(s, s - 1, s) + tf3 = TransferFunction(1, 1, s) + tf4 = TransferFunction(-1, s - 1, s) + + tfm_1 = TransferFunctionMatrix.from_Matrix(eye(2), var=s) + tfm_2 = TransferFunctionMatrix([[tf1, tf3], [tf3, tf3]]) + tfm_3 = TransferFunctionMatrix([[-tf2, tf2], [tf2, tf4]]) + tfm_4 = TransferFunctionMatrix([[tf1, tf2], [-tf2, tf1]]) + + # sensitivity, doit(), rewrite() + F_1 = MIMOFeedback(tfm_2, tfm_3) + F_2 = MIMOFeedback(tfm_2, MIMOSeries(tfm_4, -tfm_1), 1) + + assert F_1.sensitivity == Matrix([[S.Half, 0], [0, S.Half]]) + assert F_2.sensitivity == Matrix([[(-2*s**4 + s**2)/(s**2 - s + 1), + (2*s**3 - s**2)/(s**2 - s + 1)], [-s**2, s]]) + + assert F_1.doit() == \ + TransferFunctionMatrix(((TransferFunction(1, 2*s, s), + TransferFunction(1, 2, s)), (TransferFunction(1, 2, s), + TransferFunction(1, 2, s)))) == F_1.rewrite(TransferFunctionMatrix) + assert F_2.doit(cancel=False, expand=True) == \ + TransferFunctionMatrix(((TransferFunction(-s**5 + 2*s**4 - 2*s**3 + s**2, s**5 - 2*s**4 + 3*s**3 - 2*s**2 + s, s), + TransferFunction(-2*s**4 + 2*s**3, s**2 - s + 1, s)), (TransferFunction(0, 1, s), TransferFunction(-s**2 + s, 1, s)))) + assert F_2.doit(cancel=False) == \ + TransferFunctionMatrix(((TransferFunction(s*(2*s**3 - s**2)*(s**2 - s + 1) + \ + (-2*s**4 + s**2)*(s**2 - s + 1), s*(s**2 - s + 1)**2, s), TransferFunction(-2*s**4 + 2*s**3, s**2 - s + 1, s)), + (TransferFunction(0, 1, s), TransferFunction(-s**2 + s, 1, s)))) + assert F_2.doit() == \ + TransferFunctionMatrix(((TransferFunction(s*(-2*s**2 + s*(2*s - 1) + 1), s**2 - s + 1, s), + TransferFunction(-2*s**3*(s - 1), s**2 - s + 1, s)), (TransferFunction(0, 1, s), TransferFunction(s*(1 - s), 1, s)))) + assert F_2.doit(expand=True) == \ + TransferFunctionMatrix(((TransferFunction(-s**2 + s, s**2 - s + 1, s), TransferFunction(-2*s**4 + 2*s**3, s**2 - s + 1, s)), + (TransferFunction(0, 1, s), TransferFunction(-s**2 + s, 1, s)))) + + assert -(F_1.doit()) == (-F_1).doit() # First negating then calculating vs calculating then negating. + + +def test_TransferFunctionMatrix_construction(): + tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) + tf4 = TransferFunction(a0*p + p**a1 - s, p, p) + + tfm3_ = TransferFunctionMatrix([[-TF3]]) + assert tfm3_.shape == (tfm3_.num_outputs, tfm3_.num_inputs) == (1, 1) + assert tfm3_.args == Tuple(Tuple(Tuple(-TF3))) + assert tfm3_.var == s + + tfm5 = TransferFunctionMatrix([[TF1, -TF2], [TF3, tf5]]) + assert tfm5.shape == (tfm5.num_outputs, tfm5.num_inputs) == (2, 2) + assert tfm5.args == Tuple(Tuple(Tuple(TF1, -TF2), Tuple(TF3, tf5))) + assert tfm5.var == s + + tfm7 = TransferFunctionMatrix([[TF1, TF2], [TF3, -tf5], [-tf5, TF2]]) + assert tfm7.shape == (tfm7.num_outputs, tfm7.num_inputs) == (3, 2) + assert tfm7.args == Tuple(Tuple(Tuple(TF1, TF2), Tuple(TF3, -tf5), Tuple(-tf5, TF2))) + assert tfm7.var == s + + # all transfer functions will use the same complex variable. tf4 uses 'p'. + raises(ValueError, lambda: TransferFunctionMatrix([[TF1], [TF2], [tf4]])) + raises(ValueError, lambda: TransferFunctionMatrix([[TF1, tf4], [TF3, tf5]])) + + # length of all the lists in the TFM should be equal. + raises(ValueError, lambda: TransferFunctionMatrix([[TF1], [TF3, tf5]])) + raises(ValueError, lambda: TransferFunctionMatrix([[TF1, TF3], [tf5]])) + + # lists should only support transfer functions in them. + raises(TypeError, lambda: TransferFunctionMatrix([[TF1, TF2], [TF3, Matrix([1, 2])]])) + raises(TypeError, lambda: TransferFunctionMatrix([[TF1, Matrix([1, 2])], [TF3, TF2]])) + + # `arg` should strictly be nested list of TransferFunction + raises(ValueError, lambda: TransferFunctionMatrix([TF1, TF2, tf5])) + raises(ValueError, lambda: TransferFunctionMatrix([TF1])) + +def test_TransferFunctionMatrix_functions(): + tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) + + # Classmethod (from_matrix) + + mat_1 = ImmutableMatrix([ + [s*(s + 1)*(s - 3)/(s**4 + 1), 2], + [p, p*(s + 1)/(s*(s**1 + 1))] + ]) + mat_2 = ImmutableMatrix([[(2*s + 1)/(s**2 - 9)]]) + mat_3 = ImmutableMatrix([[1, 2], [3, 4]]) + assert TransferFunctionMatrix.from_Matrix(mat_1, s) == \ + TransferFunctionMatrix([[TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(2, 1, s)], + [TransferFunction(p, 1, s), TransferFunction(p, s, s)]]) + assert TransferFunctionMatrix.from_Matrix(mat_2, s) == \ + TransferFunctionMatrix([[TransferFunction(2*s + 1, s**2 - 9, s)]]) + assert TransferFunctionMatrix.from_Matrix(mat_3, p) == \ + TransferFunctionMatrix([[TransferFunction(1, 1, p), TransferFunction(2, 1, p)], + [TransferFunction(3, 1, p), TransferFunction(4, 1, p)]]) + + # Negating a TFM + + tfm1 = TransferFunctionMatrix([[TF1], [TF2]]) + assert -tfm1 == TransferFunctionMatrix([[-TF1], [-TF2]]) + + tfm2 = TransferFunctionMatrix([[TF1, TF2, TF3], [tf5, -TF1, -TF3]]) + assert -tfm2 == TransferFunctionMatrix([[-TF1, -TF2, -TF3], [-tf5, TF1, TF3]]) + + # subs() + + H_1 = TransferFunctionMatrix.from_Matrix(mat_1, s) + H_2 = TransferFunctionMatrix([[TransferFunction(a*p*s, k*s**2, s), TransferFunction(p*s, k*(s**2 - a), s)]]) + assert H_1.subs(p, 1) == TransferFunctionMatrix([[TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(2, 1, s)], [TransferFunction(1, 1, s), TransferFunction(1, s, s)]]) + assert H_1.subs({p: 1}) == TransferFunctionMatrix([[TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(2, 1, s)], [TransferFunction(1, 1, s), TransferFunction(1, s, s)]]) + assert H_1.subs({p: 1, s: 1}) == TransferFunctionMatrix([[TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(2, 1, s)], [TransferFunction(1, 1, s), TransferFunction(1, s, s)]]) # This should ignore `s` as it is `var` + assert H_2.subs(p, 2) == TransferFunctionMatrix([[TransferFunction(2*a*s, k*s**2, s), TransferFunction(2*s, k*(-a + s**2), s)]]) + assert H_2.subs(k, 1) == TransferFunctionMatrix([[TransferFunction(a*p*s, s**2, s), TransferFunction(p*s, -a + s**2, s)]]) + assert H_2.subs(a, 0) == TransferFunctionMatrix([[TransferFunction(0, k*s**2, s), TransferFunction(p*s, k*s**2, s)]]) + assert H_2.subs({p: 1, k: 1, a: a0}) == TransferFunctionMatrix([[TransferFunction(a0*s, s**2, s), TransferFunction(s, -a0 + s**2, s)]]) + + # eval_frequency() + assert H_2.eval_frequency(S(1)/2 + I) == Matrix([[2*a*p/(5*k) - 4*I*a*p/(5*k), I*p/(-a*k - 3*k/4 + I*k) + p/(-2*a*k - 3*k/2 + 2*I*k)]]) + + # transpose() + + assert H_1.transpose() == TransferFunctionMatrix([[TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(p, 1, s)], [TransferFunction(2, 1, s), TransferFunction(p, s, s)]]) + assert H_2.transpose() == TransferFunctionMatrix([[TransferFunction(a*p*s, k*s**2, s)], [TransferFunction(p*s, k*(-a + s**2), s)]]) + assert H_1.transpose().transpose() == H_1 + assert H_2.transpose().transpose() == H_2 + + # elem_poles() + + assert H_1.elem_poles() == [[[-sqrt(2)/2 - sqrt(2)*I/2, -sqrt(2)/2 + sqrt(2)*I/2, sqrt(2)/2 - sqrt(2)*I/2, sqrt(2)/2 + sqrt(2)*I/2], []], + [[], [0]]] + assert H_2.elem_poles() == [[[0, 0], [sqrt(a), -sqrt(a)]]] + assert tfm2.elem_poles() == [[[wn*(-zeta + sqrt((zeta - 1)*(zeta + 1))), wn*(-zeta - sqrt((zeta - 1)*(zeta + 1)))], [], [-p/a2]], + [[-a0], [wn*(-zeta + sqrt((zeta - 1)*(zeta + 1))), wn*(-zeta - sqrt((zeta - 1)*(zeta + 1)))], [-p/a2]]] + + # elem_zeros() + + assert H_1.elem_zeros() == [[[-1, 0, 3], []], [[], []]] + assert H_2.elem_zeros() == [[[0], [0]]] + assert tfm2.elem_zeros() == [[[], [], [a2*p]], + [[-a2/(2*a1) - sqrt(4*a0*a1 + a2**2)/(2*a1), -a2/(2*a1) + sqrt(4*a0*a1 + a2**2)/(2*a1)], [], [a2*p]]] + + # doit() + + H_3 = TransferFunctionMatrix([[Series(TransferFunction(1, s**3 - 3, s), TransferFunction(s**2 - 2*s + 5, 1, s), TransferFunction(1, s, s))]]) + H_4 = TransferFunctionMatrix([[Parallel(TransferFunction(s**3 - 3, 4*s**4 - s**2 - 2*s + 5, s), TransferFunction(4 - s**3, 4*s**4 - s**2 - 2*s + 5, s))]]) + + assert H_3.doit() == TransferFunctionMatrix([[TransferFunction(s**2 - 2*s + 5, s*(s**3 - 3), s)]]) + assert H_4.doit() == TransferFunctionMatrix([[TransferFunction(1, 4*s**4 - s**2 - 2*s + 5, s)]]) + + # _flat() + + assert H_1._flat() == [TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(2, 1, s), TransferFunction(p, 1, s), TransferFunction(p, s, s)] + assert H_2._flat() == [TransferFunction(a*p*s, k*s**2, s), TransferFunction(p*s, k*(-a + s**2), s)] + assert H_3._flat() == [Series(TransferFunction(1, s**3 - 3, s), TransferFunction(s**2 - 2*s + 5, 1, s), TransferFunction(1, s, s))] + assert H_4._flat() == [Parallel(TransferFunction(s**3 - 3, 4*s**4 - s**2 - 2*s + 5, s), TransferFunction(4 - s**3, 4*s**4 - s**2 - 2*s + 5, s))] + + # evalf() + + assert H_1.evalf() == \ + TransferFunctionMatrix(((TransferFunction(s*(s - 3.0)*(s + 1.0), s**4 + 1.0, s), TransferFunction(2.0, 1, s)), (TransferFunction(1.0*p, 1, s), TransferFunction(p, s, s)))) + assert H_2.subs({a:3.141, p:2.88, k:2}).evalf() == \ + TransferFunctionMatrix(((TransferFunction(4.5230399999999999494093572138808667659759521484375, s, s), + TransferFunction(2.87999999999999989341858963598497211933135986328125*s, 2.0*s**2 - 6.282000000000000028421709430404007434844970703125, s)),)) + + # simplify() + + H_5 = TransferFunctionMatrix([[TransferFunction(s**5 + s**3 + s, s - s**2, s), + TransferFunction((s + 3)*(s - 1), (s - 1)*(s + 5), s)]]) + + assert H_5.simplify() == simplify(H_5) == \ + TransferFunctionMatrix(((TransferFunction(-s**4 - s**2 - 1, s - 1, s), TransferFunction(s + 3, s + 5, s)),)) + + # expand() + + assert (H_1.expand() + == TransferFunctionMatrix(((TransferFunction(s**3 - 2*s**2 - 3*s, s**4 + 1, s), TransferFunction(2, 1, s)), + (TransferFunction(p, 1, s), TransferFunction(p, s, s))))) + assert H_5.expand() == \ + TransferFunctionMatrix(((TransferFunction(s**5 + s**3 + s, -s**2 + s, s), TransferFunction(s**2 + 2*s - 3, s**2 + 4*s - 5, s)),)) + +def test_TransferFunction_gbt(): + # simple transfer function, e.g. ohms law + tf = TransferFunction(1, a*s+b, s) + numZ, denZ = gbt(tf, T, 0.5) + # discretized transfer function with coefs from tf.gbt() + tf_test_bilinear = TransferFunction(s * numZ[0] + numZ[1], s * denZ[0] + denZ[1], s) + # corresponding tf with manually calculated coefs + tf_test_manual = TransferFunction(s * T/(2*(a + b*T/2)) + T/(2*(a + b*T/2)), s + (-a + b*T/2)/(a + b*T/2), s) + + assert S.Zero == (tf_test_bilinear.simplify()-tf_test_manual.simplify()).simplify().num + + tf = TransferFunction(1, a*s+b, s) + numZ, denZ = gbt(tf, T, 0) + # discretized transfer function with coefs from tf.gbt() + tf_test_forward = TransferFunction(numZ[0], s*denZ[0]+denZ[1], s) + # corresponding tf with manually calculated coefs + tf_test_manual = TransferFunction(T/a, s + (-a + b*T)/a, s) + + assert S.Zero == (tf_test_forward.simplify()-tf_test_manual.simplify()).simplify().num + + tf = TransferFunction(1, a*s+b, s) + numZ, denZ = gbt(tf, T, 1) + # discretized transfer function with coefs from tf.gbt() + tf_test_backward = TransferFunction(s*numZ[0], s*denZ[0]+denZ[1], s) + # corresponding tf with manually calculated coefs + tf_test_manual = TransferFunction(s * T/(a + b*T), s - a/(a + b*T), s) + + assert S.Zero == (tf_test_backward.simplify()-tf_test_manual.simplify()).simplify().num + + tf = TransferFunction(1, a*s+b, s) + numZ, denZ = gbt(tf, T, 0.3) + # discretized transfer function with coefs from tf.gbt() + tf_test_gbt = TransferFunction(s*numZ[0]+numZ[1], s*denZ[0]+denZ[1], s) + # corresponding tf with manually calculated coefs + tf_test_manual = TransferFunction(s*3*T/(10*(a + 3*b*T/10)) + 7*T/(10*(a + 3*b*T/10)), s + (-a + 7*b*T/10)/(a + 3*b*T/10), s) + + assert S.Zero == (tf_test_gbt.simplify()-tf_test_manual.simplify()).simplify().num + +def test_TransferFunction_bilinear(): + # simple transfer function, e.g. ohms law + tf = TransferFunction(1, a*s+b, s) + numZ, denZ = bilinear(tf, T) + # discretized transfer function with coefs from tf.bilinear() + tf_test_bilinear = TransferFunction(s*numZ[0]+numZ[1], s*denZ[0]+denZ[1], s) + # corresponding tf with manually calculated coefs + tf_test_manual = TransferFunction(s * T/(2*(a + b*T/2)) + T/(2*(a + b*T/2)), s + (-a + b*T/2)/(a + b*T/2), s) + + assert S.Zero == (tf_test_bilinear.simplify()-tf_test_manual.simplify()).simplify().num + +def test_TransferFunction_forward_diff(): + # simple transfer function, e.g. ohms law + tf = TransferFunction(1, a*s+b, s) + numZ, denZ = forward_diff(tf, T) + # discretized transfer function with coefs from tf.forward_diff() + tf_test_forward = TransferFunction(numZ[0], s*denZ[0]+denZ[1], s) + # corresponding tf with manually calculated coefs + tf_test_manual = TransferFunction(T/a, s + (-a + b*T)/a, s) + + assert S.Zero == (tf_test_forward.simplify()-tf_test_manual.simplify()).simplify().num + +def test_TransferFunction_backward_diff(): + # simple transfer function, e.g. ohms law + tf = TransferFunction(1, a*s+b, s) + numZ, denZ = backward_diff(tf, T) + # discretized transfer function with coefs from tf.backward_diff() + tf_test_backward = TransferFunction(s*numZ[0]+numZ[1], s*denZ[0]+denZ[1], s) + # corresponding tf with manually calculated coefs + tf_test_manual = TransferFunction(s * T/(a + b*T), s - a/(a + b*T), s) + + assert S.Zero == (tf_test_backward.simplify()-tf_test_manual.simplify()).simplify().num + +def test_TransferFunction_phase_margin(): + # Test for phase margin + tf1 = TransferFunction(10, p**3 + 1, p) + tf2 = TransferFunction(s**2, 10, s) + tf3 = TransferFunction(1, a*s+b, s) + tf4 = TransferFunction((s + 1)*exp(s/tau), s**2 + 2, s) + tf_m = TransferFunctionMatrix([[tf2],[tf3]]) + + assert phase_margin(tf1) == -180 + 180*atan(3*sqrt(11))/pi + assert phase_margin(tf2) == 0 + + raises(NotImplementedError, lambda: phase_margin(tf4)) + raises(ValueError, lambda: phase_margin(tf3)) + raises(ValueError, lambda: phase_margin(MIMOSeries(tf_m))) + +def test_TransferFunction_gain_margin(): + # Test for gain margin + tf1 = TransferFunction(s**2, 5*(s+1)*(s-5)*(s-10), s) + tf2 = TransferFunction(s**2 + 2*s + 1, 1, s) + tf3 = TransferFunction(1, a*s+b, s) + tf4 = TransferFunction((s + 1)*exp(s/tau), s**2 + 2, s) + tf_m = TransferFunctionMatrix([[tf2],[tf3]]) + + assert gain_margin(tf1) == -20*log(S(7)/540)/log(10) + assert gain_margin(tf2) == oo + + raises(NotImplementedError, lambda: gain_margin(tf4)) + raises(ValueError, lambda: gain_margin(tf3)) + raises(ValueError, lambda: gain_margin(MIMOSeries(tf_m))) + + +def test_StateSpace_construction(): + # using different numbers for a SISO system. + A1 = Matrix([[0, 1], [1, 0]]) + B1 = Matrix([1, 0]) + C1 = Matrix([[0, 1]]) + D1 = Matrix([0]) + ss1 = StateSpace(A1, B1, C1, D1) + + assert ss1.state_matrix == Matrix([[0, 1], [1, 0]]) + assert ss1.input_matrix == Matrix([1, 0]) + assert ss1.output_matrix == Matrix([[0, 1]]) + assert ss1.feedforward_matrix == Matrix([0]) + assert ss1.args == (Matrix([[0, 1], [1, 0]]), Matrix([[1], [0]]), Matrix([[0, 1]]), Matrix([[0]])) + + # using different symbols for a SISO system. + ss2 = StateSpace(Matrix([a0]), Matrix([a1]), + Matrix([a2]), Matrix([a3])) + + assert ss2.state_matrix == Matrix([[a0]]) + assert ss2.input_matrix == Matrix([[a1]]) + assert ss2.output_matrix == Matrix([[a2]]) + assert ss2.feedforward_matrix == Matrix([[a3]]) + assert ss2.args == (Matrix([[a0]]), Matrix([[a1]]), Matrix([[a2]]), Matrix([[a3]])) + + # using different numbers for a MIMO system. + ss3 = StateSpace(Matrix([[-1.5, -2], [1, 0]]), + Matrix([[0.5, 0], [0, 1]]), + Matrix([[0, 1], [0, 2]]), + Matrix([[2, 2], [1, 1]])) + + assert ss3.state_matrix == Matrix([[-1.5, -2], [1, 0]]) + assert ss3.input_matrix == Matrix([[0.5, 0], [0, 1]]) + assert ss3.output_matrix == Matrix([[0, 1], [0, 2]]) + assert ss3.feedforward_matrix == Matrix([[2, 2], [1, 1]]) + assert ss3.args == (Matrix([[-1.5, -2], + [1, 0]]), + Matrix([[0.5, 0], + [0, 1]]), + Matrix([[0, 1], + [0, 2]]), + Matrix([[2, 2], + [1, 1]])) + + # using different symbols for a MIMO system. + A4 = Matrix([[a0, a1], [a2, a3]]) + B4 = Matrix([[b0, b1], [b2, b3]]) + C4 = Matrix([[c0, c1], [c2, c3]]) + D4 = Matrix([[d0, d1], [d2, d3]]) + ss4 = StateSpace(A4, B4, C4, D4) + + assert ss4.state_matrix == Matrix([[a0, a1], [a2, a3]]) + assert ss4.input_matrix == Matrix([[b0, b1], [b2, b3]]) + assert ss4.output_matrix == Matrix([[c0, c1], [c2, c3]]) + assert ss4.feedforward_matrix == Matrix([[d0, d1], [d2, d3]]) + assert ss4.args == (Matrix([[a0, a1], + [a2, a3]]), + Matrix([[b0, b1], + [b2, b3]]), + Matrix([[c0, c1], + [c2, c3]]), + Matrix([[d0, d1], + [d2, d3]])) + + # using less matrices. Rest will be filled with a minimum of zeros. + ss5 = StateSpace() + assert ss5.args == (Matrix([[0]]), Matrix([[0]]), Matrix([[0]]), Matrix([[0]])) + + A6 = Matrix([[0, 1], [1, 0]]) + B6 = Matrix([1, 1]) + ss6 = StateSpace(A6, B6) + + assert ss6.state_matrix == Matrix([[0, 1], [1, 0]]) + assert ss6.input_matrix == Matrix([1, 1]) + assert ss6.output_matrix == Matrix([[0, 0]]) + assert ss6.feedforward_matrix == Matrix([[0]]) + assert ss6.args == (Matrix([[0, 1], + [1, 0]]), + Matrix([[1], + [1]]), + Matrix([[0, 0]]), + Matrix([[0]])) + + # Check if the system is SISO or MIMO. + # If system is not SISO, then it is definitely MIMO. + + assert ss1.is_SISO == True + assert ss2.is_SISO == True + assert ss3.is_SISO == False + assert ss4.is_SISO == False + assert ss5.is_SISO == True + assert ss6.is_SISO == True + + # ShapeError if matrices do not fit. + raises(ShapeError, lambda: StateSpace(Matrix([s, (s+1)**2]), Matrix([s+1]), + Matrix([s**2 - 1]), Matrix([2*s]))) + raises(ShapeError, lambda: StateSpace(Matrix([s]), Matrix([s+1, s**3 + 1]), + Matrix([s**2 - 1]), Matrix([2*s]))) + raises(ShapeError, lambda: StateSpace(Matrix([s]), Matrix([s+1]), + Matrix([[s**2 - 1], [s**2 + 2*s + 1]]), Matrix([2*s]))) + raises(ShapeError, lambda: StateSpace(Matrix([[-s, -s], [s, 0]]), + Matrix([[s/2, 0], [0, s]]), + Matrix([[0, s]]), + Matrix([[2*s, 2*s], [s, s]]))) + + # TypeError if arguments are not sympy matrices. + raises(TypeError, lambda: StateSpace(s**2, s+1, 2*s, 1)) + raises(TypeError, lambda: StateSpace(Matrix([2, 0.5]), Matrix([-1]), + Matrix([1]), 0)) +def test_StateSpace_add(): + A1 = Matrix([[4, 1],[2, -3]]) + B1 = Matrix([[5, 2],[-3, -3]]) + C1 = Matrix([[2, -4],[0, 1]]) + D1 = Matrix([[3, 2],[1, -1]]) + ss1 = StateSpace(A1, B1, C1, D1) + + A2 = Matrix([[-3, 4, 2],[-1, -3, 0],[2, 5, 3]]) + B2 = Matrix([[1, 4],[-3, -3],[-2, 1]]) + C2 = Matrix([[4, 2, -3],[1, 4, 3]]) + D2 = Matrix([[-2, 4],[0, 1]]) + ss2 = StateSpace(A2, B2, C2, D2) + ss3 = StateSpace() + ss4 = StateSpace(Matrix([1]), Matrix([2]), Matrix([3]), Matrix([4])) + + expected_add = \ + StateSpace( + Matrix([ + [4, 1, 0, 0, 0], + [2, -3, 0, 0, 0], + [0, 0, -3, 4, 2], + [0, 0, -1, -3, 0], + [0, 0, 2, 5, 3]]), + Matrix([ + [ 5, 2], + [-3, -3], + [ 1, 4], + [-3, -3], + [-2, 1]]), + Matrix([ + [2, -4, 4, 2, -3], + [0, 1, 1, 4, 3]]), + Matrix([ + [1, 6], + [1, 0]])) + + expected_mul = \ + StateSpace( + Matrix([ + [ -3, 4, 2, 0, 0], + [ -1, -3, 0, 0, 0], + [ 2, 5, 3, 0, 0], + [ 22, 18, -9, 4, 1], + [-15, -18, 0, 2, -3]]), + Matrix([ + [ 1, 4], + [ -3, -3], + [ -2, 1], + [-10, 22], + [ 6, -15]]), + Matrix([ + [14, 14, -3, 2, -4], + [ 3, -2, -6, 0, 1]]), + Matrix([ + [-6, 14], + [-2, 3]])) + + assert ss1 + ss2 == expected_add + assert ss1*ss2 == expected_mul + assert ss3 + 1/2 == StateSpace(Matrix([[0]]), Matrix([[0]]), Matrix([[0]]), Matrix([[0.5]])) + assert ss4*1.5 == StateSpace(Matrix([[1]]), Matrix([[2]]), Matrix([[4.5]]), Matrix([[6.0]])) + assert 1.5*ss4 == StateSpace(Matrix([[1]]), Matrix([[3.0]]), Matrix([[3]]), Matrix([[6.0]])) + raises(ShapeError, lambda: ss1 + ss3) + raises(ShapeError, lambda: ss2*ss4) + +def test_StateSpace_negation(): + A = Matrix([[a0, a1], [a2, a3]]) + B = Matrix([[b0, b1], [b2, b3]]) + C = Matrix([[c0, c1], [c1, c2], [c2, c3]]) + D = Matrix([[d0, d1], [d1, d2], [d2, d3]]) + SS = StateSpace(A, B, C, D) + SS_neg = -SS + + state_mat = Matrix([[-1, 1], [1, -1]]) + input_mat = Matrix([1, -1]) + output_mat = Matrix([[-1, 1]]) + feedforward_mat = Matrix([1]) + system = StateSpace(state_mat, input_mat, output_mat, feedforward_mat) + + assert SS_neg == \ + StateSpace(Matrix([[a0, a1], + [a2, a3]]), + Matrix([[b0, b1], + [b2, b3]]), + Matrix([[-c0, -c1], + [-c1, -c2], + [-c2, -c3]]), + Matrix([[-d0, -d1], + [-d1, -d2], + [-d2, -d3]])) + assert -system == \ + StateSpace(Matrix([[-1, 1], + [ 1, -1]]), + Matrix([[ 1],[-1]]), + Matrix([[1, -1]]), + Matrix([[-1]])) + assert -SS_neg == SS + assert -(-(-(-system))) == system + +def test_SymPy_substitution_functions(): + # subs + ss1 = StateSpace(Matrix([s]), Matrix([(s + 1)**2]), Matrix([s**2 - 1]), Matrix([2*s])) + ss2 = StateSpace(Matrix([s + p]), Matrix([(s + 1)*(p - 1)]), Matrix([p**3 - s**3]), Matrix([s - p])) + + assert ss1.subs({s:5}) == StateSpace(Matrix([[5]]), Matrix([[36]]), Matrix([[24]]), Matrix([[10]])) + assert ss2.subs({p:1}) == StateSpace(Matrix([[s + 1]]), Matrix([[0]]), Matrix([[1 - s**3]]), Matrix([[s - 1]])) + + # xreplace + assert ss1.xreplace({s:p}) == \ + StateSpace(Matrix([[p]]), Matrix([[(p + 1)**2]]), Matrix([[p**2 - 1]]), Matrix([[2*p]])) + assert ss2.xreplace({s:a, p:b}) == \ + StateSpace(Matrix([[a + b]]), Matrix([[(a + 1)*(b - 1)]]), Matrix([[-a**3 + b**3]]), Matrix([[a - b]])) + + # evalf + p1 = a1*s + a0 + p2 = b2*s**2 + b1*s + b0 + G = StateSpace(Matrix([p1]), Matrix([p2])) + expect = StateSpace(Matrix([[2*s + 1]]), Matrix([[5*s**2 + 4*s + 3]]), Matrix([[0]]), Matrix([[0]])) + expect_ = StateSpace(Matrix([[2.0*s + 1.0]]), Matrix([[5.0*s**2 + 4.0*s + 3.0]]), Matrix([[0]]), Matrix([[0]])) + assert G.subs({a0: 1, a1: 2, b0: 3, b1: 4, b2: 5}) == expect + assert G.subs({a0: 1, a1: 2, b0: 3, b1: 4, b2: 5}).evalf() == expect_ + assert expect.evalf() == expect_ + +def test_conversion(): + # StateSpace to TransferFunction for SISO + A1 = Matrix([[-5, -1], [3, -1]]) + B1 = Matrix([2, 5]) + C1 = Matrix([[1, 2]]) + D1 = Matrix([0]) + H1 = StateSpace(A1, B1, C1, D1) + H3 = StateSpace(Matrix([[a0, a1], [a2, a3]]), B = Matrix([[b1], [b2]]), C = Matrix([[c1, c2]])) + tm1 = H1.rewrite(TransferFunction) + tm2 = (-H1).rewrite(TransferFunction) + + tf1 = tm1[0][0] + tf2 = tm2[0][0] + + assert tf1 == TransferFunction(12*s + 59, s**2 + 6*s + 8, s) + assert tf2.num == -tf1.num + assert tf2.den == tf1.den + + # StateSpace to TransferFunction for MIMO + A2 = Matrix([[-1.5, -2, 3], [1, 0, 1], [2, 1, 1]]) + B2 = Matrix([[0.5, 0, 1], [0, 1, 2], [2, 2, 3]]) + C2 = Matrix([[0, 1, 0], [0, 2, 1], [1, 0, 2]]) + D2 = Matrix([[2, 2, 0], [1, 1, 1], [3, 2, 1]]) + H2 = StateSpace(A2, B2, C2, D2) + tm3 = H2.rewrite(TransferFunction) + + # outputs for input i obtained at Index i-1. Consider input 1 + assert tm3[0][0] == TransferFunction(2.0*s**3 + 1.0*s**2 - 10.5*s + 4.5, 1.0*s**3 + 0.5*s**2 - 6.5*s - 2.5, s) + assert tm3[0][1] == TransferFunction(2.0*s**3 + 2.0*s**2 - 10.5*s - 3.5, 1.0*s**3 + 0.5*s**2 - 6.5*s - 2.5, s) + assert tm3[0][2] == TransferFunction(2.0*s**2 + 5.0*s - 0.5, 1.0*s**3 + 0.5*s**2 - 6.5*s - 2.5, s) + assert H3.rewrite(TransferFunction) == [[TransferFunction(-c1*(a1*b2 - a3*b1 + b1*s) - c2*(-a0*b2 + a2*b1 + b2*s), + -a0*a3 + a0*s + a1*a2 + a3*s - s**2, s)]] + # TransferFunction to StateSpace + SS = TF1.rewrite(StateSpace) + assert SS == \ + StateSpace(Matrix([[ 0, 1], + [-wn**2, -2*wn*zeta]]), + Matrix([[0], + [1]]), + Matrix([[1, 0]]), + Matrix([[0]])) + assert SS.rewrite(TransferFunction)[0][0] == TF1 + + # Transfer function has to be proper + raises(ValueError, lambda: TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s).rewrite(StateSpace)) + + +def test_StateSpace_dsolve(): + # https://web.mit.edu/2.14/www/Handouts/StateSpaceResponse.pdf + # https://lpsa.swarthmore.edu/Transient/TransMethSS.html + A1 = Matrix([[0, 1], [-2, -3]]) + B1 = Matrix([[0], [1]]) + C1 = Matrix([[1, -1]]) + D1 = Matrix([0]) + I1 = Matrix([[1], [2]]) + t = symbols('t') + ss1 = StateSpace(A1, B1, C1, D1) + + # Zero input and Zero initial conditions + assert ss1.dsolve() == Matrix([[0]]) + assert ss1.dsolve(initial_conditions=I1) == Matrix([[8*exp(-t) - 9*exp(-2*t)]]) + + A2 = Matrix([[-2, 0], [1, -1]]) + C2 = eye(2,2) + I2 = Matrix([2, 3]) + ss2 = StateSpace(A=A2, C=C2) + assert ss2.dsolve(initial_conditions=I2) == Matrix([[2*exp(-2*t)], [5*exp(-t) - 2*exp(-2*t)]]) + + A3 = Matrix([[-1, 1], [-4, -4]]) + B3 = Matrix([[0], [4]]) + C3 = Matrix([[0, 1]]) + D3 = Matrix([0]) + U3 = Matrix([10]) + ss3 = StateSpace(A3, B3, C3, D3) + op = ss3.dsolve(input_vector=U3, var=t) + assert str(op.simplify().expand().evalf()[0]) == str(5.0 + 20.7880460155075*exp(-5*t/2)*sin(sqrt(7)*t/2) + - 5.0*exp(-5*t/2)*cos(sqrt(7)*t/2)) + + # Test with Heaviside as input + A4 = Matrix([[-1, 1], [-4, -4]]) + B4 = Matrix([[0], [4]]) + C4 = Matrix([[0, 1]]) + U4 = Matrix([[10*Heaviside(t)]]) + ss4 = StateSpace(A4, B4, C4) + op4 = str(ss4.dsolve(var=t, input_vector=U4)[0].simplify().expand().evalf()) + assert op4 == str(5.0*Heaviside(t) + 20.7880460155075*exp(-5*t/2)*sin(sqrt(7)*t/2)*Heaviside(t) + - 5.0*exp(-5*t/2)*cos(sqrt(7)*t/2)*Heaviside(t)) + + # Test with Symbolic Matrices + m, a, x0 = symbols('m a x_0') + A5 = Matrix([[0, 1], [0, 0]]) + B5 = Matrix([[0], [1 / m]]) + C5 = Matrix([[1, 0]]) + I5 = Matrix([[x0], [0]]) + U5 = Matrix([[exp(-a * t)]]) + ss5 = StateSpace(A5, B5, C5) + op5 = ss5.dsolve(initial_conditions=I5, input_vector=U5, var=t).simplify() + assert op5[0].args[0][0] == x0 + t/(a*m) - 1/(a**2*m) + exp(-a*t)/(a**2*m) + a11, a12, a21, a22, b1, b2, c1, c2, i1, i2 = symbols('a_11 a_12 a_21 a_22 b_1 b_2 c_1 c_2 i_1 i_2') + A6 = Matrix([[a11, a12], [a21, a22]]) + B6 = Matrix([b1, b2]) + C6 = Matrix([[c1, c2]]) + I6 = Matrix([i1, i2]) + ss6 = StateSpace(A6, B6, C6) + expr6 = ss6.dsolve(initial_conditions=I6)[0] + expr6 = expr6.subs([(a11, 0), (a12, 1), (a21, -2), (a22, -3), (b1, 0), (b2, 1), (c1, 1), (c2, -1), (i1, 1), (i2, 2)]) + assert expr6 == 8*exp(-t) - 9*exp(-2*t) + + +def test_StateSpace_functions(): + # https://in.mathworks.com/help/control/ref/statespacemodel.obsv.html + + A_mat = Matrix([[-1.5, -2], [1, 0]]) + B_mat = Matrix([0.5, 0]) + C_mat = Matrix([[0, 1]]) + D_mat = Matrix([1]) + SS1 = StateSpace(A_mat, B_mat, C_mat, D_mat) + SS2 = StateSpace(Matrix([[1, 1], [4, -2]]),Matrix([[0, 1], [0, 2]]),Matrix([[-1, 1], [1, -1]])) + SS3 = StateSpace(Matrix([[1, 1], [4, -2]]),Matrix([[1, -1], [1, -1]])) + SS4 = StateSpace(Matrix([[a0, a1], [a2, a3]]), Matrix([[b1], [b2]]), Matrix([[c1, c2]])) + + # Observability + assert SS1.is_observable() == True + assert SS2.is_observable() == False + assert SS1.observability_matrix() == Matrix([[0, 1], [1, 0]]) + assert SS2.observability_matrix() == Matrix([[-1, 1], [ 1, -1], [ 3, -3], [-3, 3]]) + assert SS1.observable_subspace() == [Matrix([[0], [1]]), Matrix([[1], [0]])] + assert SS2.observable_subspace() == [Matrix([[-1], [ 1], [ 3], [-3]])] + Qo = SS4.observability_matrix().subs([(a0, 0), (a1, -6), (a2, 1), (a3, -5), (c1, 0), (c2, 1)]) + assert Qo == Matrix([[0, 1], [1, -5]]) + + # Controllability + assert SS1.is_controllable() == True + assert SS3.is_controllable() == False + assert SS1.controllability_matrix() == Matrix([[0.5, -0.75], [ 0, 0.5]]) + assert SS3.controllability_matrix() == Matrix([[1, -1, 2, -2], [1, -1, 2, -2]]) + assert SS1.controllable_subspace() == [Matrix([[0.5], [ 0]]), Matrix([[-0.75], [ 0.5]])] + assert SS3.controllable_subspace() == [Matrix([[1], [1]])] + assert SS4.controllable_subspace() == [Matrix([ + [b1], + [b2]]), Matrix([ + [a0*b1 + a1*b2], + [a2*b1 + a3*b2]])] + Qc = SS4.controllability_matrix().subs([(a0, 0), (a1, 1), (a2, -6), (a3, -5), (b1, 0), (b2, 1)]) + assert Qc == Matrix([[0, 1], [1, -5]]) + + # Append + A1 = Matrix([[0, 1], [1, 0]]) + B1 = Matrix([[0], [1]]) + C1 = Matrix([[0, 1]]) + D1 = Matrix([[0]]) + ss1 = StateSpace(A1, B1, C1, D1) + ss2 = StateSpace(Matrix([[1, 0], [0, 1]]), Matrix([[1], [0]]), Matrix([[1, 0]]), Matrix([[1]])) + ss3 = ss1.append(ss2) + ss4 = SS4.append(ss1) + + assert ss3.num_states == ss1.num_states + ss2.num_states + assert ss3.num_inputs == ss1.num_inputs + ss2.num_inputs + assert ss3.num_outputs == ss1.num_outputs + ss2.num_outputs + assert ss3.state_matrix == Matrix([[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) + assert ss3.input_matrix == Matrix([[0, 0], [1, 0], [0, 1], [0, 0]]) + assert ss3.output_matrix == Matrix([[0, 1, 0, 0], [0, 0, 1, 0]]) + assert ss3.feedforward_matrix == Matrix([[0, 0], [0, 1]]) + + # Using symbolic matrices + assert ss4.num_states == SS4.num_states + ss1.num_states + assert ss4.num_inputs == SS4.num_inputs + ss1.num_inputs + assert ss4.num_outputs == SS4.num_outputs + ss1.num_outputs + assert ss4.state_matrix == Matrix([[a0, a1, 0, 0], [a2, a3, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) + assert ss4.input_matrix == Matrix([[b1, 0], [b2, 0], [0, 0], [0, 1]]) + assert ss4.output_matrix == Matrix([[c1, c2, 0, 0], [0, 0, 0, 1]]) + assert ss4.feedforward_matrix == Matrix([[0, 0], [0, 0]]) + + +def test_StateSpace_series(): + # For SISO Systems + a1 = Matrix([[0, 1], [1, 0]]) + b1 = Matrix([[0], [1]]) + c1 = Matrix([[0, 1]]) + d1 = Matrix([[0]]) + a2 = Matrix([[1, 0], [0, 1]]) + b2 = Matrix([[1], [0]]) + c2 = Matrix([[1, 0]]) + d2 = Matrix([[1]]) + + ss1 = StateSpace(a1, b1, c1, d1) + ss2 = StateSpace(a2, b2, c2, d2) + tf1 = TransferFunction(s, s+1, s) + ser1 = Series(ss1, ss2) + assert ser1 == Series(StateSpace(Matrix([ + [0, 1], + [1, 0]]), Matrix([ + [0], + [1]]), Matrix([[0, 1]]), Matrix([[0]])), StateSpace(Matrix([ + [1, 0], + [0, 1]]), Matrix([ + [1], + [0]]), Matrix([[1, 0]]), Matrix([[1]]))) + assert ser1.doit() == StateSpace( + Matrix([ + [0, 1, 0, 0], + [1, 0, 0, 0], + [0, 1, 1, 0], + [0, 0, 0, 1]]), + Matrix([ + [0], + [1], + [0], + [0]]), + Matrix([[0, 1, 1, 0]]), + Matrix([[0]])) + + assert ser1.num_inputs == 1 + assert ser1.num_outputs == 1 + assert ser1.rewrite(TransferFunction) == TransferFunction(s**2, s**3 - s**2 - s + 1, s) + ser2 = Series(ss1) + ser3 = Series(ser2, ss2) + assert ser3.doit() == ser1.doit() + + # TransferFunction interconnection with StateSpace + ser_tf = Series(tf1, ss1) + assert ser_tf == Series(TransferFunction(s, s + 1, s), StateSpace(Matrix([ + [0, 1], + [1, 0]]), Matrix([ + [0], + [1]]), Matrix([[0, 1]]), Matrix([[0]]))) + assert ser_tf.doit() == StateSpace( + Matrix([ + [-1, 0, 0], + [0, 0, 1], + [-1, 1, 0]]), + Matrix([ + [1], + [0], + [1]]), + Matrix([[0, 0, 1]]), + Matrix([[0]])) + assert ser_tf.rewrite(TransferFunction) == TransferFunction(s**2, s**3 + s**2 - s - 1, s) + + # For MIMO Systems + a3 = Matrix([[4, 1], [2, -3]]) + b3 = Matrix([[5, 2], [-3, -3]]) + c3 = Matrix([[2, -4], [0, 1]]) + d3 = Matrix([[3, 2], [1, -1]]) + a4 = Matrix([[-3, 4, 2], [-1, -3, 0], [2, 5, 3]]) + b4 = Matrix([[1, 4], [-3, -3], [-2, 1]]) + c4 = Matrix([[4, 2, -3], [1, 4, 3]]) + d4 = Matrix([[-2, 4], [0, 1]]) + ss3 = StateSpace(a3, b3, c3, d3) + ss4 = StateSpace(a4, b4, c4, d4) + ser4 = MIMOSeries(ss3, ss4) + assert ser4 == MIMOSeries(StateSpace(Matrix([ + [4, 1], + [2, -3]]), Matrix([ + [ 5, 2], + [-3, -3]]), Matrix([ + [2, -4], + [0, 1]]), Matrix([ + [3, 2], + [1, -1]])), StateSpace(Matrix([ + [-3, 4, 2], + [-1, -3, 0], + [ 2, 5, 3]]), Matrix([ + [ 1, 4], + [-3, -3], + [-2, 1]]), Matrix([ + [4, 2, -3], + [1, 4, 3]]), Matrix([ + [-2, 4], + [ 0, 1]]))) + assert ser4.doit() == StateSpace( + Matrix([ + [4, 1, 0, 0, 0], + [2, -3, 0, 0, 0], + [2, 0, -3, 4, 2], + [-6, 9, -1, -3, 0], + [-4, 9, 2, 5, 3]]), + Matrix([ + [5, 2], + [-3, -3], + [7, -2], + [-12, -3], + [-5, -5]]), + Matrix([ + [-4, 12, 4, 2, -3], + [0, 1, 1, 4, 3]]), + Matrix([ + [-2, -8], + [1, -1]])) + assert ser4.num_inputs == ss3.num_inputs + assert ser4.num_outputs == ss4.num_outputs + ser5 = MIMOSeries(ss3) + ser6 = MIMOSeries(ser5, ss4) + assert ser6.doit() == ser4.doit() + assert ser6.rewrite(TransferFunctionMatrix) == ser4.rewrite(TransferFunctionMatrix) + tf2 = TransferFunction(1, s, s) + tf3 = TransferFunction(1, s+1, s) + tf4 = TransferFunction(s, s+2, s) + tfm = TransferFunctionMatrix([[tf1, tf2], [tf3, tf4]]) + ser6 = MIMOSeries(ss3, tfm) + assert ser6 == MIMOSeries(StateSpace(Matrix([ + [4, 1], + [2, -3]]), Matrix([ + [ 5, 2], + [-3, -3]]), Matrix([ + [2, -4], + [0, 1]]), Matrix([ + [3, 2], + [1, -1]])), TransferFunctionMatrix(( + (TransferFunction(s, s + 1, s), TransferFunction(1, s, s)), + (TransferFunction(1, s + 1, s), TransferFunction(s, s + 2, s))))) + + +def test_StateSpace_parallel(): + # For SISO system + a1 = Matrix([[0, 1], [1, 0]]) + b1 = Matrix([[0], [1]]) + c1 = Matrix([[0, 1]]) + d1 = Matrix([[0]]) + a2 = Matrix([[1, 0], [0, 1]]) + b2 = Matrix([[1], [0]]) + c2 = Matrix([[1, 0]]) + d2 = Matrix([[1]]) + ss1 = StateSpace(a1, b1, c1, d1) + ss2 = StateSpace(a2, b2, c2, d2) + p1 = Parallel(ss1, ss2) + assert p1 == Parallel(StateSpace(Matrix([[0, 1], [1, 0]]), Matrix([[0], [1]]), Matrix([[0, 1]]), Matrix([[0]])), + StateSpace(Matrix([[1, 0],[0, 1]]), Matrix([[1],[0]]), Matrix([[1, 0]]), Matrix([[1]]))) + assert p1.doit() == StateSpace(Matrix([ + [0, 1, 0, 0], + [1, 0, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 1]]), + Matrix([ + [0], + [1], + [1], + [0]]), + Matrix([[0, 1, 1, 0]]), + Matrix([[1]])) + assert p1.rewrite(TransferFunction) == TransferFunction(s*(s + 2), s**2 - 1, s) + + # Connecting StateSpace with TransferFunction + tf1 = TransferFunction(s, s+1, s) + p2 = Parallel(ss1, tf1) + assert p2 == Parallel(StateSpace(Matrix([ + [0, 1], + [1, 0]]), Matrix([ + [0], + [1]]), Matrix([[0, 1]]), Matrix([[0]])), TransferFunction(s, s + 1, s)) + assert p2.doit() == StateSpace( + Matrix([ + [0, 1, 0], + [1, 0, 0], + [0, 0, -1]]), + Matrix([ + [0], + [1], + [1]]), + Matrix([[0, 1, -1]]), + Matrix([[1]])) + assert p2.rewrite(TransferFunction) == TransferFunction(s**2, s**2 - 1, s) + + # For MIMO + a3 = Matrix([[4, 1], [2, -3]]) + b3 = Matrix([[5, 2], [-3, -3]]) + c3 = Matrix([[2, -4], [0, 1]]) + d3 = Matrix([[3, 2], [1, -1]]) + a4 = Matrix([[-3, 4, 2], [-1, -3, 0], [2, 5, 3]]) + b4 = Matrix([[1, 4], [-3, -3], [-2, 1]]) + c4 = Matrix([[4, 2, -3], [1, 4, 3]]) + d4 = Matrix([[-2, 4], [0, 1]]) + ss3 = StateSpace(a3, b3, c3, d3) + ss4 = StateSpace(a4, b4, c4, d4) + p3 = MIMOParallel(ss3, ss4) + assert p3 == MIMOParallel(StateSpace(Matrix([ + [4, 1], + [2, -3]]), Matrix([ + [ 5, 2], + [-3, -3]]), Matrix([ + [2, -4], + [0, 1]]), Matrix([ + [3, 2], + [1, -1]])), StateSpace(Matrix([ + [-3, 4, 2], + [-1, -3, 0], + [ 2, 5, 3]]), Matrix([ + [ 1, 4], + [-3, -3], + [-2, 1]]), Matrix([ + [4, 2, -3], + [1, 4, 3]]), Matrix([ + [-2, 4], + [ 0, 1]]))) + assert p3.doit() == StateSpace(Matrix([ + [4, 1, 0, 0, 0], + [2, -3, 0, 0, 0], + [0, 0, -3, 4, 2], + [0, 0, -1, -3, 0], + [0, 0, 2, 5, 3]]), + Matrix([ + [5, 2], + [-3, -3], + [1, 4], + [-3, -3], + [-2, 1]]), + Matrix([ + [2, -4, 4, 2, -3], + [0, 1, 1, 4, 3]]), + Matrix([ + [1, 6], + [1, 0]])) + + # Using StateSpace with MIMOParallel. + tf2 = TransferFunction(1, s, s) + tf3 = TransferFunction(1, s + 1, s) + tf4 = TransferFunction(s, s + 2, s) + tfm = TransferFunctionMatrix([[tf1, tf2], [tf3, tf4]]) + p4 = MIMOParallel(tfm, ss3) + assert p4 == MIMOParallel(TransferFunctionMatrix(( + (TransferFunction(s, s + 1, s), TransferFunction(1, s, s)), + (TransferFunction(1, s + 1, s), TransferFunction(s, s + 2, s)))), + StateSpace(Matrix([ + [4, 1], + [2, -3]]), Matrix([ + [5, 2], + [-3, -3]]), Matrix([ + [2, -4], + [0, 1]]), Matrix([ + [3, 2], + [1, -1]]))) + + +def test_StateSpace_feedback(): + # For SISO + a1 = Matrix([[0, 1], [1, 0]]) + b1 = Matrix([[0], [1]]) + c1 = Matrix([[0, 1]]) + d1 = Matrix([[0]]) + a2 = Matrix([[1, 0], [0, 1]]) + b2 = Matrix([[1], [0]]) + c2 = Matrix([[1, 0]]) + d2 = Matrix([[1]]) + ss1 = StateSpace(a1, b1, c1, d1) + ss2 = StateSpace(a2, b2, c2, d2) + fd1 = Feedback(ss1, ss2) + + # Negative feedback + assert fd1 == Feedback(StateSpace(Matrix([[0, 1], [1, 0]]), Matrix([[0], [1]]), Matrix([[0, 1]]), Matrix([[0]])), + StateSpace(Matrix([[1, 0],[0, 1]]), Matrix([[1],[0]]), Matrix([[1, 0]]), Matrix([[1]])), -1) + assert fd1.doit() == StateSpace(Matrix([ + [0, 1, 0, 0], + [1, -1, -1, 0], + [0, 1, 1, 0], + [0, 0, 0, 1]]), Matrix([ + [0], + [1], + [0], + [0]]), Matrix( + [[0, 1, 0, 0]]), Matrix( + [[0]])) + assert fd1.rewrite(TransferFunction) == TransferFunction(s*(s - 1), s**3 - s + 1, s) + + # Positive Feedback + fd2 = Feedback(ss1, ss2, 1) + assert fd2.doit() == StateSpace(Matrix([ + [0, 1, 0, 0], + [1, 1, 1, 0], + [0, 1, 1, 0], + [0, 0, 0, 1]]), Matrix([ + [0], + [1], + [0], + [0]]), Matrix( + [[0, 1, 0, 0]]), Matrix( + [[0]])) + assert fd2.rewrite(TransferFunction) == TransferFunction(s*(s - 1), s**3 - 2*s**2 - s + 1, s) + + # Connection with TransferFunction + tf1 = TransferFunction(s, s+1, s) + fd3 = Feedback(ss1, tf1) + assert fd3 == Feedback(StateSpace(Matrix([ + [0, 1], + [1, 0]]), Matrix([ + [0], + [1]]), Matrix([[0, 1]]), Matrix([[0]])), + TransferFunction(s, s + 1, s), -1) + assert fd3.doit() == StateSpace (Matrix([ + [0, 1, 0], + [1, -1, 1], + [0, 1, -1]]), Matrix([ + [0], + [1], + [0]]), Matrix( + [[0, 1, 0]]), Matrix( + [[0]])) + + # For MIMO + a3 = Matrix([[4, 1], [2, -3]]) + b3 = Matrix([[5, 2], [-3, -3]]) + c3 = Matrix([[2, -4], [0, 1]]) + d3 = Matrix([[3, 2], [1, -1]]) + a4 = Matrix([[-3, 4, 2], [-1, -3, 0], [2, 5, 3]]) + b4 = Matrix([[1, 4], [-3, -3], [-2, 1]]) + c4 = Matrix([[4, 2, -3], [1, 4, 3]]) + d4 = Matrix([[-2, 4], [0, 1]]) + ss3 = StateSpace(a3, b3, c3, d3) + ss4 = StateSpace(a4, b4, c4, d4) + + # Negative Feedback + fd4 = MIMOFeedback(ss3, ss4) + assert fd4 == MIMOFeedback(StateSpace(Matrix([ + [4, 1], + [2, -3]]), Matrix([ + [ 5, 2], + [-3, -3]]), Matrix([ + [2, -4], + [0, 1]]), Matrix([ + [3, 2], + [1, -1]])), StateSpace(Matrix([ + [-3, 4, 2], + [-1, -3, 0], + [ 2, 5, 3]]), Matrix([ + [ 1, 4], + [-3, -3], + [-2, 1]]), Matrix([ + [4, 2, -3], + [1, 4, 3]]), Matrix([ + [-2, 4], + [ 0, 1]])), -1) + assert fd4.doit() == StateSpace(Matrix([ + [Rational(3), Rational(-3, 4), Rational(-15, 4), Rational(-37, 2), Rational(-15)], + [Rational(7, 2), Rational(-39, 8), Rational(9, 8), Rational(39, 4), Rational(9)], + [Rational(3), Rational(-41, 4), Rational(-45, 4), Rational(-51, 2), Rational(-19)], + [Rational(-9, 2), Rational(129, 8), Rational(73, 8), Rational(171, 4), Rational(36)], + [Rational(-3, 2), Rational(47, 8), Rational(31, 8), Rational(85, 4), Rational(18)]]), Matrix([ + [Rational(-1, 4), Rational(19, 4)], + [Rational(3, 8), Rational(-21, 8)], + [Rational(1, 4), Rational(29, 4)], + [Rational(3, 8), Rational(-93, 8)], + [Rational(5, 8), Rational(-35, 8)]]), Matrix([ + [Rational(1), Rational(-15, 4), Rational(-7, 4), Rational(-21, 2), Rational(-9)], + [Rational(1, 2), Rational(-13, 8), Rational(-13, 8), Rational(-19, 4), Rational(-3)]]), Matrix([ + [Rational(-1, 4), Rational(11, 4)], + [Rational(1, 8), Rational(9, 8)]])) + + # Positive Feedback + fd5 = MIMOFeedback(ss3, ss4, 1) + assert fd5.doit() == StateSpace(Matrix([ + [Rational(4, 7), Rational(62, 7), Rational(1), Rational(-8), Rational(-69, 7)], + [Rational(32, 7), Rational(-135, 14), Rational(-3, 2), Rational(3), Rational(36, 7)], + [Rational(-10, 7), Rational(41, 7), Rational(-4), Rational(-12), Rational(-97, 7)], + [Rational(12, 7), Rational(-111, 14), Rational(-5, 2), Rational(18), Rational(171, 7)], + [Rational(2, 7), Rational(-29, 14), Rational(-1, 2), Rational(10), Rational(81, 7)]]), Matrix([ + [Rational(6, 7), Rational(-17, 7)], + [Rational(-9, 14), Rational(15, 14)], + [Rational(6, 7), Rational(-31, 7)], + [Rational(-27, 14), Rational(87, 14)], + [Rational(-15, 14), Rational(25, 14)]]), Matrix([ + [Rational(-2, 7), Rational(11, 7), Rational(1), Rational(-4), Rational(-39, 7)], + [Rational(-2, 7), Rational(15, 14), Rational(-1, 2), Rational(-3), Rational(-18, 7)]]), Matrix([ + [Rational(4, 7), Rational(-9, 7)], + [Rational(1, 14), Rational(-11, 14)]])) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e2ef0d2c104b0d32c61e39cfc574a959ab8dc067 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/__pycache__/gamma_matrices.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/__pycache__/gamma_matrices.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a40ef8abf2f02b32b523a083860ceba839b648d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/__pycache__/gamma_matrices.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e12472c7cc7fd6d5d5e85d113f654b8152e475ef Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/tests/__pycache__/test_gamma_matrices.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/tests/__pycache__/test_gamma_matrices.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a7cdc9c78b411397c060e0a221244dd43f5b8f8f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/tests/__pycache__/test_gamma_matrices.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/tests/test_gamma_matrices.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/tests/test_gamma_matrices.py new file mode 100644 index 0000000000000000000000000000000000000000..1552cf0d19be222ba249a7e32c65c8c3abc54ac2 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/hep/tests/test_gamma_matrices.py @@ -0,0 +1,427 @@ +from sympy.matrices.dense import eye, Matrix +from sympy.tensor.tensor import tensor_indices, TensorHead, tensor_heads, \ + TensExpr, canon_bp +from sympy.physics.hep.gamma_matrices import GammaMatrix as G, LorentzIndex, \ + kahane_simplify, gamma_trace, _simplify_single_line, simplify_gamma_expression +from sympy import Symbol + + +def _is_tensor_eq(arg1, arg2): + arg1 = canon_bp(arg1) + arg2 = canon_bp(arg2) + if isinstance(arg1, TensExpr): + return arg1.equals(arg2) + elif isinstance(arg2, TensExpr): + return arg2.equals(arg1) + return arg1 == arg2 + +def execute_gamma_simplify_tests_for_function(tfunc, D): + """ + Perform tests to check if sfunc is able to simplify gamma matrix expressions. + + Parameters + ========== + + `sfunc` a function to simplify a `TIDS`, shall return the simplified `TIDS`. + `D` the number of dimension (in most cases `D=4`). + + """ + + mu, nu, rho, sigma = tensor_indices("mu, nu, rho, sigma", LorentzIndex) + a1, a2, a3, a4, a5, a6 = tensor_indices("a1:7", LorentzIndex) + mu11, mu12, mu21, mu31, mu32, mu41, mu51, mu52 = tensor_indices("mu11, mu12, mu21, mu31, mu32, mu41, mu51, mu52", LorentzIndex) + mu61, mu71, mu72 = tensor_indices("mu61, mu71, mu72", LorentzIndex) + m0, m1, m2, m3, m4, m5, m6 = tensor_indices("m0:7", LorentzIndex) + + def g(xx, yy): + return (G(xx)*G(yy) + G(yy)*G(xx))/2 + + # Some examples taken from Kahane's paper, 4 dim only: + if D == 4: + t = (G(a1)*G(mu11)*G(a2)*G(mu21)*G(-a1)*G(mu31)*G(-a2)) + assert _is_tensor_eq(tfunc(t), -4*G(mu11)*G(mu31)*G(mu21) - 4*G(mu31)*G(mu11)*G(mu21)) + + t = (G(a1)*G(mu11)*G(mu12)*\ + G(a2)*G(mu21)*\ + G(a3)*G(mu31)*G(mu32)*\ + G(a4)*G(mu41)*\ + G(-a2)*G(mu51)*G(mu52)*\ + G(-a1)*G(mu61)*\ + G(-a3)*G(mu71)*G(mu72)*\ + G(-a4)) + assert _is_tensor_eq(tfunc(t), \ + 16*G(mu31)*G(mu32)*G(mu72)*G(mu71)*G(mu11)*G(mu52)*G(mu51)*G(mu12)*G(mu61)*G(mu21)*G(mu41) + 16*G(mu31)*G(mu32)*G(mu72)*G(mu71)*G(mu12)*G(mu51)*G(mu52)*G(mu11)*G(mu61)*G(mu21)*G(mu41) + 16*G(mu71)*G(mu72)*G(mu32)*G(mu31)*G(mu11)*G(mu52)*G(mu51)*G(mu12)*G(mu61)*G(mu21)*G(mu41) + 16*G(mu71)*G(mu72)*G(mu32)*G(mu31)*G(mu12)*G(mu51)*G(mu52)*G(mu11)*G(mu61)*G(mu21)*G(mu41)) + + # Fully Lorentz-contracted expressions, these return scalars: + + def add_delta(ne): + return ne * eye(4) # DiracSpinorIndex.delta(DiracSpinorIndex.auto_left, -DiracSpinorIndex.auto_right) + + t = (G(mu)*G(-mu)) + ts = add_delta(D) + assert _is_tensor_eq(tfunc(t), ts) + + t = (G(mu)*G(nu)*G(-mu)*G(-nu)) + ts = add_delta(2*D - D**2) # -8 + assert _is_tensor_eq(tfunc(t), ts) + + t = (G(mu)*G(nu)*G(-nu)*G(-mu)) + ts = add_delta(D**2) # 16 + assert _is_tensor_eq(tfunc(t), ts) + + t = (G(mu)*G(nu)*G(-rho)*G(-nu)*G(-mu)*G(rho)) + ts = add_delta(4*D - 4*D**2 + D**3) # 16 + assert _is_tensor_eq(tfunc(t), ts) + + t = (G(mu)*G(nu)*G(rho)*G(-rho)*G(-nu)*G(-mu)) + ts = add_delta(D**3) # 64 + assert _is_tensor_eq(tfunc(t), ts) + + t = (G(a1)*G(a2)*G(a3)*G(a4)*G(-a3)*G(-a1)*G(-a2)*G(-a4)) + ts = add_delta(-8*D + 16*D**2 - 8*D**3 + D**4) # -32 + assert _is_tensor_eq(tfunc(t), ts) + + t = (G(-mu)*G(-nu)*G(-rho)*G(-sigma)*G(nu)*G(mu)*G(sigma)*G(rho)) + ts = add_delta(-16*D + 24*D**2 - 8*D**3 + D**4) # 64 + assert _is_tensor_eq(tfunc(t), ts) + + t = (G(-mu)*G(nu)*G(-rho)*G(sigma)*G(rho)*G(-nu)*G(mu)*G(-sigma)) + ts = add_delta(8*D - 12*D**2 + 6*D**3 - D**4) # -32 + assert _is_tensor_eq(tfunc(t), ts) + + t = (G(a1)*G(a2)*G(a3)*G(a4)*G(a5)*G(-a3)*G(-a2)*G(-a1)*G(-a5)*G(-a4)) + ts = add_delta(64*D - 112*D**2 + 60*D**3 - 12*D**4 + D**5) # 256 + assert _is_tensor_eq(tfunc(t), ts) + + t = (G(a1)*G(a2)*G(a3)*G(a4)*G(a5)*G(-a3)*G(-a1)*G(-a2)*G(-a4)*G(-a5)) + ts = add_delta(64*D - 120*D**2 + 72*D**3 - 16*D**4 + D**5) # -128 + assert _is_tensor_eq(tfunc(t), ts) + + t = (G(a1)*G(a2)*G(a3)*G(a4)*G(a5)*G(a6)*G(-a3)*G(-a2)*G(-a1)*G(-a6)*G(-a5)*G(-a4)) + ts = add_delta(416*D - 816*D**2 + 528*D**3 - 144*D**4 + 18*D**5 - D**6) # -128 + assert _is_tensor_eq(tfunc(t), ts) + + t = (G(a1)*G(a2)*G(a3)*G(a4)*G(a5)*G(a6)*G(-a2)*G(-a3)*G(-a1)*G(-a6)*G(-a4)*G(-a5)) + ts = add_delta(416*D - 848*D**2 + 584*D**3 - 172*D**4 + 22*D**5 - D**6) # -128 + assert _is_tensor_eq(tfunc(t), ts) + + # Expressions with free indices: + + t = (G(mu)*G(nu)*G(rho)*G(sigma)*G(-mu)) + assert _is_tensor_eq(tfunc(t), (-2*G(sigma)*G(rho)*G(nu) + (4-D)*G(nu)*G(rho)*G(sigma))) + + t = (G(mu)*G(nu)*G(-mu)) + assert _is_tensor_eq(tfunc(t), (2-D)*G(nu)) + + t = (G(mu)*G(nu)*G(rho)*G(-mu)) + assert _is_tensor_eq(tfunc(t), 2*G(nu)*G(rho) + 2*G(rho)*G(nu) - (4-D)*G(nu)*G(rho)) + + t = 2*G(m2)*G(m0)*G(m1)*G(-m0)*G(-m1) + st = tfunc(t) + assert _is_tensor_eq(st, (D*(-2*D + 4))*G(m2)) + + t = G(m2)*G(m0)*G(m1)*G(-m0)*G(-m2) + st = tfunc(t) + assert _is_tensor_eq(st, ((-D + 2)**2)*G(m1)) + + t = G(m0)*G(m1)*G(m2)*G(m3)*G(-m1) + st = tfunc(t) + assert _is_tensor_eq(st, (D - 4)*G(m0)*G(m2)*G(m3) + 4*G(m0)*g(m2, m3)) + + t = G(m0)*G(m1)*G(m2)*G(m3)*G(-m1)*G(-m0) + st = tfunc(t) + assert _is_tensor_eq(st, ((D - 4)**2)*G(m2)*G(m3) + (8*D - 16)*g(m2, m3)) + + t = G(m2)*G(m0)*G(m1)*G(-m2)*G(-m0) + st = tfunc(t) + assert _is_tensor_eq(st, ((-D + 2)*(D - 4) + 4)*G(m1)) + + t = G(m3)*G(m1)*G(m0)*G(m2)*G(-m3)*G(-m0)*G(-m2) + st = tfunc(t) + assert _is_tensor_eq(st, (-4*D + (-D + 2)**2*(D - 4) + 8)*G(m1)) + + t = 2*G(m0)*G(m1)*G(m2)*G(m3)*G(-m0) + st = tfunc(t) + assert _is_tensor_eq(st, ((-2*D + 8)*G(m1)*G(m2)*G(m3) - 4*G(m3)*G(m2)*G(m1))) + + t = G(m5)*G(m0)*G(m1)*G(m4)*G(m2)*G(-m4)*G(m3)*G(-m0) + st = tfunc(t) + assert _is_tensor_eq(st, (((-D + 2)*(-D + 4))*G(m5)*G(m1)*G(m2)*G(m3) + (2*D - 4)*G(m5)*G(m3)*G(m2)*G(m1))) + + t = -G(m0)*G(m1)*G(m2)*G(m3)*G(-m0)*G(m4) + st = tfunc(t) + assert _is_tensor_eq(st, ((D - 4)*G(m1)*G(m2)*G(m3)*G(m4) + 2*G(m3)*G(m2)*G(m1)*G(m4))) + + t = G(-m5)*G(m0)*G(m1)*G(m2)*G(m3)*G(m4)*G(-m0)*G(m5) + st = tfunc(t) + + result1 = ((-D + 4)**2 + 4)*G(m1)*G(m2)*G(m3)*G(m4) +\ + (4*D - 16)*G(m3)*G(m2)*G(m1)*G(m4) + (4*D - 16)*G(m4)*G(m1)*G(m2)*G(m3)\ + + 4*G(m2)*G(m1)*G(m4)*G(m3) + 4*G(m3)*G(m4)*G(m1)*G(m2) +\ + 4*G(m4)*G(m3)*G(m2)*G(m1) + + # Kahane's algorithm yields this result, which is equivalent to `result1` + # in four dimensions, but is not automatically recognized as equal: + result2 = 8*G(m1)*G(m2)*G(m3)*G(m4) + 8*G(m4)*G(m3)*G(m2)*G(m1) + + if D == 4: + assert _is_tensor_eq(st, (result1)) or _is_tensor_eq(st, (result2)) + else: + assert _is_tensor_eq(st, (result1)) + + # and a few very simple cases, with no contracted indices: + + t = G(m0) + st = tfunc(t) + assert _is_tensor_eq(st, t) + + t = -7*G(m0) + st = tfunc(t) + assert _is_tensor_eq(st, t) + + t = 224*G(m0)*G(m1)*G(-m2)*G(m3) + st = tfunc(t) + assert _is_tensor_eq(st, t) + + +def test_kahane_algorithm(): + # Wrap this function to convert to and from TIDS: + + def tfunc(e): + return _simplify_single_line(e) + + execute_gamma_simplify_tests_for_function(tfunc, D=4) + + +def test_kahane_simplify1(): + i0,i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15 = tensor_indices('i0:16', LorentzIndex) + mu, nu, rho, sigma = tensor_indices("mu, nu, rho, sigma", LorentzIndex) + D = 4 + t = G(i0)*G(i1) + r = kahane_simplify(t) + assert r.equals(t) + + t = G(i0)*G(i1)*G(-i0) + r = kahane_simplify(t) + assert r.equals(-2*G(i1)) + t = G(i0)*G(i1)*G(-i0) + r = kahane_simplify(t) + assert r.equals(-2*G(i1)) + + t = G(i0)*G(i1) + r = kahane_simplify(t) + assert r.equals(t) + t = G(i0)*G(i1) + r = kahane_simplify(t) + assert r.equals(t) + t = G(i0)*G(-i0) + r = kahane_simplify(t) + assert r.equals(4*eye(4)) + t = G(i0)*G(-i0) + r = kahane_simplify(t) + assert r.equals(4*eye(4)) + t = G(i0)*G(-i0) + r = kahane_simplify(t) + assert r.equals(4*eye(4)) + t = G(i0)*G(i1)*G(-i0) + r = kahane_simplify(t) + assert r.equals(-2*G(i1)) + t = G(i0)*G(i1)*G(-i0)*G(-i1) + r = kahane_simplify(t) + assert r.equals((2*D - D**2)*eye(4)) + t = G(i0)*G(i1)*G(-i0)*G(-i1) + r = kahane_simplify(t) + assert r.equals((2*D - D**2)*eye(4)) + t = G(i0)*G(-i0)*G(i1)*G(-i1) + r = kahane_simplify(t) + assert r.equals(16*eye(4)) + t = (G(mu)*G(nu)*G(-nu)*G(-mu)) + r = kahane_simplify(t) + assert r.equals(D**2*eye(4)) + t = (G(mu)*G(nu)*G(-nu)*G(-mu)) + r = kahane_simplify(t) + assert r.equals(D**2*eye(4)) + t = (G(mu)*G(nu)*G(-nu)*G(-mu)) + r = kahane_simplify(t) + assert r.equals(D**2*eye(4)) + t = (G(mu)*G(nu)*G(-rho)*G(-nu)*G(-mu)*G(rho)) + r = kahane_simplify(t) + assert r.equals((4*D - 4*D**2 + D**3)*eye(4)) + t = (G(-mu)*G(-nu)*G(-rho)*G(-sigma)*G(nu)*G(mu)*G(sigma)*G(rho)) + r = kahane_simplify(t) + assert r.equals((-16*D + 24*D**2 - 8*D**3 + D**4)*eye(4)) + t = (G(-mu)*G(nu)*G(-rho)*G(sigma)*G(rho)*G(-nu)*G(mu)*G(-sigma)) + r = kahane_simplify(t) + assert r.equals((8*D - 12*D**2 + 6*D**3 - D**4)*eye(4)) + + # Expressions with free indices: + t = (G(mu)*G(nu)*G(rho)*G(sigma)*G(-mu)) + r = kahane_simplify(t) + assert r.equals(-2*G(sigma)*G(rho)*G(nu)) + t = (G(mu)*G(-mu)*G(rho)*G(sigma)) + r = kahane_simplify(t) + assert r.equals(4*G(rho)*G(sigma)) + t = (G(rho)*G(sigma)*G(mu)*G(-mu)) + r = kahane_simplify(t) + assert r.equals(4*G(rho)*G(sigma)) + +def test_gamma_matrix_class(): + i, j, k = tensor_indices('i,j,k', LorentzIndex) + + # define another type of TensorHead to see if exprs are correctly handled: + A = TensorHead('A', [LorentzIndex]) + + t = A(k)*G(i)*G(-i) + ts = simplify_gamma_expression(t) + assert _is_tensor_eq(ts, Matrix([ + [4, 0, 0, 0], + [0, 4, 0, 0], + [0, 0, 4, 0], + [0, 0, 0, 4]])*A(k)) + + t = G(i)*A(k)*G(j) + ts = simplify_gamma_expression(t) + assert _is_tensor_eq(ts, A(k)*G(i)*G(j)) + + execute_gamma_simplify_tests_for_function(simplify_gamma_expression, D=4) + + +def test_gamma_matrix_trace(): + g = LorentzIndex.metric + + m0, m1, m2, m3, m4, m5, m6 = tensor_indices('m0:7', LorentzIndex) + n0, n1, n2, n3, n4, n5 = tensor_indices('n0:6', LorentzIndex) + + # working in D=4 dimensions + D = 4 + + # traces of odd number of gamma matrices are zero: + t = G(m0) + t1 = gamma_trace(t) + assert t1.equals(0) + + t = G(m0)*G(m1)*G(m2) + t1 = gamma_trace(t) + assert t1.equals(0) + + t = G(m0)*G(m1)*G(-m0) + t1 = gamma_trace(t) + assert t1.equals(0) + + t = G(m0)*G(m1)*G(m2)*G(m3)*G(m4) + t1 = gamma_trace(t) + assert t1.equals(0) + + # traces without internal contractions: + t = G(m0)*G(m1) + t1 = gamma_trace(t) + assert _is_tensor_eq(t1, 4*g(m0, m1)) + + t = G(m0)*G(m1)*G(m2)*G(m3) + t1 = gamma_trace(t) + t2 = -4*g(m0, m2)*g(m1, m3) + 4*g(m0, m1)*g(m2, m3) + 4*g(m0, m3)*g(m1, m2) + assert _is_tensor_eq(t1, t2) + + t = G(m0)*G(m1)*G(m2)*G(m3)*G(m4)*G(m5) + t1 = gamma_trace(t) + t2 = t1*g(-m0, -m5) + t2 = t2.contract_metric(g) + assert _is_tensor_eq(t2, D*gamma_trace(G(m1)*G(m2)*G(m3)*G(m4))) + + # traces of expressions with internal contractions: + t = G(m0)*G(-m0) + t1 = gamma_trace(t) + assert t1.equals(4*D) + + t = G(m0)*G(m1)*G(-m0)*G(-m1) + t1 = gamma_trace(t) + assert t1.equals(8*D - 4*D**2) + + t = G(m0)*G(m1)*G(m2)*G(m3)*G(m4)*G(-m0) + t1 = gamma_trace(t) + t2 = (-4*D)*g(m1, m3)*g(m2, m4) + (4*D)*g(m1, m2)*g(m3, m4) + \ + (4*D)*g(m1, m4)*g(m2, m3) + assert _is_tensor_eq(t1, t2) + + t = G(-m5)*G(m0)*G(m1)*G(m2)*G(m3)*G(m4)*G(-m0)*G(m5) + t1 = gamma_trace(t) + t2 = (32*D + 4*(-D + 4)**2 - 64)*(g(m1, m2)*g(m3, m4) - \ + g(m1, m3)*g(m2, m4) + g(m1, m4)*g(m2, m3)) + assert _is_tensor_eq(t1, t2) + + t = G(m0)*G(m1)*G(-m0)*G(m3) + t1 = gamma_trace(t) + assert t1.equals((-4*D + 8)*g(m1, m3)) + +# p, q = S1('p,q') +# ps = p(m0)*G(-m0) +# qs = q(m0)*G(-m0) +# t = ps*qs*ps*qs +# t1 = gamma_trace(t) +# assert t1 == 8*p(m0)*q(-m0)*p(m1)*q(-m1) - 4*p(m0)*p(-m0)*q(m1)*q(-m1) + + t = G(m0)*G(m1)*G(m2)*G(m3)*G(m4)*G(m5)*G(-m0)*G(-m1)*G(-m2)*G(-m3)*G(-m4)*G(-m5) + t1 = gamma_trace(t) + assert t1.equals(-4*D**6 + 120*D**5 - 1040*D**4 + 3360*D**3 - 4480*D**2 + 2048*D) + + t = G(m0)*G(m1)*G(n1)*G(m2)*G(n2)*G(m3)*G(m4)*G(-n2)*G(-n1)*G(-m0)*G(-m1)*G(-m2)*G(-m3)*G(-m4) + t1 = gamma_trace(t) + tresu = -7168*D + 16768*D**2 - 14400*D**3 + 5920*D**4 - 1232*D**5 + 120*D**6 - 4*D**7 + assert t1.equals(tresu) + + # checked with Mathematica + # In[1]:= <o + | | + |<--l(t)--->| + + Examples + ======== + + To construct an actuator, an expression (or symbol) must be supplied to + represent the force it can produce, alongside a pathway specifying its line + of action. Let's also create a global reference frame and spatially fix one + of the points in it while setting the other to be positioned such that it + can freely move in the frame's x direction specified by the coordinate + ``q``. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import (ForceActuator, LinearPathway, + ... Point, ReferenceFrame) + >>> from sympy.physics.vector import dynamicsymbols + >>> N = ReferenceFrame('N') + >>> q = dynamicsymbols('q') + >>> force = symbols('F') + >>> pA, pB = Point('pA'), Point('pB') + >>> pA.set_vel(N, 0) + >>> pB.set_pos(pA, q*N.x) + >>> pB.pos_from(pA) + q(t)*N.x + >>> linear_pathway = LinearPathway(pA, pB) + >>> actuator = ForceActuator(force, linear_pathway) + >>> actuator + ForceActuator(F, LinearPathway(pA, pB)) + + Parameters + ========== + + force : Expr + The scalar expression defining the (expansile) force that the actuator + produces. + pathway : PathwayBase + The pathway that the actuator follows. This must be an instance of a + concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``. + + """ + + def __init__(self, force, pathway): + """Initializer for ``ForceActuator``. + + Parameters + ========== + + force : Expr + The scalar expression defining the (expansile) force that the + actuator produces. + pathway : PathwayBase + The pathway that the actuator follows. This must be an instance of + a concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``. + + """ + self.force = force + self.pathway = pathway + + @property + def force(self): + """The magnitude of the force produced by the actuator.""" + return self._force + + @force.setter + def force(self, force): + if hasattr(self, '_force'): + msg = ( + f'Can\'t set attribute `force` to {repr(force)} as it is ' + f'immutable.' + ) + raise AttributeError(msg) + self._force = sympify(force, strict=True) + + @property + def pathway(self): + """The ``Pathway`` defining the actuator's line of action.""" + return self._pathway + + @pathway.setter + def pathway(self, pathway): + if hasattr(self, '_pathway'): + msg = ( + f'Can\'t set attribute `pathway` to {repr(pathway)} as it is ' + f'immutable.' + ) + raise AttributeError(msg) + if not isinstance(pathway, PathwayBase): + msg = ( + f'Value {repr(pathway)} passed to `pathway` was of type ' + f'{type(pathway)}, must be {PathwayBase}.' + ) + raise TypeError(msg) + self._pathway = pathway + + def to_loads(self): + """Loads required by the equations of motion method classes. + + Explanation + =========== + + ``KanesMethod`` requires a list of ``Point``-``Vector`` tuples to be + passed to the ``loads`` parameters of its ``kanes_equations`` method + when constructing the equations of motion. This method acts as a + utility to produce the correctly-structred pairs of points and vectors + required so that these can be easily concatenated with other items in + the list of loads and passed to ``KanesMethod.kanes_equations``. These + loads are also in the correct form to also be passed to the other + equations of motion method classes, e.g. ``LagrangesMethod``. + + Examples + ======== + + The below example shows how to generate the loads produced by a force + actuator that follows a linear pathway. In this example we'll assume + that the force actuator is being used to model a simple linear spring. + First, create a linear pathway between two points separated by the + coordinate ``q`` in the ``x`` direction of the global frame ``N``. + + >>> from sympy.physics.mechanics import (LinearPathway, Point, + ... ReferenceFrame) + >>> from sympy.physics.vector import dynamicsymbols + >>> q = dynamicsymbols('q') + >>> N = ReferenceFrame('N') + >>> pA, pB = Point('pA'), Point('pB') + >>> pB.set_pos(pA, q*N.x) + >>> pathway = LinearPathway(pA, pB) + + Now create a symbol ``k`` to describe the spring's stiffness and + instantiate a force actuator that produces a (contractile) force + proportional to both the spring's stiffness and the pathway's length. + Note that actuator classes use the sign convention that expansile + forces are positive, so for a spring to produce a contractile force the + spring force needs to be calculated as the negative for the stiffness + multiplied by the length. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import ForceActuator + >>> stiffness = symbols('k') + >>> spring_force = -stiffness*pathway.length + >>> spring = ForceActuator(spring_force, pathway) + + The forces produced by the spring can be generated in the list of loads + form that ``KanesMethod`` (and other equations of motion methods) + requires by calling the ``to_loads`` method. + + >>> spring.to_loads() + [(pA, k*q(t)*N.x), (pB, - k*q(t)*N.x)] + + A simple linear damper can be modeled in a similar way. Create another + symbol ``c`` to describe the dampers damping coefficient. This time + instantiate a force actuator that produces a force proportional to both + the damper's damping coefficient and the pathway's extension velocity. + Note that the damping force is negative as it acts in the opposite + direction to which the damper is changing in length. + + >>> damping_coefficient = symbols('c') + >>> damping_force = -damping_coefficient*pathway.extension_velocity + >>> damper = ForceActuator(damping_force, pathway) + + Again, the forces produces by the damper can be generated by calling + the ``to_loads`` method. + + >>> damper.to_loads() + [(pA, c*Derivative(q(t), t)*N.x), (pB, - c*Derivative(q(t), t)*N.x)] + + """ + return self.pathway.to_loads(self.force) + + def __repr__(self): + """Representation of a ``ForceActuator``.""" + return f'{self.__class__.__name__}({self.force}, {self.pathway})' + + +class LinearSpring(ForceActuator): + """A spring with its spring force as a linear function of its length. + + Explanation + =========== + + Note that the "linear" in the name ``LinearSpring`` refers to the fact that + the spring force is a linear function of the springs length. I.e. for a + linear spring with stiffness ``k``, distance between its ends of ``x``, and + an equilibrium length of ``0``, the spring force will be ``-k*x``, which is + a linear function in ``x``. To create a spring that follows a linear, or + straight, pathway between its two ends, a ``LinearPathway`` instance needs + to be passed to the ``pathway`` parameter. + + A ``LinearSpring`` is a subclass of ``ForceActuator`` and so follows the + same sign conventions for length, extension velocity, and the direction of + the forces it applies to its points of attachment on bodies. The sign + convention for the direction of forces is such that, for the case where a + linear spring is instantiated with a ``LinearPathway`` instance as its + pathway, they act to push the two ends of the spring away from one another. + Because springs produces a contractile force and acts to pull the two ends + together towards the equilibrium length when stretched, the scalar portion + of the forces on the endpoint are negative in order to flip the sign of the + forces on the endpoints when converted into vector quantities. The + following diagram shows the positive force sense and the distance between + the points:: + + P Q + o<--- F --->o + | | + |<--l(t)--->| + + Examples + ======== + + To construct a linear spring, an expression (or symbol) must be supplied to + represent the stiffness (spring constant) of the spring, alongside a + pathway specifying its line of action. Let's also create a global reference + frame and spatially fix one of the points in it while setting the other to + be positioned such that it can freely move in the frame's x direction + specified by the coordinate ``q``. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import (LinearPathway, LinearSpring, + ... Point, ReferenceFrame) + >>> from sympy.physics.vector import dynamicsymbols + >>> N = ReferenceFrame('N') + >>> q = dynamicsymbols('q') + >>> stiffness = symbols('k') + >>> pA, pB = Point('pA'), Point('pB') + >>> pA.set_vel(N, 0) + >>> pB.set_pos(pA, q*N.x) + >>> pB.pos_from(pA) + q(t)*N.x + >>> linear_pathway = LinearPathway(pA, pB) + >>> spring = LinearSpring(stiffness, linear_pathway) + >>> spring + LinearSpring(k, LinearPathway(pA, pB)) + + This spring will produce a force that is proportional to both its stiffness + and the pathway's length. Note that this force is negative as SymPy's sign + convention for actuators is that negative forces are contractile. + + >>> spring.force + -k*sqrt(q(t)**2) + + To create a linear spring with a non-zero equilibrium length, an expression + (or symbol) can be passed to the ``equilibrium_length`` parameter on + construction on a ``LinearSpring`` instance. Let's create a symbol ``l`` + to denote a non-zero equilibrium length and create another linear spring. + + >>> l = symbols('l') + >>> spring = LinearSpring(stiffness, linear_pathway, equilibrium_length=l) + >>> spring + LinearSpring(k, LinearPathway(pA, pB), equilibrium_length=l) + + The spring force of this new spring is again proportional to both its + stiffness and the pathway's length. However, the spring will not produce + any force when ``q(t)`` equals ``l``. Note that the force will become + expansile when ``q(t)`` is less than ``l``, as expected. + + >>> spring.force + -k*(-l + sqrt(q(t)**2)) + + Parameters + ========== + + stiffness : Expr + The spring constant. + pathway : PathwayBase + The pathway that the actuator follows. This must be an instance of a + concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``. + equilibrium_length : Expr, optional + The length at which the spring is in equilibrium, i.e. it produces no + force. The default value is 0, i.e. the spring force is a linear + function of the pathway's length with no constant offset. + + See Also + ======== + + ForceActuator: force-producing actuator (superclass of ``LinearSpring``). + LinearPathway: straight-line pathway between a pair of points. + + """ + + def __init__(self, stiffness, pathway, equilibrium_length=S.Zero): + """Initializer for ``LinearSpring``. + + Parameters + ========== + + stiffness : Expr + The spring constant. + pathway : PathwayBase + The pathway that the actuator follows. This must be an instance of + a concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``. + equilibrium_length : Expr, optional + The length at which the spring is in equilibrium, i.e. it produces + no force. The default value is 0, i.e. the spring force is a linear + function of the pathway's length with no constant offset. + + """ + self.stiffness = stiffness + self.pathway = pathway + self.equilibrium_length = equilibrium_length + + @property + def force(self): + """The spring force produced by the linear spring.""" + return -self.stiffness*(self.pathway.length - self.equilibrium_length) + + @force.setter + def force(self, force): + raise AttributeError('Can\'t set computed attribute `force`.') + + @property + def stiffness(self): + """The spring constant for the linear spring.""" + return self._stiffness + + @stiffness.setter + def stiffness(self, stiffness): + if hasattr(self, '_stiffness'): + msg = ( + f'Can\'t set attribute `stiffness` to {repr(stiffness)} as it ' + f'is immutable.' + ) + raise AttributeError(msg) + self._stiffness = sympify(stiffness, strict=True) + + @property + def equilibrium_length(self): + """The length of the spring at which it produces no force.""" + return self._equilibrium_length + + @equilibrium_length.setter + def equilibrium_length(self, equilibrium_length): + if hasattr(self, '_equilibrium_length'): + msg = ( + f'Can\'t set attribute `equilibrium_length` to ' + f'{repr(equilibrium_length)} as it is immutable.' + ) + raise AttributeError(msg) + self._equilibrium_length = sympify(equilibrium_length, strict=True) + + def __repr__(self): + """Representation of a ``LinearSpring``.""" + string = f'{self.__class__.__name__}({self.stiffness}, {self.pathway}' + if self.equilibrium_length == S.Zero: + string += ')' + else: + string += f', equilibrium_length={self.equilibrium_length})' + return string + + +class LinearDamper(ForceActuator): + """A damper whose force is a linear function of its extension velocity. + + Explanation + =========== + + Note that the "linear" in the name ``LinearDamper`` refers to the fact that + the damping force is a linear function of the damper's rate of change in + its length. I.e. for a linear damper with damping ``c`` and extension + velocity ``v``, the damping force will be ``-c*v``, which is a linear + function in ``v``. To create a damper that follows a linear, or straight, + pathway between its two ends, a ``LinearPathway`` instance needs to be + passed to the ``pathway`` parameter. + + A ``LinearDamper`` is a subclass of ``ForceActuator`` and so follows the + same sign conventions for length, extension velocity, and the direction of + the forces it applies to its points of attachment on bodies. The sign + convention for the direction of forces is such that, for the case where a + linear damper is instantiated with a ``LinearPathway`` instance as its + pathway, they act to push the two ends of the damper away from one another. + Because dampers produce a force that opposes the direction of change in + length, when extension velocity is positive the scalar portions of the + forces applied at the two endpoints are negative in order to flip the sign + of the forces on the endpoints wen converted into vector quantities. When + extension velocity is negative (i.e. when the damper is shortening), the + scalar portions of the fofces applied are also negative so that the signs + cancel producing forces on the endpoints that are in the same direction as + the positive sign convention for the forces at the endpoints of the pathway + (i.e. they act to push the endpoints away from one another). The following + diagram shows the positive force sense and the distance between the + points:: + + P Q + o<--- F --->o + | | + |<--l(t)--->| + + Examples + ======== + + To construct a linear damper, an expression (or symbol) must be supplied to + represent the damping coefficient of the damper (we'll use the symbol + ``c``), alongside a pathway specifying its line of action. Let's also + create a global reference frame and spatially fix one of the points in it + while setting the other to be positioned such that it can freely move in + the frame's x direction specified by the coordinate ``q``. The velocity + that the two points move away from one another can be specified by the + coordinate ``u`` where ``u`` is the first time derivative of ``q`` + (i.e., ``u = Derivative(q(t), t)``). + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import (LinearDamper, LinearPathway, + ... Point, ReferenceFrame) + >>> from sympy.physics.vector import dynamicsymbols + >>> N = ReferenceFrame('N') + >>> q = dynamicsymbols('q') + >>> damping = symbols('c') + >>> pA, pB = Point('pA'), Point('pB') + >>> pA.set_vel(N, 0) + >>> pB.set_pos(pA, q*N.x) + >>> pB.pos_from(pA) + q(t)*N.x + >>> pB.vel(N) + Derivative(q(t), t)*N.x + >>> linear_pathway = LinearPathway(pA, pB) + >>> damper = LinearDamper(damping, linear_pathway) + >>> damper + LinearDamper(c, LinearPathway(pA, pB)) + + This damper will produce a force that is proportional to both its damping + coefficient and the pathway's extension length. Note that this force is + negative as SymPy's sign convention for actuators is that negative forces + are contractile and the damping force of the damper will oppose the + direction of length change. + + >>> damper.force + -c*sqrt(q(t)**2)*Derivative(q(t), t)/q(t) + + Parameters + ========== + + damping : Expr + The damping constant. + pathway : PathwayBase + The pathway that the actuator follows. This must be an instance of a + concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``. + + See Also + ======== + + ForceActuator: force-producing actuator (superclass of ``LinearDamper``). + LinearPathway: straight-line pathway between a pair of points. + + """ + + def __init__(self, damping, pathway): + """Initializer for ``LinearDamper``. + + Parameters + ========== + + damping : Expr + The damping constant. + pathway : PathwayBase + The pathway that the actuator follows. This must be an instance of + a concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``. + + """ + self.damping = damping + self.pathway = pathway + + @property + def force(self): + """The damping force produced by the linear damper.""" + return -self.damping*self.pathway.extension_velocity + + @force.setter + def force(self, force): + raise AttributeError('Can\'t set computed attribute `force`.') + + @property + def damping(self): + """The damping constant for the linear damper.""" + return self._damping + + @damping.setter + def damping(self, damping): + if hasattr(self, '_damping'): + msg = ( + f'Can\'t set attribute `damping` to {repr(damping)} as it is ' + f'immutable.' + ) + raise AttributeError(msg) + self._damping = sympify(damping, strict=True) + + def __repr__(self): + """Representation of a ``LinearDamper``.""" + return f'{self.__class__.__name__}({self.damping}, {self.pathway})' + + +class TorqueActuator(ActuatorBase): + """Torque-producing actuator. + + Explanation + =========== + + A ``TorqueActuator`` is an actuator that produces a pair of equal and + opposite torques on a pair of bodies. + + Examples + ======== + + To construct a torque actuator, an expression (or symbol) must be supplied + to represent the torque it can produce, alongside a vector specifying the + axis about which the torque will act, and a pair of frames on which the + torque will act. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import (ReferenceFrame, RigidBody, + ... TorqueActuator) + >>> N = ReferenceFrame('N') + >>> A = ReferenceFrame('A') + >>> torque = symbols('T') + >>> axis = N.z + >>> parent = RigidBody('parent', frame=N) + >>> child = RigidBody('child', frame=A) + >>> bodies = (child, parent) + >>> actuator = TorqueActuator(torque, axis, *bodies) + >>> actuator + TorqueActuator(T, axis=N.z, target_frame=A, reaction_frame=N) + + Note that because torques actually act on frames, not bodies, + ``TorqueActuator`` will extract the frame associated with a ``RigidBody`` + when one is passed instead of a ``ReferenceFrame``. + + Parameters + ========== + + torque : Expr + The scalar expression defining the torque that the actuator produces. + axis : Vector + The axis about which the actuator applies torques. + target_frame : ReferenceFrame | RigidBody + The primary frame on which the actuator will apply the torque. + reaction_frame : ReferenceFrame | RigidBody | None + The secondary frame on which the actuator will apply the torque. Note + that the (equal and opposite) reaction torque is applied to this frame. + + """ + + def __init__(self, torque, axis, target_frame, reaction_frame=None): + """Initializer for ``TorqueActuator``. + + Parameters + ========== + + torque : Expr + The scalar expression defining the torque that the actuator + produces. + axis : Vector + The axis about which the actuator applies torques. + target_frame : ReferenceFrame | RigidBody + The primary frame on which the actuator will apply the torque. + reaction_frame : ReferenceFrame | RigidBody | None + The secondary frame on which the actuator will apply the torque. + Note that the (equal and opposite) reaction torque is applied to + this frame. + + """ + self.torque = torque + self.axis = axis + self.target_frame = target_frame + self.reaction_frame = reaction_frame + + @classmethod + def at_pin_joint(cls, torque, pin_joint): + """Alternate constructor to instantiate from a ``PinJoint`` instance. + + Examples + ======== + + To create a pin joint the ``PinJoint`` class requires a name, parent + body, and child body to be passed to its constructor. It is also + possible to control the joint axis using the ``joint_axis`` keyword + argument. In this example let's use the parent body's reference frame's + z-axis as the joint axis. + + >>> from sympy.physics.mechanics import (PinJoint, ReferenceFrame, + ... RigidBody, TorqueActuator) + >>> N = ReferenceFrame('N') + >>> A = ReferenceFrame('A') + >>> parent = RigidBody('parent', frame=N) + >>> child = RigidBody('child', frame=A) + >>> pin_joint = PinJoint( + ... 'pin', + ... parent, + ... child, + ... joint_axis=N.z, + ... ) + + Let's also create a symbol ``T`` that will represent the torque applied + by the torque actuator. + + >>> from sympy import symbols + >>> torque = symbols('T') + + To create the torque actuator from the ``torque`` and ``pin_joint`` + variables previously instantiated, these can be passed to the alternate + constructor class method ``at_pin_joint`` of the ``TorqueActuator`` + class. It should be noted that a positive torque will cause a positive + displacement of the joint coordinate or that the torque is applied on + the child body with a reaction torque on the parent. + + >>> actuator = TorqueActuator.at_pin_joint(torque, pin_joint) + >>> actuator + TorqueActuator(T, axis=N.z, target_frame=A, reaction_frame=N) + + Parameters + ========== + + torque : Expr + The scalar expression defining the torque that the actuator + produces. + pin_joint : PinJoint + The pin joint, and by association the parent and child bodies, on + which the torque actuator will act. The pair of bodies acted upon + by the torque actuator are the parent and child bodies of the pin + joint, with the child acting as the reaction body. The pin joint's + axis is used as the axis about which the torque actuator will apply + its torque. + + """ + if not isinstance(pin_joint, PinJoint): + msg = ( + f'Value {repr(pin_joint)} passed to `pin_joint` was of type ' + f'{type(pin_joint)}, must be {PinJoint}.' + ) + raise TypeError(msg) + return cls( + torque, + pin_joint.joint_axis, + pin_joint.child_interframe, + pin_joint.parent_interframe, + ) + + @property + def torque(self): + """The magnitude of the torque produced by the actuator.""" + return self._torque + + @torque.setter + def torque(self, torque): + if hasattr(self, '_torque'): + msg = ( + f'Can\'t set attribute `torque` to {repr(torque)} as it is ' + f'immutable.' + ) + raise AttributeError(msg) + self._torque = sympify(torque, strict=True) + + @property + def axis(self): + """The axis about which the torque acts.""" + return self._axis + + @axis.setter + def axis(self, axis): + if hasattr(self, '_axis'): + msg = ( + f'Can\'t set attribute `axis` to {repr(axis)} as it is ' + f'immutable.' + ) + raise AttributeError(msg) + if not isinstance(axis, Vector): + msg = ( + f'Value {repr(axis)} passed to `axis` was of type ' + f'{type(axis)}, must be {Vector}.' + ) + raise TypeError(msg) + self._axis = axis + + @property + def target_frame(self): + """The primary reference frames on which the torque will act.""" + return self._target_frame + + @target_frame.setter + def target_frame(self, target_frame): + if hasattr(self, '_target_frame'): + msg = ( + f'Can\'t set attribute `target_frame` to {repr(target_frame)} ' + f'as it is immutable.' + ) + raise AttributeError(msg) + if isinstance(target_frame, RigidBody): + target_frame = target_frame.frame + elif not isinstance(target_frame, ReferenceFrame): + msg = ( + f'Value {repr(target_frame)} passed to `target_frame` was of ' + f'type {type(target_frame)}, must be {ReferenceFrame}.' + ) + raise TypeError(msg) + self._target_frame = target_frame + + @property + def reaction_frame(self): + """The primary reference frames on which the torque will act.""" + return self._reaction_frame + + @reaction_frame.setter + def reaction_frame(self, reaction_frame): + if hasattr(self, '_reaction_frame'): + msg = ( + f'Can\'t set attribute `reaction_frame` to ' + f'{repr(reaction_frame)} as it is immutable.' + ) + raise AttributeError(msg) + if isinstance(reaction_frame, RigidBody): + reaction_frame = reaction_frame.frame + elif ( + not isinstance(reaction_frame, ReferenceFrame) + and reaction_frame is not None + ): + msg = ( + f'Value {repr(reaction_frame)} passed to `reaction_frame` was ' + f'of type {type(reaction_frame)}, must be {ReferenceFrame}.' + ) + raise TypeError(msg) + self._reaction_frame = reaction_frame + + def to_loads(self): + """Loads required by the equations of motion method classes. + + Explanation + =========== + + ``KanesMethod`` requires a list of ``Point``-``Vector`` tuples to be + passed to the ``loads`` parameters of its ``kanes_equations`` method + when constructing the equations of motion. This method acts as a + utility to produce the correctly-structred pairs of points and vectors + required so that these can be easily concatenated with other items in + the list of loads and passed to ``KanesMethod.kanes_equations``. These + loads are also in the correct form to also be passed to the other + equations of motion method classes, e.g. ``LagrangesMethod``. + + Examples + ======== + + The below example shows how to generate the loads produced by a torque + actuator that acts on a pair of bodies attached by a pin joint. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import (PinJoint, ReferenceFrame, + ... RigidBody, TorqueActuator) + >>> torque = symbols('T') + >>> N = ReferenceFrame('N') + >>> A = ReferenceFrame('A') + >>> parent = RigidBody('parent', frame=N) + >>> child = RigidBody('child', frame=A) + >>> pin_joint = PinJoint( + ... 'pin', + ... parent, + ... child, + ... joint_axis=N.z, + ... ) + >>> actuator = TorqueActuator.at_pin_joint(torque, pin_joint) + + The forces produces by the damper can be generated by calling the + ``to_loads`` method. + + >>> actuator.to_loads() + [(A, T*N.z), (N, - T*N.z)] + + Alternatively, if a torque actuator is created without a reaction frame + then the loads returned by the ``to_loads`` method will contain just + the single load acting on the target frame. + + >>> actuator = TorqueActuator(torque, N.z, N) + >>> actuator.to_loads() + [(N, T*N.z)] + + """ + loads = [ + Torque(self.target_frame, self.torque*self.axis), + ] + if self.reaction_frame is not None: + loads.append(Torque(self.reaction_frame, -self.torque*self.axis)) + return loads + + def __repr__(self): + """Representation of a ``TorqueActuator``.""" + string = ( + f'{self.__class__.__name__}({self.torque}, axis={self.axis}, ' + f'target_frame={self.target_frame}' + ) + if self.reaction_frame is not None: + string += f', reaction_frame={self.reaction_frame})' + else: + string += ')' + return string + + +class DuffingSpring(ForceActuator): + """A nonlinear spring based on the Duffing equation. + + Explanation + =========== + + Here, ``DuffingSpring`` represents the force exerted by a nonlinear spring based on the Duffing equation: + F = -beta*x-alpha*x**3, where x is the displacement from the equilibrium position, beta is the linear spring constant, + and alpha is the coefficient for the nonlinear cubic term. + + Parameters + ========== + + linear_stiffness : Expr + The linear stiffness coefficient (beta). + nonlinear_stiffness : Expr + The nonlinear stiffness coefficient (alpha). + pathway : PathwayBase + The pathway that the actuator follows. + equilibrium_length : Expr, optional + The length at which the spring is in equilibrium (x). + """ + + def __init__(self, linear_stiffness, nonlinear_stiffness, pathway, equilibrium_length=S.Zero): + self.linear_stiffness = sympify(linear_stiffness, strict=True) + self.nonlinear_stiffness = sympify(nonlinear_stiffness, strict=True) + self.equilibrium_length = sympify(equilibrium_length, strict=True) + + if not isinstance(pathway, PathwayBase): + raise TypeError("pathway must be an instance of PathwayBase.") + self._pathway = pathway + + @property + def linear_stiffness(self): + return self._linear_stiffness + + @linear_stiffness.setter + def linear_stiffness(self, linear_stiffness): + if hasattr(self, '_linear_stiffness'): + msg = ( + f'Can\'t set attribute `linear_stiffness` to ' + f'{repr(linear_stiffness)} as it is immutable.' + ) + raise AttributeError(msg) + self._linear_stiffness = sympify(linear_stiffness, strict=True) + + @property + def nonlinear_stiffness(self): + return self._nonlinear_stiffness + + @nonlinear_stiffness.setter + def nonlinear_stiffness(self, nonlinear_stiffness): + if hasattr(self, '_nonlinear_stiffness'): + msg = ( + f'Can\'t set attribute `nonlinear_stiffness` to ' + f'{repr(nonlinear_stiffness)} as it is immutable.' + ) + raise AttributeError(msg) + self._nonlinear_stiffness = sympify(nonlinear_stiffness, strict=True) + + @property + def pathway(self): + return self._pathway + + @pathway.setter + def pathway(self, pathway): + if hasattr(self, '_pathway'): + msg = ( + f'Can\'t set attribute `pathway` to {repr(pathway)} as it is ' + f'immutable.' + ) + raise AttributeError(msg) + if not isinstance(pathway, PathwayBase): + msg = ( + f'Value {repr(pathway)} passed to `pathway` was of type ' + f'{type(pathway)}, must be {PathwayBase}.' + ) + raise TypeError(msg) + self._pathway = pathway + + @property + def equilibrium_length(self): + return self._equilibrium_length + + @equilibrium_length.setter + def equilibrium_length(self, equilibrium_length): + if hasattr(self, '_equilibrium_length'): + msg = ( + f'Can\'t set attribute `equilibrium_length` to ' + f'{repr(equilibrium_length)} as it is immutable.' + ) + raise AttributeError(msg) + self._equilibrium_length = sympify(equilibrium_length, strict=True) + + @property + def force(self): + """The force produced by the Duffing spring.""" + displacement = self.pathway.length - self.equilibrium_length + return -self.linear_stiffness * displacement - self.nonlinear_stiffness * displacement**3 + + @force.setter + def force(self, force): + if hasattr(self, '_force'): + msg = ( + f'Can\'t set attribute `force` to {repr(force)} as it is ' + f'immutable.' + ) + raise AttributeError(msg) + self._force = sympify(force, strict=True) + + def __repr__(self): + return (f"{self.__class__.__name__}(" + f"{self.linear_stiffness}, {self.nonlinear_stiffness}, {self.pathway}, " + f"equilibrium_length={self.equilibrium_length})") + +class CoulombKineticFriction(ForceActuator): + r"""Coulomb kinetic friction with Stribeck and viscous effects. + + Explanation + =========== + + This represents a Coulomb kinetic friction with the Stribeck and viscous effect, + described by the function: + + .. math:: + F = (\mu_k f_n + (\mu_s - \mu_k) f_n e^{-(\frac{v}{v_s})^2}) \text{sign}(v) + \sigma v + + where :math:`\mu_k` is the coefficient of kinetic friction, :math:`\mu_s` is the + coefficient of static friction, :math:`f_n` is the normal force, :math:`v` is the + relative velocity, :math:`v_s` is the Stribeck friction coefficient, and + :math:`\sigma` is the viscous friction constant. + + The default friction force is :math:`F = \mu_k f_n`. + When specified, the actuator includes: + + - Stribeck effect: :math:`(\mu_s - \mu_k) f_n e^{-(\frac{v}{v_s})^2}` + - Viscous effect: :math:`\sigma v` + + Notes + ===== + + The actuator makes the following assumptions: + + - The actuator assumes relative motion is non-zero. + - The normal force is assumed to be a non-negative scalar. + - The resultant friction force is opposite to the velocity direction. + - Each point in the pathway is fixed within separate objects that are sliding relative to each other. In other words, these two points are fixed in the mutually sliding objects. + + This actuator has been tested for straightforward motions, like a block sliding + on a surface. + + The friction force is defined to always oppose the direction of relative velocity :math:`v`. + Specifically: + + - The default Coulomb friction force :math:`\mu_k f_n \text{sign}(v)` is opposite to :math:`v`. + - The Stribeck effect :math:`(\mu_s - \mu_k) f_n e^{-(\frac{v}{v_s})^2} \text{sign}(v)` is also opposite to :math:`v`. + - The viscous friction term :math:`\sigma v` is opposite to :math:`v`. + + Examples + ======== + + The below example shows how to generate the loads produced by a Coulomb kinetic + friction actuator in a mass-spring system with friction. + + >>> import sympy as sm + >>> from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point, + ... LinearPathway, CoulombKineticFriction, LinearSpring, KanesMethod, Particle) + + >>> x, v = dynamicsymbols('x, v', real=True) + >>> m, g, k, mu_k, mu_s, v_s, sigma = sm.symbols('m, g, k, mu_k, mu_s, v_s, sigma') + + >>> N = ReferenceFrame('N') + >>> O, P = Point('O'), Point('P') + >>> O.set_vel(N, 0) + >>> P.set_pos(O, x*N.x) + + >>> pathway = LinearPathway(O, P) + >>> friction = CoulombKineticFriction(mu_k, m*g, pathway, v_s=v_s, sigma=sigma, mu_s=mu_k) + >>> spring = LinearSpring(k, pathway) + >>> block = Particle('block', point=P, mass=m) + + >>> kane = KanesMethod(N, (x,), (v,), kd_eqs=(x.diff() - v,)) + >>> friction.to_loads() + [(O, (g*m*mu_k*sign(sign(x(t))*Derivative(x(t), t)) + sigma*sign(x(t))*Derivative(x(t), t))*x(t)/Abs(x(t))*N.x), (P, (-g*m*mu_k*sign(sign(x(t))*Derivative(x(t), t)) - sigma*sign(x(t))*Derivative(x(t), t))*x(t)/Abs(x(t))*N.x)] + >>> loads = friction.to_loads() + spring.to_loads() + >>> fr, frstar = kane.kanes_equations([block], loads) + >>> eom = fr + frstar + >>> eom + Matrix([[-k*x(t) - m*Derivative(v(t), t) + (-g*m*mu_k*sign(v(t)*sign(x(t))) - sigma*v(t)*sign(x(t)))*x(t)/Abs(x(t))]]) + + Parameters + ========== + + f_n : sympifiable + The normal force between the surfaces. It should always be a non-negative scalar. + mu_k : sympifiable + The coefficient of kinetic friction. + pathway : PathwayBase + The pathway that the actuator follows. + v_s : sympifiable, optional + The Stribeck friction coefficient. + sigma : sympifiable, optional + The viscous friction coefficient. + mu_s : sympifiable, optional + The coefficient of static friction. Defaults to mu_k, meaning the Stribeck effect evaluates to 0 by default. + + References + ========== + + .. [Moore2022] https://moorepants.github.io/learn-multibody-dynamics/loads.html#friction. + .. [Flores2023] Paulo Flores, Jorge Ambrosio, Hamid M. Lankarani, + "Contact-impact events with friction in multibody dynamics: Back to basics", + Mechanism and Machine Theory, vol. 184, 2023. https://doi.org/10.1016/j.mechmachtheory.2023.105305. + .. [Rogner2017] I. Rogner, "Friction modelling for robotic applications with planar motion", + Chalmers University of Technology, Department of Electrical Engineering, 2017. + + """ + + def __init__(self, mu_k, f_n, pathway, *, v_s=None, sigma=None, mu_s=None): + self._mu_k = sympify(mu_k, strict=True) if mu_k is not None else 1 + self._mu_s = sympify(mu_s, strict=True) if mu_s is not None else self._mu_k + self._f_n = sympify(f_n, strict=True) + self._sigma = sympify(sigma, strict=True) if sigma is not None else 0 + self._v_s = sympify(v_s, strict=True) if v_s is not None or v_s == 0 else 0.01 + self.pathway = pathway + + @property + def mu_k(self): + """The coefficient of kinetic friction.""" + return self._mu_k + + @property + def mu_s(self): + """The coefficient of static friction.""" + return self._mu_s + + @property + def f_n(self): + """The normal force between the surfaces.""" + return self._f_n + + @property + def sigma(self): + """The viscous friction coefficient.""" + return self._sigma + + @property + def v_s(self): + """The Stribeck friction coefficient.""" + return self._v_s + + @property + def force(self): + v = self.pathway.extension_velocity + f_c = self.mu_k * self.f_n + f_max = self.mu_s * self.f_n + stribeck_term = (f_max - f_c) * exp(-(v / self.v_s)**2) if self.v_s is not None else 0 + viscous_term = self.sigma * v if self.sigma is not None else 0 + return (f_c + stribeck_term) * -sign(v) - viscous_term + + @force.setter + def force(self, force): + raise AttributeError('Can\'t set computed attribute `force`.') + + def __repr__(self): + return (f'{self.__class__.__name__}({self._mu_k}, {self._mu_s} ' + f'{self._f_n}, {self.pathway}, {self._v_s}, ' + f'{self._sigma})') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/functions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/functions.py new file mode 100644 index 0000000000000000000000000000000000000000..42abe2b7fe608b4602cdab518f209b446b2dbe03 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/functions.py @@ -0,0 +1,735 @@ +from sympy.utilities import dict_merge +from sympy.utilities.iterables import iterable +from sympy.physics.vector import (Dyadic, Vector, ReferenceFrame, + Point, dynamicsymbols) +from sympy.physics.vector.printing import (vprint, vsprint, vpprint, vlatex, + init_vprinting) +from sympy.physics.mechanics.particle import Particle +from sympy.physics.mechanics.rigidbody import RigidBody +from sympy.simplify.simplify import simplify +from sympy import Matrix, Mul, Derivative, sin, cos, tan, S +from sympy.core.function import AppliedUndef +from sympy.physics.mechanics.inertia import (inertia as _inertia, + inertia_of_point_mass as _inertia_of_point_mass) +from sympy.utilities.exceptions import sympy_deprecation_warning + +__all__ = ['linear_momentum', + 'angular_momentum', + 'kinetic_energy', + 'potential_energy', + 'Lagrangian', + 'mechanics_printing', + 'mprint', + 'msprint', + 'mpprint', + 'mlatex', + 'msubs', + 'find_dynamicsymbols'] + +# These are functions that we've moved and renamed during extracting the +# basic vector calculus code from the mechanics packages. + +mprint = vprint +msprint = vsprint +mpprint = vpprint +mlatex = vlatex + + +def mechanics_printing(**kwargs): + """ + Initializes time derivative printing for all SymPy objects in + mechanics module. + """ + + init_vprinting(**kwargs) + +mechanics_printing.__doc__ = init_vprinting.__doc__ + + +def inertia(frame, ixx, iyy, izz, ixy=0, iyz=0, izx=0): + sympy_deprecation_warning( + """ + The inertia function has been moved. + Import it from "sympy.physics.mechanics". + """, + deprecated_since_version="1.13", + active_deprecations_target="moved-mechanics-functions" + ) + return _inertia(frame, ixx, iyy, izz, ixy, iyz, izx) + + +def inertia_of_point_mass(mass, pos_vec, frame): + sympy_deprecation_warning( + """ + The inertia_of_point_mass function has been moved. + Import it from "sympy.physics.mechanics". + """, + deprecated_since_version="1.13", + active_deprecations_target="moved-mechanics-functions" + ) + return _inertia_of_point_mass(mass, pos_vec, frame) + + +def linear_momentum(frame, *body): + """Linear momentum of the system. + + Explanation + =========== + + This function returns the linear momentum of a system of Particle's and/or + RigidBody's. The linear momentum of a system is equal to the vector sum of + the linear momentum of its constituents. Consider a system, S, comprised of + a rigid body, A, and a particle, P. The linear momentum of the system, L, + is equal to the vector sum of the linear momentum of the particle, L1, and + the linear momentum of the rigid body, L2, i.e. + + L = L1 + L2 + + Parameters + ========== + + frame : ReferenceFrame + The frame in which linear momentum is desired. + body1, body2, body3... : Particle and/or RigidBody + The body (or bodies) whose linear momentum is required. + + Examples + ======== + + >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame + >>> from sympy.physics.mechanics import RigidBody, outer, linear_momentum + >>> N = ReferenceFrame('N') + >>> P = Point('P') + >>> P.set_vel(N, 10 * N.x) + >>> Pa = Particle('Pa', P, 1) + >>> Ac = Point('Ac') + >>> Ac.set_vel(N, 25 * N.y) + >>> I = outer(N.x, N.x) + >>> A = RigidBody('A', Ac, N, 20, (I, Ac)) + >>> linear_momentum(N, A, Pa) + 10*N.x + 500*N.y + + """ + + if not isinstance(frame, ReferenceFrame): + raise TypeError('Please specify a valid ReferenceFrame') + else: + linear_momentum_sys = Vector(0) + for e in body: + if isinstance(e, (RigidBody, Particle)): + linear_momentum_sys += e.linear_momentum(frame) + else: + raise TypeError('*body must have only Particle or RigidBody') + return linear_momentum_sys + + +def angular_momentum(point, frame, *body): + """Angular momentum of a system. + + Explanation + =========== + + This function returns the angular momentum of a system of Particle's and/or + RigidBody's. The angular momentum of such a system is equal to the vector + sum of the angular momentum of its constituents. Consider a system, S, + comprised of a rigid body, A, and a particle, P. The angular momentum of + the system, H, is equal to the vector sum of the angular momentum of the + particle, H1, and the angular momentum of the rigid body, H2, i.e. + + H = H1 + H2 + + Parameters + ========== + + point : Point + The point about which angular momentum of the system is desired. + frame : ReferenceFrame + The frame in which angular momentum is desired. + body1, body2, body3... : Particle and/or RigidBody + The body (or bodies) whose angular momentum is required. + + Examples + ======== + + >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame + >>> from sympy.physics.mechanics import RigidBody, outer, angular_momentum + >>> N = ReferenceFrame('N') + >>> O = Point('O') + >>> O.set_vel(N, 0 * N.x) + >>> P = O.locatenew('P', 1 * N.x) + >>> P.set_vel(N, 10 * N.x) + >>> Pa = Particle('Pa', P, 1) + >>> Ac = O.locatenew('Ac', 2 * N.y) + >>> Ac.set_vel(N, 5 * N.y) + >>> a = ReferenceFrame('a') + >>> a.set_ang_vel(N, 10 * N.z) + >>> I = outer(N.z, N.z) + >>> A = RigidBody('A', Ac, a, 20, (I, Ac)) + >>> angular_momentum(O, N, Pa, A) + 10*N.z + + """ + + if not isinstance(frame, ReferenceFrame): + raise TypeError('Please enter a valid ReferenceFrame') + if not isinstance(point, Point): + raise TypeError('Please specify a valid Point') + else: + angular_momentum_sys = Vector(0) + for e in body: + if isinstance(e, (RigidBody, Particle)): + angular_momentum_sys += e.angular_momentum(point, frame) + else: + raise TypeError('*body must have only Particle or RigidBody') + return angular_momentum_sys + + +def kinetic_energy(frame, *body): + """Kinetic energy of a multibody system. + + Explanation + =========== + + This function returns the kinetic energy of a system of Particle's and/or + RigidBody's. The kinetic energy of such a system is equal to the sum of + the kinetic energies of its constituents. Consider a system, S, comprising + a rigid body, A, and a particle, P. The kinetic energy of the system, T, + is equal to the vector sum of the kinetic energy of the particle, T1, and + the kinetic energy of the rigid body, T2, i.e. + + T = T1 + T2 + + Kinetic energy is a scalar. + + Parameters + ========== + + frame : ReferenceFrame + The frame in which the velocity or angular velocity of the body is + defined. + body1, body2, body3... : Particle and/or RigidBody + The body (or bodies) whose kinetic energy is required. + + Examples + ======== + + >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame + >>> from sympy.physics.mechanics import RigidBody, outer, kinetic_energy + >>> N = ReferenceFrame('N') + >>> O = Point('O') + >>> O.set_vel(N, 0 * N.x) + >>> P = O.locatenew('P', 1 * N.x) + >>> P.set_vel(N, 10 * N.x) + >>> Pa = Particle('Pa', P, 1) + >>> Ac = O.locatenew('Ac', 2 * N.y) + >>> Ac.set_vel(N, 5 * N.y) + >>> a = ReferenceFrame('a') + >>> a.set_ang_vel(N, 10 * N.z) + >>> I = outer(N.z, N.z) + >>> A = RigidBody('A', Ac, a, 20, (I, Ac)) + >>> kinetic_energy(N, Pa, A) + 350 + + """ + + if not isinstance(frame, ReferenceFrame): + raise TypeError('Please enter a valid ReferenceFrame') + ke_sys = S.Zero + for e in body: + if isinstance(e, (RigidBody, Particle)): + ke_sys += e.kinetic_energy(frame) + else: + raise TypeError('*body must have only Particle or RigidBody') + return ke_sys + + +def potential_energy(*body): + """Potential energy of a multibody system. + + Explanation + =========== + + This function returns the potential energy of a system of Particle's and/or + RigidBody's. The potential energy of such a system is equal to the sum of + the potential energy of its constituents. Consider a system, S, comprising + a rigid body, A, and a particle, P. The potential energy of the system, V, + is equal to the vector sum of the potential energy of the particle, V1, and + the potential energy of the rigid body, V2, i.e. + + V = V1 + V2 + + Potential energy is a scalar. + + Parameters + ========== + + body1, body2, body3... : Particle and/or RigidBody + The body (or bodies) whose potential energy is required. + + Examples + ======== + + >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame + >>> from sympy.physics.mechanics import RigidBody, outer, potential_energy + >>> from sympy import symbols + >>> M, m, g, h = symbols('M m g h') + >>> N = ReferenceFrame('N') + >>> O = Point('O') + >>> O.set_vel(N, 0 * N.x) + >>> P = O.locatenew('P', 1 * N.x) + >>> Pa = Particle('Pa', P, m) + >>> Ac = O.locatenew('Ac', 2 * N.y) + >>> a = ReferenceFrame('a') + >>> I = outer(N.z, N.z) + >>> A = RigidBody('A', Ac, a, M, (I, Ac)) + >>> Pa.potential_energy = m * g * h + >>> A.potential_energy = M * g * h + >>> potential_energy(Pa, A) + M*g*h + g*h*m + + """ + + pe_sys = S.Zero + for e in body: + if isinstance(e, (RigidBody, Particle)): + pe_sys += e.potential_energy + else: + raise TypeError('*body must have only Particle or RigidBody') + return pe_sys + + +def gravity(acceleration, *bodies): + from sympy.physics.mechanics.loads import gravity as _gravity + sympy_deprecation_warning( + """ + The gravity function has been moved. + Import it from "sympy.physics.mechanics.loads". + """, + deprecated_since_version="1.13", + active_deprecations_target="moved-mechanics-functions" + ) + return _gravity(acceleration, *bodies) + + +def center_of_mass(point, *bodies): + """ + Returns the position vector from the given point to the center of mass + of the given bodies(particles or rigidbodies). + + Example + ======= + + >>> from sympy import symbols, S + >>> from sympy.physics.vector import Point + >>> from sympy.physics.mechanics import Particle, ReferenceFrame, RigidBody, outer + >>> from sympy.physics.mechanics.functions import center_of_mass + >>> a = ReferenceFrame('a') + >>> m = symbols('m', real=True) + >>> p1 = Particle('p1', Point('p1_pt'), S(1)) + >>> p2 = Particle('p2', Point('p2_pt'), S(2)) + >>> p3 = Particle('p3', Point('p3_pt'), S(3)) + >>> p4 = Particle('p4', Point('p4_pt'), m) + >>> b_f = ReferenceFrame('b_f') + >>> b_cm = Point('b_cm') + >>> mb = symbols('mb') + >>> b = RigidBody('b', b_cm, b_f, mb, (outer(b_f.x, b_f.x), b_cm)) + >>> p2.point.set_pos(p1.point, a.x) + >>> p3.point.set_pos(p1.point, a.x + a.y) + >>> p4.point.set_pos(p1.point, a.y) + >>> b.masscenter.set_pos(p1.point, a.y + a.z) + >>> point_o=Point('o') + >>> point_o.set_pos(p1.point, center_of_mass(p1.point, p1, p2, p3, p4, b)) + >>> expr = 5/(m + mb + 6)*a.x + (m + mb + 3)/(m + mb + 6)*a.y + mb/(m + mb + 6)*a.z + >>> point_o.pos_from(p1.point) + 5/(m + mb + 6)*a.x + (m + mb + 3)/(m + mb + 6)*a.y + mb/(m + mb + 6)*a.z + + """ + if not bodies: + raise TypeError("No bodies(instances of Particle or Rigidbody) were passed.") + + total_mass = 0 + vec = Vector(0) + for i in bodies: + total_mass += i.mass + + masscenter = getattr(i, 'masscenter', None) + if masscenter is None: + masscenter = i.point + vec += i.mass*masscenter.pos_from(point) + + return vec/total_mass + + +def Lagrangian(frame, *body): + """Lagrangian of a multibody system. + + Explanation + =========== + + This function returns the Lagrangian of a system of Particle's and/or + RigidBody's. The Lagrangian of such a system is equal to the difference + between the kinetic energies and potential energies of its constituents. If + T and V are the kinetic and potential energies of a system then it's + Lagrangian, L, is defined as + + L = T - V + + The Lagrangian is a scalar. + + Parameters + ========== + + frame : ReferenceFrame + The frame in which the velocity or angular velocity of the body is + defined to determine the kinetic energy. + + body1, body2, body3... : Particle and/or RigidBody + The body (or bodies) whose Lagrangian is required. + + Examples + ======== + + >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame + >>> from sympy.physics.mechanics import RigidBody, outer, Lagrangian + >>> from sympy import symbols + >>> M, m, g, h = symbols('M m g h') + >>> N = ReferenceFrame('N') + >>> O = Point('O') + >>> O.set_vel(N, 0 * N.x) + >>> P = O.locatenew('P', 1 * N.x) + >>> P.set_vel(N, 10 * N.x) + >>> Pa = Particle('Pa', P, 1) + >>> Ac = O.locatenew('Ac', 2 * N.y) + >>> Ac.set_vel(N, 5 * N.y) + >>> a = ReferenceFrame('a') + >>> a.set_ang_vel(N, 10 * N.z) + >>> I = outer(N.z, N.z) + >>> A = RigidBody('A', Ac, a, 20, (I, Ac)) + >>> Pa.potential_energy = m * g * h + >>> A.potential_energy = M * g * h + >>> Lagrangian(N, Pa, A) + -M*g*h - g*h*m + 350 + + """ + + if not isinstance(frame, ReferenceFrame): + raise TypeError('Please supply a valid ReferenceFrame') + for e in body: + if not isinstance(e, (RigidBody, Particle)): + raise TypeError('*body must have only Particle or RigidBody') + return kinetic_energy(frame, *body) - potential_energy(*body) + + +def find_dynamicsymbols(expression, exclude=None, reference_frame=None): + """Find all dynamicsymbols in expression. + + Explanation + =========== + + If the optional ``exclude`` kwarg is used, only dynamicsymbols + not in the iterable ``exclude`` are returned. + If we intend to apply this function on a vector, the optional + ``reference_frame`` is also used to inform about the corresponding frame + with respect to which the dynamic symbols of the given vector is to be + determined. + + Parameters + ========== + + expression : SymPy expression + + exclude : iterable of dynamicsymbols, optional + + reference_frame : ReferenceFrame, optional + The frame with respect to which the dynamic symbols of the + given vector is to be determined. + + Examples + ======== + + >>> from sympy.physics.mechanics import dynamicsymbols, find_dynamicsymbols + >>> from sympy.physics.mechanics import ReferenceFrame + >>> x, y = dynamicsymbols('x, y') + >>> expr = x + x.diff()*y + >>> find_dynamicsymbols(expr) + {x(t), y(t), Derivative(x(t), t)} + >>> find_dynamicsymbols(expr, exclude=[x, y]) + {Derivative(x(t), t)} + >>> a, b, c = dynamicsymbols('a, b, c') + >>> A = ReferenceFrame('A') + >>> v = a * A.x + b * A.y + c * A.z + >>> find_dynamicsymbols(v, reference_frame=A) + {a(t), b(t), c(t)} + + """ + t_set = {dynamicsymbols._t} + if exclude: + if iterable(exclude): + exclude_set = set(exclude) + else: + raise TypeError("exclude kwarg must be iterable") + else: + exclude_set = set() + if isinstance(expression, Vector): + if reference_frame is None: + raise ValueError("You must provide reference_frame when passing a " + "vector expression, got %s." % reference_frame) + else: + expression = expression.to_matrix(reference_frame) + return {i for i in expression.atoms(AppliedUndef, Derivative) if + i.free_symbols == t_set} - exclude_set + + +def msubs(expr, *sub_dicts, smart=False, **kwargs): + """A custom subs for use on expressions derived in physics.mechanics. + + Traverses the expression tree once, performing the subs found in sub_dicts. + Terms inside ``Derivative`` expressions are ignored: + + Examples + ======== + + >>> from sympy.physics.mechanics import dynamicsymbols, msubs + >>> x = dynamicsymbols('x') + >>> msubs(x.diff() + x, {x: 1}) + Derivative(x(t), t) + 1 + + Note that sub_dicts can be a single dictionary, or several dictionaries: + + >>> x, y, z = dynamicsymbols('x, y, z') + >>> sub1 = {x: 1, y: 2} + >>> sub2 = {z: 3, x.diff(): 4} + >>> msubs(x.diff() + x + y + z, sub1, sub2) + 10 + + If smart=True (default False), also checks for conditions that may result + in ``nan``, but if simplified would yield a valid expression. For example: + + >>> from sympy import sin, tan + >>> (sin(x)/tan(x)).subs(x, 0) + nan + >>> msubs(sin(x)/tan(x), {x: 0}, smart=True) + 1 + + It does this by first replacing all ``tan`` with ``sin/cos``. Then each + node is traversed. If the node is a fraction, subs is first evaluated on + the denominator. If this results in 0, simplification of the entire + fraction is attempted. Using this selective simplification, only + subexpressions that result in 1/0 are targeted, resulting in faster + performance. + + """ + + sub_dict = dict_merge(*sub_dicts) + if smart: + func = _smart_subs + elif hasattr(expr, 'msubs'): + return expr.msubs(sub_dict) + else: + func = lambda expr, sub_dict: _crawl(expr, _sub_func, sub_dict) + if isinstance(expr, (Matrix, Vector, Dyadic)): + return expr.applyfunc(lambda x: func(x, sub_dict)) + else: + return func(expr, sub_dict) + + +def _crawl(expr, func, *args, **kwargs): + """Crawl the expression tree, and apply func to every node.""" + val = func(expr, *args, **kwargs) + if val is not None: + return val + new_args = (_crawl(arg, func, *args, **kwargs) for arg in expr.args) + return expr.func(*new_args) + + +def _sub_func(expr, sub_dict): + """Perform direct matching substitution, ignoring derivatives.""" + if expr in sub_dict: + return sub_dict[expr] + elif not expr.args or expr.is_Derivative: + return expr + + +def _tan_repl_func(expr): + """Replace tan with sin/cos.""" + if isinstance(expr, tan): + return sin(*expr.args) / cos(*expr.args) + elif not expr.args or expr.is_Derivative: + return expr + + +def _smart_subs(expr, sub_dict): + """Performs subs, checking for conditions that may result in `nan` or + `oo`, and attempts to simplify them out. + + The expression tree is traversed twice, and the following steps are + performed on each expression node: + - First traverse: + Replace all `tan` with `sin/cos`. + - Second traverse: + If node is a fraction, check if the denominator evaluates to 0. + If so, attempt to simplify it out. Then if node is in sub_dict, + sub in the corresponding value. + + """ + expr = _crawl(expr, _tan_repl_func) + + def _recurser(expr, sub_dict): + # Decompose the expression into num, den + num, den = _fraction_decomp(expr) + if den != 1: + # If there is a non trivial denominator, we need to handle it + denom_subbed = _recurser(den, sub_dict) + if denom_subbed.evalf() == 0: + # If denom is 0 after this, attempt to simplify the bad expr + expr = simplify(expr) + else: + # Expression won't result in nan, find numerator + num_subbed = _recurser(num, sub_dict) + return num_subbed / denom_subbed + # We have to crawl the tree manually, because `expr` may have been + # modified in the simplify step. First, perform subs as normal: + val = _sub_func(expr, sub_dict) + if val is not None: + return val + new_args = (_recurser(arg, sub_dict) for arg in expr.args) + return expr.func(*new_args) + return _recurser(expr, sub_dict) + + +def _fraction_decomp(expr): + """Return num, den such that expr = num/den.""" + if not isinstance(expr, Mul): + return expr, 1 + num = [] + den = [] + for a in expr.args: + if a.is_Pow and a.args[1] < 0: + den.append(1 / a) + else: + num.append(a) + if not den: + return expr, 1 + num = Mul(*num) + den = Mul(*den) + return num, den + + +def _f_list_parser(fl, ref_frame): + """Parses the provided forcelist composed of items + of the form (obj, force). + Returns a tuple containing: + vel_list: The velocity (ang_vel for Frames, vel for Points) in + the provided reference frame. + f_list: The forces. + + Used internally in the KanesMethod and LagrangesMethod classes. + + """ + def flist_iter(): + for pair in fl: + obj, force = pair + if isinstance(obj, ReferenceFrame): + yield obj.ang_vel_in(ref_frame), force + elif isinstance(obj, Point): + yield obj.vel(ref_frame), force + else: + raise TypeError('First entry in each forcelist pair must ' + 'be a point or frame.') + + if not fl: + vel_list, f_list = (), () + else: + unzip = lambda l: list(zip(*l)) if l[0] else [(), ()] + vel_list, f_list = unzip(list(flist_iter())) + return vel_list, f_list + + +def _validate_coordinates(coordinates=None, speeds=None, check_duplicates=True, + is_dynamicsymbols=True, u_auxiliary=None): + """Validate the generalized coordinates and generalized speeds. + + Parameters + ========== + coordinates : iterable, optional + Generalized coordinates to be validated. + speeds : iterable, optional + Generalized speeds to be validated. + check_duplicates : bool, optional + Checks if there are duplicates in the generalized coordinates and + generalized speeds. If so it will raise a ValueError. The default is + True. + is_dynamicsymbols : iterable, optional + Checks if all the generalized coordinates and generalized speeds are + dynamicsymbols. If any is not a dynamicsymbol, a ValueError will be + raised. The default is True. + u_auxiliary : iterable, optional + Auxiliary generalized speeds to be validated. + + """ + t_set = {dynamicsymbols._t} + # Convert input to iterables + if coordinates is None: + coordinates = [] + elif not iterable(coordinates): + coordinates = [coordinates] + if speeds is None: + speeds = [] + elif not iterable(speeds): + speeds = [speeds] + if u_auxiliary is None: + u_auxiliary = [] + elif not iterable(u_auxiliary): + u_auxiliary = [u_auxiliary] + + msgs = [] + if check_duplicates: # Check for duplicates + seen = set() + coord_duplicates = {x for x in coordinates if x in seen or seen.add(x)} + seen = set() + speed_duplicates = {x for x in speeds if x in seen or seen.add(x)} + seen = set() + aux_duplicates = {x for x in u_auxiliary if x in seen or seen.add(x)} + overlap_coords = set(coordinates).intersection(speeds) + overlap_aux = set(coordinates).union(speeds).intersection(u_auxiliary) + if coord_duplicates: + msgs.append(f'The generalized coordinates {coord_duplicates} are ' + f'duplicated, all generalized coordinates should be ' + f'unique.') + if speed_duplicates: + msgs.append(f'The generalized speeds {speed_duplicates} are ' + f'duplicated, all generalized speeds should be unique.') + if aux_duplicates: + msgs.append(f'The auxiliary speeds {aux_duplicates} are duplicated,' + f' all auxiliary speeds should be unique.') + if overlap_coords: + msgs.append(f'{overlap_coords} are defined as both generalized ' + f'coordinates and generalized speeds.') + if overlap_aux: + msgs.append(f'The auxiliary speeds {overlap_aux} are also defined ' + f'as generalized coordinates or generalized speeds.') + if is_dynamicsymbols: # Check whether all coordinates are dynamicsymbols + for coordinate in coordinates: + if not (isinstance(coordinate, (AppliedUndef, Derivative)) and + coordinate.free_symbols == t_set): + msgs.append(f'Generalized coordinate "{coordinate}" is not a ' + f'dynamicsymbol.') + for speed in speeds: + if not (isinstance(speed, (AppliedUndef, Derivative)) and + speed.free_symbols == t_set): + msgs.append( + f'Generalized speed "{speed}" is not a dynamicsymbol.') + for aux in u_auxiliary: + if not (isinstance(aux, (AppliedUndef, Derivative)) and + aux.free_symbols == t_set): + msgs.append( + f'Auxiliary speed "{aux}" is not a dynamicsymbol.') + if msgs: + raise ValueError('\n'.join(msgs)) + + +def _parse_linear_solver(linear_solver): + """Helper function to retrieve a specified linear solver.""" + if callable(linear_solver): + return linear_solver + return lambda A, b: Matrix.solve(A, b, method=linear_solver) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/inertia.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/inertia.py new file mode 100644 index 0000000000000000000000000000000000000000..683c1f630f3cedb82d02a9c5ba2309ae438b7fff --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/inertia.py @@ -0,0 +1,199 @@ +from sympy import sympify +from sympy.physics.vector import Point, Dyadic, ReferenceFrame, outer +from collections import namedtuple + +__all__ = ['inertia', 'inertia_of_point_mass', 'Inertia'] + + +def inertia(frame, ixx, iyy, izz, ixy=0, iyz=0, izx=0): + """Simple way to create inertia Dyadic object. + + Explanation + =========== + + Creates an inertia Dyadic based on the given tensor values and a body-fixed + reference frame. + + Parameters + ========== + + frame : ReferenceFrame + The frame the inertia is defined in. + ixx : Sympifyable + The xx element in the inertia dyadic. + iyy : Sympifyable + The yy element in the inertia dyadic. + izz : Sympifyable + The zz element in the inertia dyadic. + ixy : Sympifyable + The xy element in the inertia dyadic. + iyz : Sympifyable + The yz element in the inertia dyadic. + izx : Sympifyable + The zx element in the inertia dyadic. + + Examples + ======== + + >>> from sympy.physics.mechanics import ReferenceFrame, inertia + >>> N = ReferenceFrame('N') + >>> inertia(N, 1, 2, 3) + (N.x|N.x) + 2*(N.y|N.y) + 3*(N.z|N.z) + + """ + + if not isinstance(frame, ReferenceFrame): + raise TypeError('Need to define the inertia in a frame') + ixx, iyy, izz = sympify(ixx), sympify(iyy), sympify(izz) + ixy, iyz, izx = sympify(ixy), sympify(iyz), sympify(izx) + return (ixx*outer(frame.x, frame.x) + ixy*outer(frame.x, frame.y) + + izx*outer(frame.x, frame.z) + ixy*outer(frame.y, frame.x) + + iyy*outer(frame.y, frame.y) + iyz*outer(frame.y, frame.z) + + izx*outer(frame.z, frame.x) + iyz*outer(frame.z, frame.y) + + izz*outer(frame.z, frame.z)) + + +def inertia_of_point_mass(mass, pos_vec, frame): + """Inertia dyadic of a point mass relative to point O. + + Parameters + ========== + + mass : Sympifyable + Mass of the point mass + pos_vec : Vector + Position from point O to point mass + frame : ReferenceFrame + Reference frame to express the dyadic in + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import ReferenceFrame, inertia_of_point_mass + >>> N = ReferenceFrame('N') + >>> r, m = symbols('r m') + >>> px = r * N.x + >>> inertia_of_point_mass(m, px, N) + m*r**2*(N.y|N.y) + m*r**2*(N.z|N.z) + + """ + + return mass*( + (outer(frame.x, frame.x) + + outer(frame.y, frame.y) + + outer(frame.z, frame.z)) * + (pos_vec.dot(pos_vec)) - outer(pos_vec, pos_vec)) + + +class Inertia(namedtuple('Inertia', ['dyadic', 'point'])): + """Inertia object consisting of a Dyadic and a Point of reference. + + Explanation + =========== + + This is a simple class to store the Point and Dyadic, belonging to an + inertia. + + Attributes + ========== + + dyadic : Dyadic + The dyadic of the inertia. + point : Point + The reference point of the inertia. + + Examples + ======== + + >>> from sympy.physics.mechanics import ReferenceFrame, Point, Inertia + >>> N = ReferenceFrame('N') + >>> Po = Point('Po') + >>> Inertia(N.x.outer(N.x) + N.y.outer(N.y) + N.z.outer(N.z), Po) + ((N.x|N.x) + (N.y|N.y) + (N.z|N.z), Po) + + In the example above the Dyadic was created manually, one can however also + use the ``inertia`` function for this or the class method ``from_tensor`` as + shown below. + + >>> Inertia.from_inertia_scalars(Po, N, 1, 1, 1) + ((N.x|N.x) + (N.y|N.y) + (N.z|N.z), Po) + + """ + __slots__ = () + + def __new__(cls, dyadic, point): + # Switch order if given in the wrong order + if isinstance(dyadic, Point) and isinstance(point, Dyadic): + point, dyadic = dyadic, point + if not isinstance(point, Point): + raise TypeError('Reference point should be of type Point') + if not isinstance(dyadic, Dyadic): + raise TypeError('Inertia value should be expressed as a Dyadic') + return super().__new__(cls, dyadic, point) + + @classmethod + def from_inertia_scalars(cls, point, frame, ixx, iyy, izz, ixy=0, iyz=0, + izx=0): + """Simple way to create an Inertia object based on the tensor values. + + Explanation + =========== + + This class method uses the :func`~.inertia` to create the Dyadic based + on the tensor values. + + Parameters + ========== + + point : Point + The reference point of the inertia. + frame : ReferenceFrame + The frame the inertia is defined in. + ixx : Sympifyable + The xx element in the inertia dyadic. + iyy : Sympifyable + The yy element in the inertia dyadic. + izz : Sympifyable + The zz element in the inertia dyadic. + ixy : Sympifyable + The xy element in the inertia dyadic. + iyz : Sympifyable + The yz element in the inertia dyadic. + izx : Sympifyable + The zx element in the inertia dyadic. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import ReferenceFrame, Point, Inertia + >>> ixx, iyy, izz, ixy, iyz, izx = symbols('ixx iyy izz ixy iyz izx') + >>> N = ReferenceFrame('N') + >>> P = Point('P') + >>> I = Inertia.from_inertia_scalars(P, N, ixx, iyy, izz, ixy, iyz, izx) + + The tensor values can easily be seen when converting the dyadic to a + matrix. + + >>> I.dyadic.to_matrix(N) + Matrix([ + [ixx, ixy, izx], + [ixy, iyy, iyz], + [izx, iyz, izz]]) + + """ + return cls(inertia(frame, ixx, iyy, izz, ixy, iyz, izx), point) + + def __add__(self, other): + raise TypeError(f"unsupported operand type(s) for +: " + f"'{self.__class__.__name__}' and " + f"'{other.__class__.__name__}'") + + def __mul__(self, other): + raise TypeError(f"unsupported operand type(s) for *: " + f"'{self.__class__.__name__}' and " + f"'{other.__class__.__name__}'") + + __radd__ = __add__ + __rmul__ = __mul__ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/joint.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/joint.py new file mode 100644 index 0000000000000000000000000000000000000000..6f3fe661532cff6bf8dda4ab4383fc09f75e9e44 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/joint.py @@ -0,0 +1,2188 @@ +# coding=utf-8 + +from abc import ABC, abstractmethod + +from sympy import pi, Derivative, Matrix +from sympy.core.function import AppliedUndef +from sympy.physics.mechanics.body_base import BodyBase +from sympy.physics.mechanics.functions import _validate_coordinates +from sympy.physics.vector import (Vector, dynamicsymbols, cross, Point, + ReferenceFrame) +from sympy.utilities.iterables import iterable +from sympy.utilities.exceptions import sympy_deprecation_warning + +__all__ = ['Joint', 'PinJoint', 'PrismaticJoint', 'CylindricalJoint', + 'PlanarJoint', 'SphericalJoint', 'WeldJoint'] + + +class Joint(ABC): + """Abstract base class for all specific joints. + + Explanation + =========== + + A joint subtracts degrees of freedom from a body. This is the base class + for all specific joints and holds all common methods acting as an interface + for all joints. Custom joint can be created by inheriting Joint class and + defining all abstract functions. + + The abstract methods are: + + - ``_generate_coordinates`` + - ``_generate_speeds`` + - ``_orient_frames`` + - ``_set_angular_velocity`` + - ``_set_linear_velocity`` + + Parameters + ========== + + name : string + A unique name for the joint. + parent : Particle or RigidBody + The parent body of joint. + child : Particle or RigidBody + The child body of joint. + coordinates : iterable of dynamicsymbols, optional + Generalized coordinates of the joint. + speeds : iterable of dynamicsymbols, optional + Generalized speeds of joint. + parent_point : Point or Vector, optional + Attachment point where the joint is fixed to the parent body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the parent's mass + center. + child_point : Point or Vector, optional + Attachment point where the joint is fixed to the child body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the child's mass + center. + parent_axis : Vector, optional + .. deprecated:: 1.12 + Axis fixed in the parent body which aligns with an axis fixed in the + child body. The default is the x axis of parent's reference frame. + For more information on this deprecation, see + :ref:`deprecated-mechanics-joint-axis`. + child_axis : Vector, optional + .. deprecated:: 1.12 + Axis fixed in the child body which aligns with an axis fixed in the + parent body. The default is the x axis of child's reference frame. + For more information on this deprecation, see + :ref:`deprecated-mechanics-joint-axis`. + parent_interframe : ReferenceFrame, optional + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the parent's own frame. + child_interframe : ReferenceFrame, optional + Intermediate frame of the child body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the child's own frame. + parent_joint_pos : Point or Vector, optional + .. deprecated:: 1.12 + This argument is replaced by parent_point and will be removed in a + future version. + See :ref:`deprecated-mechanics-joint-pos` for more information. + child_joint_pos : Point or Vector, optional + .. deprecated:: 1.12 + This argument is replaced by child_point and will be removed in a + future version. + See :ref:`deprecated-mechanics-joint-pos` for more information. + + Attributes + ========== + + name : string + The joint's name. + parent : Particle or RigidBody + The joint's parent body. + child : Particle or RigidBody + The joint's child body. + coordinates : Matrix + Matrix of the joint's generalized coordinates. + speeds : Matrix + Matrix of the joint's generalized speeds. + parent_point : Point + Attachment point where the joint is fixed to the parent body. + child_point : Point + Attachment point where the joint is fixed to the child body. + parent_axis : Vector + The axis fixed in the parent frame that represents the joint. + child_axis : Vector + The axis fixed in the child frame that represents the joint. + parent_interframe : ReferenceFrame + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. + child_interframe : ReferenceFrame + Intermediate frame of the child body with respect to which the joint + transformation is formulated. + kdes : Matrix + Kinematical differential equations of the joint. + + Notes + ===== + + When providing a vector as the intermediate frame, a new intermediate frame + is created which aligns its X axis with the provided vector. This is done + with a single fixed rotation about a rotation axis. This rotation axis is + determined by taking the cross product of the ``body.x`` axis with the + provided vector. In the case where the provided vector is in the ``-body.x`` + direction, the rotation is done about the ``body.y`` axis. + + """ + + def __init__(self, name, parent, child, coordinates=None, speeds=None, + parent_point=None, child_point=None, parent_interframe=None, + child_interframe=None, parent_axis=None, child_axis=None, + parent_joint_pos=None, child_joint_pos=None): + + if not isinstance(name, str): + raise TypeError('Supply a valid name.') + self._name = name + + if not isinstance(parent, BodyBase): + raise TypeError('Parent must be a body.') + self._parent = parent + + if not isinstance(child, BodyBase): + raise TypeError('Child must be a body.') + self._child = child + + if parent_axis is not None or child_axis is not None: + sympy_deprecation_warning( + """ + The parent_axis and child_axis arguments for the Joint classes + are deprecated. Instead use parent_interframe, child_interframe. + """, + deprecated_since_version="1.12", + active_deprecations_target="deprecated-mechanics-joint-axis", + stacklevel=4 + ) + if parent_interframe is None: + parent_interframe = parent_axis + if child_interframe is None: + child_interframe = child_axis + + # Set parent and child frame attributes + if hasattr(self._parent, 'frame'): + self._parent_frame = self._parent.frame + else: + if isinstance(parent_interframe, ReferenceFrame): + self._parent_frame = parent_interframe + else: + self._parent_frame = ReferenceFrame( + f'{self.name}_{self._parent.name}_frame') + if hasattr(self._child, 'frame'): + self._child_frame = self._child.frame + else: + if isinstance(child_interframe, ReferenceFrame): + self._child_frame = child_interframe + else: + self._child_frame = ReferenceFrame( + f'{self.name}_{self._child.name}_frame') + + self._parent_interframe = self._locate_joint_frame( + self._parent, parent_interframe, self._parent_frame) + self._child_interframe = self._locate_joint_frame( + self._child, child_interframe, self._child_frame) + self._parent_axis = self._axis(parent_axis, self._parent_frame) + self._child_axis = self._axis(child_axis, self._child_frame) + + if parent_joint_pos is not None or child_joint_pos is not None: + sympy_deprecation_warning( + """ + The parent_joint_pos and child_joint_pos arguments for the Joint + classes are deprecated. Instead use parent_point and child_point. + """, + deprecated_since_version="1.12", + active_deprecations_target="deprecated-mechanics-joint-pos", + stacklevel=4 + ) + if parent_point is None: + parent_point = parent_joint_pos + if child_point is None: + child_point = child_joint_pos + self._parent_point = self._locate_joint_pos( + self._parent, parent_point, self._parent_frame) + self._child_point = self._locate_joint_pos( + self._child, child_point, self._child_frame) + + self._coordinates = self._generate_coordinates(coordinates) + self._speeds = self._generate_speeds(speeds) + _validate_coordinates(self.coordinates, self.speeds) + self._kdes = self._generate_kdes() + + self._orient_frames() + self._set_angular_velocity() + self._set_linear_velocity() + + def __str__(self): + return self.name + + def __repr__(self): + return self.__str__() + + @property + def name(self): + """Name of the joint.""" + return self._name + + @property + def parent(self): + """Parent body of Joint.""" + return self._parent + + @property + def child(self): + """Child body of Joint.""" + return self._child + + @property + def coordinates(self): + """Matrix of the joint's generalized coordinates.""" + return self._coordinates + + @property + def speeds(self): + """Matrix of the joint's generalized speeds.""" + return self._speeds + + @property + def kdes(self): + """Kinematical differential equations of the joint.""" + return self._kdes + + @property + def parent_axis(self): + """The axis of parent frame.""" + # Will be removed with `deprecated-mechanics-joint-axis` + return self._parent_axis + + @property + def child_axis(self): + """The axis of child frame.""" + # Will be removed with `deprecated-mechanics-joint-axis` + return self._child_axis + + @property + def parent_point(self): + """Attachment point where the joint is fixed to the parent body.""" + return self._parent_point + + @property + def child_point(self): + """Attachment point where the joint is fixed to the child body.""" + return self._child_point + + @property + def parent_interframe(self): + return self._parent_interframe + + @property + def child_interframe(self): + return self._child_interframe + + @abstractmethod + def _generate_coordinates(self, coordinates): + """Generate Matrix of the joint's generalized coordinates.""" + pass + + @abstractmethod + def _generate_speeds(self, speeds): + """Generate Matrix of the joint's generalized speeds.""" + pass + + @abstractmethod + def _orient_frames(self): + """Orient frames as per the joint.""" + pass + + @abstractmethod + def _set_angular_velocity(self): + """Set angular velocity of the joint related frames.""" + pass + + @abstractmethod + def _set_linear_velocity(self): + """Set velocity of related points to the joint.""" + pass + + @staticmethod + def _to_vector(matrix, frame): + """Converts a matrix to a vector in the given frame.""" + return Vector([(matrix, frame)]) + + @staticmethod + def _axis(ax, *frames): + """Check whether an axis is fixed in one of the frames.""" + if ax is None: + ax = frames[0].x + return ax + if not isinstance(ax, Vector): + raise TypeError("Axis must be a Vector.") + ref_frame = None # Find a body in which the axis can be expressed + for frame in frames: + try: + ax.to_matrix(frame) + except ValueError: + pass + else: + ref_frame = frame + break + if ref_frame is None: + raise ValueError("Axis cannot be expressed in one of the body's " + "frames.") + if not ax.dt(ref_frame) == 0: + raise ValueError('Axis cannot be time-varying when viewed from the ' + 'associated body.') + return ax + + @staticmethod + def _choose_rotation_axis(frame, axis): + components = axis.to_matrix(frame) + x, y, z = components[0], components[1], components[2] + + if x != 0: + if y != 0: + if z != 0: + return cross(axis, frame.x) + if z != 0: + return frame.y + return frame.z + else: + if y != 0: + return frame.x + return frame.y + + @staticmethod + def _create_aligned_interframe(frame, align_axis, frame_axis=None, + frame_name=None): + """ + Returns an intermediate frame, where the ``frame_axis`` defined in + ``frame`` is aligned with ``axis``. By default this means that the X + axis will be aligned with ``axis``. + + Parameters + ========== + + frame : BodyBase or ReferenceFrame + The body or reference frame with respect to which the intermediate + frame is oriented. + align_axis : Vector + The vector with respect to which the intermediate frame will be + aligned. + frame_axis : Vector + The vector of the frame which should get aligned with ``axis``. The + default is the X axis of the frame. + frame_name : string + Name of the to be created intermediate frame. The default adds + "_int_frame" to the name of ``frame``. + + Example + ======= + + An intermediate frame, where the X axis of the parent becomes aligned + with ``parent.y + parent.z`` can be created as follows: + + >>> from sympy.physics.mechanics.joint import Joint + >>> from sympy.physics.mechanics import RigidBody + >>> parent = RigidBody('parent') + >>> parent_interframe = Joint._create_aligned_interframe( + ... parent, parent.y + parent.z) + >>> parent_interframe + parent_int_frame + >>> parent.frame.dcm(parent_interframe) + Matrix([ + [ 0, -sqrt(2)/2, -sqrt(2)/2], + [sqrt(2)/2, 1/2, -1/2], + [sqrt(2)/2, -1/2, 1/2]]) + >>> (parent.y + parent.z).express(parent_interframe) + sqrt(2)*parent_int_frame.x + + Notes + ===== + + The direction cosine matrix between the given frame and intermediate + frame is formed using a simple rotation about an axis that is normal to + both ``align_axis`` and ``frame_axis``. In general, the normal axis is + formed by crossing the ``frame_axis`` with the ``align_axis``. The + exception is if the axes are parallel with opposite directions, in which + case the rotation vector is chosen using the rules in the following + table with the vectors expressed in the given frame: + + .. list-table:: + :header-rows: 1 + + * - ``align_axis`` + - ``frame_axis`` + - ``rotation_axis`` + * - ``-x`` + - ``x`` + - ``z`` + * - ``-y`` + - ``y`` + - ``x`` + * - ``-z`` + - ``z`` + - ``y`` + * - ``-x-y`` + - ``x+y`` + - ``z`` + * - ``-y-z`` + - ``y+z`` + - ``x`` + * - ``-x-z`` + - ``x+z`` + - ``y`` + * - ``-x-y-z`` + - ``x+y+z`` + - ``(x+y+z) × x`` + + """ + if isinstance(frame, BodyBase): + frame = frame.frame + if frame_axis is None: + frame_axis = frame.x + if frame_name is None: + if frame.name[-6:] == '_frame': + frame_name = f'{frame.name[:-6]}_int_frame' + else: + frame_name = f'{frame.name}_int_frame' + angle = frame_axis.angle_between(align_axis) + rotation_axis = cross(frame_axis, align_axis) + if rotation_axis == Vector(0) and angle == 0: + return frame + if angle == pi: + rotation_axis = Joint._choose_rotation_axis(frame, align_axis) + + int_frame = ReferenceFrame(frame_name) + int_frame.orient_axis(frame, rotation_axis, angle) + int_frame.set_ang_vel(frame, 0 * rotation_axis) + return int_frame + + def _generate_kdes(self): + """Generate kinematical differential equations.""" + kdes = [] + t = dynamicsymbols._t + for i in range(len(self.coordinates)): + kdes.append(-self.coordinates[i].diff(t) + self.speeds[i]) + return Matrix(kdes) + + def _locate_joint_pos(self, body, joint_pos, body_frame=None): + """Returns the attachment point of a body.""" + if body_frame is None: + body_frame = body.frame + if joint_pos is None: + return body.masscenter + if not isinstance(joint_pos, (Point, Vector)): + raise TypeError('Attachment point must be a Point or Vector.') + if isinstance(joint_pos, Vector): + point_name = f'{self.name}_{body.name}_joint' + joint_pos = body.masscenter.locatenew(point_name, joint_pos) + if not joint_pos.pos_from(body.masscenter).dt(body_frame) == 0: + raise ValueError('Attachment point must be fixed to the associated ' + 'body.') + return joint_pos + + def _locate_joint_frame(self, body, interframe, body_frame=None): + """Returns the attachment frame of a body.""" + if body_frame is None: + body_frame = body.frame + if interframe is None: + return body_frame + if isinstance(interframe, Vector): + interframe = Joint._create_aligned_interframe( + body_frame, interframe, + frame_name=f'{self.name}_{body.name}_int_frame') + elif not isinstance(interframe, ReferenceFrame): + raise TypeError('Interframe must be a ReferenceFrame.') + if not interframe.ang_vel_in(body_frame) == 0: + raise ValueError(f'Interframe {interframe} is not fixed to body ' + f'{body}.') + body.masscenter.set_vel(interframe, 0) # Fixate interframe to body + return interframe + + def _fill_coordinate_list(self, coordinates, n_coords, label='q', offset=0, + number_single=False): + """Helper method for _generate_coordinates and _generate_speeds. + + Parameters + ========== + + coordinates : iterable + Iterable of coordinates or speeds that have been provided. + n_coords : Integer + Number of coordinates that should be returned. + label : String, optional + Coordinate type either 'q' (coordinates) or 'u' (speeds). The + Default is 'q'. + offset : Integer + Count offset when creating new dynamicsymbols. The default is 0. + number_single : Boolean + Boolean whether if n_coords == 1, number should still be used. The + default is False. + + """ + + def create_symbol(number): + if n_coords == 1 and not number_single: + return dynamicsymbols(f'{label}_{self.name}') + return dynamicsymbols(f'{label}{number}_{self.name}') + + name = 'generalized coordinate' if label == 'q' else 'generalized speed' + generated_coordinates = [] + if coordinates is None: + coordinates = [] + elif not iterable(coordinates): + coordinates = [coordinates] + if not (len(coordinates) == 0 or len(coordinates) == n_coords): + raise ValueError(f'Expected {n_coords} {name}s, instead got ' + f'{len(coordinates)} {name}s.') + # Supports more iterables, also Matrix + for i, coord in enumerate(coordinates): + if coord is None: + generated_coordinates.append(create_symbol(i + offset)) + elif isinstance(coord, (AppliedUndef, Derivative)): + generated_coordinates.append(coord) + else: + raise TypeError(f'The {name} {coord} should have been a ' + f'dynamicsymbol.') + for i in range(len(coordinates) + offset, n_coords + offset): + generated_coordinates.append(create_symbol(i)) + return Matrix(generated_coordinates) + + +class PinJoint(Joint): + """Pin (Revolute) Joint. + + .. raw:: html + :file: ../../../doc/src/explanation/modules/physics/mechanics/PinJoint.svg + + Explanation + =========== + + A pin joint is defined such that the joint rotation axis is fixed in both + the child and parent and the location of the joint is relative to the mass + center of each body. The child rotates an angle, θ, from the parent about + the rotation axis and has a simple angular speed, ω, relative to the + parent. The direction cosine matrix between the child interframe and + parent interframe is formed using a simple rotation about the joint axis. + The page on the joints framework gives a more detailed explanation of the + intermediate frames. + + Parameters + ========== + + name : string + A unique name for the joint. + parent : Particle or RigidBody + The parent body of joint. + child : Particle or RigidBody + The child body of joint. + coordinates : dynamicsymbol, optional + Generalized coordinates of the joint. + speeds : dynamicsymbol, optional + Generalized speeds of joint. + parent_point : Point or Vector, optional + Attachment point where the joint is fixed to the parent body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the parent's mass + center. + child_point : Point or Vector, optional + Attachment point where the joint is fixed to the child body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the child's mass + center. + parent_axis : Vector, optional + .. deprecated:: 1.12 + Axis fixed in the parent body which aligns with an axis fixed in the + child body. The default is the x axis of parent's reference frame. + For more information on this deprecation, see + :ref:`deprecated-mechanics-joint-axis`. + child_axis : Vector, optional + .. deprecated:: 1.12 + Axis fixed in the child body which aligns with an axis fixed in the + parent body. The default is the x axis of child's reference frame. + For more information on this deprecation, see + :ref:`deprecated-mechanics-joint-axis`. + parent_interframe : ReferenceFrame, optional + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the parent's own frame. + child_interframe : ReferenceFrame, optional + Intermediate frame of the child body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the child's own frame. + joint_axis : Vector + The axis about which the rotation occurs. Note that the components + of this axis are the same in the parent_interframe and child_interframe. + parent_joint_pos : Point or Vector, optional + .. deprecated:: 1.12 + This argument is replaced by parent_point and will be removed in a + future version. + See :ref:`deprecated-mechanics-joint-pos` for more information. + child_joint_pos : Point or Vector, optional + .. deprecated:: 1.12 + This argument is replaced by child_point and will be removed in a + future version. + See :ref:`deprecated-mechanics-joint-pos` for more information. + + Attributes + ========== + + name : string + The joint's name. + parent : Particle or RigidBody + The joint's parent body. + child : Particle or RigidBody + The joint's child body. + coordinates : Matrix + Matrix of the joint's generalized coordinates. The default value is + ``dynamicsymbols(f'q_{joint.name}')``. + speeds : Matrix + Matrix of the joint's generalized speeds. The default value is + ``dynamicsymbols(f'u_{joint.name}')``. + parent_point : Point + Attachment point where the joint is fixed to the parent body. + child_point : Point + Attachment point where the joint is fixed to the child body. + parent_axis : Vector + The axis fixed in the parent frame that represents the joint. + child_axis : Vector + The axis fixed in the child frame that represents the joint. + parent_interframe : ReferenceFrame + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. + child_interframe : ReferenceFrame + Intermediate frame of the child body with respect to which the joint + transformation is formulated. + joint_axis : Vector + The axis about which the rotation occurs. Note that the components of + this axis are the same in the parent_interframe and child_interframe. + kdes : Matrix + Kinematical differential equations of the joint. + + Examples + ========= + + A single pin joint is created from two bodies and has the following basic + attributes: + + >>> from sympy.physics.mechanics import RigidBody, PinJoint + >>> parent = RigidBody('P') + >>> parent + P + >>> child = RigidBody('C') + >>> child + C + >>> joint = PinJoint('PC', parent, child) + >>> joint + PinJoint: PC parent: P child: C + >>> joint.name + 'PC' + >>> joint.parent + P + >>> joint.child + C + >>> joint.parent_point + P_masscenter + >>> joint.child_point + C_masscenter + >>> joint.parent_axis + P_frame.x + >>> joint.child_axis + C_frame.x + >>> joint.coordinates + Matrix([[q_PC(t)]]) + >>> joint.speeds + Matrix([[u_PC(t)]]) + >>> child.frame.ang_vel_in(parent.frame) + u_PC(t)*P_frame.x + >>> child.frame.dcm(parent.frame) + Matrix([ + [1, 0, 0], + [0, cos(q_PC(t)), sin(q_PC(t))], + [0, -sin(q_PC(t)), cos(q_PC(t))]]) + >>> joint.child_point.pos_from(joint.parent_point) + 0 + + To further demonstrate the use of the pin joint, the kinematics of simple + double pendulum that rotates about the Z axis of each connected body can be + created as follows. + + >>> from sympy import symbols, trigsimp + >>> from sympy.physics.mechanics import RigidBody, PinJoint + >>> l1, l2 = symbols('l1 l2') + + First create bodies to represent the fixed ceiling and one to represent + each pendulum bob. + + >>> ceiling = RigidBody('C') + >>> upper_bob = RigidBody('U') + >>> lower_bob = RigidBody('L') + + The first joint will connect the upper bob to the ceiling by a distance of + ``l1`` and the joint axis will be about the Z axis for each body. + + >>> ceiling_joint = PinJoint('P1', ceiling, upper_bob, + ... child_point=-l1*upper_bob.frame.x, + ... joint_axis=ceiling.frame.z) + + The second joint will connect the lower bob to the upper bob by a distance + of ``l2`` and the joint axis will also be about the Z axis for each body. + + >>> pendulum_joint = PinJoint('P2', upper_bob, lower_bob, + ... child_point=-l2*lower_bob.frame.x, + ... joint_axis=upper_bob.frame.z) + + Once the joints are established the kinematics of the connected bodies can + be accessed. First the direction cosine matrices of pendulum link relative + to the ceiling are found: + + >>> upper_bob.frame.dcm(ceiling.frame) + Matrix([ + [ cos(q_P1(t)), sin(q_P1(t)), 0], + [-sin(q_P1(t)), cos(q_P1(t)), 0], + [ 0, 0, 1]]) + >>> trigsimp(lower_bob.frame.dcm(ceiling.frame)) + Matrix([ + [ cos(q_P1(t) + q_P2(t)), sin(q_P1(t) + q_P2(t)), 0], + [-sin(q_P1(t) + q_P2(t)), cos(q_P1(t) + q_P2(t)), 0], + [ 0, 0, 1]]) + + The position of the lower bob's masscenter is found with: + + >>> lower_bob.masscenter.pos_from(ceiling.masscenter) + l1*U_frame.x + l2*L_frame.x + + The angular velocities of the two pendulum links can be computed with + respect to the ceiling. + + >>> upper_bob.frame.ang_vel_in(ceiling.frame) + u_P1(t)*C_frame.z + >>> lower_bob.frame.ang_vel_in(ceiling.frame) + u_P1(t)*C_frame.z + u_P2(t)*U_frame.z + + And finally, the linear velocities of the two pendulum bobs can be computed + with respect to the ceiling. + + >>> upper_bob.masscenter.vel(ceiling.frame) + l1*u_P1(t)*U_frame.y + >>> lower_bob.masscenter.vel(ceiling.frame) + l1*u_P1(t)*U_frame.y + l2*(u_P1(t) + u_P2(t))*L_frame.y + + """ + + def __init__(self, name, parent, child, coordinates=None, speeds=None, + parent_point=None, child_point=None, parent_interframe=None, + child_interframe=None, parent_axis=None, child_axis=None, + joint_axis=None, parent_joint_pos=None, child_joint_pos=None): + + self._joint_axis = joint_axis + super().__init__(name, parent, child, coordinates, speeds, parent_point, + child_point, parent_interframe, child_interframe, + parent_axis, child_axis, parent_joint_pos, + child_joint_pos) + + def __str__(self): + return (f'PinJoint: {self.name} parent: {self.parent} ' + f'child: {self.child}') + + @property + def joint_axis(self): + """Axis about which the child rotates with respect to the parent.""" + return self._joint_axis + + def _generate_coordinates(self, coordinate): + return self._fill_coordinate_list(coordinate, 1, 'q') + + def _generate_speeds(self, speed): + return self._fill_coordinate_list(speed, 1, 'u') + + def _orient_frames(self): + self._joint_axis = self._axis(self.joint_axis, self.parent_interframe) + self.child_interframe.orient_axis( + self.parent_interframe, self.joint_axis, self.coordinates[0]) + + def _set_angular_velocity(self): + self.child_interframe.set_ang_vel(self.parent_interframe, self.speeds[ + 0] * self.joint_axis.normalize()) + + def _set_linear_velocity(self): + self.child_point.set_pos(self.parent_point, 0) + self.parent_point.set_vel(self._parent_frame, 0) + self.child_point.set_vel(self._child_frame, 0) + self.child.masscenter.v2pt_theory(self.parent_point, + self._parent_frame, self._child_frame) + + +class PrismaticJoint(Joint): + """Prismatic (Sliding) Joint. + + .. image:: PrismaticJoint.svg + + Explanation + =========== + + It is defined such that the child body translates with respect to the parent + body along the body-fixed joint axis. The location of the joint is defined + by two points, one in each body, which coincide when the generalized + coordinate is zero. The direction cosine matrix between the + parent_interframe and child_interframe is the identity matrix. Therefore, + the direction cosine matrix between the parent and child frames is fully + defined by the definition of the intermediate frames. The page on the joints + framework gives a more detailed explanation of the intermediate frames. + + Parameters + ========== + + name : string + A unique name for the joint. + parent : Particle or RigidBody + The parent body of joint. + child : Particle or RigidBody + The child body of joint. + coordinates : dynamicsymbol, optional + Generalized coordinates of the joint. The default value is + ``dynamicsymbols(f'q_{joint.name}')``. + speeds : dynamicsymbol, optional + Generalized speeds of joint. The default value is + ``dynamicsymbols(f'u_{joint.name}')``. + parent_point : Point or Vector, optional + Attachment point where the joint is fixed to the parent body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the parent's mass + center. + child_point : Point or Vector, optional + Attachment point where the joint is fixed to the child body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the child's mass + center. + parent_axis : Vector, optional + .. deprecated:: 1.12 + Axis fixed in the parent body which aligns with an axis fixed in the + child body. The default is the x axis of parent's reference frame. + For more information on this deprecation, see + :ref:`deprecated-mechanics-joint-axis`. + child_axis : Vector, optional + .. deprecated:: 1.12 + Axis fixed in the child body which aligns with an axis fixed in the + parent body. The default is the x axis of child's reference frame. + For more information on this deprecation, see + :ref:`deprecated-mechanics-joint-axis`. + parent_interframe : ReferenceFrame, optional + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the parent's own frame. + child_interframe : ReferenceFrame, optional + Intermediate frame of the child body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the child's own frame. + joint_axis : Vector + The axis along which the translation occurs. Note that the components + of this axis are the same in the parent_interframe and child_interframe. + parent_joint_pos : Point or Vector, optional + .. deprecated:: 1.12 + This argument is replaced by parent_point and will be removed in a + future version. + See :ref:`deprecated-mechanics-joint-pos` for more information. + child_joint_pos : Point or Vector, optional + .. deprecated:: 1.12 + This argument is replaced by child_point and will be removed in a + future version. + See :ref:`deprecated-mechanics-joint-pos` for more information. + + Attributes + ========== + + name : string + The joint's name. + parent : Particle or RigidBody + The joint's parent body. + child : Particle or RigidBody + The joint's child body. + coordinates : Matrix + Matrix of the joint's generalized coordinates. + speeds : Matrix + Matrix of the joint's generalized speeds. + parent_point : Point + Attachment point where the joint is fixed to the parent body. + child_point : Point + Attachment point where the joint is fixed to the child body. + parent_axis : Vector + The axis fixed in the parent frame that represents the joint. + child_axis : Vector + The axis fixed in the child frame that represents the joint. + parent_interframe : ReferenceFrame + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. + child_interframe : ReferenceFrame + Intermediate frame of the child body with respect to which the joint + transformation is formulated. + kdes : Matrix + Kinematical differential equations of the joint. + + Examples + ========= + + A single prismatic joint is created from two bodies and has the following + basic attributes: + + >>> from sympy.physics.mechanics import RigidBody, PrismaticJoint + >>> parent = RigidBody('P') + >>> parent + P + >>> child = RigidBody('C') + >>> child + C + >>> joint = PrismaticJoint('PC', parent, child) + >>> joint + PrismaticJoint: PC parent: P child: C + >>> joint.name + 'PC' + >>> joint.parent + P + >>> joint.child + C + >>> joint.parent_point + P_masscenter + >>> joint.child_point + C_masscenter + >>> joint.parent_axis + P_frame.x + >>> joint.child_axis + C_frame.x + >>> joint.coordinates + Matrix([[q_PC(t)]]) + >>> joint.speeds + Matrix([[u_PC(t)]]) + >>> child.frame.ang_vel_in(parent.frame) + 0 + >>> child.frame.dcm(parent.frame) + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> joint.child_point.pos_from(joint.parent_point) + q_PC(t)*P_frame.x + + To further demonstrate the use of the prismatic joint, the kinematics of two + masses sliding, one moving relative to a fixed body and the other relative + to the moving body. about the X axis of each connected body can be created + as follows. + + >>> from sympy.physics.mechanics import PrismaticJoint, RigidBody + + First create bodies to represent the fixed ceiling and one to represent + a particle. + + >>> wall = RigidBody('W') + >>> Part1 = RigidBody('P1') + >>> Part2 = RigidBody('P2') + + The first joint will connect the particle to the ceiling and the + joint axis will be about the X axis for each body. + + >>> J1 = PrismaticJoint('J1', wall, Part1) + + The second joint will connect the second particle to the first particle + and the joint axis will also be about the X axis for each body. + + >>> J2 = PrismaticJoint('J2', Part1, Part2) + + Once the joint is established the kinematics of the connected bodies can + be accessed. First the direction cosine matrices of Part relative + to the ceiling are found: + + >>> Part1.frame.dcm(wall.frame) + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + + >>> Part2.frame.dcm(wall.frame) + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + + The position of the particles' masscenter is found with: + + >>> Part1.masscenter.pos_from(wall.masscenter) + q_J1(t)*W_frame.x + + >>> Part2.masscenter.pos_from(wall.masscenter) + q_J1(t)*W_frame.x + q_J2(t)*P1_frame.x + + The angular velocities of the two particle links can be computed with + respect to the ceiling. + + >>> Part1.frame.ang_vel_in(wall.frame) + 0 + + >>> Part2.frame.ang_vel_in(wall.frame) + 0 + + And finally, the linear velocities of the two particles can be computed + with respect to the ceiling. + + >>> Part1.masscenter.vel(wall.frame) + u_J1(t)*W_frame.x + + >>> Part2.masscenter.vel(wall.frame) + u_J1(t)*W_frame.x + Derivative(q_J2(t), t)*P1_frame.x + + """ + + def __init__(self, name, parent, child, coordinates=None, speeds=None, + parent_point=None, child_point=None, parent_interframe=None, + child_interframe=None, parent_axis=None, child_axis=None, + joint_axis=None, parent_joint_pos=None, child_joint_pos=None): + + self._joint_axis = joint_axis + super().__init__(name, parent, child, coordinates, speeds, parent_point, + child_point, parent_interframe, child_interframe, + parent_axis, child_axis, parent_joint_pos, + child_joint_pos) + + def __str__(self): + return (f'PrismaticJoint: {self.name} parent: {self.parent} ' + f'child: {self.child}') + + @property + def joint_axis(self): + """Axis along which the child translates with respect to the parent.""" + return self._joint_axis + + def _generate_coordinates(self, coordinate): + return self._fill_coordinate_list(coordinate, 1, 'q') + + def _generate_speeds(self, speed): + return self._fill_coordinate_list(speed, 1, 'u') + + def _orient_frames(self): + self._joint_axis = self._axis(self.joint_axis, self.parent_interframe) + self.child_interframe.orient_axis( + self.parent_interframe, self.joint_axis, 0) + + def _set_angular_velocity(self): + self.child_interframe.set_ang_vel(self.parent_interframe, 0) + + def _set_linear_velocity(self): + axis = self.joint_axis.normalize() + self.child_point.set_pos(self.parent_point, self.coordinates[0] * axis) + self.parent_point.set_vel(self._parent_frame, 0) + self.child_point.set_vel(self._child_frame, 0) + self.child_point.set_vel(self._parent_frame, self.speeds[0] * axis) + self.child.masscenter.set_vel(self._parent_frame, self.speeds[0] * axis) + + +class CylindricalJoint(Joint): + """Cylindrical Joint. + + .. image:: CylindricalJoint.svg + :align: center + :width: 600 + + Explanation + =========== + + A cylindrical joint is defined such that the child body both rotates about + and translates along the body-fixed joint axis with respect to the parent + body. The joint axis is both the rotation axis and translation axis. The + location of the joint is defined by two points, one in each body, which + coincide when the generalized coordinate corresponding to the translation is + zero. The direction cosine matrix between the child interframe and parent + interframe is formed using a simple rotation about the joint axis. The page + on the joints framework gives a more detailed explanation of the + intermediate frames. + + Parameters + ========== + + name : string + A unique name for the joint. + parent : Particle or RigidBody + The parent body of joint. + child : Particle or RigidBody + The child body of joint. + rotation_coordinate : dynamicsymbol, optional + Generalized coordinate corresponding to the rotation angle. The default + value is ``dynamicsymbols(f'q0_{joint.name}')``. + translation_coordinate : dynamicsymbol, optional + Generalized coordinate corresponding to the translation distance. The + default value is ``dynamicsymbols(f'q1_{joint.name}')``. + rotation_speed : dynamicsymbol, optional + Generalized speed corresponding to the angular velocity. The default + value is ``dynamicsymbols(f'u0_{joint.name}')``. + translation_speed : dynamicsymbol, optional + Generalized speed corresponding to the translation velocity. The default + value is ``dynamicsymbols(f'u1_{joint.name}')``. + parent_point : Point or Vector, optional + Attachment point where the joint is fixed to the parent body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the parent's mass + center. + child_point : Point or Vector, optional + Attachment point where the joint is fixed to the child body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the child's mass + center. + parent_interframe : ReferenceFrame, optional + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the parent's own frame. + child_interframe : ReferenceFrame, optional + Intermediate frame of the child body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the child's own frame. + joint_axis : Vector, optional + The rotation as well as translation axis. Note that the components of + this axis are the same in the parent_interframe and child_interframe. + + Attributes + ========== + + name : string + The joint's name. + parent : Particle or RigidBody + The joint's parent body. + child : Particle or RigidBody + The joint's child body. + rotation_coordinate : dynamicsymbol + Generalized coordinate corresponding to the rotation angle. + translation_coordinate : dynamicsymbol + Generalized coordinate corresponding to the translation distance. + rotation_speed : dynamicsymbol + Generalized speed corresponding to the angular velocity. + translation_speed : dynamicsymbol + Generalized speed corresponding to the translation velocity. + coordinates : Matrix + Matrix of the joint's generalized coordinates. + speeds : Matrix + Matrix of the joint's generalized speeds. + parent_point : Point + Attachment point where the joint is fixed to the parent body. + child_point : Point + Attachment point where the joint is fixed to the child body. + parent_interframe : ReferenceFrame + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. + child_interframe : ReferenceFrame + Intermediate frame of the child body with respect to which the joint + transformation is formulated. + kdes : Matrix + Kinematical differential equations of the joint. + joint_axis : Vector + The axis of rotation and translation. + + Examples + ========= + + A single cylindrical joint is created between two bodies and has the + following basic attributes: + + >>> from sympy.physics.mechanics import RigidBody, CylindricalJoint + >>> parent = RigidBody('P') + >>> parent + P + >>> child = RigidBody('C') + >>> child + C + >>> joint = CylindricalJoint('PC', parent, child) + >>> joint + CylindricalJoint: PC parent: P child: C + >>> joint.name + 'PC' + >>> joint.parent + P + >>> joint.child + C + >>> joint.parent_point + P_masscenter + >>> joint.child_point + C_masscenter + >>> joint.parent_axis + P_frame.x + >>> joint.child_axis + C_frame.x + >>> joint.coordinates + Matrix([ + [q0_PC(t)], + [q1_PC(t)]]) + >>> joint.speeds + Matrix([ + [u0_PC(t)], + [u1_PC(t)]]) + >>> child.frame.ang_vel_in(parent.frame) + u0_PC(t)*P_frame.x + >>> child.frame.dcm(parent.frame) + Matrix([ + [1, 0, 0], + [0, cos(q0_PC(t)), sin(q0_PC(t))], + [0, -sin(q0_PC(t)), cos(q0_PC(t))]]) + >>> joint.child_point.pos_from(joint.parent_point) + q1_PC(t)*P_frame.x + >>> child.masscenter.vel(parent.frame) + u1_PC(t)*P_frame.x + + To further demonstrate the use of the cylindrical joint, the kinematics of + two cylindrical joints perpendicular to each other can be created as follows. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import RigidBody, CylindricalJoint + >>> r, l, w = symbols('r l w') + + First create bodies to represent the fixed floor with a fixed pole on it. + The second body represents a freely moving tube around that pole. The third + body represents a solid flag freely translating along and rotating around + the Y axis of the tube. + + >>> floor = RigidBody('floor') + >>> tube = RigidBody('tube') + >>> flag = RigidBody('flag') + + The first joint will connect the first tube to the floor with it translating + along and rotating around the Z axis of both bodies. + + >>> floor_joint = CylindricalJoint('C1', floor, tube, joint_axis=floor.z) + + The second joint will connect the tube perpendicular to the flag along the Y + axis of both the tube and the flag, with the joint located at a distance + ``r`` from the tube's center of mass and a combination of the distances + ``l`` and ``w`` from the flag's center of mass. + + >>> flag_joint = CylindricalJoint('C2', tube, flag, + ... parent_point=r * tube.y, + ... child_point=-w * flag.y + l * flag.z, + ... joint_axis=tube.y) + + Once the joints are established the kinematics of the connected bodies can + be accessed. First the direction cosine matrices of both the body and the + flag relative to the floor are found: + + >>> tube.frame.dcm(floor.frame) + Matrix([ + [ cos(q0_C1(t)), sin(q0_C1(t)), 0], + [-sin(q0_C1(t)), cos(q0_C1(t)), 0], + [ 0, 0, 1]]) + >>> flag.frame.dcm(floor.frame) + Matrix([ + [cos(q0_C1(t))*cos(q0_C2(t)), sin(q0_C1(t))*cos(q0_C2(t)), -sin(q0_C2(t))], + [ -sin(q0_C1(t)), cos(q0_C1(t)), 0], + [sin(q0_C2(t))*cos(q0_C1(t)), sin(q0_C1(t))*sin(q0_C2(t)), cos(q0_C2(t))]]) + + The position of the flag's center of mass is found with: + + >>> flag.masscenter.pos_from(floor.masscenter) + q1_C1(t)*floor_frame.z + (r + q1_C2(t))*tube_frame.y + w*flag_frame.y - l*flag_frame.z + + The angular velocities of the two tubes can be computed with respect to the + floor. + + >>> tube.frame.ang_vel_in(floor.frame) + u0_C1(t)*floor_frame.z + >>> flag.frame.ang_vel_in(floor.frame) + u0_C1(t)*floor_frame.z + u0_C2(t)*tube_frame.y + + Finally, the linear velocities of the two tube centers of mass can be + computed with respect to the floor, while expressed in the tube's frame. + + >>> tube.masscenter.vel(floor.frame).to_matrix(tube.frame) + Matrix([ + [ 0], + [ 0], + [u1_C1(t)]]) + >>> flag.masscenter.vel(floor.frame).to_matrix(tube.frame).simplify() + Matrix([ + [-l*u0_C2(t)*cos(q0_C2(t)) - r*u0_C1(t) - w*u0_C1(t) - q1_C2(t)*u0_C1(t)], + [ -l*u0_C1(t)*sin(q0_C2(t)) + Derivative(q1_C2(t), t)], + [ l*u0_C2(t)*sin(q0_C2(t)) + u1_C1(t)]]) + + """ + + def __init__(self, name, parent, child, rotation_coordinate=None, + translation_coordinate=None, rotation_speed=None, + translation_speed=None, parent_point=None, child_point=None, + parent_interframe=None, child_interframe=None, + joint_axis=None): + self._joint_axis = joint_axis + coordinates = (rotation_coordinate, translation_coordinate) + speeds = (rotation_speed, translation_speed) + super().__init__(name, parent, child, coordinates, speeds, + parent_point, child_point, + parent_interframe=parent_interframe, + child_interframe=child_interframe) + + def __str__(self): + return (f'CylindricalJoint: {self.name} parent: {self.parent} ' + f'child: {self.child}') + + @property + def joint_axis(self): + """Axis about and along which the rotation and translation occurs.""" + return self._joint_axis + + @property + def rotation_coordinate(self): + """Generalized coordinate corresponding to the rotation angle.""" + return self.coordinates[0] + + @property + def translation_coordinate(self): + """Generalized coordinate corresponding to the translation distance.""" + return self.coordinates[1] + + @property + def rotation_speed(self): + """Generalized speed corresponding to the angular velocity.""" + return self.speeds[0] + + @property + def translation_speed(self): + """Generalized speed corresponding to the translation velocity.""" + return self.speeds[1] + + def _generate_coordinates(self, coordinates): + return self._fill_coordinate_list(coordinates, 2, 'q') + + def _generate_speeds(self, speeds): + return self._fill_coordinate_list(speeds, 2, 'u') + + def _orient_frames(self): + self._joint_axis = self._axis(self.joint_axis, self.parent_interframe) + self.child_interframe.orient_axis( + self.parent_interframe, self.joint_axis, self.rotation_coordinate) + + def _set_angular_velocity(self): + self.child_interframe.set_ang_vel( + self.parent_interframe, + self.rotation_speed * self.joint_axis.normalize()) + + def _set_linear_velocity(self): + self.child_point.set_pos( + self.parent_point, + self.translation_coordinate * self.joint_axis.normalize()) + self.parent_point.set_vel(self._parent_frame, 0) + self.child_point.set_vel(self._child_frame, 0) + self.child_point.set_vel( + self._parent_frame, + self.translation_speed * self.joint_axis.normalize()) + self.child.masscenter.v2pt_theory(self.child_point, self._parent_frame, + self.child_interframe) + + +class PlanarJoint(Joint): + """Planar Joint. + + .. raw:: html + :file: ../../../doc/src/modules/physics/mechanics/api/PlanarJoint.svg + + Explanation + =========== + + A planar joint is defined such that the child body translates over a fixed + plane of the parent body as well as rotate about the rotation axis, which + is perpendicular to that plane. The origin of this plane is the + ``parent_point`` and the plane is spanned by two nonparallel planar vectors. + The location of the ``child_point`` is based on the planar vectors + ($\\vec{v}_1$, $\\vec{v}_2$) and generalized coordinates ($q_1$, $q_2$), + i.e. $\\vec{r} = q_1 \\hat{v}_1 + q_2 \\hat{v}_2$. The direction cosine + matrix between the ``child_interframe`` and ``parent_interframe`` is formed + using a simple rotation ($q_0$) about the rotation axis. + + In order to simplify the definition of the ``PlanarJoint``, the + ``rotation_axis`` and ``planar_vectors`` are set to be the unit vectors of + the ``parent_interframe`` according to the table below. This ensures that + you can only define these vectors by creating a separate frame and supplying + that as the interframe. If you however would only like to supply the normals + of the plane with respect to the parent and child bodies, then you can also + supply those to the ``parent_interframe`` and ``child_interframe`` + arguments. An example of both of these cases is in the examples section + below and the page on the joints framework provides a more detailed + explanation of the intermediate frames. + + .. list-table:: + + * - ``rotation_axis`` + - ``parent_interframe.x`` + * - ``planar_vectors[0]`` + - ``parent_interframe.y`` + * - ``planar_vectors[1]`` + - ``parent_interframe.z`` + + Parameters + ========== + + name : string + A unique name for the joint. + parent : Particle or RigidBody + The parent body of joint. + child : Particle or RigidBody + The child body of joint. + rotation_coordinate : dynamicsymbol, optional + Generalized coordinate corresponding to the rotation angle. The default + value is ``dynamicsymbols(f'q0_{joint.name}')``. + planar_coordinates : iterable of dynamicsymbols, optional + Two generalized coordinates used for the planar translation. The default + value is ``dynamicsymbols(f'q1_{joint.name} q2_{joint.name}')``. + rotation_speed : dynamicsymbol, optional + Generalized speed corresponding to the angular velocity. The default + value is ``dynamicsymbols(f'u0_{joint.name}')``. + planar_speeds : dynamicsymbols, optional + Two generalized speeds used for the planar translation velocity. The + default value is ``dynamicsymbols(f'u1_{joint.name} u2_{joint.name}')``. + parent_point : Point or Vector, optional + Attachment point where the joint is fixed to the parent body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the parent's mass + center. + child_point : Point or Vector, optional + Attachment point where the joint is fixed to the child body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the child's mass + center. + parent_interframe : ReferenceFrame, optional + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the parent's own frame. + child_interframe : ReferenceFrame, optional + Intermediate frame of the child body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the child's own frame. + + Attributes + ========== + + name : string + The joint's name. + parent : Particle or RigidBody + The joint's parent body. + child : Particle or RigidBody + The joint's child body. + rotation_coordinate : dynamicsymbol + Generalized coordinate corresponding to the rotation angle. + planar_coordinates : Matrix + Two generalized coordinates used for the planar translation. + rotation_speed : dynamicsymbol + Generalized speed corresponding to the angular velocity. + planar_speeds : Matrix + Two generalized speeds used for the planar translation velocity. + coordinates : Matrix + Matrix of the joint's generalized coordinates. + speeds : Matrix + Matrix of the joint's generalized speeds. + parent_point : Point + Attachment point where the joint is fixed to the parent body. + child_point : Point + Attachment point where the joint is fixed to the child body. + parent_interframe : ReferenceFrame + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. + child_interframe : ReferenceFrame + Intermediate frame of the child body with respect to which the joint + transformation is formulated. + kdes : Matrix + Kinematical differential equations of the joint. + rotation_axis : Vector + The axis about which the rotation occurs. + planar_vectors : list + The vectors that describe the planar translation directions. + + Examples + ========= + + A single planar joint is created between two bodies and has the following + basic attributes: + + >>> from sympy.physics.mechanics import RigidBody, PlanarJoint + >>> parent = RigidBody('P') + >>> parent + P + >>> child = RigidBody('C') + >>> child + C + >>> joint = PlanarJoint('PC', parent, child) + >>> joint + PlanarJoint: PC parent: P child: C + >>> joint.name + 'PC' + >>> joint.parent + P + >>> joint.child + C + >>> joint.parent_point + P_masscenter + >>> joint.child_point + C_masscenter + >>> joint.rotation_axis + P_frame.x + >>> joint.planar_vectors + [P_frame.y, P_frame.z] + >>> joint.rotation_coordinate + q0_PC(t) + >>> joint.planar_coordinates + Matrix([ + [q1_PC(t)], + [q2_PC(t)]]) + >>> joint.coordinates + Matrix([ + [q0_PC(t)], + [q1_PC(t)], + [q2_PC(t)]]) + >>> joint.rotation_speed + u0_PC(t) + >>> joint.planar_speeds + Matrix([ + [u1_PC(t)], + [u2_PC(t)]]) + >>> joint.speeds + Matrix([ + [u0_PC(t)], + [u1_PC(t)], + [u2_PC(t)]]) + >>> child.frame.ang_vel_in(parent.frame) + u0_PC(t)*P_frame.x + >>> child.frame.dcm(parent.frame) + Matrix([ + [1, 0, 0], + [0, cos(q0_PC(t)), sin(q0_PC(t))], + [0, -sin(q0_PC(t)), cos(q0_PC(t))]]) + >>> joint.child_point.pos_from(joint.parent_point) + q1_PC(t)*P_frame.y + q2_PC(t)*P_frame.z + >>> child.masscenter.vel(parent.frame) + u1_PC(t)*P_frame.y + u2_PC(t)*P_frame.z + + To further demonstrate the use of the planar joint, the kinematics of a + block sliding on a slope, can be created as follows. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import PlanarJoint, RigidBody, ReferenceFrame + >>> a, d, h = symbols('a d h') + + First create bodies to represent the slope and the block. + + >>> ground = RigidBody('G') + >>> block = RigidBody('B') + + To define the slope you can either define the plane by specifying the + ``planar_vectors`` or/and the ``rotation_axis``. However it is advisable to + create a rotated intermediate frame, so that the ``parent_vectors`` and + ``rotation_axis`` will be the unit vectors of this intermediate frame. + + >>> slope = ReferenceFrame('A') + >>> slope.orient_axis(ground.frame, ground.y, a) + + The planar joint can be created using these bodies and intermediate frame. + We can specify the origin of the slope to be ``d`` above the slope's center + of mass and the block's center of mass to be a distance ``h`` above the + slope's surface. Note that we can specify the normal of the plane using the + rotation axis argument. + + >>> joint = PlanarJoint('PC', ground, block, parent_point=d * ground.x, + ... child_point=-h * block.x, parent_interframe=slope) + + Once the joint is established the kinematics of the bodies can be accessed. + First the ``rotation_axis``, which is normal to the plane and the + ``plane_vectors``, can be found. + + >>> joint.rotation_axis + A.x + >>> joint.planar_vectors + [A.y, A.z] + + The direction cosine matrix of the block with respect to the ground can be + found with: + + >>> block.frame.dcm(ground.frame) + Matrix([ + [ cos(a), 0, -sin(a)], + [sin(a)*sin(q0_PC(t)), cos(q0_PC(t)), sin(q0_PC(t))*cos(a)], + [sin(a)*cos(q0_PC(t)), -sin(q0_PC(t)), cos(a)*cos(q0_PC(t))]]) + + The angular velocity of the block can be computed with respect to the + ground. + + >>> block.frame.ang_vel_in(ground.frame) + u0_PC(t)*A.x + + The position of the block's center of mass can be found with: + + >>> block.masscenter.pos_from(ground.masscenter) + d*G_frame.x + h*B_frame.x + q1_PC(t)*A.y + q2_PC(t)*A.z + + Finally, the linear velocity of the block's center of mass can be + computed with respect to the ground. + + >>> block.masscenter.vel(ground.frame) + u1_PC(t)*A.y + u2_PC(t)*A.z + + In some cases it could be your preference to only define the normals of the + plane with respect to both bodies. This can most easily be done by supplying + vectors to the ``interframe`` arguments. What will happen in this case is + that an interframe will be created with its ``x`` axis aligned with the + provided vector. For a further explanation of how this is done see the notes + of the ``Joint`` class. In the code below, the above example (with the block + on the slope) is recreated by supplying vectors to the interframe arguments. + Note that the previously described option is however more computationally + efficient, because the algorithm now has to compute the rotation angle + between the provided vector and the 'x' axis. + + >>> from sympy import symbols, cos, sin + >>> from sympy.physics.mechanics import PlanarJoint, RigidBody + >>> a, d, h = symbols('a d h') + >>> ground = RigidBody('G') + >>> block = RigidBody('B') + >>> joint = PlanarJoint( + ... 'PC', ground, block, parent_point=d * ground.x, + ... child_point=-h * block.x, child_interframe=block.x, + ... parent_interframe=cos(a) * ground.x + sin(a) * ground.z) + >>> block.frame.dcm(ground.frame).simplify() + Matrix([ + [ cos(a), 0, sin(a)], + [-sin(a)*sin(q0_PC(t)), cos(q0_PC(t)), sin(q0_PC(t))*cos(a)], + [-sin(a)*cos(q0_PC(t)), -sin(q0_PC(t)), cos(a)*cos(q0_PC(t))]]) + + """ + + def __init__(self, name, parent, child, rotation_coordinate=None, + planar_coordinates=None, rotation_speed=None, + planar_speeds=None, parent_point=None, child_point=None, + parent_interframe=None, child_interframe=None): + # A ready to merge implementation of setting the planar_vectors and + # rotation_axis was added and removed in PR #24046 + coordinates = (rotation_coordinate, planar_coordinates) + speeds = (rotation_speed, planar_speeds) + super().__init__(name, parent, child, coordinates, speeds, + parent_point, child_point, + parent_interframe=parent_interframe, + child_interframe=child_interframe) + + def __str__(self): + return (f'PlanarJoint: {self.name} parent: {self.parent} ' + f'child: {self.child}') + + @property + def rotation_coordinate(self): + """Generalized coordinate corresponding to the rotation angle.""" + return self.coordinates[0] + + @property + def planar_coordinates(self): + """Two generalized coordinates used for the planar translation.""" + return self.coordinates[1:, 0] + + @property + def rotation_speed(self): + """Generalized speed corresponding to the angular velocity.""" + return self.speeds[0] + + @property + def planar_speeds(self): + """Two generalized speeds used for the planar translation velocity.""" + return self.speeds[1:, 0] + + @property + def rotation_axis(self): + """The axis about which the rotation occurs.""" + return self.parent_interframe.x + + @property + def planar_vectors(self): + """The vectors that describe the planar translation directions.""" + return [self.parent_interframe.y, self.parent_interframe.z] + + def _generate_coordinates(self, coordinates): + rotation_speed = self._fill_coordinate_list(coordinates[0], 1, 'q', + number_single=True) + planar_speeds = self._fill_coordinate_list(coordinates[1], 2, 'q', 1) + return rotation_speed.col_join(planar_speeds) + + def _generate_speeds(self, speeds): + rotation_speed = self._fill_coordinate_list(speeds[0], 1, 'u', + number_single=True) + planar_speeds = self._fill_coordinate_list(speeds[1], 2, 'u', 1) + return rotation_speed.col_join(planar_speeds) + + def _orient_frames(self): + self.child_interframe.orient_axis( + self.parent_interframe, self.rotation_axis, + self.rotation_coordinate) + + def _set_angular_velocity(self): + self.child_interframe.set_ang_vel( + self.parent_interframe, + self.rotation_speed * self.rotation_axis) + + def _set_linear_velocity(self): + self.child_point.set_pos( + self.parent_point, + self.planar_coordinates[0] * self.planar_vectors[0] + + self.planar_coordinates[1] * self.planar_vectors[1]) + self.parent_point.set_vel(self.parent_interframe, 0) + self.child_point.set_vel(self.child_interframe, 0) + self.child_point.set_vel( + self._parent_frame, self.planar_speeds[0] * self.planar_vectors[0] + + self.planar_speeds[1] * self.planar_vectors[1]) + self.child.masscenter.v2pt_theory(self.child_point, self._parent_frame, + self._child_frame) + + +class SphericalJoint(Joint): + """Spherical (Ball-and-Socket) Joint. + + .. image:: SphericalJoint.svg + :align: center + :width: 600 + + Explanation + =========== + + A spherical joint is defined such that the child body is free to rotate in + any direction, without allowing a translation of the ``child_point``. As can + also be seen in the image, the ``parent_point`` and ``child_point`` are + fixed on top of each other, i.e. the ``joint_point``. This rotation is + defined using the :func:`parent_interframe.orient(child_interframe, + rot_type, amounts, rot_order) + ` method. The default + rotation consists of three relative rotations, i.e. body-fixed rotations. + Based on the direction cosine matrix following from these rotations, the + angular velocity is computed based on the generalized coordinates and + generalized speeds. + + Parameters + ========== + + name : string + A unique name for the joint. + parent : Particle or RigidBody + The parent body of joint. + child : Particle or RigidBody + The child body of joint. + coordinates: iterable of dynamicsymbols, optional + Generalized coordinates of the joint. + speeds : iterable of dynamicsymbols, optional + Generalized speeds of joint. + parent_point : Point or Vector, optional + Attachment point where the joint is fixed to the parent body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the parent's mass + center. + child_point : Point or Vector, optional + Attachment point where the joint is fixed to the child body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the child's mass + center. + parent_interframe : ReferenceFrame, optional + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the parent's own frame. + child_interframe : ReferenceFrame, optional + Intermediate frame of the child body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the child's own frame. + rot_type : str, optional + The method used to generate the direction cosine matrix. Supported + methods are: + + - ``'Body'``: three successive rotations about new intermediate axes, + also called "Euler and Tait-Bryan angles" + - ``'Space'``: three successive rotations about the parent frames' unit + vectors + + The default method is ``'Body'``. + amounts : + Expressions defining the rotation angles or direction cosine matrix. + These must match the ``rot_type``. See examples below for details. The + input types are: + + - ``'Body'``: 3-tuple of expressions, symbols, or functions + - ``'Space'``: 3-tuple of expressions, symbols, or functions + + The default amounts are the given ``coordinates``. + rot_order : str or int, optional + If applicable, the order of the successive of rotations. The string + ``'123'`` and integer ``123`` are equivalent, for example. Required for + ``'Body'`` and ``'Space'``. The default value is ``123``. + + Attributes + ========== + + name : string + The joint's name. + parent : Particle or RigidBody + The joint's parent body. + child : Particle or RigidBody + The joint's child body. + coordinates : Matrix + Matrix of the joint's generalized coordinates. + speeds : Matrix + Matrix of the joint's generalized speeds. + parent_point : Point + Attachment point where the joint is fixed to the parent body. + child_point : Point + Attachment point where the joint is fixed to the child body. + parent_interframe : ReferenceFrame + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. + child_interframe : ReferenceFrame + Intermediate frame of the child body with respect to which the joint + transformation is formulated. + kdes : Matrix + Kinematical differential equations of the joint. + + Examples + ========= + + A single spherical joint is created from two bodies and has the following + basic attributes: + + >>> from sympy.physics.mechanics import RigidBody, SphericalJoint + >>> parent = RigidBody('P') + >>> parent + P + >>> child = RigidBody('C') + >>> child + C + >>> joint = SphericalJoint('PC', parent, child) + >>> joint + SphericalJoint: PC parent: P child: C + >>> joint.name + 'PC' + >>> joint.parent + P + >>> joint.child + C + >>> joint.parent_point + P_masscenter + >>> joint.child_point + C_masscenter + >>> joint.parent_interframe + P_frame + >>> joint.child_interframe + C_frame + >>> joint.coordinates + Matrix([ + [q0_PC(t)], + [q1_PC(t)], + [q2_PC(t)]]) + >>> joint.speeds + Matrix([ + [u0_PC(t)], + [u1_PC(t)], + [u2_PC(t)]]) + >>> child.frame.ang_vel_in(parent.frame).to_matrix(child.frame) + Matrix([ + [ u0_PC(t)*cos(q1_PC(t))*cos(q2_PC(t)) + u1_PC(t)*sin(q2_PC(t))], + [-u0_PC(t)*sin(q2_PC(t))*cos(q1_PC(t)) + u1_PC(t)*cos(q2_PC(t))], + [ u0_PC(t)*sin(q1_PC(t)) + u2_PC(t)]]) + >>> child.frame.x.to_matrix(parent.frame) + Matrix([ + [ cos(q1_PC(t))*cos(q2_PC(t))], + [sin(q0_PC(t))*sin(q1_PC(t))*cos(q2_PC(t)) + sin(q2_PC(t))*cos(q0_PC(t))], + [sin(q0_PC(t))*sin(q2_PC(t)) - sin(q1_PC(t))*cos(q0_PC(t))*cos(q2_PC(t))]]) + >>> joint.child_point.pos_from(joint.parent_point) + 0 + + To further demonstrate the use of the spherical joint, the kinematics of a + spherical joint with a ZXZ rotation can be created as follows. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import RigidBody, SphericalJoint + >>> l1 = symbols('l1') + + First create bodies to represent the fixed floor and a pendulum bob. + + >>> floor = RigidBody('F') + >>> bob = RigidBody('B') + + The joint will connect the bob to the floor, with the joint located at a + distance of ``l1`` from the child's center of mass and the rotation set to a + body-fixed ZXZ rotation. + + >>> joint = SphericalJoint('S', floor, bob, child_point=l1 * bob.y, + ... rot_type='body', rot_order='ZXZ') + + Now that the joint is established, the kinematics of the connected body can + be accessed. + + The position of the bob's masscenter is found with: + + >>> bob.masscenter.pos_from(floor.masscenter) + - l1*B_frame.y + + The angular velocities of the pendulum link can be computed with respect to + the floor. + + >>> bob.frame.ang_vel_in(floor.frame).to_matrix( + ... floor.frame).simplify() + Matrix([ + [u1_S(t)*cos(q0_S(t)) + u2_S(t)*sin(q0_S(t))*sin(q1_S(t))], + [u1_S(t)*sin(q0_S(t)) - u2_S(t)*sin(q1_S(t))*cos(q0_S(t))], + [ u0_S(t) + u2_S(t)*cos(q1_S(t))]]) + + Finally, the linear velocity of the bob's center of mass can be computed. + + >>> bob.masscenter.vel(floor.frame).to_matrix(bob.frame) + Matrix([ + [ l1*(u0_S(t)*cos(q1_S(t)) + u2_S(t))], + [ 0], + [-l1*(u0_S(t)*sin(q1_S(t))*sin(q2_S(t)) + u1_S(t)*cos(q2_S(t)))]]) + + """ + def __init__(self, name, parent, child, coordinates=None, speeds=None, + parent_point=None, child_point=None, parent_interframe=None, + child_interframe=None, rot_type='BODY', amounts=None, + rot_order=123): + self._rot_type = rot_type + self._amounts = amounts + self._rot_order = rot_order + super().__init__(name, parent, child, coordinates, speeds, + parent_point, child_point, + parent_interframe=parent_interframe, + child_interframe=child_interframe) + + def __str__(self): + return (f'SphericalJoint: {self.name} parent: {self.parent} ' + f'child: {self.child}') + + def _generate_coordinates(self, coordinates): + return self._fill_coordinate_list(coordinates, 3, 'q') + + def _generate_speeds(self, speeds): + return self._fill_coordinate_list(speeds, len(self.coordinates), 'u') + + def _orient_frames(self): + supported_rot_types = ('BODY', 'SPACE') + if self._rot_type.upper() not in supported_rot_types: + raise NotImplementedError( + f'Rotation type "{self._rot_type}" is not implemented. ' + f'Implemented rotation types are: {supported_rot_types}') + amounts = self.coordinates if self._amounts is None else self._amounts + self.child_interframe.orient(self.parent_interframe, self._rot_type, + amounts, self._rot_order) + + def _set_angular_velocity(self): + t = dynamicsymbols._t + vel = self.child_interframe.ang_vel_in(self.parent_interframe).xreplace( + {q.diff(t): u for q, u in zip(self.coordinates, self.speeds)} + ) + self.child_interframe.set_ang_vel(self.parent_interframe, vel) + + def _set_linear_velocity(self): + self.child_point.set_pos(self.parent_point, 0) + self.parent_point.set_vel(self._parent_frame, 0) + self.child_point.set_vel(self._child_frame, 0) + self.child.masscenter.v2pt_theory(self.parent_point, self._parent_frame, + self._child_frame) + + +class WeldJoint(Joint): + """Weld Joint. + + .. raw:: html + :file: ../../../doc/src/modules/physics/mechanics/api/WeldJoint.svg + + Explanation + =========== + + A weld joint is defined such that there is no relative motion between the + child and parent bodies. The direction cosine matrix between the attachment + frame (``parent_interframe`` and ``child_interframe``) is the identity + matrix and the attachment points (``parent_point`` and ``child_point``) are + coincident. The page on the joints framework gives a more detailed + explanation of the intermediate frames. + + Parameters + ========== + + name : string + A unique name for the joint. + parent : Particle or RigidBody + The parent body of joint. + child : Particle or RigidBody + The child body of joint. + parent_point : Point or Vector, optional + Attachment point where the joint is fixed to the parent body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the parent's mass + center. + child_point : Point or Vector, optional + Attachment point where the joint is fixed to the child body. If a + vector is provided, then the attachment point is computed by adding the + vector to the body's mass center. The default value is the child's mass + center. + parent_interframe : ReferenceFrame, optional + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the parent's own frame. + child_interframe : ReferenceFrame, optional + Intermediate frame of the child body with respect to which the joint + transformation is formulated. If a Vector is provided then an interframe + is created which aligns its X axis with the given vector. The default + value is the child's own frame. + + Attributes + ========== + + name : string + The joint's name. + parent : Particle or RigidBody + The joint's parent body. + child : Particle or RigidBody + The joint's child body. + coordinates : Matrix + Matrix of the joint's generalized coordinates. The default value is + ``dynamicsymbols(f'q_{joint.name}')``. + speeds : Matrix + Matrix of the joint's generalized speeds. The default value is + ``dynamicsymbols(f'u_{joint.name}')``. + parent_point : Point + Attachment point where the joint is fixed to the parent body. + child_point : Point + Attachment point where the joint is fixed to the child body. + parent_interframe : ReferenceFrame + Intermediate frame of the parent body with respect to which the joint + transformation is formulated. + child_interframe : ReferenceFrame + Intermediate frame of the child body with respect to which the joint + transformation is formulated. + kdes : Matrix + Kinematical differential equations of the joint. + + Examples + ========= + + A single weld joint is created from two bodies and has the following basic + attributes: + + >>> from sympy.physics.mechanics import RigidBody, WeldJoint + >>> parent = RigidBody('P') + >>> parent + P + >>> child = RigidBody('C') + >>> child + C + >>> joint = WeldJoint('PC', parent, child) + >>> joint + WeldJoint: PC parent: P child: C + >>> joint.name + 'PC' + >>> joint.parent + P + >>> joint.child + C + >>> joint.parent_point + P_masscenter + >>> joint.child_point + C_masscenter + >>> joint.coordinates + Matrix(0, 0, []) + >>> joint.speeds + Matrix(0, 0, []) + >>> child.frame.ang_vel_in(parent.frame) + 0 + >>> child.frame.dcm(parent.frame) + Matrix([ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1]]) + >>> joint.child_point.pos_from(joint.parent_point) + 0 + + To further demonstrate the use of the weld joint, two relatively-fixed + bodies rotated by a quarter turn about the Y axis can be created as follows: + + >>> from sympy import symbols, pi + >>> from sympy.physics.mechanics import ReferenceFrame, RigidBody, WeldJoint + >>> l1, l2 = symbols('l1 l2') + + First create the bodies to represent the parent and rotated child body. + + >>> parent = RigidBody('P') + >>> child = RigidBody('C') + + Next the intermediate frame specifying the fixed rotation with respect to + the parent can be created. + + >>> rotated_frame = ReferenceFrame('Pr') + >>> rotated_frame.orient_axis(parent.frame, parent.y, pi / 2) + + The weld between the parent body and child body is located at a distance + ``l1`` from the parent's center of mass in the X direction and ``l2`` from + the child's center of mass in the child's negative X direction. + + >>> weld = WeldJoint('weld', parent, child, parent_point=l1 * parent.x, + ... child_point=-l2 * child.x, + ... parent_interframe=rotated_frame) + + Now that the joint has been established, the kinematics of the bodies can be + accessed. The direction cosine matrix of the child body with respect to the + parent can be found: + + >>> child.frame.dcm(parent.frame) + Matrix([ + [0, 0, -1], + [0, 1, 0], + [1, 0, 0]]) + + As can also been seen from the direction cosine matrix, the parent X axis is + aligned with the child's Z axis: + >>> parent.x == child.z + True + + The position of the child's center of mass with respect to the parent's + center of mass can be found with: + + >>> child.masscenter.pos_from(parent.masscenter) + l1*P_frame.x + l2*C_frame.x + + The angular velocity of the child with respect to the parent is 0 as one + would expect. + + >>> child.frame.ang_vel_in(parent.frame) + 0 + + """ + + def __init__(self, name, parent, child, parent_point=None, child_point=None, + parent_interframe=None, child_interframe=None): + super().__init__(name, parent, child, [], [], parent_point, + child_point, parent_interframe=parent_interframe, + child_interframe=child_interframe) + self._kdes = Matrix(1, 0, []).T # Removes stackability problems #10770 + + def __str__(self): + return (f'WeldJoint: {self.name} parent: {self.parent} ' + f'child: {self.child}') + + def _generate_coordinates(self, coordinate): + return Matrix() + + def _generate_speeds(self, speed): + return Matrix() + + def _orient_frames(self): + self.child_interframe.orient_axis(self.parent_interframe, + self.parent_interframe.x, 0) + + def _set_angular_velocity(self): + self.child_interframe.set_ang_vel(self.parent_interframe, 0) + + def _set_linear_velocity(self): + self.child_point.set_pos(self.parent_point, 0) + self.parent_point.set_vel(self._parent_frame, 0) + self.child_point.set_vel(self._child_frame, 0) + self.child.masscenter.set_vel(self._parent_frame, 0) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/kane.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/kane.py new file mode 100644 index 0000000000000000000000000000000000000000..805587a4fe9d7696f45c5815ee5406b103150698 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/kane.py @@ -0,0 +1,859 @@ +from sympy import zeros, Matrix, diff, eye, linear_eq_to_matrix +from sympy.core.sorting import default_sort_key +from sympy.physics.vector import (ReferenceFrame, dynamicsymbols, + partial_velocity) +from sympy.physics.mechanics.method import _Methods +from sympy.physics.mechanics.particle import Particle +from sympy.physics.mechanics.rigidbody import RigidBody +from sympy.physics.mechanics.functions import (msubs, find_dynamicsymbols, + _f_list_parser, + _validate_coordinates, + _parse_linear_solver) +from sympy.physics.mechanics.linearize import Linearizer +from sympy.utilities.iterables import iterable + + +__all__ = ['KanesMethod'] + + +class KanesMethod(_Methods): + r"""Kane's method object. + + Explanation + =========== + + This object is used to do the "book-keeping" as you go through and form + equations of motion in the way Kane presents in: + Kane, T., Levinson, D. Dynamics Theory and Applications. 1985 McGraw-Hill + + The attributes are for equations in the form [M] udot = forcing. + + Attributes + ========== + + q, u : Matrix + Matrices of the generalized coordinates and speeds + bodies : iterable + Iterable of Particle and RigidBody objects in the system. + loads : iterable + Iterable of (Point, vector) or (ReferenceFrame, vector) tuples + describing the forces on the system. + auxiliary_eqs : Matrix + If applicable, the set of auxiliary Kane's + equations used to solve for non-contributing + forces. + mass_matrix : Matrix + The system's dynamics mass matrix: [k_d; k_dnh] + forcing : Matrix + The system's dynamics forcing vector: -[f_d; f_dnh] + mass_matrix_kin : Matrix + The "mass matrix" for kinematic differential equations: k_kqdot + forcing_kin : Matrix + The forcing vector for kinematic differential equations: -(k_ku*u + f_k) + mass_matrix_full : Matrix + The "mass matrix" for the u's and q's with dynamics and kinematics + forcing_full : Matrix + The "forcing vector" for the u's and q's with dynamics and kinematics + + Parameters + ========== + + frame : ReferenceFrame + The inertial reference frame for the system. + q_ind : iterable of dynamicsymbols + Independent generalized coordinates. + u_ind : iterable of dynamicsymbols + Independent generalized speeds. + kd_eqs : iterable of Expr, optional + Kinematic differential equations, which linearly relate the generalized + speeds to the time-derivatives of the generalized coordinates. + q_dependent : iterable of dynamicsymbols, optional + Dependent generalized coordinates. + configuration_constraints : iterable of Expr, optional + Constraints on the system's configuration, i.e. holonomic constraints. + u_dependent : iterable of dynamicsymbols, optional + Dependent generalized speeds. + velocity_constraints : iterable of Expr, optional + Constraints on the system's velocity, i.e. the combination of the + nonholonomic constraints and the time-derivative of the holonomic + constraints. + acceleration_constraints : iterable of Expr, optional + Constraints on the system's acceleration, by default these are the + time-derivative of the velocity constraints. + u_auxiliary : iterable of dynamicsymbols, optional + Auxiliary generalized speeds. + bodies : iterable of Particle and/or RigidBody, optional + The particles and rigid bodies in the system. + forcelist : iterable of tuple[Point | ReferenceFrame, Vector], optional + Forces and torques applied on the system. + explicit_kinematics : bool + Boolean whether the mass matrices and forcing vectors should use the + explicit form (default) or implicit form for kinematics. + See the notes for more details. + kd_eqs_solver : str, callable + Method used to solve the kinematic differential equations. If a string + is supplied, it should be a valid method that can be used with the + :meth:`sympy.matrices.matrixbase.MatrixBase.solve`. If a callable is + supplied, it should have the format ``f(A, rhs)``, where it solves the + equations and returns the solution. The default utilizes LU solve. See + the notes for more information. + constraint_solver : str, callable + Method used to solve the velocity constraints. If a string is + supplied, it should be a valid method that can be used with the + :meth:`sympy.matrices.matrixbase.MatrixBase.solve`. If a callable is + supplied, it should have the format ``f(A, rhs)``, where it solves the + equations and returns the solution. The default utilizes LU solve. See + the notes for more information. + + Notes + ===== + + The mass matrices and forcing vectors related to kinematic equations + are given in the explicit form by default. In other words, the kinematic + mass matrix is $\mathbf{k_{k\dot{q}}} = \mathbf{I}$. + In order to get the implicit form of those matrices/vectors, you can set the + ``explicit_kinematics`` attribute to ``False``. So $\mathbf{k_{k\dot{q}}}$ + is not necessarily an identity matrix. This can provide more compact + equations for non-simple kinematics. + + Two linear solvers can be supplied to ``KanesMethod``: one for solving the + kinematic differential equations and one to solve the velocity constraints. + Both of these sets of equations can be expressed as a linear system ``Ax = rhs``, + which have to be solved in order to obtain the equations of motion. + + The default solver ``'LU'``, which stands for LU solve, results relatively low + number of operations. The weakness of this method is that it can result in zero + division errors. + + If zero divisions are encountered, a possible solver which may solve the problem + is ``"CRAMER"``. This method uses Cramer's rule to solve the system. This method + is slower and results in more operations than the default solver. However it only + uses a single division by default per entry of the solution. + + While a valid list of solvers can be found at + :meth:`sympy.matrices.matrixbase.MatrixBase.solve`, it is also possible to supply a + `callable`. This way it is possible to use a different solver routine. If the + kinematic differential equations are not too complex it can be worth it to simplify + the solution by using ``lambda A, b: simplify(Matrix.LUsolve(A, b))``. Another + option solver one may use is :func:`sympy.solvers.solveset.linsolve`. This can be + done using `lambda A, b: tuple(linsolve((A, b)))[0]`, where we select the first + solution as our system should have only one unique solution. + + Examples + ======== + + This is a simple example for a one degree of freedom translational + spring-mass-damper. + + In this example, we first need to do the kinematics. + This involves creating generalized speeds and coordinates and their + derivatives. + Then we create a point and set its velocity in a frame. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import dynamicsymbols, ReferenceFrame + >>> from sympy.physics.mechanics import Point, Particle, KanesMethod + >>> q, u = dynamicsymbols('q u') + >>> qd, ud = dynamicsymbols('q u', 1) + >>> m, c, k = symbols('m c k') + >>> N = ReferenceFrame('N') + >>> P = Point('P') + >>> P.set_vel(N, u * N.x) + + Next we need to arrange/store information in the way that KanesMethod + requires. The kinematic differential equations should be an iterable of + expressions. A list of forces/torques must be constructed, where each entry + in the list is a (Point, Vector) or (ReferenceFrame, Vector) tuple, where + the Vectors represent the Force or Torque. + Next a particle needs to be created, and it needs to have a point and mass + assigned to it. + Finally, a list of all bodies and particles needs to be created. + + >>> kd = [qd - u] + >>> FL = [(P, (-k * q - c * u) * N.x)] + >>> pa = Particle('pa', P, m) + >>> BL = [pa] + + Finally we can generate the equations of motion. + First we create the KanesMethod object and supply an inertial frame, + coordinates, generalized speeds, and the kinematic differential equations. + Additional quantities such as configuration and motion constraints, + dependent coordinates and speeds, and auxiliary speeds are also supplied + here (see the online documentation). + Next we form FR* and FR to complete: Fr + Fr* = 0. + We have the equations of motion at this point. + It makes sense to rearrange them though, so we calculate the mass matrix and + the forcing terms, for E.o.M. in the form: [MM] udot = forcing, where MM is + the mass matrix, udot is a vector of the time derivatives of the + generalized speeds, and forcing is a vector representing "forcing" terms. + + >>> KM = KanesMethod(N, q_ind=[q], u_ind=[u], kd_eqs=kd) + >>> (fr, frstar) = KM.kanes_equations(BL, FL) + >>> MM = KM.mass_matrix + >>> forcing = KM.forcing + >>> rhs = MM.inv() * forcing + >>> rhs + Matrix([[(-c*u(t) - k*q(t))/m]]) + >>> KM.linearize(A_and_B=True)[0] + Matrix([ + [ 0, 1], + [-k/m, -c/m]]) + + Please look at the documentation pages for more information on how to + perform linearization and how to deal with dependent coordinates & speeds, + and how do deal with bringing non-contributing forces into evidence. + + """ + + def __init__(self, frame, q_ind, u_ind, kd_eqs=None, q_dependent=None, + configuration_constraints=None, u_dependent=None, + velocity_constraints=None, acceleration_constraints=None, + u_auxiliary=None, bodies=None, forcelist=None, + explicit_kinematics=True, kd_eqs_solver='LU', + constraint_solver='LU'): + + """Please read the online documentation. """ + if not q_ind: + q_ind = [dynamicsymbols('dummy_q')] + kd_eqs = [dynamicsymbols('dummy_kd')] + + if not isinstance(frame, ReferenceFrame): + raise TypeError('An inertial ReferenceFrame must be supplied') + self._inertial = frame + + self._fr = None + self._frstar = None + + self._forcelist = forcelist + self._bodylist = bodies + + self.explicit_kinematics = explicit_kinematics + self._constraint_solver = constraint_solver + self._initialize_vectors(q_ind, q_dependent, u_ind, u_dependent, + u_auxiliary) + _validate_coordinates(self.q, self.u) + self._initialize_kindiffeq_matrices(kd_eqs, kd_eqs_solver) + self._initialize_constraint_matrices( + configuration_constraints, velocity_constraints, + acceleration_constraints, constraint_solver) + + def _initialize_vectors(self, q_ind, q_dep, u_ind, u_dep, u_aux): + """Initialize the coordinate and speed vectors.""" + + none_handler = lambda x: Matrix(x) if x else Matrix() + + # Initialize generalized coordinates + q_dep = none_handler(q_dep) + if not iterable(q_ind): + raise TypeError('Generalized coordinates must be an iterable.') + if not iterable(q_dep): + raise TypeError('Dependent coordinates must be an iterable.') + q_ind = Matrix(q_ind) + self._qdep = q_dep + self._q = Matrix([q_ind, q_dep]) + self._qdot = self.q.diff(dynamicsymbols._t) + + # Initialize generalized speeds + u_dep = none_handler(u_dep) + if not iterable(u_ind): + raise TypeError('Generalized speeds must be an iterable.') + if not iterable(u_dep): + raise TypeError('Dependent speeds must be an iterable.') + u_ind = Matrix(u_ind) + self._udep = u_dep + self._u = Matrix([u_ind, u_dep]) + self._udot = self.u.diff(dynamicsymbols._t) + self._uaux = none_handler(u_aux) + + def _initialize_constraint_matrices(self, config, vel, acc, linear_solver='LU'): + """Initializes constraint matrices.""" + linear_solver = _parse_linear_solver(linear_solver) + # Define vector dimensions + o = len(self.u) + m = len(self._udep) + p = o - m + none_handler = lambda x: Matrix(x) if x else Matrix() + + # Initialize configuration constraints + config = none_handler(config) + if len(self._qdep) != len(config): + raise ValueError('There must be an equal number of dependent ' + 'coordinates and configuration constraints.') + self._f_h = none_handler(config) + + # Initialize velocity and acceleration constraints + vel = none_handler(vel) + acc = none_handler(acc) + if len(vel) != m: + raise ValueError('There must be an equal number of dependent ' + 'speeds and velocity constraints.') + if acc and (len(acc) != m): + raise ValueError('There must be an equal number of dependent ' + 'speeds and acceleration constraints.') + if vel: + + # When calling kanes_equations, another class instance will be + # created if auxiliary u's are present. In this case, the + # computation of kinetic differential equation matrices will be + # skipped as this was computed during the original KanesMethod + # object, and the qd_u_map will not be available. + if self._qdot_u_map is not None: + vel = msubs(vel, self._qdot_u_map) + self._k_nh, f_nh_neg = linear_eq_to_matrix(vel, self.u[:]) + self._f_nh = -f_nh_neg + + # If no acceleration constraints given, calculate them. + if not acc: + _f_dnh = (self._k_nh.diff(dynamicsymbols._t) * self.u + + self._f_nh.diff(dynamicsymbols._t)) + if self._qdot_u_map is not None: + _f_dnh = msubs(_f_dnh, self._qdot_u_map) + self._f_dnh = _f_dnh + self._k_dnh = self._k_nh + else: + if self._qdot_u_map is not None: + acc = msubs(acc, self._qdot_u_map) + + self._k_dnh, f_dnh_neg = linear_eq_to_matrix(acc, self._udot[:]) + self._f_dnh = -f_dnh_neg + # Form of non-holonomic constraints is B*u + C = 0. + # We partition B into independent and dependent columns: + # Ars is then -B_dep.inv() * B_ind, and it relates dependent speeds + # to independent speeds as: udep = Ars*uind, neglecting the C term. + B_ind = self._k_nh[:, :p] + B_dep = self._k_nh[:, p:o] + self._Ars = -linear_solver(B_dep, B_ind) + else: + self._f_nh = Matrix() + self._k_nh = Matrix() + self._f_dnh = Matrix() + self._k_dnh = Matrix() + self._Ars = Matrix() + + def _initialize_kindiffeq_matrices(self, kdeqs, linear_solver='LU'): + """Initialize the kinematic differential equation matrices. + + Parameters + ========== + kdeqs : sequence of sympy expressions + Kinematic differential equations in the form of f(u,q',q,t) where + f() = 0. The equations have to be linear in the time-derivatives of + the generalized coordinates and in the generalized speeds. + + """ + linear_solver = _parse_linear_solver(linear_solver) + if kdeqs: + if len(self.q) != len(kdeqs): + raise ValueError('There must be an equal number of kinematic ' + 'differential equations and coordinates.') + + u = self.u + qdot = self._qdot + + kdeqs = Matrix(kdeqs) + + u_zero = dict.fromkeys(u, 0) + uaux_zero = dict.fromkeys(self._uaux, 0) + qdot_zero = dict.fromkeys(qdot, 0) + + # Extract the linear coefficient matrices as per the following + # equation: + # + # k_ku(q,t)*u(t) + k_kqdot(q,t)*q'(t) + f_k(q,t) = 0 + # + k_ku = kdeqs.jacobian(u) + k_kqdot = kdeqs.jacobian(qdot) + f_k = kdeqs.xreplace(u_zero).xreplace(qdot_zero) + + # The kinematic differential equations should be linear in both q' + # and u so check for u and q' in the components. + dy_syms = find_dynamicsymbols(k_ku.row_join(k_kqdot).row_join(f_k)) + nonlin_vars = [vari for vari in u[:] + qdot[:] if vari in dy_syms] + if nonlin_vars: + msg = ('The provided kinematic differential equations are ' + 'nonlinear in {}. They must be linear in the ' + 'generalized speeds and derivatives of the generalized ' + 'coordinates.') + raise ValueError(msg.format(nonlin_vars)) + + self._f_k_implicit = f_k.xreplace(uaux_zero) + self._k_ku_implicit = k_ku.xreplace(uaux_zero) + self._k_kqdot_implicit = k_kqdot + + # Solve for q'(t) such that the coefficient matrices are now in + # this form: + # + # k_kqdot^-1*k_ku*u(t) + I*q'(t) + k_kqdot^-1*f_k = 0 + # + # NOTE : Solving the kinematic differential equations here is not + # necessary and prevents the equations from being provided in fully + # implicit form. + f_k_explicit = linear_solver(k_kqdot, f_k) + k_ku_explicit = linear_solver(k_kqdot, k_ku) + self._qdot_u_map = dict(zip(qdot, -(k_ku_explicit*u + f_k_explicit))) + + self._f_k = f_k_explicit.xreplace(uaux_zero) + self._k_ku = k_ku_explicit.xreplace(uaux_zero) + self._k_kqdot = eye(len(qdot)) + + else: + self._qdot_u_map = None + self._f_k_implicit = self._f_k = Matrix() + self._k_ku_implicit = self._k_ku = Matrix() + self._k_kqdot_implicit = self._k_kqdot = Matrix() + + def _form_fr(self, fl): + """Form the generalized active force.""" + if fl is not None and (len(fl) == 0 or not iterable(fl)): + raise ValueError('Force pairs must be supplied in an ' + 'non-empty iterable or None.') + + N = self._inertial + # pull out relevant velocities for constructing partial velocities + vel_list, f_list = _f_list_parser(fl, N) + vel_list = [msubs(i, self._qdot_u_map) for i in vel_list] + f_list = [msubs(i, self._qdot_u_map) for i in f_list] + + # Fill Fr with dot product of partial velocities and forces + o = len(self.u) + b = len(f_list) + FR = zeros(o, 1) + partials = partial_velocity(vel_list, self.u, N) + for i in range(o): + FR[i] = sum(partials[j][i].dot(f_list[j]) for j in range(b)) + + # In case there are dependent speeds + if self._udep: + p = o - len(self._udep) + FRtilde = FR[:p, 0] + FRold = FR[p:o, 0] + FRtilde += self._Ars.T * FRold + FR = FRtilde + + self._forcelist = fl + self._fr = FR + return FR + + def _form_frstar(self, bl): + """Form the generalized inertia force.""" + + if not iterable(bl): + raise TypeError('Bodies must be supplied in an iterable.') + + t = dynamicsymbols._t + N = self._inertial + # Dicts setting things to zero + udot_zero = dict.fromkeys(self._udot, 0) + uaux_zero = dict.fromkeys(self._uaux, 0) + uauxdot = [diff(i, t) for i in self._uaux] + uauxdot_zero = dict.fromkeys(uauxdot, 0) + # Dictionary of q' and q'' to u and u' + q_ddot_u_map = {k.diff(t): v.diff(t).xreplace( + self._qdot_u_map) for (k, v) in self._qdot_u_map.items()} + q_ddot_u_map.update(self._qdot_u_map) + + # Fill up the list of partials: format is a list with num elements + # equal to number of entries in body list. Each of these elements is a + # list - either of length 1 for the translational components of + # particles or of length 2 for the translational and rotational + # components of rigid bodies. The inner most list is the list of + # partial velocities. + def get_partial_velocity(body): + if isinstance(body, RigidBody): + vlist = [body.masscenter.vel(N), body.frame.ang_vel_in(N)] + elif isinstance(body, Particle): + vlist = [body.point.vel(N),] + else: + raise TypeError('The body list may only contain either ' + 'RigidBody or Particle as list elements.') + v = [msubs(vel, self._qdot_u_map) for vel in vlist] + return partial_velocity(v, self.u, N) + partials = [get_partial_velocity(body) for body in bl] + + # Compute fr_star in two components: + # fr_star = -(MM*u' + nonMM) + o = len(self.u) + MM = zeros(o, o) + nonMM = zeros(o, 1) + zero_uaux = lambda expr: msubs(expr, uaux_zero) + zero_udot_uaux = lambda expr: msubs(msubs(expr, udot_zero), uaux_zero) + for i, body in enumerate(bl): + if isinstance(body, RigidBody): + M = zero_uaux(body.mass) + I = zero_uaux(body.central_inertia) + vel = zero_uaux(body.masscenter.vel(N)) + omega = zero_uaux(body.frame.ang_vel_in(N)) + acc = zero_udot_uaux(body.masscenter.acc(N)) + inertial_force = (M.diff(t) * vel + M * acc) + inertial_torque = zero_uaux((I.dt(body.frame).dot(omega)) + + msubs(I.dot(body.frame.ang_acc_in(N)), udot_zero) + + (omega.cross(I.dot(omega)))) + for j in range(o): + tmp_vel = zero_uaux(partials[i][0][j]) + tmp_ang = zero_uaux(I.dot(partials[i][1][j])) + for k in range(o): + # translational + MM[j, k] += M*tmp_vel.dot(partials[i][0][k]) + # rotational + MM[j, k] += tmp_ang.dot(partials[i][1][k]) + nonMM[j] += inertial_force.dot(partials[i][0][j]) + nonMM[j] += inertial_torque.dot(partials[i][1][j]) + else: + M = zero_uaux(body.mass) + vel = zero_uaux(body.point.vel(N)) + acc = zero_udot_uaux(body.point.acc(N)) + inertial_force = (M.diff(t) * vel + M * acc) + for j in range(o): + temp = zero_uaux(partials[i][0][j]) + for k in range(o): + MM[j, k] += M*temp.dot(partials[i][0][k]) + nonMM[j] += inertial_force.dot(partials[i][0][j]) + # Compose fr_star out of MM and nonMM + MM = zero_uaux(msubs(MM, q_ddot_u_map)) + nonMM = msubs(msubs(nonMM, q_ddot_u_map), + udot_zero, uauxdot_zero, uaux_zero) + fr_star = -(MM * msubs(Matrix(self._udot), uauxdot_zero) + nonMM) + + # If there are dependent speeds, we need to find fr_star_tilde + if self._udep: + p = o - len(self._udep) + fr_star_ind = fr_star[:p, 0] + fr_star_dep = fr_star[p:o, 0] + fr_star = fr_star_ind + (self._Ars.T * fr_star_dep) + # Apply the same to MM + MMi = MM[:p, :] + MMd = MM[p:o, :] + MM = MMi + (self._Ars.T * MMd) + # Apply the same to nonMM + nonMM = nonMM[:p, :] + (self._Ars.T * nonMM[p:o, :]) + + self._bodylist = bl + self._frstar = fr_star + self._k_d = MM + self._f_d = -(self._fr - nonMM) + return fr_star + + def to_linearizer(self, linear_solver='LU'): + """Returns an instance of the Linearizer class, initiated from the + data in the KanesMethod class. This may be more desirable than using + the linearize class method, as the Linearizer object will allow more + efficient recalculation (i.e. about varying operating points). + + Parameters + ========== + linear_solver : str, callable + Method used to solve the several symbolic linear systems of the + form ``A*x=b`` in the linearization process. If a string is + supplied, it should be a valid method that can be used with the + :meth:`sympy.matrices.matrixbase.MatrixBase.solve`. If a callable is + supplied, it should have the format ``x = f(A, b)``, where it + solves the equations and returns the solution. The default is + ``'LU'`` which corresponds to SymPy's ``A.LUsolve(b)``. + ``LUsolve()`` is fast to compute but will often result in + divide-by-zero and thus ``nan`` results. + + Returns + ======= + Linearizer + An instantiated + :class:`sympy.physics.mechanics.linearize.Linearizer`. + + """ + + if (self._fr is None) or (self._frstar is None): + raise ValueError('Need to compute Fr, Fr* first.') + + # Get required equation components. The Kane's method class breaks + # these into pieces. Need to reassemble + f_c = self._f_h + if self._f_nh and self._k_nh: + f_v = self._f_nh + self._k_nh*Matrix(self.u) + else: + f_v = Matrix() + if self._f_dnh and self._k_dnh: + f_a = self._f_dnh + self._k_dnh*Matrix(self._udot) + else: + f_a = Matrix() + # Dicts to sub to zero, for splitting up expressions + u_zero = dict.fromkeys(self.u, 0) + ud_zero = dict.fromkeys(self._udot, 0) + qd_zero = dict.fromkeys(self._qdot, 0) + qd_u_zero = dict.fromkeys(Matrix([self._qdot, self.u]), 0) + # Break the kinematic differential eqs apart into f_0 and f_1 + f_0 = msubs(self._f_k, u_zero) + self._k_kqdot*Matrix(self._qdot) + f_1 = msubs(self._f_k, qd_zero) + self._k_ku*Matrix(self.u) + # Break the dynamic differential eqs into f_2 and f_3 + f_2 = msubs(self._frstar, qd_u_zero) + f_3 = msubs(self._frstar, ud_zero) + self._fr + f_4 = zeros(len(f_2), 1) + + # Get the required vector components + q = self.q + u = self.u + if self._qdep: + q_i = q[:-len(self._qdep)] + else: + q_i = q + q_d = self._qdep + if self._udep: + u_i = u[:-len(self._udep)] + else: + u_i = u + u_d = self._udep + + # Form dictionary to set auxiliary speeds & their derivatives to 0. + uaux = self._uaux + uauxdot = uaux.diff(dynamicsymbols._t) + uaux_zero = dict.fromkeys(Matrix([uaux, uauxdot]), 0) + + # Checking for dynamic symbols outside the dynamic differential + # equations; throws error if there is. + sym_list = set(Matrix([q, self._qdot, u, self._udot, uaux, uauxdot])) + if any(find_dynamicsymbols(i, sym_list) for i in [self._k_kqdot, + self._k_ku, self._f_k, self._k_dnh, self._f_dnh, self._k_d]): + raise ValueError('Cannot have dynamicsymbols outside dynamic \ + forcing vector.') + + # Find all other dynamic symbols, forming the forcing vector r. + # Sort r to make it canonical. + r = list(find_dynamicsymbols(msubs(self._f_d, uaux_zero), sym_list)) + r.sort(key=default_sort_key) + + # Check for any derivatives of variables in r that are also found in r. + for i in r: + if diff(i, dynamicsymbols._t) in r: + raise ValueError('Cannot have derivatives of specified \ + quantities when linearizing forcing terms.') + return Linearizer(f_0, f_1, f_2, f_3, f_4, f_c, f_v, f_a, q, u, q_i, + q_d, u_i, u_d, r, linear_solver=linear_solver) + + # TODO : Remove `new_method` after 1.1 has been released. + def linearize(self, *, new_method=None, linear_solver='LU', **kwargs): + """ Linearize the equations of motion about a symbolic operating point. + + Parameters + ========== + new_method + Deprecated, does nothing and will be removed. + linear_solver : str, callable + Method used to solve the several symbolic linear systems of the + form ``A*x=b`` in the linearization process. If a string is + supplied, it should be a valid method that can be used with the + :meth:`sympy.matrices.matrixbase.MatrixBase.solve`. If a callable is + supplied, it should have the format ``x = f(A, b)``, where it + solves the equations and returns the solution. The default is + ``'LU'`` which corresponds to SymPy's ``A.LUsolve(b)``. + ``LUsolve()`` is fast to compute but will often result in + divide-by-zero and thus ``nan`` results. + **kwargs + Extra keyword arguments are passed to + :meth:`sympy.physics.mechanics.linearize.Linearizer.linearize`. + + Explanation + =========== + + If kwarg A_and_B is False (default), returns M, A, B, r for the + linearized form, M*[q', u']^T = A*[q_ind, u_ind]^T + B*r. + + If kwarg A_and_B is True, returns A, B, r for the linearized form + dx = A*x + B*r, where x = [q_ind, u_ind]^T. Note that this is + computationally intensive if there are many symbolic parameters. For + this reason, it may be more desirable to use the default A_and_B=False, + returning M, A, and B. Values may then be substituted in to these + matrices, and the state space form found as + A = P.T*M.inv()*A, B = P.T*M.inv()*B, where P = Linearizer.perm_mat. + + In both cases, r is found as all dynamicsymbols in the equations of + motion that are not part of q, u, q', or u'. They are sorted in + canonical form. + + The operating points may be also entered using the ``op_point`` kwarg. + This takes a dictionary of {symbol: value}, or a an iterable of such + dictionaries. The values may be numeric or symbolic. The more values + you can specify beforehand, the faster this computation will run. + + For more documentation, please see the ``Linearizer`` class. + + """ + + linearizer = self.to_linearizer(linear_solver=linear_solver) + result = linearizer.linearize(**kwargs) + return result + (linearizer.r,) + + def kanes_equations(self, bodies=None, loads=None): + """ Method to form Kane's equations, Fr + Fr* = 0. + + Explanation + =========== + + Returns (Fr, Fr*). In the case where auxiliary generalized speeds are + present (say, s auxiliary speeds, o generalized speeds, and m motion + constraints) the length of the returned vectors will be o - m + s in + length. The first o - m equations will be the constrained Kane's + equations, then the s auxiliary Kane's equations. These auxiliary + equations can be accessed with the auxiliary_eqs property. + + Parameters + ========== + + bodies : iterable + An iterable of all RigidBody's and Particle's in the system. + A system must have at least one body. + loads : iterable + Takes in an iterable of (Particle, Vector) or (ReferenceFrame, Vector) + tuples which represent the force at a point or torque on a frame. + Must be either a non-empty iterable of tuples or None which corresponds + to a system with no constraints. + """ + if bodies is None: + bodies = self.bodies + if loads is None and self._forcelist is not None: + loads = self._forcelist + if loads == []: + loads = None + if not self._k_kqdot: + raise AttributeError('Create an instance of KanesMethod with ' + 'kinematic differential equations to use this method.') + fr = self._form_fr(loads) + frstar = self._form_frstar(bodies) + if self._uaux: + if not self._udep: + km = KanesMethod(self._inertial, self.q, self._uaux, + u_auxiliary=self._uaux, constraint_solver=self._constraint_solver) + else: + km = KanesMethod(self._inertial, self.q, self._uaux, + u_auxiliary=self._uaux, u_dependent=self._udep, + velocity_constraints=(self._k_nh * self.u + + self._f_nh), + acceleration_constraints=(self._k_dnh * self._udot + + self._f_dnh), + constraint_solver=self._constraint_solver + ) + km._qdot_u_map = self._qdot_u_map + self._km = km + fraux = km._form_fr(loads) + frstaraux = km._form_frstar(bodies) + self._aux_eq = fraux + frstaraux + self._fr = fr.col_join(fraux) + self._frstar = frstar.col_join(frstaraux) + return (self._fr, self._frstar) + + def _form_eoms(self): + fr, frstar = self.kanes_equations(self.bodylist, self.forcelist) + return fr + frstar + + def rhs(self, inv_method=None): + """Returns the system's equations of motion in first order form. The + output is the right hand side of:: + + x' = |q'| =: f(q, u, r, p, t) + |u'| + + The right hand side is what is needed by most numerical ODE + integrators. + + Parameters + ========== + + inv_method : str + The specific sympy inverse matrix calculation method to use. For a + list of valid methods, see + :meth:`~sympy.matrices.matrixbase.MatrixBase.inv` + + """ + rhs = zeros(len(self.q) + len(self.u), 1) + kdes = self.kindiffdict() + for i, q_i in enumerate(self.q): + rhs[i] = kdes[q_i.diff()] + + if inv_method is None: + rhs[len(self.q):, 0] = self.mass_matrix.LUsolve(self.forcing) + else: + rhs[len(self.q):, 0] = (self.mass_matrix.inv(inv_method, + try_block_diag=True) * + self.forcing) + + return rhs + + def kindiffdict(self): + """Returns a dictionary mapping q' to u.""" + if not self._qdot_u_map: + raise AttributeError('Create an instance of KanesMethod with ' + 'kinematic differential equations to use this method.') + return self._qdot_u_map + + @property + def auxiliary_eqs(self): + """A matrix containing the auxiliary equations.""" + if not self._fr or not self._frstar: + raise ValueError('Need to compute Fr, Fr* first.') + if not self._uaux: + raise ValueError('No auxiliary speeds have been declared.') + return self._aux_eq + + @property + def mass_matrix_kin(self): + r"""The kinematic "mass matrix" $\mathbf{k_{k\dot{q}}}$ of the system.""" + return self._k_kqdot if self.explicit_kinematics else self._k_kqdot_implicit + + @property + def forcing_kin(self): + """The kinematic "forcing vector" of the system.""" + if self.explicit_kinematics: + return -(self._k_ku * Matrix(self.u) + self._f_k) + else: + return -(self._k_ku_implicit * Matrix(self.u) + self._f_k_implicit) + + @property + def mass_matrix(self): + """The mass matrix of the system.""" + if not self._fr or not self._frstar: + raise ValueError('Need to compute Fr, Fr* first.') + return Matrix([self._k_d, self._k_dnh]) + + @property + def forcing(self): + """The forcing vector of the system.""" + if not self._fr or not self._frstar: + raise ValueError('Need to compute Fr, Fr* first.') + return -Matrix([self._f_d, self._f_dnh]) + + @property + def mass_matrix_full(self): + """The mass matrix of the system, augmented by the kinematic + differential equations in explicit or implicit form.""" + if not self._fr or not self._frstar: + raise ValueError('Need to compute Fr, Fr* first.') + o, n = len(self.u), len(self.q) + return (self.mass_matrix_kin.row_join(zeros(n, o))).col_join( + zeros(o, n).row_join(self.mass_matrix)) + + @property + def forcing_full(self): + """The forcing vector of the system, augmented by the kinematic + differential equations in explicit or implicit form.""" + return Matrix([self.forcing_kin, self.forcing]) + + @property + def q(self): + return self._q + + @property + def u(self): + return self._u + + @property + def bodylist(self): + return self._bodylist + + @property + def forcelist(self): + return self._forcelist + + @property + def bodies(self): + return self._bodylist + + @property + def loads(self): + return self._forcelist diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/lagrange.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/lagrange.py new file mode 100644 index 0000000000000000000000000000000000000000..282176a404f77762abc3ee8c6a575519b2de1f02 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/lagrange.py @@ -0,0 +1,512 @@ +from sympy import diff, zeros, Matrix, eye, sympify +from sympy.core.sorting import default_sort_key +from sympy.physics.vector import dynamicsymbols, ReferenceFrame +from sympy.physics.mechanics.method import _Methods +from sympy.physics.mechanics.functions import ( + find_dynamicsymbols, msubs, _f_list_parser, _validate_coordinates) +from sympy.physics.mechanics.linearize import Linearizer +from sympy.utilities.iterables import iterable + +__all__ = ['LagrangesMethod'] + + +class LagrangesMethod(_Methods): + """Lagrange's method object. + + Explanation + =========== + + This object generates the equations of motion in a two step procedure. The + first step involves the initialization of LagrangesMethod by supplying the + Lagrangian and the generalized coordinates, at the bare minimum. If there + are any constraint equations, they can be supplied as keyword arguments. + The Lagrange multipliers are automatically generated and are equal in + number to the constraint equations. Similarly any non-conservative forces + can be supplied in an iterable (as described below and also shown in the + example) along with a ReferenceFrame. This is also discussed further in the + __init__ method. + + Attributes + ========== + + q, u : Matrix + Matrices of the generalized coordinates and speeds + loads : iterable + Iterable of (Point, vector) or (ReferenceFrame, vector) tuples + describing the forces on the system. + bodies : iterable + Iterable containing the rigid bodies and particles of the system. + mass_matrix : Matrix + The system's mass matrix + forcing : Matrix + The system's forcing vector + mass_matrix_full : Matrix + The "mass matrix" for the qdot's, qdoubledot's, and the + lagrange multipliers (lam) + forcing_full : Matrix + The forcing vector for the qdot's, qdoubledot's and + lagrange multipliers (lam) + + Examples + ======== + + This is a simple example for a one degree of freedom translational + spring-mass-damper. + + In this example, we first need to do the kinematics. + This involves creating generalized coordinates and their derivatives. + Then we create a point and set its velocity in a frame. + + >>> from sympy.physics.mechanics import LagrangesMethod, Lagrangian + >>> from sympy.physics.mechanics import ReferenceFrame, Particle, Point + >>> from sympy.physics.mechanics import dynamicsymbols + >>> from sympy import symbols + >>> q = dynamicsymbols('q') + >>> qd = dynamicsymbols('q', 1) + >>> m, k, b = symbols('m k b') + >>> N = ReferenceFrame('N') + >>> P = Point('P') + >>> P.set_vel(N, qd * N.x) + + We need to then prepare the information as required by LagrangesMethod to + generate equations of motion. + First we create the Particle, which has a point attached to it. + Following this the lagrangian is created from the kinetic and potential + energies. + Then, an iterable of nonconservative forces/torques must be constructed, + where each item is a (Point, Vector) or (ReferenceFrame, Vector) tuple, + with the Vectors representing the nonconservative forces or torques. + + >>> Pa = Particle('Pa', P, m) + >>> Pa.potential_energy = k * q**2 / 2.0 + >>> L = Lagrangian(N, Pa) + >>> fl = [(P, -b * qd * N.x)] + + Finally we can generate the equations of motion. + First we create the LagrangesMethod object. To do this one must supply + the Lagrangian, and the generalized coordinates. The constraint equations, + the forcelist, and the inertial frame may also be provided, if relevant. + Next we generate Lagrange's equations of motion, such that: + Lagrange's equations of motion = 0. + We have the equations of motion at this point. + + >>> l = LagrangesMethod(L, [q], forcelist = fl, frame = N) + >>> print(l.form_lagranges_equations()) + Matrix([[b*Derivative(q(t), t) + 1.0*k*q(t) + m*Derivative(q(t), (t, 2))]]) + + We can also solve for the states using the 'rhs' method. + + >>> print(l.rhs()) + 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, qs, forcelist=None, bodies=None, frame=None, + hol_coneqs=None, nonhol_coneqs=None): + """Supply the following for the initialization of LagrangesMethod. + + Lagrangian : Sympifyable + + qs : array_like + The generalized coordinates + + hol_coneqs : array_like, optional + The holonomic constraint equations + + nonhol_coneqs : array_like, optional + The nonholonomic constraint equations + + forcelist : iterable, optional + Takes an iterable of (Point, Vector) or (ReferenceFrame, Vector) + tuples which represent the force at a point or torque on a frame. + This feature is primarily to account for the nonconservative forces + and/or moments. + + bodies : iterable, optional + Takes an iterable containing the rigid bodies and particles of the + system. + + frame : ReferenceFrame, optional + Supply the inertial frame. This is used to determine the + generalized forces due to non-conservative forces. + """ + + self._L = Matrix([sympify(Lagrangian)]) + self.eom = None + 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() # The coeffecients of the multipliers + + forcelist = forcelist if forcelist else [] + if not iterable(forcelist): + raise TypeError('Force pairs must be supplied in an iterable.') + self._forcelist = forcelist + if frame and not isinstance(frame, ReferenceFrame): + raise TypeError('frame must be a valid ReferenceFrame') + self._bodies = bodies + self.inertial = frame + + self.lam_vec = Matrix() + + self._term1 = Matrix() + self._term2 = Matrix() + self._term3 = Matrix() + self._term4 = Matrix() + + # Creating the qs, qdots and qdoubledots + if not iterable(qs): + raise TypeError('Generalized coordinates must be an iterable') + self._q = Matrix(qs) + self._qdots = self.q.diff(dynamicsymbols._t) + self._qdoubledots = self._qdots.diff(dynamicsymbols._t) + _validate_coordinates(self.q) + + mat_build = lambda x: Matrix(x) if x else Matrix() + hol_coneqs = mat_build(hol_coneqs) + nonhol_coneqs = mat_build(nonhol_coneqs) + self.coneqs = Matrix([hol_coneqs.diff(dynamicsymbols._t), + nonhol_coneqs]) + self._hol_coneqs = hol_coneqs + + def form_lagranges_equations(self): + """Method to form Lagrange's equations of motion. + + Returns a vector of equations of motion using Lagrange's equations of + the second kind. + """ + + qds = self._qdots + qdd_zero = dict.fromkeys(self._qdoubledots, 0) + n = len(self.q) + + # Internally we represent the EOM as four terms: + # EOM = term1 - term2 - term3 - term4 = 0 + + # First term + self._term1 = self._L.jacobian(qds) + self._term1 = self._term1.diff(dynamicsymbols._t).T + + # Second term + self._term2 = self._L.jacobian(self.q).T + + # Third term + if self.coneqs: + coneqs = self.coneqs + m = len(coneqs) + # Creating the multipliers + self.lam_vec = Matrix(dynamicsymbols('lam1:' + str(m + 1))) + self.lam_coeffs = -coneqs.jacobian(qds) + self._term3 = self.lam_coeffs.T * self.lam_vec + # Extracting the coeffecients of the qdds from the diff coneqs + diffconeqs = coneqs.diff(dynamicsymbols._t) + self._m_cd = diffconeqs.jacobian(self._qdoubledots) + # The remaining terms i.e. the 'forcing' terms in diff coneqs + self._f_cd = -diffconeqs.subs(qdd_zero) + else: + self._term3 = zeros(n, 1) + + # Fourth term + if self.forcelist: + N = self.inertial + self._term4 = zeros(n, 1) + for i, qd in enumerate(qds): + flist = zip(*_f_list_parser(self.forcelist, N)) + self._term4[i] = sum(v.diff(qd, N).dot(f) for (v, f) in flist) + else: + self._term4 = zeros(n, 1) + + # Form the dynamic mass and forcing matrices + without_lam = self._term1 - self._term2 - self._term4 + self._m_d = without_lam.jacobian(self._qdoubledots) + self._f_d = -without_lam.subs(qdd_zero) + + # Form the EOM + self.eom = without_lam - self._term3 + return self.eom + + def _form_eoms(self): + return self.form_lagranges_equations() + + @property + def mass_matrix(self): + """Returns the mass matrix, which is augmented by the Lagrange + multipliers, if necessary. + + Explanation + =========== + + If the system is described by 'n' generalized coordinates and there are + no constraint equations then an n X n matrix is returned. + + If there are 'n' generalized coordinates and 'm' constraint equations + have been supplied during initialization then an n X (n+m) matrix is + returned. The (n + m - 1)th and (n + m)th columns contain the + coefficients of the Lagrange multipliers. + """ + + if self.eom is None: + raise ValueError('Need to compute the equations of motion first') + if self.coneqs: + return (self._m_d).row_join(self.lam_coeffs.T) + else: + return self._m_d + + @property + def mass_matrix_full(self): + """Augments the coefficients of qdots to the mass_matrix.""" + + if self.eom is None: + raise ValueError('Need to compute the equations of motion first') + n = len(self.q) + m = len(self.coneqs) + row1 = eye(n).row_join(zeros(n, n + m)) + row2 = zeros(n, n).row_join(self.mass_matrix) + if self.coneqs: + row3 = zeros(m, n).row_join(self._m_cd).row_join(zeros(m, m)) + return row1.col_join(row2).col_join(row3) + else: + return row1.col_join(row2) + + @property + def forcing(self): + """Returns the forcing vector from 'lagranges_equations' method.""" + + if self.eom is None: + raise ValueError('Need to compute the equations of motion first') + return self._f_d + + @property + def forcing_full(self): + """Augments qdots to the forcing vector above.""" + + if self.eom is None: + raise ValueError('Need to compute the equations of motion first') + if self.coneqs: + return self._qdots.col_join(self.forcing).col_join(self._f_cd) + else: + return self._qdots.col_join(self.forcing) + + def to_linearizer(self, q_ind=None, qd_ind=None, q_dep=None, qd_dep=None, + linear_solver='LU'): + """Returns an instance of the Linearizer class, initiated from the data + in the LagrangesMethod class. This may be more desirable than using the + linearize class method, as the Linearizer object will allow more + efficient recalculation (i.e. about varying operating points). + + Parameters + ========== + + q_ind, qd_ind : array_like, optional + The independent generalized coordinates and speeds. + q_dep, qd_dep : array_like, optional + The dependent generalized coordinates and speeds. + linear_solver : str, callable + Method used to solve the several symbolic linear systems of the + form ``A*x=b`` in the linearization process. If a string is + supplied, it should be a valid method that can be used with the + :meth:`sympy.matrices.matrixbase.MatrixBase.solve`. If a callable is + supplied, it should have the format ``x = f(A, b)``, where it + solves the equations and returns the solution. The default is + ``'LU'`` which corresponds to SymPy's ``A.LUsolve(b)``. + ``LUsolve()`` is fast to compute but will often result in + divide-by-zero and thus ``nan`` results. + + Returns + ======= + Linearizer + An instantiated + :class:`sympy.physics.mechanics.linearize.Linearizer`. + + """ + + # Compose vectors + t = dynamicsymbols._t + q = self.q + u = self._qdots + ud = u.diff(t) + # Get vector of lagrange multipliers + lams = self.lam_vec + + mat_build = lambda x: Matrix(x) if x else Matrix() + q_i = mat_build(q_ind) + q_d = mat_build(q_dep) + u_i = mat_build(qd_ind) + u_d = mat_build(qd_dep) + + # Compose general form equations + f_c = self._hol_coneqs + f_v = self.coneqs + f_a = f_v.diff(t) + f_0 = u + f_1 = -u + f_2 = self._term1 + f_3 = -(self._term2 + self._term4) + f_4 = -self._term3 + + # Check that there are an appropriate number of independent and + # dependent coordinates + if len(q_d) != len(f_c) or len(u_d) != len(f_v): + raise ValueError(("Must supply {:} dependent coordinates, and " + + "{:} dependent speeds").format(len(f_c), len(f_v))) + if set(Matrix([q_i, q_d])) != set(q): + raise ValueError("Must partition q into q_ind and q_dep, with " + + "no extra or missing symbols.") + if set(Matrix([u_i, u_d])) != set(u): + raise ValueError("Must partition qd into qd_ind and qd_dep, " + + "with no extra or missing symbols.") + + # Find all other dynamic symbols, forming the forcing vector r. + # Sort r to make it canonical. + insyms = set(Matrix([q, u, ud, lams])) + r = list(find_dynamicsymbols(f_3, insyms)) + r.sort(key=default_sort_key) + # Check for any derivatives of variables in r that are also found in r. + for i in r: + if diff(i, dynamicsymbols._t) in r: + raise ValueError('Cannot have derivatives of specified \ + quantities when linearizing forcing terms.') + + return Linearizer(f_0, f_1, f_2, f_3, f_4, f_c, f_v, f_a, q, u, q_i, + q_d, u_i, u_d, r, lams, linear_solver=linear_solver) + + def linearize(self, q_ind=None, qd_ind=None, q_dep=None, qd_dep=None, + linear_solver='LU', **kwargs): + """Linearize the equations of motion about a symbolic operating point. + + Parameters + ========== + linear_solver : str, callable + Method used to solve the several symbolic linear systems of the + form ``A*x=b`` in the linearization process. If a string is + supplied, it should be a valid method that can be used with the + :meth:`sympy.matrices.matrixbase.MatrixBase.solve`. If a callable is + supplied, it should have the format ``x = f(A, b)``, where it + solves the equations and returns the solution. The default is + ``'LU'`` which corresponds to SymPy's ``A.LUsolve(b)``. + ``LUsolve()`` is fast to compute but will often result in + divide-by-zero and thus ``nan`` results. + **kwargs + Extra keyword arguments are passed to + :meth:`sympy.physics.mechanics.linearize.Linearizer.linearize`. + + Explanation + =========== + + If kwarg A_and_B is False (default), returns M, A, B, r for the + linearized form, M*[q', u']^T = A*[q_ind, u_ind]^T + B*r. + + If kwarg A_and_B is True, returns A, B, r for the linearized form + dx = A*x + B*r, where x = [q_ind, u_ind]^T. Note that this is + computationally intensive if there are many symbolic parameters. For + this reason, it may be more desirable to use the default A_and_B=False, + returning M, A, and B. Values may then be substituted in to these + matrices, and the state space form found as + A = P.T*M.inv()*A, B = P.T*M.inv()*B, where P = Linearizer.perm_mat. + + In both cases, r is found as all dynamicsymbols in the equations of + motion that are not part of q, u, q', or u'. They are sorted in + canonical form. + + The operating points may be also entered using the ``op_point`` kwarg. + This takes a dictionary of {symbol: value}, or a an iterable of such + dictionaries. The values may be numeric or symbolic. The more values + you can specify beforehand, the faster this computation will run. + + For more documentation, please see the ``Linearizer`` class.""" + + linearizer = self.to_linearizer(q_ind, qd_ind, q_dep, qd_dep, + linear_solver=linear_solver) + result = linearizer.linearize(**kwargs) + return result + (linearizer.r,) + + def solve_multipliers(self, op_point=None, sol_type='dict'): + """Solves for the values of the lagrange multipliers symbolically at + the specified operating point. + + Parameters + ========== + + op_point : dict or iterable of dicts, optional + Point at which to solve at. The operating point is specified as + a dictionary or iterable of dictionaries of {symbol: value}. The + value may be numeric or symbolic itself. + + sol_type : str, optional + Solution return type. Valid options are: + - 'dict': A dict of {symbol : value} (default) + - 'Matrix': An ordered column matrix of the solution + """ + + # Determine number of multipliers + k = len(self.lam_vec) + if k == 0: + raise ValueError("System has no lagrange multipliers to solve for.") + # Compose dict of operating conditions + if isinstance(op_point, dict): + op_point_dict = op_point + elif iterable(op_point): + op_point_dict = {} + for op in op_point: + op_point_dict.update(op) + elif op_point is None: + op_point_dict = {} + else: + raise TypeError("op_point must be either a dictionary or an " + "iterable of dictionaries.") + # Compose the system to be solved + mass_matrix = self.mass_matrix.col_join(-self.lam_coeffs.row_join( + zeros(k, k))) + force_matrix = self.forcing.col_join(self._f_cd) + # Sub in the operating point + mass_matrix = msubs(mass_matrix, op_point_dict) + force_matrix = msubs(force_matrix, op_point_dict) + # Solve for the multipliers + sol_list = mass_matrix.LUsolve(-force_matrix)[-k:] + if sol_type == 'dict': + return dict(zip(self.lam_vec, sol_list)) + elif sol_type == 'Matrix': + return Matrix(sol_list) + else: + raise ValueError("Unknown sol_type {:}.".format(sol_type)) + + def rhs(self, inv_method=None, **kwargs): + """Returns equations that can be solved numerically. + + Parameters + ========== + + inv_method : str + The specific sympy inverse matrix calculation method to use. For a + list of valid methods, see + :meth:`~sympy.matrices.matrixbase.MatrixBase.inv` + """ + + if inv_method is None: + self._rhs = self.mass_matrix_full.LUsolve(self.forcing_full) + else: + self._rhs = (self.mass_matrix_full.inv(inv_method, + try_block_diag=True) * self.forcing_full) + return self._rhs + + @property + def q(self): + return self._q + + @property + def u(self): + return self._qdots + + @property + def bodies(self): + return self._bodies + + @property + def forcelist(self): + return self._forcelist + + @property + def loads(self): + return self._forcelist diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/linearize.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/linearize.py new file mode 100644 index 0000000000000000000000000000000000000000..b94ddb865a7236a5ac6f1a41ba96679eb8b2cd8f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/linearize.py @@ -0,0 +1,474 @@ +__all__ = ['Linearizer'] + +from sympy import Matrix, eye, zeros +from sympy.core.symbol import Dummy +from sympy.utilities.iterables import flatten +from sympy.physics.vector import dynamicsymbols +from sympy.physics.mechanics.functions import msubs, _parse_linear_solver + +from collections import namedtuple +from collections.abc import Iterable + + +class Linearizer: + """This object holds the general model form for a dynamic system. This + model is used for computing the linearized form of the system, while + properly dealing with constraints leading to dependent coordinates and + speeds. The notation and method is described in [1]_. + + Attributes + ========== + + f_0, f_1, f_2, f_3, f_4, f_c, f_v, f_a : Matrix + Matrices holding the general system form. + q, u, r : Matrix + Matrices holding the generalized coordinates, speeds, and + input vectors. + q_i, u_i : Matrix + Matrices of the independent generalized coordinates and speeds. + q_d, u_d : Matrix + Matrices of the dependent generalized coordinates and speeds. + perm_mat : Matrix + Permutation matrix such that [q_ind, u_ind]^T = perm_mat*[q, u]^T + + References + ========== + + .. [1] D. L. Peterson, G. Gede, and M. Hubbard, "Symbolic linearization of + equations of motion of constrained multibody systems," Multibody + Syst Dyn, vol. 33, no. 2, pp. 143-161, Feb. 2015, doi: + 10.1007/s11044-014-9436-5. + + """ + + def __init__(self, f_0, f_1, f_2, f_3, f_4, f_c, f_v, f_a, q, u, q_i=None, + q_d=None, u_i=None, u_d=None, r=None, lams=None, + linear_solver='LU'): + """ + Parameters + ========== + + f_0, f_1, f_2, f_3, f_4, f_c, f_v, f_a : array_like + System of equations holding the general system form. + Supply empty array or Matrix if the parameter + does not exist. + q : array_like + The generalized coordinates. + u : array_like + The generalized speeds + q_i, u_i : array_like, optional + The independent generalized coordinates and speeds. + q_d, u_d : array_like, optional + The dependent generalized coordinates and speeds. + r : array_like, optional + The input variables. + lams : array_like, optional + The lagrange multipliers + linear_solver : str, callable + Method used to solve the several symbolic linear systems of the + form ``A*x=b`` in the linearization process. If a string is + supplied, it should be a valid method that can be used with the + :meth:`sympy.matrices.matrixbase.MatrixBase.solve`. If a callable is + supplied, it should have the format ``x = f(A, b)``, where it + solves the equations and returns the solution. The default is + ``'LU'`` which corresponds to SymPy's ``A.LUsolve(b)``. + ``LUsolve()`` is fast to compute but will often result in + divide-by-zero and thus ``nan`` results. + + """ + self.linear_solver = _parse_linear_solver(linear_solver) + + # Generalized equation form + self.f_0 = Matrix(f_0) + self.f_1 = Matrix(f_1) + self.f_2 = Matrix(f_2) + self.f_3 = Matrix(f_3) + self.f_4 = Matrix(f_4) + self.f_c = Matrix(f_c) + self.f_v = Matrix(f_v) + self.f_a = Matrix(f_a) + + # Generalized equation variables + self.q = Matrix(q) + self.u = Matrix(u) + none_handler = lambda x: Matrix(x) if x else Matrix() + self.q_i = none_handler(q_i) + self.q_d = none_handler(q_d) + self.u_i = none_handler(u_i) + self.u_d = none_handler(u_d) + self.r = none_handler(r) + self.lams = none_handler(lams) + + # Derivatives of generalized equation variables + self._qd = self.q.diff(dynamicsymbols._t) + self._ud = self.u.diff(dynamicsymbols._t) + # If the user doesn't actually use generalized variables, and the + # qd and u vectors have any intersecting variables, this can cause + # problems. We'll fix this with some hackery, and Dummy variables + dup_vars = set(self._qd).intersection(self.u) + self._qd_dup = Matrix([var if var not in dup_vars else Dummy() for var + in self._qd]) + + # Derive dimension terms + l = len(self.f_c) + m = len(self.f_v) + n = len(self.q) + o = len(self.u) + s = len(self.r) + k = len(self.lams) + dims = namedtuple('dims', ['l', 'm', 'n', 'o', 's', 'k']) + self._dims = dims(l, m, n, o, s, k) + + self._Pq = None + self._Pqi = None + self._Pqd = None + self._Pu = None + self._Pui = None + self._Pud = None + self._C_0 = None + self._C_1 = None + self._C_2 = None + self.perm_mat = None + + self._setup_done = False + + def _setup(self): + # Calculations here only need to be run once. They are moved out of + # the __init__ method to increase the speed of Linearizer creation. + self._form_permutation_matrices() + self._form_block_matrices() + self._form_coefficient_matrices() + self._setup_done = True + + def _form_permutation_matrices(self): + """Form the permutation matrices Pq and Pu.""" + + # Extract dimension variables + l, m, n, o, s, k = self._dims + # Compute permutation matrices + if n != 0: + self._Pq = permutation_matrix(self.q, Matrix([self.q_i, self.q_d])) + if l > 0: + self._Pqi = self._Pq[:, :-l] + self._Pqd = self._Pq[:, -l:] + else: + self._Pqi = self._Pq + self._Pqd = Matrix() + if o != 0: + self._Pu = permutation_matrix(self.u, Matrix([self.u_i, self.u_d])) + if m > 0: + self._Pui = self._Pu[:, :-m] + self._Pud = self._Pu[:, -m:] + else: + self._Pui = self._Pu + self._Pud = Matrix() + # Compute combination permutation matrix for computing A and B + P_col1 = Matrix([self._Pqi, zeros(o + k, n - l)]) + P_col2 = Matrix([zeros(n, o - m), self._Pui, zeros(k, o - m)]) + if P_col1: + if P_col2: + self.perm_mat = P_col1.row_join(P_col2) + else: + self.perm_mat = P_col1 + else: + self.perm_mat = P_col2 + + def _form_coefficient_matrices(self): + """Form the coefficient matrices C_0, C_1, and C_2.""" + + # Extract dimension variables + l, m, n, o, s, k = self._dims + # Build up the coefficient matrices C_0, C_1, and C_2 + # If there are configuration constraints (l > 0), form C_0 as normal. + # If not, C_0 is I_(nxn). Note that this works even if n=0 + if l > 0: + f_c_jac_q = self.f_c.jacobian(self.q) + self._C_0 = (eye(n) - self._Pqd * + self.linear_solver(f_c_jac_q*self._Pqd, + f_c_jac_q))*self._Pqi + else: + self._C_0 = eye(n) + # If there are motion constraints (m > 0), form C_1 and C_2 as normal. + # If not, C_1 is 0, and C_2 is I_(oxo). Note that this works even if + # o = 0. + if m > 0: + f_v_jac_u = self.f_v.jacobian(self.u) + temp = f_v_jac_u * self._Pud + if n != 0: + f_v_jac_q = self.f_v.jacobian(self.q) + self._C_1 = -self._Pud * self.linear_solver(temp, f_v_jac_q) + else: + self._C_1 = zeros(o, n) + self._C_2 = (eye(o) - self._Pud * + self.linear_solver(temp, f_v_jac_u))*self._Pui + else: + self._C_1 = zeros(o, n) + self._C_2 = eye(o) + + def _form_block_matrices(self): + """Form the block matrices for composing M, A, and B.""" + + # Extract dimension variables + l, m, n, o, s, k = self._dims + # Block Matrix Definitions. These are only defined if under certain + # conditions. If undefined, an empty matrix is used instead + if n != 0: + self._M_qq = self.f_0.jacobian(self._qd) + self._A_qq = -(self.f_0 + self.f_1).jacobian(self.q) + else: + self._M_qq = Matrix() + self._A_qq = Matrix() + if n != 0 and m != 0: + self._M_uqc = self.f_a.jacobian(self._qd_dup) + self._A_uqc = -self.f_a.jacobian(self.q) + else: + self._M_uqc = Matrix() + self._A_uqc = Matrix() + if n != 0 and o - m + k != 0: + self._M_uqd = self.f_3.jacobian(self._qd_dup) + self._A_uqd = -(self.f_2 + self.f_3 + self.f_4).jacobian(self.q) + else: + self._M_uqd = Matrix() + self._A_uqd = Matrix() + if o != 0 and m != 0: + self._M_uuc = self.f_a.jacobian(self._ud) + self._A_uuc = -self.f_a.jacobian(self.u) + else: + self._M_uuc = Matrix() + self._A_uuc = Matrix() + if o != 0 and o - m + k != 0: + self._M_uud = self.f_2.jacobian(self._ud) + self._A_uud = -(self.f_2 + self.f_3).jacobian(self.u) + else: + self._M_uud = Matrix() + self._A_uud = Matrix() + if o != 0 and n != 0: + self._A_qu = -self.f_1.jacobian(self.u) + else: + self._A_qu = Matrix() + if k != 0 and o - m + k != 0: + self._M_uld = self.f_4.jacobian(self.lams) + else: + self._M_uld = Matrix() + if s != 0 and o - m + k != 0: + self._B_u = -self.f_3.jacobian(self.r) + else: + self._B_u = Matrix() + + def linearize(self, op_point=None, A_and_B=False, simplify=False): + """Linearize the system about the operating point. Note that + q_op, u_op, qd_op, ud_op must satisfy the equations of motion. + These may be either symbolic or numeric. + + Parameters + ========== + op_point : dict or iterable of dicts, optional + Dictionary or iterable of dictionaries containing the operating + point conditions for all or a subset of the generalized + coordinates, generalized speeds, and time derivatives of the + generalized speeds. These will be substituted into the linearized + system before the linearization is complete. Leave set to ``None`` + if you want the operating point to be an arbitrary set of symbols. + Note that any reduction in symbols (whether substituted for numbers + or expressions with a common parameter) will result in faster + runtime. + A_and_B : bool, optional + If A_and_B=False (default), (M, A, B) is returned and of + A_and_B=True, (A, B) is returned. See below. + simplify : bool, optional + Determines if returned values are simplified before return. + For large expressions this may be time consuming. Default is False. + + Returns + ======= + M, A, B : Matrices, ``A_and_B=False`` + Matrices from the implicit form: + ``[M]*[q', u']^T = [A]*[q_ind, u_ind]^T + [B]*r`` + A, B : Matrices, ``A_and_B=True`` + Matrices from the explicit form: + ``[q_ind', u_ind']^T = [A]*[q_ind, u_ind]^T + [B]*r`` + + Notes + ===== + + Note that the process of solving with A_and_B=True is computationally + intensive if there are many symbolic parameters. For this reason, it + may be more desirable to use the default A_and_B=False, returning M, A, + and B. More values may then be substituted in to these matrices later + on. The state space form can then be found as A = P.T*M.LUsolve(A), B = + P.T*M.LUsolve(B), where P = Linearizer.perm_mat. + + """ + + # Run the setup if needed: + if not self._setup_done: + self._setup() + + # Compose dict of operating conditions + if isinstance(op_point, dict): + op_point_dict = op_point + elif isinstance(op_point, Iterable): + op_point_dict = {} + for op in op_point: + op_point_dict.update(op) + else: + op_point_dict = {} + + # Extract dimension variables + l, m, n, o, s, k = self._dims + + # Rename terms to shorten expressions + M_qq = self._M_qq + M_uqc = self._M_uqc + M_uqd = self._M_uqd + M_uuc = self._M_uuc + M_uud = self._M_uud + M_uld = self._M_uld + A_qq = self._A_qq + A_uqc = self._A_uqc + A_uqd = self._A_uqd + A_qu = self._A_qu + A_uuc = self._A_uuc + A_uud = self._A_uud + B_u = self._B_u + C_0 = self._C_0 + C_1 = self._C_1 + C_2 = self._C_2 + + # Build up Mass Matrix + # |M_qq 0_nxo 0_nxk| + # M = |M_uqc M_uuc 0_mxk| + # |M_uqd M_uud M_uld| + if o != 0: + col2 = Matrix([zeros(n, o), M_uuc, M_uud]) + if k != 0: + col3 = Matrix([zeros(n + m, k), M_uld]) + if n != 0: + col1 = Matrix([M_qq, M_uqc, M_uqd]) + if o != 0 and k != 0: + M = col1.row_join(col2).row_join(col3) + elif o != 0: + M = col1.row_join(col2) + else: + M = col1 + elif k != 0: + M = col2.row_join(col3) + else: + M = col2 + M_eq = msubs(M, op_point_dict) + + # Build up state coefficient matrix A + # |(A_qq + A_qu*C_1)*C_0 A_qu*C_2| + # A = |(A_uqc + A_uuc*C_1)*C_0 A_uuc*C_2| + # |(A_uqd + A_uud*C_1)*C_0 A_uud*C_2| + # Col 1 is only defined if n != 0 + if n != 0: + r1c1 = A_qq + if o != 0: + r1c1 += (A_qu * C_1) + r1c1 = r1c1 * C_0 + if m != 0: + r2c1 = A_uqc + if o != 0: + r2c1 += (A_uuc * C_1) + r2c1 = r2c1 * C_0 + else: + r2c1 = Matrix() + if o - m + k != 0: + r3c1 = A_uqd + if o != 0: + r3c1 += (A_uud * C_1) + r3c1 = r3c1 * C_0 + else: + r3c1 = Matrix() + col1 = Matrix([r1c1, r2c1, r3c1]) + else: + col1 = Matrix() + # Col 2 is only defined if o != 0 + if o != 0: + if n != 0: + r1c2 = A_qu * C_2 + else: + r1c2 = Matrix() + if m != 0: + r2c2 = A_uuc * C_2 + else: + r2c2 = Matrix() + if o - m + k != 0: + r3c2 = A_uud * C_2 + else: + r3c2 = Matrix() + col2 = Matrix([r1c2, r2c2, r3c2]) + else: + col2 = Matrix() + if col1: + if col2: + Amat = col1.row_join(col2) + else: + Amat = col1 + else: + Amat = col2 + Amat_eq = msubs(Amat, op_point_dict) + + # Build up the B matrix if there are forcing variables + # |0_(n + m)xs| + # B = |B_u | + if s != 0 and o - m + k != 0: + Bmat = zeros(n + m, s).col_join(B_u) + Bmat_eq = msubs(Bmat, op_point_dict) + else: + Bmat_eq = Matrix() + + # kwarg A_and_B indicates to return A, B for forming the equation + # dx = [A]x + [B]r, where x = [q_indnd, u_indnd]^T, + if A_and_B: + A_cont = self.perm_mat.T * self.linear_solver(M_eq, Amat_eq) + if Bmat_eq: + B_cont = self.perm_mat.T * self.linear_solver(M_eq, Bmat_eq) + else: + # Bmat = Matrix([]), so no need to sub + B_cont = Bmat_eq + if simplify: + A_cont.simplify() + B_cont.simplify() + return A_cont, B_cont + # Otherwise return M, A, B for forming the equation + # [M]dx = [A]x + [B]r, where x = [q, u]^T + else: + if simplify: + M_eq.simplify() + Amat_eq.simplify() + Bmat_eq.simplify() + return M_eq, Amat_eq, Bmat_eq + + +def permutation_matrix(orig_vec, per_vec): + """Compute the permutation matrix to change order of + orig_vec into order of per_vec. + + Parameters + ========== + + orig_vec : array_like + Symbols in original ordering. + per_vec : array_like + Symbols in new ordering. + + Returns + ======= + + p_matrix : Matrix + Permutation matrix such that orig_vec == (p_matrix * per_vec). + """ + if not isinstance(orig_vec, (list, tuple)): + orig_vec = flatten(orig_vec) + if not isinstance(per_vec, (list, tuple)): + per_vec = flatten(per_vec) + if set(orig_vec) != set(per_vec): + raise ValueError("orig_vec and per_vec must be the same length, " + "and contain the same symbols.") + ind_list = [orig_vec.index(i) for i in per_vec] + p_matrix = zeros(len(orig_vec)) + for i, j in enumerate(ind_list): + p_matrix[i, j] = 1 + return p_matrix diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/loads.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/loads.py new file mode 100644 index 0000000000000000000000000000000000000000..3b9db763ffd6f99905e9d17fdc07f4171de4801b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/loads.py @@ -0,0 +1,177 @@ +from abc import ABC +from collections import namedtuple +from sympy.physics.mechanics.body_base import BodyBase +from sympy.physics.vector import Vector, ReferenceFrame, Point + +__all__ = ['LoadBase', 'Force', 'Torque'] + + +class LoadBase(ABC, namedtuple('LoadBase', ['location', 'vector'])): + """Abstract base class for the various loading types.""" + + def __add__(self, other): + raise TypeError(f"unsupported operand type(s) for +: " + f"'{self.__class__.__name__}' and " + f"'{other.__class__.__name__}'") + + def __mul__(self, other): + raise TypeError(f"unsupported operand type(s) for *: " + f"'{self.__class__.__name__}' and " + f"'{other.__class__.__name__}'") + + __radd__ = __add__ + __rmul__ = __mul__ + + +class Force(LoadBase): + """Force acting upon a point. + + Explanation + =========== + + A force is a vector that is bound to a line of action. This class stores + both a point, which lies on the line of action, and the vector. A tuple can + also be used, with the location as the first entry and the vector as second + entry. + + Examples + ======== + + A force of magnitude 2 along N.x acting on a point Po can be created as + follows: + + >>> from sympy.physics.mechanics import Point, ReferenceFrame, Force + >>> N = ReferenceFrame('N') + >>> Po = Point('Po') + >>> Force(Po, 2 * N.x) + (Po, 2*N.x) + + If a body is supplied, then the center of mass of that body is used. + + >>> from sympy.physics.mechanics import Particle + >>> P = Particle('P', point=Po) + >>> Force(P, 2 * N.x) + (Po, 2*N.x) + + """ + + def __new__(cls, point, force): + if isinstance(point, BodyBase): + point = point.masscenter + if not isinstance(point, Point): + raise TypeError('Force location should be a Point.') + if not isinstance(force, Vector): + raise TypeError('Force vector should be a Vector.') + return super().__new__(cls, point, force) + + def __repr__(self): + return (f'{self.__class__.__name__}(point={self.point}, ' + f'force={self.force})') + + @property + def point(self): + return self.location + + @property + def force(self): + return self.vector + + +class Torque(LoadBase): + """Torque acting upon a frame. + + Explanation + =========== + + A torque is a free vector that is acting on a reference frame, which is + associated with a rigid body. This class stores both the frame and the + vector. A tuple can also be used, with the location as the first item and + the vector as second item. + + Examples + ======== + + A torque of magnitude 2 about N.x acting on a frame N can be created as + follows: + + >>> from sympy.physics.mechanics import ReferenceFrame, Torque + >>> N = ReferenceFrame('N') + >>> Torque(N, 2 * N.x) + (N, 2*N.x) + + If a body is supplied, then the frame fixed to that body is used. + + >>> from sympy.physics.mechanics import RigidBody + >>> rb = RigidBody('rb', frame=N) + >>> Torque(rb, 2 * N.x) + (N, 2*N.x) + + """ + + def __new__(cls, frame, torque): + if isinstance(frame, BodyBase): + frame = frame.frame + if not isinstance(frame, ReferenceFrame): + raise TypeError('Torque location should be a ReferenceFrame.') + if not isinstance(torque, Vector): + raise TypeError('Torque vector should be a Vector.') + return super().__new__(cls, frame, torque) + + def __repr__(self): + return (f'{self.__class__.__name__}(frame={self.frame}, ' + f'torque={self.torque})') + + @property + def frame(self): + return self.location + + @property + def torque(self): + return self.vector + + +def gravity(acceleration, *bodies): + """ + Returns a list of gravity forces given the acceleration + due to gravity and any number of particles or rigidbodies. + + Example + ======= + + >>> from sympy.physics.mechanics import ReferenceFrame, Particle, RigidBody + >>> from sympy.physics.mechanics.loads import gravity + >>> from sympy import symbols + >>> N = ReferenceFrame('N') + >>> g = symbols('g') + >>> P = Particle('P') + >>> B = RigidBody('B') + >>> gravity(g*N.y, P, B) + [(P_masscenter, P_mass*g*N.y), + (B_masscenter, B_mass*g*N.y)] + + """ + + gravity_force = [] + for body in bodies: + if not isinstance(body, BodyBase): + raise TypeError(f'{type(body)} is not a body type') + gravity_force.append(Force(body.masscenter, body.mass * acceleration)) + return gravity_force + + +def _parse_load(load): + """Helper function to parse loads and convert tuples to load objects.""" + if isinstance(load, LoadBase): + return load + elif isinstance(load, tuple): + if len(load) != 2: + raise ValueError(f'Load {load} should have a length of 2.') + if isinstance(load[0], Point): + return Force(load[0], load[1]) + elif isinstance(load[0], ReferenceFrame): + return Torque(load[0], load[1]) + else: + raise ValueError(f'Load not recognized. The load location {load[0]}' + f' should either be a Point or a ReferenceFrame.') + raise TypeError(f'Load type {type(load)} not recognized as a load. It ' + f'should be a Force, Torque or tuple.') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/method.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/method.py new file mode 100644 index 0000000000000000000000000000000000000000..5c2c4a5f388e56e37bd9ecdf6daffc08ffa51070 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/method.py @@ -0,0 +1,39 @@ +from abc import ABC, abstractmethod + +class _Methods(ABC): + """Abstract Base Class for all methods.""" + + @abstractmethod + def q(self): + pass + + @abstractmethod + def u(self): + pass + + @abstractmethod + def bodies(self): + pass + + @abstractmethod + def loads(self): + pass + + @abstractmethod + def mass_matrix(self): + pass + + @abstractmethod + def forcing(self): + pass + + @abstractmethod + def mass_matrix_full(self): + pass + + @abstractmethod + def forcing_full(self): + pass + + def _form_eoms(self): + raise NotImplementedError("Subclasses must implement this.") diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/models.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/models.py new file mode 100644 index 0000000000000000000000000000000000000000..a89b929ffd540a07787f6f94714850b348c90781 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/models.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python +"""This module contains some sample symbolic models used for testing and +examples.""" + +# Internal imports +from sympy.core import backend as sm +import sympy.physics.mechanics as me + + +def multi_mass_spring_damper(n=1, apply_gravity=False, + apply_external_forces=False): + r"""Returns a system containing the symbolic equations of motion and + associated variables for a simple multi-degree of freedom point mass, + spring, damper system with optional gravitational and external + specified forces. For example, a two mass system under the influence of + gravity and external forces looks like: + + :: + + ---------------- + | | | | g + \ | | | V + k0 / --- c0 | + | | | x0, v0 + --------- V + | m0 | ----- + --------- | + | | | | + \ v | | | + k1 / f0 --- c1 | + | | | x1, v1 + --------- V + | m1 | ----- + --------- + | f1 + V + + Parameters + ========== + + n : integer + The number of masses in the serial chain. + apply_gravity : boolean + If true, gravity will be applied to each mass. + apply_external_forces : boolean + If true, a time varying external force will be applied to each mass. + + Returns + ======= + + kane : sympy.physics.mechanics.kane.KanesMethod + A KanesMethod object. + + """ + + mass = sm.symbols('m:{}'.format(n)) + stiffness = sm.symbols('k:{}'.format(n)) + damping = sm.symbols('c:{}'.format(n)) + + acceleration_due_to_gravity = sm.symbols('g') + + coordinates = me.dynamicsymbols('x:{}'.format(n)) + speeds = me.dynamicsymbols('v:{}'.format(n)) + specifieds = me.dynamicsymbols('f:{}'.format(n)) + + ceiling = me.ReferenceFrame('N') + origin = me.Point('origin') + origin.set_vel(ceiling, 0) + + points = [origin] + kinematic_equations = [] + particles = [] + forces = [] + + for i in range(n): + + center = points[-1].locatenew('center{}'.format(i), + coordinates[i] * ceiling.x) + center.set_vel(ceiling, points[-1].vel(ceiling) + + speeds[i] * ceiling.x) + points.append(center) + + block = me.Particle('block{}'.format(i), center, mass[i]) + + kinematic_equations.append(speeds[i] - coordinates[i].diff()) + + total_force = (-stiffness[i] * coordinates[i] - + damping[i] * speeds[i]) + try: + total_force += (stiffness[i + 1] * coordinates[i + 1] + + damping[i + 1] * speeds[i + 1]) + except IndexError: # no force from below on last mass + pass + + if apply_gravity: + total_force += mass[i] * acceleration_due_to_gravity + + if apply_external_forces: + total_force += specifieds[i] + + forces.append((center, total_force * ceiling.x)) + + particles.append(block) + + kane = me.KanesMethod(ceiling, q_ind=coordinates, u_ind=speeds, + kd_eqs=kinematic_equations) + kane.kanes_equations(particles, forces) + + return kane + + +def n_link_pendulum_on_cart(n=1, cart_force=True, joint_torques=False): + r"""Returns the system containing the symbolic first order equations of + motion for a 2D n-link pendulum on a sliding cart under the influence of + gravity. + + :: + + | + o y v + \ 0 ^ g + \ | + --\-|---- + | \| | + F-> | o --|---> x + | | + --------- + o o + + Parameters + ========== + + n : integer + The number of links in the pendulum. + cart_force : boolean, default=True + If true an external specified lateral force is applied to the cart. + joint_torques : boolean, default=False + If true joint torques will be added as specified inputs at each + joint. + + Returns + ======= + + kane : sympy.physics.mechanics.kane.KanesMethod + A KanesMethod object. + + Notes + ===== + + The degrees of freedom of the system are n + 1, i.e. one for each + pendulum link and one for the lateral motion of the cart. + + M x' = F, where x = [u0, ..., un+1, q0, ..., qn+1] + + The joint angles are all defined relative to the ground where the x axis + defines the ground line and the y axis points up. The joint torques are + applied between each adjacent link and the between the cart and the + lower link where a positive torque corresponds to positive angle. + + """ + if n <= 0: + raise ValueError('The number of links must be a positive integer.') + + q = me.dynamicsymbols('q:{}'.format(n + 1)) + u = me.dynamicsymbols('u:{}'.format(n + 1)) + + if joint_torques is True: + T = me.dynamicsymbols('T1:{}'.format(n + 1)) + + m = sm.symbols('m:{}'.format(n + 1)) + l = sm.symbols('l:{}'.format(n)) + g, t = sm.symbols('g t') + + I = me.ReferenceFrame('I') + O = me.Point('O') + O.set_vel(I, 0) + + P0 = me.Point('P0') + P0.set_pos(O, q[0] * I.x) + P0.set_vel(I, u[0] * I.x) + Pa0 = me.Particle('Pa0', P0, m[0]) + + frames = [I] + points = [P0] + particles = [Pa0] + forces = [(P0, -m[0] * g * I.y)] + kindiffs = [q[0].diff(t) - u[0]] + + if cart_force is True or joint_torques is True: + specified = [] + else: + specified = None + + for i in range(n): + Bi = I.orientnew('B{}'.format(i), 'Axis', [q[i + 1], I.z]) + Bi.set_ang_vel(I, u[i + 1] * I.z) + frames.append(Bi) + + Pi = points[-1].locatenew('P{}'.format(i + 1), l[i] * Bi.y) + Pi.v2pt_theory(points[-1], I, Bi) + points.append(Pi) + + Pai = me.Particle('Pa' + str(i + 1), Pi, m[i + 1]) + particles.append(Pai) + + forces.append((Pi, -m[i + 1] * g * I.y)) + + if joint_torques is True: + + specified.append(T[i]) + + if i == 0: + forces.append((I, -T[i] * I.z)) + + if i == n - 1: + forces.append((Bi, T[i] * I.z)) + else: + forces.append((Bi, T[i] * I.z - T[i + 1] * I.z)) + + kindiffs.append(q[i + 1].diff(t) - u[i + 1]) + + if cart_force is True: + F = me.dynamicsymbols('F') + forces.append((P0, F * I.x)) + specified.append(F) + + kane = me.KanesMethod(I, q_ind=q, u_ind=u, kd_eqs=kindiffs) + kane.kanes_equations(particles, forces) + + return kane diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/pathway.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/pathway.py new file mode 100644 index 0000000000000000000000000000000000000000..b86ba85b1d9d1434c51de3fd7cc429442fdbedb0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/pathway.py @@ -0,0 +1,688 @@ +"""Implementations of pathways for use by actuators.""" + +from abc import ABC, abstractmethod + +from sympy.core.singleton import S +from sympy.physics.mechanics.loads import Force +from sympy.physics.mechanics.wrapping_geometry import WrappingGeometryBase +from sympy.physics.vector import Point, dynamicsymbols + + +__all__ = ['PathwayBase', 'LinearPathway', 'ObstacleSetPathway', + 'WrappingPathway'] + + +class PathwayBase(ABC): + """Abstract base class for all pathway classes to inherit from. + + Notes + ===== + + Instances of this class cannot be directly instantiated by users. However, + it can be used to created custom pathway types through subclassing. + + """ + + def __init__(self, *attachments): + """Initializer for ``PathwayBase``.""" + self.attachments = attachments + + @property + def attachments(self): + """The pair of points defining a pathway's ends.""" + return self._attachments + + @attachments.setter + def attachments(self, attachments): + if hasattr(self, '_attachments'): + msg = ( + f'Can\'t set attribute `attachments` to {repr(attachments)} ' + f'as it is immutable.' + ) + raise AttributeError(msg) + if len(attachments) != 2: + msg = ( + f'Value {repr(attachments)} passed to `attachments` was an ' + f'iterable of length {len(attachments)}, must be an iterable ' + f'of length 2.' + ) + raise ValueError(msg) + for i, point in enumerate(attachments): + if not isinstance(point, Point): + msg = ( + f'Value {repr(point)} passed to `attachments` at index ' + f'{i} was of type {type(point)}, must be {Point}.' + ) + raise TypeError(msg) + self._attachments = tuple(attachments) + + @property + @abstractmethod + def length(self): + """An expression representing the pathway's length.""" + pass + + @property + @abstractmethod + def extension_velocity(self): + """An expression representing the pathway's extension velocity.""" + pass + + @abstractmethod + def to_loads(self, force): + """Loads required by the equations of motion method classes. + + Explanation + =========== + + ``KanesMethod`` requires a list of ``Point``-``Vector`` tuples to be + passed to the ``loads`` parameters of its ``kanes_equations`` method + when constructing the equations of motion. This method acts as a + utility to produce the correctly-structred pairs of points and vectors + required so that these can be easily concatenated with other items in + the list of loads and passed to ``KanesMethod.kanes_equations``. These + loads are also in the correct form to also be passed to the other + equations of motion method classes, e.g. ``LagrangesMethod``. + + """ + pass + + def __repr__(self): + """Default representation of a pathway.""" + attachments = ', '.join(str(a) for a in self.attachments) + return f'{self.__class__.__name__}({attachments})' + + +class LinearPathway(PathwayBase): + """Linear pathway between a pair of attachment points. + + Explanation + =========== + + A linear pathway forms a straight-line segment between two points and is + the simplest pathway that can be formed. It will not interact with any + other objects in the system, i.e. a ``LinearPathway`` will intersect other + objects to ensure that the path between its two ends (its attachments) is + the shortest possible. + + A linear pathway is made up of two points that can move relative to each + other, and a pair of equal and opposite forces acting on the points. If the + positive time-varying Euclidean distance between the two points is defined, + then the "extension velocity" is the time derivative of this distance. The + extension velocity is positive when the two points are moving away from + each other and negative when moving closer to each other. The direction for + the force acting on either point is determined by constructing a unit + vector directed from the other point to this point. This establishes a sign + convention such that a positive force magnitude tends to push the points + apart. The following diagram shows the positive force sense and the + distance between the points:: + + P Q + o<--- F --->o + | | + |<--l(t)--->| + + Examples + ======== + + >>> from sympy.physics.mechanics import LinearPathway + + To construct a pathway, two points are required to be passed to the + ``attachments`` parameter as a ``tuple``. + + >>> from sympy.physics.mechanics import Point + >>> pA, pB = Point('pA'), Point('pB') + >>> linear_pathway = LinearPathway(pA, pB) + >>> linear_pathway + LinearPathway(pA, pB) + + The pathway created above isn't very interesting without the positions and + velocities of its attachment points being described. Without this its not + possible to describe how the pathway moves, i.e. its length or its + extension velocity. + + >>> from sympy.physics.mechanics import ReferenceFrame + >>> from sympy.physics.vector import dynamicsymbols + >>> N = ReferenceFrame('N') + >>> q = dynamicsymbols('q') + >>> pB.set_pos(pA, q*N.x) + >>> pB.pos_from(pA) + q(t)*N.x + + A pathway's length can be accessed via its ``length`` attribute. + + >>> linear_pathway.length + sqrt(q(t)**2) + + Note how what appears to be an overly-complex expression is returned. This + is actually required as it ensures that a pathway's length is always + positive. + + A pathway's extension velocity can be accessed similarly via its + ``extension_velocity`` attribute. + + >>> linear_pathway.extension_velocity + sqrt(q(t)**2)*Derivative(q(t), t)/q(t) + + Parameters + ========== + + attachments : tuple[Point, Point] + Pair of ``Point`` objects between which the linear pathway spans. + Constructor expects two points to be passed, e.g. + ``LinearPathway(Point('pA'), Point('pB'))``. More or fewer points will + cause an error to be thrown. + + """ + + def __init__(self, *attachments): + """Initializer for ``LinearPathway``. + + Parameters + ========== + + attachments : Point + Pair of ``Point`` objects between which the linear pathway spans. + Constructor expects two points to be passed, e.g. + ``LinearPathway(Point('pA'), Point('pB'))``. More or fewer points + will cause an error to be thrown. + + """ + super().__init__(*attachments) + + @property + def length(self): + """Exact analytical expression for the pathway's length.""" + return _point_pair_length(*self.attachments) + + @property + def extension_velocity(self): + """Exact analytical expression for the pathway's extension velocity.""" + return _point_pair_extension_velocity(*self.attachments) + + def to_loads(self, force): + """Loads required by the equations of motion method classes. + + Explanation + =========== + + ``KanesMethod`` requires a list of ``Point``-``Vector`` tuples to be + passed to the ``loads`` parameters of its ``kanes_equations`` method + when constructing the equations of motion. This method acts as a + utility to produce the correctly-structred pairs of points and vectors + required so that these can be easily concatenated with other items in + the list of loads and passed to ``KanesMethod.kanes_equations``. These + loads are also in the correct form to also be passed to the other + equations of motion method classes, e.g. ``LagrangesMethod``. + + Examples + ======== + + The below example shows how to generate the loads produced in a linear + actuator that produces an expansile force ``F``. First, create a linear + actuator between two points separated by the coordinate ``q`` in the + ``x`` direction of the global frame ``N``. + + >>> from sympy.physics.mechanics import (LinearPathway, Point, + ... ReferenceFrame) + >>> from sympy.physics.vector import dynamicsymbols + >>> q = dynamicsymbols('q') + >>> N = ReferenceFrame('N') + >>> pA, pB = Point('pA'), Point('pB') + >>> pB.set_pos(pA, q*N.x) + >>> linear_pathway = LinearPathway(pA, pB) + + Now create a symbol ``F`` to describe the magnitude of the (expansile) + force that will be produced along the pathway. The list of loads that + ``KanesMethod`` requires can be produced by calling the pathway's + ``to_loads`` method with ``F`` passed as the only argument. + + >>> from sympy import symbols + >>> F = symbols('F') + >>> linear_pathway.to_loads(F) + [(pA, - F*q(t)/sqrt(q(t)**2)*N.x), (pB, F*q(t)/sqrt(q(t)**2)*N.x)] + + Parameters + ========== + + force : Expr + Magnitude of the force acting along the length of the pathway. As + per the sign conventions for the pathway length, pathway extension + velocity, and pair of point forces, if this ``Expr`` is positive + then the force will act to push the pair of points away from one + another (it is expansile). + + """ + relative_position = _point_pair_relative_position(*self.attachments) + loads = [ + Force(self.attachments[0], -force*relative_position/self.length), + Force(self.attachments[-1], force*relative_position/self.length), + ] + return loads + + +class ObstacleSetPathway(PathwayBase): + """Obstacle-set pathway between a set of attachment points. + + Explanation + =========== + + An obstacle-set pathway forms a series of straight-line segment between + pairs of consecutive points in a set of points. It is similar to multiple + linear pathways joined end-to-end. It will not interact with any other + objects in the system, i.e. an ``ObstacleSetPathway`` will intersect other + objects to ensure that the path between its pairs of points (its + attachments) is the shortest possible. + + Examples + ======== + + To construct an obstacle-set pathway, three or more points are required to + be passed to the ``attachments`` parameter as a ``tuple``. + + >>> from sympy.physics.mechanics import ObstacleSetPathway, Point + >>> pA, pB, pC, pD = Point('pA'), Point('pB'), Point('pC'), Point('pD') + >>> obstacle_set_pathway = ObstacleSetPathway(pA, pB, pC, pD) + >>> obstacle_set_pathway + ObstacleSetPathway(pA, pB, pC, pD) + + The pathway created above isn't very interesting without the positions and + velocities of its attachment points being described. Without this its not + possible to describe how the pathway moves, i.e. its length or its + extension velocity. + + >>> from sympy import cos, sin + >>> from sympy.physics.mechanics import ReferenceFrame + >>> from sympy.physics.vector import dynamicsymbols + >>> N = ReferenceFrame('N') + >>> q = dynamicsymbols('q') + >>> pO = Point('pO') + >>> pA.set_pos(pO, N.y) + >>> pB.set_pos(pO, -N.x) + >>> pC.set_pos(pA, cos(q) * N.x - (sin(q) + 1) * N.y) + >>> pD.set_pos(pA, sin(q) * N.x + (cos(q) - 1) * N.y) + >>> pB.pos_from(pA) + - N.x - N.y + >>> pC.pos_from(pA) + cos(q(t))*N.x + (-sin(q(t)) - 1)*N.y + >>> pD.pos_from(pA) + sin(q(t))*N.x + (cos(q(t)) - 1)*N.y + + A pathway's length can be accessed via its ``length`` attribute. + + >>> obstacle_set_pathway.length.simplify() + sqrt(2)*(sqrt(cos(q(t)) + 1) + 2) + + A pathway's extension velocity can be accessed similarly via its + ``extension_velocity`` attribute. + + >>> obstacle_set_pathway.extension_velocity.simplify() + -sqrt(2)*sin(q(t))*Derivative(q(t), t)/(2*sqrt(cos(q(t)) + 1)) + + Parameters + ========== + + attachments : tuple[Point, ...] + The set of ``Point`` objects that define the segmented obstacle-set + pathway. + + """ + + def __init__(self, *attachments): + """Initializer for ``ObstacleSetPathway``. + + Parameters + ========== + + attachments : tuple[Point, ...] + The set of ``Point`` objects that define the segmented obstacle-set + pathway. + + """ + super().__init__(*attachments) + + @property + def attachments(self): + """The set of points defining a pathway's segmented path.""" + return self._attachments + + @attachments.setter + def attachments(self, attachments): + if hasattr(self, '_attachments'): + msg = ( + f'Can\'t set attribute `attachments` to {repr(attachments)} ' + f'as it is immutable.' + ) + raise AttributeError(msg) + if len(attachments) <= 2: + msg = ( + f'Value {repr(attachments)} passed to `attachments` was an ' + f'iterable of length {len(attachments)}, must be an iterable ' + f'of length 3 or greater.' + ) + raise ValueError(msg) + for i, point in enumerate(attachments): + if not isinstance(point, Point): + msg = ( + f'Value {repr(point)} passed to `attachments` at index ' + f'{i} was of type {type(point)}, must be {Point}.' + ) + raise TypeError(msg) + self._attachments = tuple(attachments) + + @property + def length(self): + """Exact analytical expression for the pathway's length.""" + length = S.Zero + attachment_pairs = zip(self.attachments[:-1], self.attachments[1:]) + for attachment_pair in attachment_pairs: + length += _point_pair_length(*attachment_pair) + return length + + @property + def extension_velocity(self): + """Exact analytical expression for the pathway's extension velocity.""" + extension_velocity = S.Zero + attachment_pairs = zip(self.attachments[:-1], self.attachments[1:]) + for attachment_pair in attachment_pairs: + extension_velocity += _point_pair_extension_velocity(*attachment_pair) + return extension_velocity + + def to_loads(self, force): + """Loads required by the equations of motion method classes. + + Explanation + =========== + + ``KanesMethod`` requires a list of ``Point``-``Vector`` tuples to be + passed to the ``loads`` parameters of its ``kanes_equations`` method + when constructing the equations of motion. This method acts as a + utility to produce the correctly-structred pairs of points and vectors + required so that these can be easily concatenated with other items in + the list of loads and passed to ``KanesMethod.kanes_equations``. These + loads are also in the correct form to also be passed to the other + equations of motion method classes, e.g. ``LagrangesMethod``. + + Examples + ======== + + The below example shows how to generate the loads produced in an + actuator that follows an obstacle-set pathway between four points and + produces an expansile force ``F``. First, create a pair of reference + frames, ``A`` and ``B``, in which the four points ``pA``, ``pB``, + ``pC``, and ``pD`` will be located. The first two points in frame ``A`` + and the second two in frame ``B``. Frame ``B`` will also be oriented + such that it relates to ``A`` via a rotation of ``q`` about an axis + ``N.z`` in a global frame (``N.z``, ``A.z``, and ``B.z`` are parallel). + + >>> from sympy.physics.mechanics import (ObstacleSetPathway, Point, + ... ReferenceFrame) + >>> from sympy.physics.vector import dynamicsymbols + >>> q = dynamicsymbols('q') + >>> N = ReferenceFrame('N') + >>> N = ReferenceFrame('N') + >>> A = N.orientnew('A', 'axis', (0, N.x)) + >>> B = A.orientnew('B', 'axis', (q, N.z)) + >>> pO = Point('pO') + >>> pA, pB, pC, pD = Point('pA'), Point('pB'), Point('pC'), Point('pD') + >>> pA.set_pos(pO, A.x) + >>> pB.set_pos(pO, -A.y) + >>> pC.set_pos(pO, B.y) + >>> pD.set_pos(pO, B.x) + >>> obstacle_set_pathway = ObstacleSetPathway(pA, pB, pC, pD) + + Now create a symbol ``F`` to describe the magnitude of the (expansile) + force that will be produced along the pathway. The list of loads that + ``KanesMethod`` requires can be produced by calling the pathway's + ``to_loads`` method with ``F`` passed as the only argument. + + >>> from sympy import Symbol + >>> F = Symbol('F') + >>> obstacle_set_pathway.to_loads(F) + [(pA, sqrt(2)*F/2*A.x + sqrt(2)*F/2*A.y), + (pB, - sqrt(2)*F/2*A.x - sqrt(2)*F/2*A.y), + (pB, - F/sqrt(2*cos(q(t)) + 2)*A.y - F/sqrt(2*cos(q(t)) + 2)*B.y), + (pC, F/sqrt(2*cos(q(t)) + 2)*A.y + F/sqrt(2*cos(q(t)) + 2)*B.y), + (pC, - sqrt(2)*F/2*B.x + sqrt(2)*F/2*B.y), + (pD, sqrt(2)*F/2*B.x - sqrt(2)*F/2*B.y)] + + Parameters + ========== + + force : Expr + The force acting along the length of the pathway. It is assumed + that this ``Expr`` represents an expansile force. + + """ + loads = [] + attachment_pairs = zip(self.attachments[:-1], self.attachments[1:]) + for attachment_pair in attachment_pairs: + relative_position = _point_pair_relative_position(*attachment_pair) + length = _point_pair_length(*attachment_pair) + loads.extend([ + Force(attachment_pair[0], -force*relative_position/length), + Force(attachment_pair[1], force*relative_position/length), + ]) + return loads + + +class WrappingPathway(PathwayBase): + """Pathway that wraps a geometry object. + + Explanation + =========== + + A wrapping pathway interacts with a geometry object and forms a path that + wraps smoothly along its surface. The wrapping pathway along the geometry + object will be the geodesic that the geometry object defines based on the + two points. It will not interact with any other objects in the system, i.e. + a ``WrappingPathway`` will intersect other objects to ensure that the path + between its two ends (its attachments) is the shortest possible. + + To explain the sign conventions used for pathway length, extension + velocity, and direction of applied forces, we can ignore the geometry with + which the wrapping pathway interacts. A wrapping pathway is made up of two + points that can move relative to each other, and a pair of equal and + opposite forces acting on the points. If the positive time-varying + Euclidean distance between the two points is defined, then the "extension + velocity" is the time derivative of this distance. The extension velocity + is positive when the two points are moving away from each other and + negative when moving closer to each other. The direction for the force + acting on either point is determined by constructing a unit vector directed + from the other point to this point. This establishes a sign convention such + that a positive force magnitude tends to push the points apart. The + following diagram shows the positive force sense and the distance between + the points:: + + P Q + o<--- F --->o + | | + |<--l(t)--->| + + Examples + ======== + + >>> from sympy.physics.mechanics import WrappingPathway + + To construct a wrapping pathway, like other pathways, a pair of points must + be passed, followed by an instance of a wrapping geometry class as a + keyword argument. We'll use a cylinder with radius ``r`` and its axis + parallel to ``N.x`` passing through a point ``pO``. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import Point, ReferenceFrame, WrappingCylinder + >>> r = symbols('r') + >>> N = ReferenceFrame('N') + >>> pA, pB, pO = Point('pA'), Point('pB'), Point('pO') + >>> cylinder = WrappingCylinder(r, pO, N.x) + >>> wrapping_pathway = WrappingPathway(pA, pB, cylinder) + >>> wrapping_pathway + WrappingPathway(pA, pB, geometry=WrappingCylinder(radius=r, point=pO, + axis=N.x)) + + Parameters + ========== + + attachment_1 : Point + First of the pair of ``Point`` objects between which the wrapping + pathway spans. + attachment_2 : Point + Second of the pair of ``Point`` objects between which the wrapping + pathway spans. + geometry : WrappingGeometryBase + Geometry about which the pathway wraps. + + """ + + def __init__(self, attachment_1, attachment_2, geometry): + """Initializer for ``WrappingPathway``. + + Parameters + ========== + + attachment_1 : Point + First of the pair of ``Point`` objects between which the wrapping + pathway spans. + attachment_2 : Point + Second of the pair of ``Point`` objects between which the wrapping + pathway spans. + geometry : WrappingGeometryBase + Geometry about which the pathway wraps. + The geometry about which the pathway wraps. + + """ + super().__init__(attachment_1, attachment_2) + self.geometry = geometry + + @property + def geometry(self): + """Geometry around which the pathway wraps.""" + return self._geometry + + @geometry.setter + def geometry(self, geometry): + if hasattr(self, '_geometry'): + msg = ( + f'Can\'t set attribute `geometry` to {repr(geometry)} as it ' + f'is immutable.' + ) + raise AttributeError(msg) + if not isinstance(geometry, WrappingGeometryBase): + msg = ( + f'Value {repr(geometry)} passed to `geometry` was of type ' + f'{type(geometry)}, must be {WrappingGeometryBase}.' + ) + raise TypeError(msg) + self._geometry = geometry + + @property + def length(self): + """Exact analytical expression for the pathway's length.""" + return self.geometry.geodesic_length(*self.attachments) + + @property + def extension_velocity(self): + """Exact analytical expression for the pathway's extension velocity.""" + return self.length.diff(dynamicsymbols._t) + + def to_loads(self, force): + """Loads required by the equations of motion method classes. + + Explanation + =========== + + ``KanesMethod`` requires a list of ``Point``-``Vector`` tuples to be + passed to the ``loads`` parameters of its ``kanes_equations`` method + when constructing the equations of motion. This method acts as a + utility to produce the correctly-structred pairs of points and vectors + required so that these can be easily concatenated with other items in + the list of loads and passed to ``KanesMethod.kanes_equations``. These + loads are also in the correct form to also be passed to the other + equations of motion method classes, e.g. ``LagrangesMethod``. + + Examples + ======== + + The below example shows how to generate the loads produced in an + actuator that produces an expansile force ``F`` while wrapping around a + cylinder. First, create a cylinder with radius ``r`` and an axis + parallel to the ``N.z`` direction of the global frame ``N`` that also + passes through a point ``pO``. + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import (Point, ReferenceFrame, + ... WrappingCylinder) + >>> N = ReferenceFrame('N') + >>> r = symbols('r', positive=True) + >>> pO = Point('pO') + >>> cylinder = WrappingCylinder(r, pO, N.z) + + Create the pathway of the actuator using the ``WrappingPathway`` class, + defined to span between two points ``pA`` and ``pB``. Both points lie + on the surface of the cylinder and the location of ``pB`` is defined + relative to ``pA`` by the dynamics symbol ``q``. + + >>> from sympy import cos, sin + >>> from sympy.physics.mechanics import WrappingPathway, dynamicsymbols + >>> q = dynamicsymbols('q') + >>> pA = Point('pA') + >>> pB = Point('pB') + >>> pA.set_pos(pO, r*N.x) + >>> pB.set_pos(pO, r*(cos(q)*N.x + sin(q)*N.y)) + >>> pB.pos_from(pA) + (r*cos(q(t)) - r)*N.x + r*sin(q(t))*N.y + >>> pathway = WrappingPathway(pA, pB, cylinder) + + Now create a symbol ``F`` to describe the magnitude of the (expansile) + force that will be produced along the pathway. The list of loads that + ``KanesMethod`` requires can be produced by calling the pathway's + ``to_loads`` method with ``F`` passed as the only argument. + + >>> F = symbols('F') + >>> loads = pathway.to_loads(F) + >>> [load.__class__(load.location, load.vector.simplify()) for load in loads] + [(pA, F*N.y), (pB, F*sin(q(t))*N.x - F*cos(q(t))*N.y), + (pO, - F*sin(q(t))*N.x + F*(cos(q(t)) - 1)*N.y)] + + Parameters + ========== + + force : Expr + Magnitude of the force acting along the length of the pathway. It + is assumed that this ``Expr`` represents an expansile force. + + """ + pA, pB = self.attachments + pO = self.geometry.point + pA_force, pB_force = self.geometry.geodesic_end_vectors(pA, pB) + pO_force = -(pA_force + pB_force) + + loads = [ + Force(pA, force * pA_force), + Force(pB, force * pB_force), + Force(pO, force * pO_force), + ] + return loads + + def __repr__(self): + """Representation of a ``WrappingPathway``.""" + attachments = ', '.join(str(a) for a in self.attachments) + return ( + f'{self.__class__.__name__}({attachments}, ' + f'geometry={self.geometry})' + ) + + +def _point_pair_relative_position(point_1, point_2): + """The relative position between a pair of points.""" + return point_2.pos_from(point_1) + + +def _point_pair_length(point_1, point_2): + """The length of the direct linear path between two points.""" + return _point_pair_relative_position(point_1, point_2).magnitude() + + +def _point_pair_extension_velocity(point_1, point_2): + """The extension velocity of the direct linear path between two points.""" + return _point_pair_length(point_1, point_2).diff(dynamicsymbols._t) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/system.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/system.py new file mode 100644 index 0000000000000000000000000000000000000000..c8e0657d7da54ca5aaad9b37b816235641968470 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/system.py @@ -0,0 +1,1553 @@ +from functools import wraps + +from sympy.core.basic import Basic +from sympy.matrices.immutable import ImmutableMatrix +from sympy.matrices.dense import Matrix, eye, zeros +from sympy.core.containers import OrderedSet +from sympy.physics.mechanics.actuator import ActuatorBase +from sympy.physics.mechanics.body_base import BodyBase +from sympy.physics.mechanics.functions import ( + Lagrangian, _validate_coordinates, find_dynamicsymbols) +from sympy.physics.mechanics.joint import Joint +from sympy.physics.mechanics.kane import KanesMethod +from sympy.physics.mechanics.lagrange import LagrangesMethod +from sympy.physics.mechanics.loads import _parse_load, gravity +from sympy.physics.mechanics.method import _Methods +from sympy.physics.mechanics.particle import Particle +from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols +from sympy.utilities.iterables import iterable +from sympy.utilities.misc import filldedent + +__all__ = ['SymbolicSystem', 'System'] + + +def _reset_eom_method(method): + """Decorator to reset the eom_method if a property is changed.""" + + @wraps(method) + def wrapper(self, *args, **kwargs): + self._eom_method = None + return method(self, *args, **kwargs) + + return wrapper + + +class System(_Methods): + """Class to define a multibody system and form its equations of motion. + + Explanation + =========== + + A ``System`` instance stores the different objects associated with a model, + including bodies, joints, constraints, and other relevant information. With + all the relationships between components defined, the ``System`` can be used + to form the equations of motion using a backend, such as ``KanesMethod``. + The ``System`` has been designed to be compatible with third-party + libraries for greater flexibility and integration with other tools. + + Attributes + ========== + + frame : ReferenceFrame + Inertial reference frame of the system. + fixed_point : Point + A fixed point in the inertial reference frame. + x : Vector + Unit vector fixed in the inertial reference frame. + y : Vector + Unit vector fixed in the inertial reference frame. + z : Vector + Unit vector fixed in the inertial reference frame. + q : ImmutableMatrix + Matrix of all the generalized coordinates, i.e. the independent + generalized coordinates stacked upon the dependent. + u : ImmutableMatrix + Matrix of all the generalized speeds, i.e. the independent generealized + speeds stacked upon the dependent. + q_ind : ImmutableMatrix + Matrix of the independent generalized coordinates. + q_dep : ImmutableMatrix + Matrix of the dependent generalized coordinates. + u_ind : ImmutableMatrix + Matrix of the independent generalized speeds. + u_dep : ImmutableMatrix + Matrix of the dependent generalized speeds. + u_aux : ImmutableMatrix + Matrix of auxiliary generalized speeds. + kdes : ImmutableMatrix + Matrix of the kinematical differential equations as expressions equated + to the zero matrix. + bodies : tuple of BodyBase subclasses + Tuple of all bodies that make up the system. + joints : tuple of Joint + Tuple of all joints that connect bodies in the system. + loads : tuple of LoadBase subclasses + Tuple of all loads that have been applied to the system. + actuators : tuple of ActuatorBase subclasses + Tuple of all actuators present in the system. + holonomic_constraints : ImmutableMatrix + Matrix with the holonomic constraints as expressions equated to the zero + matrix. + nonholonomic_constraints : ImmutableMatrix + Matrix with the nonholonomic constraints as expressions equated to the + zero matrix. + velocity_constraints : ImmutableMatrix + Matrix with the velocity constraints as expressions equated to the zero + matrix. These are by default derived as the time derivatives of the + holonomic constraints extended with the nonholonomic constraints. + eom_method : subclass of KanesMethod or LagrangesMethod + Backend for forming the equations of motion. + + Examples + ======== + + In the example below a cart with a pendulum is created. The cart moves along + the x axis of the rail and the pendulum rotates about the z axis. The length + of the pendulum is ``l`` with the pendulum represented as a particle. To + move the cart a time dependent force ``F`` is applied to the cart. + + We first need to import some functions and create some of our variables. + + >>> from sympy import symbols, simplify + >>> from sympy.physics.mechanics import ( + ... mechanics_printing, dynamicsymbols, RigidBody, Particle, + ... ReferenceFrame, PrismaticJoint, PinJoint, System) + >>> mechanics_printing(pretty_print=False) + >>> g, l = symbols('g l') + >>> F = dynamicsymbols('F') + + The next step is to create bodies. It is also useful to create a frame for + locating the particle with respect to the pin joint later on, as a particle + does not have a body-fixed frame. + + >>> rail = RigidBody('rail') + >>> cart = RigidBody('cart') + >>> bob = Particle('bob') + >>> bob_frame = ReferenceFrame('bob_frame') + + Initialize the system, with the rail as the Newtonian reference. The body is + also automatically added to the system. + + >>> system = System.from_newtonian(rail) + >>> print(system.bodies[0]) + rail + + Create the joints, while immediately also adding them to the system. + + >>> system.add_joints( + ... PrismaticJoint('slider', rail, cart, joint_axis=rail.x), + ... PinJoint('pin', cart, bob, joint_axis=cart.z, + ... child_interframe=bob_frame, + ... child_point=l * bob_frame.y) + ... ) + >>> system.joints + (PrismaticJoint: slider parent: rail child: cart, + PinJoint: pin parent: cart child: bob) + + While adding the joints, the associated generalized coordinates, generalized + speeds, kinematic differential equations and bodies are also added to the + system. + + >>> system.q + Matrix([ + [q_slider], + [ q_pin]]) + >>> system.u + Matrix([ + [u_slider], + [ u_pin]]) + >>> system.kdes + Matrix([ + [u_slider - q_slider'], + [ u_pin - q_pin']]) + >>> [body.name for body in system.bodies] + ['rail', 'cart', 'bob'] + + With the kinematics established, we can now apply gravity and the cart force + ``F``. + + >>> system.apply_uniform_gravity(-g * system.y) + >>> system.add_loads((cart.masscenter, F * rail.x)) + >>> system.loads + ((rail_masscenter, - g*rail_mass*rail_frame.y), + (cart_masscenter, - cart_mass*g*rail_frame.y), + (bob_masscenter, - bob_mass*g*rail_frame.y), + (cart_masscenter, F*rail_frame.x)) + + With the entire system defined, we can now form the equations of motion. + Before forming the equations of motion, one can also run some checks that + will try to identify some common errors. + + >>> system.validate_system() + >>> system.form_eoms() + Matrix([ + [bob_mass*l*u_pin**2*sin(q_pin) - bob_mass*l*cos(q_pin)*u_pin' + - (bob_mass + cart_mass)*u_slider' + F], + [ -bob_mass*g*l*sin(q_pin) - bob_mass*l**2*u_pin' + - bob_mass*l*cos(q_pin)*u_slider']]) + >>> simplify(system.mass_matrix) + Matrix([ + [ bob_mass + cart_mass, bob_mass*l*cos(q_pin)], + [bob_mass*l*cos(q_pin), bob_mass*l**2]]) + >>> system.forcing + Matrix([ + [bob_mass*l*u_pin**2*sin(q_pin) + F], + [ -bob_mass*g*l*sin(q_pin)]]) + + The complexity of the above example can be increased if we add a constraint + to prevent the particle from moving in the horizontal (x) direction. This + can be done by adding a holonomic constraint. After which we should also + redefine what our (in)dependent generalized coordinates and speeds are. + + >>> system.add_holonomic_constraints( + ... bob.masscenter.pos_from(rail.masscenter).dot(system.x) + ... ) + >>> system.q_ind = system.get_joint('pin').coordinates + >>> system.q_dep = system.get_joint('slider').coordinates + >>> system.u_ind = system.get_joint('pin').speeds + >>> system.u_dep = system.get_joint('slider').speeds + + With the updated system the equations of motion can be formed again. + + >>> system.validate_system() + >>> system.form_eoms() + Matrix([[-bob_mass*g*l*sin(q_pin) + - bob_mass*l**2*u_pin' + - bob_mass*l*cos(q_pin)*u_slider' + - l*(bob_mass*l*u_pin**2*sin(q_pin) + - bob_mass*l*cos(q_pin)*u_pin' + - (bob_mass + cart_mass)*u_slider')*cos(q_pin) + - l*F*cos(q_pin)]]) + >>> simplify(system.mass_matrix) + Matrix([ + [bob_mass*l**2*sin(q_pin)**2, -cart_mass*l*cos(q_pin)], + [ l*cos(q_pin), 1]]) + >>> simplify(system.forcing) + Matrix([ + [-l*(bob_mass*g*sin(q_pin) + bob_mass*l*u_pin**2*sin(2*q_pin)/2 + + F*cos(q_pin))], + [ + l*u_pin**2*sin(q_pin)]]) + + """ + + def __init__(self, frame=None, fixed_point=None): + """Initialize the system. + + Parameters + ========== + + frame : ReferenceFrame, optional + The inertial frame of the system. If none is supplied, a new frame + will be created. + fixed_point : Point, optional + A fixed point in the inertial reference frame. If none is supplied, + a new fixed_point will be created. + + """ + if frame is None: + frame = ReferenceFrame('inertial_frame') + elif not isinstance(frame, ReferenceFrame): + raise TypeError('Frame must be an instance of ReferenceFrame.') + self._frame = frame + if fixed_point is None: + fixed_point = Point('inertial_point') + elif not isinstance(fixed_point, Point): + raise TypeError('Fixed point must be an instance of Point.') + self._fixed_point = fixed_point + self._fixed_point.set_vel(self._frame, 0) + self._q_ind = ImmutableMatrix(1, 0, []).T + self._q_dep = ImmutableMatrix(1, 0, []).T + self._u_ind = ImmutableMatrix(1, 0, []).T + self._u_dep = ImmutableMatrix(1, 0, []).T + self._u_aux = ImmutableMatrix(1, 0, []).T + self._kdes = ImmutableMatrix(1, 0, []).T + self._hol_coneqs = ImmutableMatrix(1, 0, []).T + self._nonhol_coneqs = ImmutableMatrix(1, 0, []).T + self._vel_constrs = None + self._bodies = [] + self._joints = [] + self._loads = [] + self._actuators = [] + self._eom_method = None + + @classmethod + def from_newtonian(cls, newtonian): + """Constructs the system with respect to a Newtonian body.""" + if isinstance(newtonian, Particle): + raise TypeError('A Particle has no frame so cannot act as ' + 'the Newtonian.') + system = cls(frame=newtonian.frame, fixed_point=newtonian.masscenter) + system.add_bodies(newtonian) + return system + + @property + def fixed_point(self): + """Fixed point in the inertial reference frame.""" + return self._fixed_point + + @property + def frame(self): + """Inertial reference frame of the system.""" + return self._frame + + @property + def x(self): + """Unit vector fixed in the inertial reference frame.""" + return self._frame.x + + @property + def y(self): + """Unit vector fixed in the inertial reference frame.""" + return self._frame.y + + @property + def z(self): + """Unit vector fixed in the inertial reference frame.""" + return self._frame.z + + @property + def bodies(self): + """Tuple of all bodies that have been added to the system.""" + return tuple(self._bodies) + + @bodies.setter + @_reset_eom_method + def bodies(self, bodies): + bodies = self._objects_to_list(bodies) + self._check_objects(bodies, [], BodyBase, 'Bodies', 'bodies') + self._bodies = bodies + + @property + def joints(self): + """Tuple of all joints that have been added to the system.""" + return tuple(self._joints) + + @joints.setter + @_reset_eom_method + def joints(self, joints): + joints = self._objects_to_list(joints) + self._check_objects(joints, [], Joint, 'Joints', 'joints') + self._joints = [] + self.add_joints(*joints) + + @property + def loads(self): + """Tuple of loads that have been applied on the system.""" + return tuple(self._loads) + + @loads.setter + @_reset_eom_method + def loads(self, loads): + loads = self._objects_to_list(loads) + self._loads = [_parse_load(load) for load in loads] + + @property + def actuators(self): + """Tuple of actuators present in the system.""" + return tuple(self._actuators) + + @actuators.setter + @_reset_eom_method + def actuators(self, actuators): + actuators = self._objects_to_list(actuators) + self._check_objects(actuators, [], ActuatorBase, 'Actuators', + 'actuators') + self._actuators = actuators + + @property + def q(self): + """Matrix of all the generalized coordinates with the independent + stacked upon the dependent.""" + return self._q_ind.col_join(self._q_dep) + + @property + def u(self): + """Matrix of all the generalized speeds with the independent stacked + upon the dependent.""" + return self._u_ind.col_join(self._u_dep) + + @property + def q_ind(self): + """Matrix of the independent generalized coordinates.""" + return self._q_ind + + @q_ind.setter + @_reset_eom_method + def q_ind(self, q_ind): + self._q_ind, self._q_dep = self._parse_coordinates( + self._objects_to_list(q_ind), True, [], self.q_dep, 'coordinates') + + @property + def q_dep(self): + """Matrix of the dependent generalized coordinates.""" + return self._q_dep + + @q_dep.setter + @_reset_eom_method + def q_dep(self, q_dep): + self._q_ind, self._q_dep = self._parse_coordinates( + self._objects_to_list(q_dep), False, self.q_ind, [], 'coordinates') + + @property + def u_ind(self): + """Matrix of the independent generalized speeds.""" + return self._u_ind + + @u_ind.setter + @_reset_eom_method + def u_ind(self, u_ind): + self._u_ind, self._u_dep = self._parse_coordinates( + self._objects_to_list(u_ind), True, [], self.u_dep, 'speeds') + + @property + def u_dep(self): + """Matrix of the dependent generalized speeds.""" + return self._u_dep + + @u_dep.setter + @_reset_eom_method + def u_dep(self, u_dep): + self._u_ind, self._u_dep = self._parse_coordinates( + self._objects_to_list(u_dep), False, self.u_ind, [], 'speeds') + + @property + def u_aux(self): + """Matrix of auxiliary generalized speeds.""" + return self._u_aux + + @u_aux.setter + @_reset_eom_method + def u_aux(self, u_aux): + self._u_aux = self._parse_coordinates( + self._objects_to_list(u_aux), True, [], [], 'u_auxiliary')[0] + + @property + def kdes(self): + """Kinematical differential equations as expressions equated to the zero + matrix. These equations describe the coupling between the generalized + coordinates and the generalized speeds.""" + return self._kdes + + @kdes.setter + @_reset_eom_method + def kdes(self, kdes): + kdes = self._objects_to_list(kdes) + self._kdes = self._parse_expressions( + kdes, [], 'kinematic differential equations') + + @property + def holonomic_constraints(self): + """Matrix with the holonomic constraints as expressions equated to the + zero matrix.""" + return self._hol_coneqs + + @holonomic_constraints.setter + @_reset_eom_method + def holonomic_constraints(self, constraints): + constraints = self._objects_to_list(constraints) + self._hol_coneqs = self._parse_expressions( + constraints, [], 'holonomic constraints') + + @property + def nonholonomic_constraints(self): + """Matrix with the nonholonomic constraints as expressions equated to + the zero matrix.""" + return self._nonhol_coneqs + + @nonholonomic_constraints.setter + @_reset_eom_method + def nonholonomic_constraints(self, constraints): + constraints = self._objects_to_list(constraints) + self._nonhol_coneqs = self._parse_expressions( + constraints, [], 'nonholonomic constraints') + + @property + def velocity_constraints(self): + """Matrix with the velocity constraints as expressions equated to the + zero matrix. The velocity constraints are by default derived from the + holonomic and nonholonomic constraints unless they are explicitly set. + """ + if self._vel_constrs is None: + return self.holonomic_constraints.diff(dynamicsymbols._t).col_join( + self.nonholonomic_constraints) + return self._vel_constrs + + @velocity_constraints.setter + @_reset_eom_method + def velocity_constraints(self, constraints): + if constraints is None: + self._vel_constrs = None + return + constraints = self._objects_to_list(constraints) + self._vel_constrs = self._parse_expressions( + constraints, [], 'velocity constraints') + + @property + def eom_method(self): + """Backend for forming the equations of motion.""" + return self._eom_method + + @staticmethod + def _objects_to_list(lst): + """Helper to convert passed objects to a list.""" + if not iterable(lst): # Only one object + return [lst] + return list(lst[:]) # converts Matrix and tuple to flattened list + + @staticmethod + def _check_objects(objects, obj_lst, expected_type, obj_name, type_name): + """Helper to check the objects that are being added to the system. + + Explanation + =========== + This method checks that the objects that are being added to the system + are of the correct type and have not already been added. If any of the + objects are not of the correct type or have already been added, then + an error is raised. + + Parameters + ========== + objects : iterable + The objects that would be added to the system. + obj_lst : list + The list of objects that are already in the system. + expected_type : type + The type that the objects should be. + obj_name : str + The name of the category of objects. This string is used to + formulate the error message for the user. + type_name : str + The name of the type that the objects should be. This string is used + to formulate the error message for the user. + + """ + seen = set(obj_lst) + duplicates = set() + wrong_types = set() + for obj in objects: + if not isinstance(obj, expected_type): + wrong_types.add(obj) + if obj in seen: + duplicates.add(obj) + else: + seen.add(obj) + if wrong_types: + raise TypeError(f'{obj_name} {wrong_types} are not {type_name}.') + if duplicates: + raise ValueError(f'{obj_name} {duplicates} have already been added ' + f'to the system.') + + def _parse_coordinates(self, new_coords, independent, old_coords_ind, + old_coords_dep, coord_type='coordinates'): + """Helper to parse coordinates and speeds.""" + # Construct lists of the independent and dependent coordinates + coords_ind, coords_dep = old_coords_ind[:], old_coords_dep[:] + if not iterable(independent): + independent = [independent] * len(new_coords) + for coord, indep in zip(new_coords, independent): + if indep: + coords_ind.append(coord) + else: + coords_dep.append(coord) + # Check types and duplicates + current = {'coordinates': self.q_ind[:] + self.q_dep[:], + 'speeds': self.u_ind[:] + self.u_dep[:], + 'u_auxiliary': self._u_aux[:], + coord_type: coords_ind + coords_dep} + _validate_coordinates(**current) + return (ImmutableMatrix(1, len(coords_ind), coords_ind).T, + ImmutableMatrix(1, len(coords_dep), coords_dep).T) + + @staticmethod + def _parse_expressions(new_expressions, old_expressions, name, + check_negatives=False): + """Helper to parse expressions like constraints.""" + old_expressions = old_expressions[:] + new_expressions = list(new_expressions) # Converts a possible tuple + if check_negatives: + check_exprs = old_expressions + [-expr for expr in old_expressions] + else: + check_exprs = old_expressions + System._check_objects(new_expressions, check_exprs, Basic, name, + 'expressions') + for expr in new_expressions: + if expr == 0: + raise ValueError(f'Parsed {name} are zero.') + return ImmutableMatrix(1, len(old_expressions) + len(new_expressions), + old_expressions + new_expressions).T + + @_reset_eom_method + def add_coordinates(self, *coordinates, independent=True): + """Add generalized coordinate(s) to the system. + + Parameters + ========== + + *coordinates : dynamicsymbols + One or more generalized coordinates to be added to the system. + independent : bool or list of bool, optional + Boolean whether a coordinate is dependent or independent. The + default is True, so the coordinates are added as independent by + default. + + """ + self._q_ind, self._q_dep = self._parse_coordinates( + coordinates, independent, self.q_ind, self.q_dep, 'coordinates') + + @_reset_eom_method + def add_speeds(self, *speeds, independent=True): + """Add generalized speed(s) to the system. + + Parameters + ========== + + *speeds : dynamicsymbols + One or more generalized speeds to be added to the system. + independent : bool or list of bool, optional + Boolean whether a speed is dependent or independent. The default is + True, so the speeds are added as independent by default. + + """ + self._u_ind, self._u_dep = self._parse_coordinates( + speeds, independent, self.u_ind, self.u_dep, 'speeds') + + @_reset_eom_method + def add_auxiliary_speeds(self, *speeds): + """Add auxiliary speed(s) to the system. + + Parameters + ========== + + *speeds : dynamicsymbols + One or more auxiliary speeds to be added to the system. + + """ + self._u_aux = self._parse_coordinates( + speeds, True, self._u_aux, [], 'u_auxiliary')[0] + + @_reset_eom_method + def add_kdes(self, *kdes): + """Add kinematic differential equation(s) to the system. + + Parameters + ========== + + *kdes : Expr + One or more kinematic differential equations. + + """ + self._kdes = self._parse_expressions( + kdes, self.kdes, 'kinematic differential equations', + check_negatives=True) + + @_reset_eom_method + def add_holonomic_constraints(self, *constraints): + """Add holonomic constraint(s) to the system. + + Parameters + ========== + + *constraints : Expr + One or more holonomic constraints, which are expressions that should + be zero. + + """ + self._hol_coneqs = self._parse_expressions( + constraints, self._hol_coneqs, 'holonomic constraints', + check_negatives=True) + + @_reset_eom_method + def add_nonholonomic_constraints(self, *constraints): + """Add nonholonomic constraint(s) to the system. + + Parameters + ========== + + *constraints : Expr + One or more nonholonomic constraints, which are expressions that + should be zero. + + """ + self._nonhol_coneqs = self._parse_expressions( + constraints, self._nonhol_coneqs, 'nonholonomic constraints', + check_negatives=True) + + @_reset_eom_method + def add_bodies(self, *bodies): + """Add body(ies) to the system. + + Parameters + ========== + + bodies : Particle or RigidBody + One or more bodies. + + """ + self._check_objects(bodies, self.bodies, BodyBase, 'Bodies', 'bodies') + self._bodies.extend(bodies) + + @_reset_eom_method + def add_loads(self, *loads): + """Add load(s) to the system. + + Parameters + ========== + + *loads : Force or Torque + One or more loads. + + """ + loads = [_parse_load(load) for load in loads] # Checks the loads + self._loads.extend(loads) + + @_reset_eom_method + def apply_uniform_gravity(self, acceleration): + """Apply uniform gravity to all bodies in the system by adding loads. + + Parameters + ========== + + acceleration : Vector + The acceleration due to gravity. + + """ + self.add_loads(*gravity(acceleration, *self.bodies)) + + @_reset_eom_method + def add_actuators(self, *actuators): + """Add actuator(s) to the system. + + Parameters + ========== + + *actuators : subclass of ActuatorBase + One or more actuators. + + """ + self._check_objects(actuators, self.actuators, ActuatorBase, + 'Actuators', 'actuators') + self._actuators.extend(actuators) + + @_reset_eom_method + def add_joints(self, *joints): + """Add joint(s) to the system. + + Explanation + =========== + + This methods adds one or more joints to the system including its + associated objects, i.e. generalized coordinates, generalized speeds, + kinematic differential equations and the bodies. + + Parameters + ========== + + *joints : subclass of Joint + One or more joints. + + Notes + ===== + + For the generalized coordinates, generalized speeds and bodies it is + checked whether they are already known by the system instance. If they + are, then they are not added. The kinematic differential equations are + however always added to the system, so you should not also manually add + those on beforehand. + + """ + self._check_objects(joints, self.joints, Joint, 'Joints', 'joints') + self._joints.extend(joints) + coordinates, speeds, kdes, bodies = (OrderedSet() for _ in range(4)) + for joint in joints: + coordinates.update(joint.coordinates) + speeds.update(joint.speeds) + kdes.update(joint.kdes) + bodies.update((joint.parent, joint.child)) + coordinates = coordinates.difference(self.q) + speeds = speeds.difference(self.u) + kdes = kdes.difference(self.kdes[:] + (-self.kdes)[:]) + bodies = bodies.difference(self.bodies) + self.add_coordinates(*tuple(coordinates)) + self.add_speeds(*tuple(speeds)) + self.add_kdes(*(kde for kde in tuple(kdes) if not kde == 0)) + self.add_bodies(*tuple(bodies)) + + def get_body(self, name): + """Retrieve a body from the system by name. + + Parameters + ========== + + name : str + The name of the body to retrieve. + + Returns + ======= + + RigidBody or Particle + The body with the given name, or None if no such body exists. + + """ + for body in self._bodies: + if body.name == name: + return body + + def get_joint(self, name): + """Retrieve a joint from the system by name. + + Parameters + ========== + + name : str + The name of the joint to retrieve. + + Returns + ======= + + subclass of Joint + The joint with the given name, or None if no such joint exists. + + """ + for joint in self._joints: + if joint.name == name: + return joint + + def _form_eoms(self): + return self.form_eoms() + + def form_eoms(self, eom_method=KanesMethod, **kwargs): + """Form the equations of motion of the system. + + Parameters + ========== + + eom_method : subclass of KanesMethod or LagrangesMethod + Backend class to be used for forming the equations of motion. The + default is ``KanesMethod``. + + Returns + ======== + + ImmutableMatrix + Vector of equations of motions. + + Examples + ======== + + This is a simple example for a one degree of freedom translational + spring-mass-damper. + + >>> from sympy import S, symbols + >>> from sympy.physics.mechanics import ( + ... LagrangesMethod, dynamicsymbols, PrismaticJoint, Particle, + ... RigidBody, System) + >>> q = dynamicsymbols('q') + >>> qd = dynamicsymbols('q', 1) + >>> m, k, b = symbols('m k b') + >>> wall = RigidBody('W') + >>> system = System.from_newtonian(wall) + >>> bob = Particle('P', mass=m) + >>> bob.potential_energy = S.Half * k * q**2 + >>> system.add_joints(PrismaticJoint('J', wall, bob, q, qd)) + >>> system.add_loads((bob.masscenter, b * qd * system.x)) + >>> system.form_eoms(LagrangesMethod) + Matrix([[-b*Derivative(q(t), t) + k*q(t) + m*Derivative(q(t), (t, 2))]]) + + We can also solve for the states using the 'rhs' method. + + >>> system.rhs() + Matrix([ + [ Derivative(q(t), t)], + [(b*Derivative(q(t), t) - k*q(t))/m]]) + + """ + # KanesMethod does not accept empty iterables + loads = self.loads + tuple( + load for act in self.actuators for load in act.to_loads()) + loads = loads if loads else None + if issubclass(eom_method, KanesMethod): + disallowed_kwargs = { + "frame", "q_ind", "u_ind", "kd_eqs", "q_dependent", + "u_dependent", "u_auxiliary", "configuration_constraints", + "velocity_constraints", "forcelist", "bodies"} + wrong_kwargs = disallowed_kwargs.intersection(kwargs) + if wrong_kwargs: + raise ValueError( + f"The following keyword arguments are not allowed to be " + f"overwritten in {eom_method.__name__}: {wrong_kwargs}.") + kwargs = {"frame": self.frame, "q_ind": self.q_ind, + "u_ind": self.u_ind, "kd_eqs": self.kdes, + "q_dependent": self.q_dep, "u_dependent": self.u_dep, + "configuration_constraints": self.holonomic_constraints, + "velocity_constraints": self.velocity_constraints, + "u_auxiliary": self.u_aux, + "forcelist": loads, "bodies": self.bodies, + "explicit_kinematics": False, **kwargs} + self._eom_method = eom_method(**kwargs) + elif issubclass(eom_method, LagrangesMethod): + disallowed_kwargs = { + "frame", "qs", "forcelist", "bodies", "hol_coneqs", + "nonhol_coneqs", "Lagrangian"} + wrong_kwargs = disallowed_kwargs.intersection(kwargs) + if wrong_kwargs: + raise ValueError( + f"The following keyword arguments are not allowed to be " + f"overwritten in {eom_method.__name__}: {wrong_kwargs}.") + kwargs = {"frame": self.frame, "qs": self.q, "forcelist": loads, + "bodies": self.bodies, + "hol_coneqs": self.holonomic_constraints, + "nonhol_coneqs": self.nonholonomic_constraints, **kwargs} + if "Lagrangian" not in kwargs: + kwargs["Lagrangian"] = Lagrangian(kwargs["frame"], + *kwargs["bodies"]) + self._eom_method = eom_method(**kwargs) + else: + raise NotImplementedError(f'{eom_method} has not been implemented.') + return self.eom_method._form_eoms() + + def rhs(self, inv_method=None): + """Compute the equations of motion in the explicit form. + + Parameters + ========== + + inv_method : str + The specific sympy inverse matrix calculation method to use. For a + list of valid methods, see + :meth:`~sympy.matrices.matrixbase.MatrixBase.inv` + + Returns + ======== + + ImmutableMatrix + Equations of motion in the explicit form. + + See Also + ======== + + sympy.physics.mechanics.kane.KanesMethod.rhs: + KanesMethod's ``rhs`` function. + sympy.physics.mechanics.lagrange.LagrangesMethod.rhs: + LagrangesMethod's ``rhs`` function. + + """ + return self.eom_method.rhs(inv_method=inv_method) + + @property + def mass_matrix(self): + r"""The mass matrix of the system. + + Explanation + =========== + + The mass matrix $M_d$ and the forcing vector $f_d$ of a system describe + the system's dynamics according to the following equations: + + .. math:: + M_d \dot{u} = f_d + + where $\dot{u}$ is the time derivative of the generalized speeds. + + """ + return self.eom_method.mass_matrix + + @property + def mass_matrix_full(self): + r"""The mass matrix of the system, augmented by the kinematic + differential equations in explicit or implicit form. + + Explanation + =========== + + The full mass matrix $M_m$ and the full forcing vector $f_m$ of a system + describe the dynamics and kinematics according to the following + equation: + + .. math:: + M_m \dot{x} = f_m + + where $x$ is the state vector stacking $q$ and $u$. + + """ + return self.eom_method.mass_matrix_full + + @property + def forcing(self): + """The forcing vector of the system.""" + return self.eom_method.forcing + + @property + def forcing_full(self): + """The forcing vector of the system, augmented by the kinematic + differential equations in explicit or implicit form.""" + return self.eom_method.forcing_full + + def validate_system(self, eom_method=KanesMethod, check_duplicates=False): + """Validates the system using some basic checks. + + Explanation + =========== + + This method validates the system based on the following checks: + + - The number of dependent generalized coordinates should equal the + number of holonomic constraints. + - All generalized coordinates defined by the joints should also be known + to the system. + - If ``KanesMethod`` is used as a ``eom_method``: + - All generalized speeds and kinematic differential equations + defined by the joints should also be known to the system. + - The number of dependent generalized speeds should equal the number + of velocity constraints. + - The number of generalized coordinates should be less than or equal + to the number of generalized speeds. + - The number of generalized coordinates should equal the number of + kinematic differential equations. + - If ``LagrangesMethod`` is used as ``eom_method``: + - There should not be any generalized speeds that are not + derivatives of the generalized coordinates (this includes the + generalized speeds defined by the joints). + + Parameters + ========== + + eom_method : subclass of KanesMethod or LagrangesMethod + Backend class that will be used for forming the equations of motion. + There are different checks for the different backends. The default + is ``KanesMethod``. + check_duplicates : bool + Boolean whether the system should be checked for duplicate + definitions. The default is False, because duplicates are already + checked when adding objects to the system. + + Notes + ===== + + This method is not guaranteed to be backwards compatible as it may + improve over time. The method can become both more and less strict in + certain areas. However a well-defined system should always pass all + these tests. + + """ + msgs = [] + # Save some data in variables + n_hc = self.holonomic_constraints.shape[0] + n_vc = self.velocity_constraints.shape[0] + n_q_dep, n_u_dep = self.q_dep.shape[0], self.u_dep.shape[0] + q_set, u_set = set(self.q), set(self.u) + n_q, n_u = len(q_set), len(u_set) + # Check number of holonomic constraints + if n_q_dep != n_hc: + msgs.append(filldedent(f""" + The number of dependent generalized coordinates {n_q_dep} should be + equal to the number of holonomic constraints {n_hc}.""")) + # Check if all joint coordinates and speeds are present + missing_q = set() + for joint in self.joints: + missing_q.update(set(joint.coordinates).difference(q_set)) + if missing_q: + msgs.append(filldedent(f""" + The generalized coordinates {missing_q} used in joints are not added + to the system.""")) + # Method dependent checks + if issubclass(eom_method, KanesMethod): + n_kdes = len(self.kdes) + missing_kdes, missing_u = set(), set() + for joint in self.joints: + missing_u.update(set(joint.speeds).difference(u_set)) + missing_kdes.update(set(joint.kdes).difference( + self.kdes[:] + (-self.kdes)[:])) + if missing_u: + msgs.append(filldedent(f""" + The generalized speeds {missing_u} used in joints are not added + to the system.""")) + if missing_kdes: + msgs.append(filldedent(f""" + The kinematic differential equations {missing_kdes} used in + joints are not added to the system.""")) + if n_u_dep != n_vc: + msgs.append(filldedent(f""" + The number of dependent generalized speeds {n_u_dep} should be + equal to the number of velocity constraints {n_vc}.""")) + if n_q > n_u: + msgs.append(filldedent(f""" + The number of generalized coordinates {n_q} should be less than + or equal to the number of generalized speeds {n_u}.""")) + if n_u != n_kdes: + msgs.append(filldedent(f""" + The number of generalized speeds {n_u} should be equal to the + number of kinematic differential equations {n_kdes}.""")) + elif issubclass(eom_method, LagrangesMethod): + not_qdots = set(self.u).difference(self.q.diff(dynamicsymbols._t)) + for joint in self.joints: + not_qdots.update(set( + joint.speeds).difference(self.q.diff(dynamicsymbols._t))) + if not_qdots: + msgs.append(filldedent(f""" + The generalized speeds {not_qdots} are not supported by this + method. Only derivatives of the generalized coordinates are + supported. If these symbols are used in your expressions, then + this will result in wrong equations of motion.""")) + if self.u_aux: + msgs.append(filldedent(f""" + This method does not support auxiliary speeds. If these symbols + are used in your expressions, then this will result in wrong + equations of motion. The auxiliary speeds are {self.u_aux}.""")) + else: + raise NotImplementedError(f'{eom_method} has not been implemented.') + if check_duplicates: # Should be redundant + duplicates_to_check = [('generalized coordinates', self.q), + ('generalized speeds', self.u), + ('auxiliary speeds', self.u_aux), + ('bodies', self.bodies), + ('joints', self.joints)] + for name, lst in duplicates_to_check: + seen = set() + duplicates = {x for x in lst if x in seen or seen.add(x)} + if duplicates: + msgs.append(filldedent(f""" + The {name} {duplicates} exist multiple times within the + system.""")) + if msgs: + raise ValueError('\n'.join(msgs)) + + +class SymbolicSystem: + """SymbolicSystem is a class that contains all the information about a + system in a symbolic format such as the equations of motions and the bodies + and loads in the system. + + There are three ways that the equations of motion can be described for + Symbolic System: + + + [1] Explicit form where the kinematics and dynamics are combined + x' = F_1(x, t, r, p) + + [2] Implicit form where the kinematics and dynamics are combined + M_2(x, p) x' = F_2(x, t, r, p) + + [3] Implicit form where the kinematics and dynamics are separate + M_3(q, p) u' = F_3(q, u, t, r, p) + q' = G(q, u, t, r, p) + + where + + x : states, e.g. [q, u] + t : time + r : specified (exogenous) inputs + p : constants + q : generalized coordinates + u : generalized speeds + F_1 : right hand side of the combined equations in explicit form + F_2 : right hand side of the combined equations in implicit form + F_3 : right hand side of the dynamical equations in implicit form + M_2 : mass matrix of the combined equations in implicit form + M_3 : mass matrix of the dynamical equations in implicit form + G : right hand side of the kinematical differential equations + + Parameters + ========== + + coord_states : ordered iterable of functions of time + This input will either be a collection of the coordinates or states + of the system depending on whether or not the speeds are also + given. If speeds are specified this input will be assumed to + be the coordinates otherwise this input will be assumed to + be the states. + + right_hand_side : Matrix + This variable is the right hand side of the equations of motion in + any of the forms. The specific form will be assumed depending on + whether a mass matrix or coordinate derivatives are given. + + speeds : ordered iterable of functions of time, optional + This is a collection of the generalized speeds of the system. If + given it will be assumed that the first argument (coord_states) + will represent the generalized coordinates of the system. + + mass_matrix : Matrix, optional + The matrix of the implicit forms of the equations of motion (forms + [2] and [3]). The distinction between the forms is determined by + whether or not the coordinate derivatives are passed in. If + they are given form [3] will be assumed otherwise form [2] is + assumed. + + coordinate_derivatives : Matrix, optional + The right hand side of the kinematical equations in explicit form. + If given it will be assumed that the equations of motion are being + entered in form [3]. + + alg_con : Iterable, optional + The indexes of the rows in the equations of motion that contain + algebraic constraints instead of differential equations. If the + equations are input in form [3], it will be assumed the indexes are + referencing the mass_matrix/right_hand_side combination and not the + coordinate_derivatives. + + output_eqns : Dictionary, optional + Any output equations that are desired to be tracked are stored in a + dictionary where the key corresponds to the name given for the + specific equation and the value is the equation itself in symbolic + form + + coord_idxs : Iterable, optional + If coord_states corresponds to the states rather than the + coordinates this variable will tell SymbolicSystem which indexes of + the states correspond to generalized coordinates. + + speed_idxs : Iterable, optional + If coord_states corresponds to the states rather than the + coordinates this variable will tell SymbolicSystem which indexes of + the states correspond to generalized speeds. + + bodies : iterable of Body/Rigidbody objects, optional + Iterable containing the bodies of the system + + loads : iterable of load instances (described below), optional + Iterable containing the loads of the system where forces are given + by (point of application, force vector) and torques are given by + (reference frame acting upon, torque vector). Ex [(point, force), + (ref_frame, torque)] + + Attributes + ========== + + coordinates : Matrix, shape(n, 1) + This is a matrix containing the generalized coordinates of the system + + speeds : Matrix, shape(m, 1) + This is a matrix containing the generalized speeds of the system + + states : Matrix, shape(o, 1) + This is a matrix containing the state variables of the system + + alg_con : List + This list contains the indices of the algebraic constraints in the + combined equations of motion. The presence of these constraints + requires that a DAE solver be used instead of an ODE solver. + If the system is given in form [3] the alg_con variable will be + adjusted such that it is a representation of the combined kinematics + and dynamics thus make sure it always matches the mass matrix + entered. + + dyn_implicit_mat : Matrix, shape(m, m) + This is the M matrix in form [3] of the equations of motion (the mass + matrix or generalized inertia matrix of the dynamical equations of + motion in implicit form). + + dyn_implicit_rhs : Matrix, shape(m, 1) + This is the F vector in form [3] of the equations of motion (the right + hand side of the dynamical equations of motion in implicit form). + + comb_implicit_mat : Matrix, shape(o, o) + This is the M matrix in form [2] of the equations of motion. + This matrix contains a block diagonal structure where the top + left block (the first rows) represent the matrix in the + implicit form of the kinematical equations and the bottom right + block (the last rows) represent the matrix in the implicit form + of the dynamical equations. + + comb_implicit_rhs : Matrix, shape(o, 1) + This is the F vector in form [2] of the equations of motion. The top + part of the vector represents the right hand side of the implicit form + of the kinemaical equations and the bottom of the vector represents the + right hand side of the implicit form of the dynamical equations of + motion. + + comb_explicit_rhs : Matrix, shape(o, 1) + This vector represents the right hand side of the combined equations of + motion in explicit form (form [1] from above). + + kin_explicit_rhs : Matrix, shape(m, 1) + This is the right hand side of the explicit form of the kinematical + equations of motion as can be seen in form [3] (the G matrix). + + output_eqns : Dictionary + If output equations were given they are stored in a dictionary where + the key corresponds to the name given for the specific equation and + the value is the equation itself in symbolic form + + bodies : Tuple + If the bodies in the system were given they are stored in a tuple for + future access + + loads : Tuple + If the loads in the system were given they are stored in a tuple for + future access. This includes forces and torques where forces are given + by (point of application, force vector) and torques are given by + (reference frame acted upon, torque vector). + + Example + ======= + + As a simple example, the dynamics of a simple pendulum will be input into a + SymbolicSystem object manually. First some imports will be needed and then + symbols will be set up for the length of the pendulum (l), mass at the end + of the pendulum (m), and a constant for gravity (g). :: + + >>> from sympy import Matrix, sin, symbols + >>> from sympy.physics.mechanics import dynamicsymbols, SymbolicSystem + >>> l, m, g = symbols('l m g') + + The system will be defined by an angle of theta from the vertical and a + generalized speed of omega will be used where omega = theta_dot. :: + + >>> theta, omega = dynamicsymbols('theta omega') + + Now the equations of motion are ready to be formed and passed to the + SymbolicSystem object. :: + + >>> kin_explicit_rhs = Matrix([omega]) + >>> dyn_implicit_mat = Matrix([l**2 * m]) + >>> dyn_implicit_rhs = Matrix([-g * l * m * sin(theta)]) + >>> symsystem = SymbolicSystem([theta], dyn_implicit_rhs, [omega], + ... dyn_implicit_mat) + + Notes + ===== + + m : number of generalized speeds + n : number of generalized coordinates + o : number of states + + """ + + def __init__(self, coord_states, right_hand_side, speeds=None, + mass_matrix=None, coordinate_derivatives=None, alg_con=None, + output_eqns={}, coord_idxs=None, speed_idxs=None, bodies=None, + loads=None): + """Initializes a SymbolicSystem object""" + + # Extract information on speeds, coordinates and states + if speeds is None: + self._states = Matrix(coord_states) + + if coord_idxs is None: + self._coordinates = None + else: + coords = [coord_states[i] for i in coord_idxs] + self._coordinates = Matrix(coords) + + if speed_idxs is None: + self._speeds = None + else: + speeds_inter = [coord_states[i] for i in speed_idxs] + self._speeds = Matrix(speeds_inter) + else: + self._coordinates = Matrix(coord_states) + self._speeds = Matrix(speeds) + self._states = self._coordinates.col_join(self._speeds) + + # Extract equations of motion form + if coordinate_derivatives is not None: + self._kin_explicit_rhs = coordinate_derivatives + self._dyn_implicit_rhs = right_hand_side + self._dyn_implicit_mat = mass_matrix + self._comb_implicit_rhs = None + self._comb_implicit_mat = None + self._comb_explicit_rhs = None + elif mass_matrix is not None: + self._kin_explicit_rhs = None + self._dyn_implicit_rhs = None + self._dyn_implicit_mat = None + self._comb_implicit_rhs = right_hand_side + self._comb_implicit_mat = mass_matrix + self._comb_explicit_rhs = None + else: + self._kin_explicit_rhs = None + self._dyn_implicit_rhs = None + self._dyn_implicit_mat = None + self._comb_implicit_rhs = None + self._comb_implicit_mat = None + self._comb_explicit_rhs = right_hand_side + + # Set the remainder of the inputs as instance attributes + if alg_con is not None and coordinate_derivatives is not None: + alg_con = [i + len(coordinate_derivatives) for i in alg_con] + self._alg_con = alg_con + self.output_eqns = output_eqns + + # Change the body and loads iterables to tuples if they are not tuples + # already + if not isinstance(bodies, tuple) and bodies is not None: + bodies = tuple(bodies) + if not isinstance(loads, tuple) and loads is not None: + loads = tuple(loads) + self._bodies = bodies + self._loads = loads + + @property + def coordinates(self): + """Returns the column matrix of the generalized coordinates""" + if self._coordinates is None: + raise AttributeError("The coordinates were not specified.") + else: + return self._coordinates + + @property + def speeds(self): + """Returns the column matrix of generalized speeds""" + if self._speeds is None: + raise AttributeError("The speeds were not specified.") + else: + return self._speeds + + @property + def states(self): + """Returns the column matrix of the state variables""" + return self._states + + @property + def alg_con(self): + """Returns a list with the indices of the rows containing algebraic + constraints in the combined form of the equations of motion""" + return self._alg_con + + @property + def dyn_implicit_mat(self): + """Returns the matrix, M, corresponding to the dynamic equations in + implicit form, M x' = F, where the kinematical equations are not + included""" + if self._dyn_implicit_mat is None: + raise AttributeError("dyn_implicit_mat is not specified for " + "equations of motion form [1] or [2].") + else: + return self._dyn_implicit_mat + + @property + def dyn_implicit_rhs(self): + """Returns the column matrix, F, corresponding to the dynamic equations + in implicit form, M x' = F, where the kinematical equations are not + included""" + if self._dyn_implicit_rhs is None: + raise AttributeError("dyn_implicit_rhs is not specified for " + "equations of motion form [1] or [2].") + else: + return self._dyn_implicit_rhs + + @property + def comb_implicit_mat(self): + """Returns the matrix, M, corresponding to the equations of motion in + implicit form (form [2]), M x' = F, where the kinematical equations are + included""" + if self._comb_implicit_mat is None: + if self._dyn_implicit_mat is not None: + num_kin_eqns = len(self._kin_explicit_rhs) + num_dyn_eqns = len(self._dyn_implicit_rhs) + zeros1 = zeros(num_kin_eqns, num_dyn_eqns) + zeros2 = zeros(num_dyn_eqns, num_kin_eqns) + inter1 = eye(num_kin_eqns).row_join(zeros1) + inter2 = zeros2.row_join(self._dyn_implicit_mat) + self._comb_implicit_mat = inter1.col_join(inter2) + return self._comb_implicit_mat + else: + raise AttributeError("comb_implicit_mat is not specified for " + "equations of motion form [1].") + else: + return self._comb_implicit_mat + + @property + def comb_implicit_rhs(self): + """Returns the column matrix, F, corresponding to the equations of + motion in implicit form (form [2]), M x' = F, where the kinematical + equations are included""" + if self._comb_implicit_rhs is None: + if self._dyn_implicit_rhs is not None: + kin_inter = self._kin_explicit_rhs + dyn_inter = self._dyn_implicit_rhs + self._comb_implicit_rhs = kin_inter.col_join(dyn_inter) + return self._comb_implicit_rhs + else: + raise AttributeError("comb_implicit_mat is not specified for " + "equations of motion in form [1].") + else: + return self._comb_implicit_rhs + + def compute_explicit_form(self): + """If the explicit right hand side of the combined equations of motion + is to provided upon initialization, this method will calculate it. This + calculation can potentially take awhile to compute.""" + if self._comb_explicit_rhs is not None: + raise AttributeError("comb_explicit_rhs is already formed.") + + inter1 = getattr(self, 'kin_explicit_rhs', None) + if inter1 is not None: + inter2 = self._dyn_implicit_mat.LUsolve(self._dyn_implicit_rhs) + out = inter1.col_join(inter2) + else: + out = self._comb_implicit_mat.LUsolve(self._comb_implicit_rhs) + + self._comb_explicit_rhs = out + + @property + def comb_explicit_rhs(self): + """Returns the right hand side of the equations of motion in explicit + form, x' = F, where the kinematical equations are included""" + if self._comb_explicit_rhs is None: + raise AttributeError("Please run .combute_explicit_form before " + "attempting to access comb_explicit_rhs.") + else: + return self._comb_explicit_rhs + + @property + def kin_explicit_rhs(self): + """Returns the right hand side of the kinematical equations in explicit + form, q' = G""" + if self._kin_explicit_rhs is None: + raise AttributeError("kin_explicit_rhs is not specified for " + "equations of motion form [1] or [2].") + else: + return self._kin_explicit_rhs + + def dynamic_symbols(self): + """Returns a column matrix containing all of the symbols in the system + that depend on time""" + # Create a list of all of the expressions in the equations of motion + if self._comb_explicit_rhs is None: + eom_expressions = (self.comb_implicit_mat[:] + + self.comb_implicit_rhs[:]) + else: + eom_expressions = (self._comb_explicit_rhs[:]) + + functions_of_time = set() + for expr in eom_expressions: + functions_of_time = functions_of_time.union( + find_dynamicsymbols(expr)) + functions_of_time = functions_of_time.union(self._states) + + return tuple(functions_of_time) + + def constant_symbols(self): + """Returns a column matrix containing all of the symbols in the system + that do not depend on time""" + # Create a list of all of the expressions in the equations of motion + if self._comb_explicit_rhs is None: + eom_expressions = (self.comb_implicit_mat[:] + + self.comb_implicit_rhs[:]) + else: + eom_expressions = (self._comb_explicit_rhs[:]) + + constants = set() + for expr in eom_expressions: + constants = constants.union(expr.free_symbols) + constants.remove(dynamicsymbols._t) + + return tuple(constants) + + @property + def bodies(self): + """Returns the bodies in the system""" + if self._bodies is None: + raise AttributeError("bodies were not specified for the system.") + else: + return self._bodies + + @property + def loads(self): + """Returns the loads in the system""" + if self._loads is None: + raise AttributeError("loads were not specified for the system.") + else: + return self._loads diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cb7e3bdfcfb9bd1c883e4bcf4fb1bfef778f4cb7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_actuator.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_actuator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..764962f7ae5b8e4a3d4b2f1d411bc788a60371da Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_actuator.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_body.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_body.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..75e489baa44ef7f034059f3dee18385252e2933a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_body.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_functions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_functions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7049960a7b05a8b53d7eaf78f24e7bc7fadd7f55 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_functions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_inertia.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_inertia.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..289707355e1a4029cd46e139e486d6ee41384356 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_inertia.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_jointsmethod.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_jointsmethod.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e9cf7efecaefdacce02c917a2f364a1bac7a2252 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_jointsmethod.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7cd2f18b429fd4e3032a5f7c0447e0194ffe6d27 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane2.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane2.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..881beee6adf0e07f0c769dbe0b06ebacec4e8507 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane2.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane3.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane3.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9917861f53ae217328b7ffd39b7f5afe110ff8a6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane3.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane4.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane4.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..556844974034a1d157975c73f4842bfc8acae6a4 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane4.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane5.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane5.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..108d3b7162688936b4100d01e2fc3aaea04e9ef4 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_kane5.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_lagrange.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_lagrange.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d76a7b2da983145ee4942388278b264f5277c7a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_lagrange.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_lagrange2.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_lagrange2.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9978fc9f1389b20c7a625651c20b4851ecd8126b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_lagrange2.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_linearity_of_velocity_constraints.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_linearity_of_velocity_constraints.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..00dd43b7253959be06e281d1cac9ad68931dfb1a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_linearity_of_velocity_constraints.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_linearize.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_linearize.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f92deafd19ab7b3ca9f31c24a91bf185e2353259 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_linearize.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_loads.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_loads.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..172e4c734ac9328ecaf9e8da42ca5c72ec87ca7d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_loads.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_method.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_method.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..554eaf8427939089defee9243b876ffb69f654fb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_method.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_models.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..785b9a8c5ef55f906eb660d9c8c9142b81d5dd1b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_models.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_particle.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_particle.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..01ab33b6d0c62d8bdf6499f261a7b608cb00d7c9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_particle.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_pathway.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_pathway.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..122668203b191a93643a6b97f55ee182a97d6419 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_pathway.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_rigidbody.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_rigidbody.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..81ea28e0fd10672a1310c2884095a4d001a59b27 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_rigidbody.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_system.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_system.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8578d0bd387d6de22899df4c683325d615c47ed0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_system.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_system_class.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_system_class.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36d072cce770ed3a5a42d0b3bb38913bb8ca18c7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_system_class.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_wrapping_geometry.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_wrapping_geometry.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dae24c826804742135cc4cf430a43bd577b143d0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/__pycache__/test_wrapping_geometry.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_actuator.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_actuator.py new file mode 100644 index 0000000000000000000000000000000000000000..5d69bccfe7a86d7555242a64923d77cb52cade88 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_actuator.py @@ -0,0 +1,1084 @@ +"""Tests for the ``sympy.physics.mechanics.actuator.py`` module.""" + +import pytest + +from sympy import ( + S, + Matrix, + Symbol, + SympifyError, + sqrt, + Abs, + symbols, + exp, + sign, +) +from sympy.physics.mechanics import ( + ActuatorBase, + Force, + ForceActuator, + KanesMethod, + LinearDamper, + LinearPathway, + LinearSpring, + Particle, + PinJoint, + Point, + ReferenceFrame, + RigidBody, + TorqueActuator, + Vector, + dynamicsymbols, + DuffingSpring, + CoulombKineticFriction, +) + +from sympy.core.expr import Expr as ExprType + +target = RigidBody('target') +reaction = RigidBody('reaction') + + +class TestForceActuator: + + @pytest.fixture(autouse=True) + def _linear_pathway_fixture(self): + self.force = Symbol('F') + self.pA = Point('pA') + self.pB = Point('pB') + self.pathway = LinearPathway(self.pA, self.pB) + self.q1 = dynamicsymbols('q1') + self.q2 = dynamicsymbols('q2') + self.q3 = dynamicsymbols('q3') + self.q1d = dynamicsymbols('q1', 1) + self.q2d = dynamicsymbols('q2', 1) + self.q3d = dynamicsymbols('q3', 1) + self.N = ReferenceFrame('N') + + def test_is_actuator_base_subclass(self): + assert issubclass(ForceActuator, ActuatorBase) + + @pytest.mark.parametrize( + 'force, expected_force', + [ + (1, S.One), + (S.One, S.One), + (Symbol('F'), Symbol('F')), + (dynamicsymbols('F'), dynamicsymbols('F')), + (Symbol('F')**2 + Symbol('F'), Symbol('F')**2 + Symbol('F')), + ] + ) + def test_valid_constructor_force(self, force, expected_force): + instance = ForceActuator(force, self.pathway) + assert isinstance(instance, ForceActuator) + assert hasattr(instance, 'force') + assert isinstance(instance.force, ExprType) + assert instance.force == expected_force + + @pytest.mark.parametrize('force', [None, 'F']) + def test_invalid_constructor_force_not_sympifyable(self, force): + with pytest.raises(SympifyError): + _ = ForceActuator(force, self.pathway) + + @pytest.mark.parametrize( + 'pathway', + [ + LinearPathway(Point('pA'), Point('pB')), + ] + ) + def test_valid_constructor_pathway(self, pathway): + instance = ForceActuator(self.force, pathway) + assert isinstance(instance, ForceActuator) + assert hasattr(instance, 'pathway') + assert isinstance(instance.pathway, LinearPathway) + assert instance.pathway == pathway + + def test_invalid_constructor_pathway_not_pathway_base(self): + with pytest.raises(TypeError): + _ = ForceActuator(self.force, None) + + @pytest.mark.parametrize( + 'property_name, fixture_attr_name', + [ + ('force', 'force'), + ('pathway', 'pathway'), + ] + ) + def test_properties_are_immutable(self, property_name, fixture_attr_name): + instance = ForceActuator(self.force, self.pathway) + value = getattr(self, fixture_attr_name) + with pytest.raises(AttributeError): + setattr(instance, property_name, value) + + def test_repr(self): + actuator = ForceActuator(self.force, self.pathway) + expected = "ForceActuator(F, LinearPathway(pA, pB))" + assert repr(actuator) == expected + + def test_to_loads_static_pathway(self): + self.pB.set_pos(self.pA, 2*self.N.x) + actuator = ForceActuator(self.force, self.pathway) + expected = [ + (self.pA, - self.force*self.N.x), + (self.pB, self.force*self.N.x), + ] + assert actuator.to_loads() == expected + + def test_to_loads_2D_pathway(self): + self.pB.set_pos(self.pA, 2*self.q1*self.N.x) + actuator = ForceActuator(self.force, self.pathway) + expected = [ + (self.pA, - self.force*(self.q1/sqrt(self.q1**2))*self.N.x), + (self.pB, self.force*(self.q1/sqrt(self.q1**2))*self.N.x), + ] + assert actuator.to_loads() == expected + + def test_to_loads_3D_pathway(self): + self.pB.set_pos( + self.pA, + self.q1*self.N.x - self.q2*self.N.y + 2*self.q3*self.N.z, + ) + actuator = ForceActuator(self.force, self.pathway) + length = sqrt(self.q1**2 + self.q2**2 + 4*self.q3**2) + pO_force = ( + - self.force*self.q1*self.N.x/length + + self.force*self.q2*self.N.y/length + - 2*self.force*self.q3*self.N.z/length + ) + pI_force = ( + self.force*self.q1*self.N.x/length + - self.force*self.q2*self.N.y/length + + 2*self.force*self.q3*self.N.z/length + ) + expected = [ + (self.pA, pO_force), + (self.pB, pI_force), + ] + assert actuator.to_loads() == expected + + +class TestLinearSpring: + + @pytest.fixture(autouse=True) + def _linear_spring_fixture(self): + self.stiffness = Symbol('k') + self.l = Symbol('l') + self.pA = Point('pA') + self.pB = Point('pB') + self.pathway = LinearPathway(self.pA, self.pB) + self.q = dynamicsymbols('q') + self.N = ReferenceFrame('N') + + def test_is_force_actuator_subclass(self): + assert issubclass(LinearSpring, ForceActuator) + + def test_is_actuator_base_subclass(self): + assert issubclass(LinearSpring, ActuatorBase) + + @pytest.mark.parametrize( + ( + 'stiffness, ' + 'expected_stiffness, ' + 'equilibrium_length, ' + 'expected_equilibrium_length, ' + 'force' + ), + [ + ( + 1, + S.One, + 0, + S.Zero, + -sqrt(dynamicsymbols('q')**2), + ), + ( + Symbol('k'), + Symbol('k'), + 0, + S.Zero, + -Symbol('k')*sqrt(dynamicsymbols('q')**2), + ), + ( + Symbol('k'), + Symbol('k'), + S.Zero, + S.Zero, + -Symbol('k')*sqrt(dynamicsymbols('q')**2), + ), + ( + Symbol('k'), + Symbol('k'), + Symbol('l'), + Symbol('l'), + -Symbol('k')*(sqrt(dynamicsymbols('q')**2) - Symbol('l')), + ), + ] + ) + def test_valid_constructor( + self, + stiffness, + expected_stiffness, + equilibrium_length, + expected_equilibrium_length, + force, + ): + self.pB.set_pos(self.pA, self.q*self.N.x) + spring = LinearSpring(stiffness, self.pathway, equilibrium_length) + + assert isinstance(spring, LinearSpring) + + assert hasattr(spring, 'stiffness') + assert isinstance(spring.stiffness, ExprType) + assert spring.stiffness == expected_stiffness + + assert hasattr(spring, 'pathway') + assert isinstance(spring.pathway, LinearPathway) + assert spring.pathway == self.pathway + + assert hasattr(spring, 'equilibrium_length') + assert isinstance(spring.equilibrium_length, ExprType) + assert spring.equilibrium_length == expected_equilibrium_length + + assert hasattr(spring, 'force') + assert isinstance(spring.force, ExprType) + assert spring.force == force + + @pytest.mark.parametrize('stiffness', [None, 'k']) + def test_invalid_constructor_stiffness_not_sympifyable(self, stiffness): + with pytest.raises(SympifyError): + _ = LinearSpring(stiffness, self.pathway, self.l) + + def test_invalid_constructor_pathway_not_pathway_base(self): + with pytest.raises(TypeError): + _ = LinearSpring(self.stiffness, None, self.l) + + @pytest.mark.parametrize('equilibrium_length', [None, 'l']) + def test_invalid_constructor_equilibrium_length_not_sympifyable( + self, + equilibrium_length, + ): + with pytest.raises(SympifyError): + _ = LinearSpring(self.stiffness, self.pathway, equilibrium_length) + + @pytest.mark.parametrize( + 'property_name, fixture_attr_name', + [ + ('stiffness', 'stiffness'), + ('pathway', 'pathway'), + ('equilibrium_length', 'l'), + ] + ) + def test_properties_are_immutable(self, property_name, fixture_attr_name): + spring = LinearSpring(self.stiffness, self.pathway, self.l) + value = getattr(self, fixture_attr_name) + with pytest.raises(AttributeError): + setattr(spring, property_name, value) + + @pytest.mark.parametrize( + 'equilibrium_length, expected', + [ + (S.Zero, 'LinearSpring(k, LinearPathway(pA, pB))'), + ( + Symbol('l'), + 'LinearSpring(k, LinearPathway(pA, pB), equilibrium_length=l)', + ), + ] + ) + def test_repr(self, equilibrium_length, expected): + self.pB.set_pos(self.pA, self.q*self.N.x) + spring = LinearSpring(self.stiffness, self.pathway, equilibrium_length) + assert repr(spring) == expected + + def test_to_loads(self): + self.pB.set_pos(self.pA, self.q*self.N.x) + spring = LinearSpring(self.stiffness, self.pathway, self.l) + normal = self.q/sqrt(self.q**2)*self.N.x + pA_force = self.stiffness*(sqrt(self.q**2) - self.l)*normal + pB_force = -self.stiffness*(sqrt(self.q**2) - self.l)*normal + expected = [Force(self.pA, pA_force), Force(self.pB, pB_force)] + loads = spring.to_loads() + + for load, (point, vector) in zip(loads, expected): + assert isinstance(load, Force) + assert load.point == point + assert (load.vector - vector).simplify() == 0 + + +class TestLinearDamper: + + @pytest.fixture(autouse=True) + def _linear_damper_fixture(self): + self.damping = Symbol('c') + self.l = Symbol('l') + self.pA = Point('pA') + self.pB = Point('pB') + self.pathway = LinearPathway(self.pA, self.pB) + self.q = dynamicsymbols('q') + self.dq = dynamicsymbols('q', 1) + self.u = dynamicsymbols('u') + self.N = ReferenceFrame('N') + + def test_is_force_actuator_subclass(self): + assert issubclass(LinearDamper, ForceActuator) + + def test_is_actuator_base_subclass(self): + assert issubclass(LinearDamper, ActuatorBase) + + def test_valid_constructor(self): + self.pB.set_pos(self.pA, self.q*self.N.x) + damper = LinearDamper(self.damping, self.pathway) + + assert isinstance(damper, LinearDamper) + + assert hasattr(damper, 'damping') + assert isinstance(damper.damping, ExprType) + assert damper.damping == self.damping + + assert hasattr(damper, 'pathway') + assert isinstance(damper.pathway, LinearPathway) + assert damper.pathway == self.pathway + + def test_valid_constructor_force(self): + self.pB.set_pos(self.pA, self.q*self.N.x) + damper = LinearDamper(self.damping, self.pathway) + + expected_force = -self.damping*sqrt(self.q**2)*self.dq/self.q + assert hasattr(damper, 'force') + assert isinstance(damper.force, ExprType) + assert damper.force == expected_force + + @pytest.mark.parametrize('damping', [None, 'c']) + def test_invalid_constructor_damping_not_sympifyable(self, damping): + with pytest.raises(SympifyError): + _ = LinearDamper(damping, self.pathway) + + def test_invalid_constructor_pathway_not_pathway_base(self): + with pytest.raises(TypeError): + _ = LinearDamper(self.damping, None) + + @pytest.mark.parametrize( + 'property_name, fixture_attr_name', + [ + ('damping', 'damping'), + ('pathway', 'pathway'), + ] + ) + def test_properties_are_immutable(self, property_name, fixture_attr_name): + damper = LinearDamper(self.damping, self.pathway) + value = getattr(self, fixture_attr_name) + with pytest.raises(AttributeError): + setattr(damper, property_name, value) + + def test_repr(self): + self.pB.set_pos(self.pA, self.q*self.N.x) + damper = LinearDamper(self.damping, self.pathway) + expected = 'LinearDamper(c, LinearPathway(pA, pB))' + assert repr(damper) == expected + + def test_to_loads(self): + self.pB.set_pos(self.pA, self.q*self.N.x) + damper = LinearDamper(self.damping, self.pathway) + direction = self.q**2/self.q**2*self.N.x + pA_force = self.damping*self.dq*direction + pB_force = -self.damping*self.dq*direction + expected = [Force(self.pA, pA_force), Force(self.pB, pB_force)] + assert damper.to_loads() == expected + + +class TestForcedMassSpringDamperModel(): + r"""A single degree of freedom translational forced mass-spring-damper. + + Notes + ===== + + This system is well known to have the governing equation: + + .. math:: + m \ddot{x} = F - k x - c \dot{x} + + where $F$ is an externally applied force, $m$ is the mass of the particle + to which the spring and damper are attached, $k$ is the spring's stiffness, + $c$ is the dampers damping coefficient, and $x$ is the generalized + coordinate representing the system's single (translational) degree of + freedom. + + """ + + @pytest.fixture(autouse=True) + def _force_mass_spring_damper_model_fixture(self): + self.m = Symbol('m') + self.k = Symbol('k') + self.c = Symbol('c') + self.F = Symbol('F') + + self.q = dynamicsymbols('q') + self.dq = dynamicsymbols('q', 1) + self.u = dynamicsymbols('u') + + self.frame = ReferenceFrame('N') + self.origin = Point('pO') + self.origin.set_vel(self.frame, 0) + + self.attachment = Point('pA') + self.attachment.set_pos(self.origin, self.q*self.frame.x) + + self.mass = Particle('mass', self.attachment, self.m) + self.pathway = LinearPathway(self.origin, self.attachment) + + self.kanes_method = KanesMethod( + self.frame, + q_ind=[self.q], + u_ind=[self.u], + kd_eqs=[self.dq - self.u], + ) + self.bodies = [self.mass] + + self.mass_matrix = Matrix([[self.m]]) + self.forcing = Matrix([[self.F - self.c*self.u - self.k*self.q]]) + + def test_force_acuator(self): + stiffness = -self.k*self.pathway.length + spring = ForceActuator(stiffness, self.pathway) + damping = -self.c*self.pathway.extension_velocity + damper = ForceActuator(damping, self.pathway) + + loads = [ + (self.attachment, self.F*self.frame.x), + *spring.to_loads(), + *damper.to_loads(), + ] + self.kanes_method.kanes_equations(self.bodies, loads) + + assert self.kanes_method.mass_matrix == self.mass_matrix + assert self.kanes_method.forcing == self.forcing + + def test_linear_spring_linear_damper(self): + spring = LinearSpring(self.k, self.pathway) + damper = LinearDamper(self.c, self.pathway) + + loads = [ + (self.attachment, self.F*self.frame.x), + *spring.to_loads(), + *damper.to_loads(), + ] + self.kanes_method.kanes_equations(self.bodies, loads) + + assert self.kanes_method.mass_matrix == self.mass_matrix + assert self.kanes_method.forcing == self.forcing + + +class TestTorqueActuator: + + @pytest.fixture(autouse=True) + def _torque_actuator_fixture(self): + self.torque = Symbol('T') + self.N = ReferenceFrame('N') + self.A = ReferenceFrame('A') + self.axis = self.N.z + self.target = RigidBody('target', frame=self.N) + self.reaction = RigidBody('reaction', frame=self.A) + + def test_is_actuator_base_subclass(self): + assert issubclass(TorqueActuator, ActuatorBase) + + @pytest.mark.parametrize( + 'torque', + [ + Symbol('T'), + dynamicsymbols('T'), + Symbol('T')**2 + Symbol('T'), + ] + ) + @pytest.mark.parametrize( + 'target_frame, reaction_frame', + [ + (target.frame, reaction.frame), + (target, reaction.frame), + (target.frame, reaction), + (target, reaction), + ] + ) + def test_valid_constructor_with_reaction( + self, + torque, + target_frame, + reaction_frame, + ): + instance = TorqueActuator( + torque, + self.axis, + target_frame, + reaction_frame, + ) + assert isinstance(instance, TorqueActuator) + + assert hasattr(instance, 'torque') + assert isinstance(instance.torque, ExprType) + assert instance.torque == torque + + assert hasattr(instance, 'axis') + assert isinstance(instance.axis, Vector) + assert instance.axis == self.axis + + assert hasattr(instance, 'target_frame') + assert isinstance(instance.target_frame, ReferenceFrame) + assert instance.target_frame == target.frame + + assert hasattr(instance, 'reaction_frame') + assert isinstance(instance.reaction_frame, ReferenceFrame) + assert instance.reaction_frame == reaction.frame + + @pytest.mark.parametrize( + 'torque', + [ + Symbol('T'), + dynamicsymbols('T'), + Symbol('T')**2 + Symbol('T'), + ] + ) + @pytest.mark.parametrize('target_frame', [target.frame, target]) + def test_valid_constructor_without_reaction(self, torque, target_frame): + instance = TorqueActuator(torque, self.axis, target_frame) + assert isinstance(instance, TorqueActuator) + + assert hasattr(instance, 'torque') + assert isinstance(instance.torque, ExprType) + assert instance.torque == torque + + assert hasattr(instance, 'axis') + assert isinstance(instance.axis, Vector) + assert instance.axis == self.axis + + assert hasattr(instance, 'target_frame') + assert isinstance(instance.target_frame, ReferenceFrame) + assert instance.target_frame == target.frame + + assert hasattr(instance, 'reaction_frame') + assert instance.reaction_frame is None + + @pytest.mark.parametrize('torque', [None, 'T']) + def test_invalid_constructor_torque_not_sympifyable(self, torque): + with pytest.raises(SympifyError): + _ = TorqueActuator(torque, self.axis, self.target) + + @pytest.mark.parametrize('axis', [Symbol('a'), dynamicsymbols('a')]) + def test_invalid_constructor_axis_not_vector(self, axis): + with pytest.raises(TypeError): + _ = TorqueActuator(self.torque, axis, self.target, self.reaction) + + @pytest.mark.parametrize( + 'frames', + [ + (None, ReferenceFrame('child')), + (ReferenceFrame('parent'), True), + (None, RigidBody('child')), + (RigidBody('parent'), True), + ] + ) + def test_invalid_constructor_frames_not_frame(self, frames): + with pytest.raises(TypeError): + _ = TorqueActuator(self.torque, self.axis, *frames) + + @pytest.mark.parametrize( + 'property_name, fixture_attr_name', + [ + ('torque', 'torque'), + ('axis', 'axis'), + ('target_frame', 'target'), + ('reaction_frame', 'reaction'), + ] + ) + def test_properties_are_immutable(self, property_name, fixture_attr_name): + actuator = TorqueActuator( + self.torque, + self.axis, + self.target, + self.reaction, + ) + value = getattr(self, fixture_attr_name) + with pytest.raises(AttributeError): + setattr(actuator, property_name, value) + + def test_repr_without_reaction(self): + actuator = TorqueActuator(self.torque, self.axis, self.target) + expected = 'TorqueActuator(T, axis=N.z, target_frame=N)' + assert repr(actuator) == expected + + def test_repr_with_reaction(self): + actuator = TorqueActuator( + self.torque, + self.axis, + self.target, + self.reaction, + ) + expected = 'TorqueActuator(T, axis=N.z, target_frame=N, reaction_frame=A)' + assert repr(actuator) == expected + + def test_at_pin_joint_constructor(self): + pin_joint = PinJoint( + 'pin', + self.target, + self.reaction, + coordinates=dynamicsymbols('q'), + speeds=dynamicsymbols('u'), + parent_interframe=self.N, + joint_axis=self.axis, + ) + instance = TorqueActuator.at_pin_joint(self.torque, pin_joint) + assert isinstance(instance, TorqueActuator) + + assert hasattr(instance, 'torque') + assert isinstance(instance.torque, ExprType) + assert instance.torque == self.torque + + assert hasattr(instance, 'axis') + assert isinstance(instance.axis, Vector) + assert instance.axis == self.axis + + assert hasattr(instance, 'target_frame') + assert isinstance(instance.target_frame, ReferenceFrame) + assert instance.target_frame == self.A + + assert hasattr(instance, 'reaction_frame') + assert isinstance(instance.reaction_frame, ReferenceFrame) + assert instance.reaction_frame == self.N + + def test_at_pin_joint_pin_joint_not_pin_joint_invalid(self): + with pytest.raises(TypeError): + _ = TorqueActuator.at_pin_joint(self.torque, Symbol('pin')) + + def test_to_loads_without_reaction(self): + actuator = TorqueActuator(self.torque, self.axis, self.target) + expected = [ + (self.N, self.torque*self.axis), + ] + assert actuator.to_loads() == expected + + def test_to_loads_with_reaction(self): + actuator = TorqueActuator( + self.torque, + self.axis, + self.target, + self.reaction, + ) + expected = [ + (self.N, self.torque*self.axis), + (self.A, - self.torque*self.axis), + ] + assert actuator.to_loads() == expected + + +class NonSympifyable: + pass + + +class TestDuffingSpring: + @pytest.fixture(autouse=True) + # Set up common variables that will be used in multiple tests + def _duffing_spring_fixture(self): + self.linear_stiffness = Symbol('beta') + self.nonlinear_stiffness = Symbol('alpha') + self.equilibrium_length = Symbol('l') + self.pA = Point('pA') + self.pB = Point('pB') + self.pathway = LinearPathway(self.pA, self.pB) + self.q = dynamicsymbols('q') + self.N = ReferenceFrame('N') + + # Simples tests to check that DuffingSpring is a subclass of ForceActuator and ActuatorBase + def test_is_force_actuator_subclass(self): + assert issubclass(DuffingSpring, ForceActuator) + + def test_is_actuator_base_subclass(self): + assert issubclass(DuffingSpring, ActuatorBase) + + @pytest.mark.parametrize( + # Create parametrized tests that allows running the same test function multiple times with different sets of arguments + ( + 'linear_stiffness, ' + 'expected_linear_stiffness, ' + 'nonlinear_stiffness, ' + 'expected_nonlinear_stiffness, ' + 'equilibrium_length, ' + 'expected_equilibrium_length, ' + 'force' + ), + [ + ( + 1, + S.One, + 1, + S.One, + 0, + S.Zero, + -sqrt(dynamicsymbols('q')**2)-(sqrt(dynamicsymbols('q')**2))**3, + ), + ( + Symbol('beta'), + Symbol('beta'), + Symbol('alpha'), + Symbol('alpha'), + 0, + S.Zero, + -Symbol('beta')*sqrt(dynamicsymbols('q')**2)-Symbol('alpha')*(sqrt(dynamicsymbols('q')**2))**3, + ), + ( + Symbol('beta'), + Symbol('beta'), + Symbol('alpha'), + Symbol('alpha'), + S.Zero, + S.Zero, + -Symbol('beta')*sqrt(dynamicsymbols('q')**2)-Symbol('alpha')*(sqrt(dynamicsymbols('q')**2))**3, + ), + ( + Symbol('beta'), + Symbol('beta'), + Symbol('alpha'), + Symbol('alpha'), + Symbol('l'), + Symbol('l'), + -Symbol('beta') * (sqrt(dynamicsymbols('q')**2) - Symbol('l')) - Symbol('alpha') * (sqrt(dynamicsymbols('q')**2) - Symbol('l'))**3, + ), + ] + ) + + # Check if DuffingSpring correctly initializes its attributes + # It tests various combinations of linear & nonlinear stiffness, equilibriun length, and the resulting force expression + def test_valid_constructor( + self, + linear_stiffness, + expected_linear_stiffness, + nonlinear_stiffness, + expected_nonlinear_stiffness, + equilibrium_length, + expected_equilibrium_length, + force, + ): + self.pB.set_pos(self.pA, self.q*self.N.x) + spring = DuffingSpring(linear_stiffness, nonlinear_stiffness, self.pathway, equilibrium_length) + + assert isinstance(spring, DuffingSpring) + + assert hasattr(spring, 'linear_stiffness') + assert isinstance(spring.linear_stiffness, ExprType) + assert spring.linear_stiffness == expected_linear_stiffness + + assert hasattr(spring, 'nonlinear_stiffness') + assert isinstance(spring.nonlinear_stiffness, ExprType) + assert spring.nonlinear_stiffness == expected_nonlinear_stiffness + + assert hasattr(spring, 'pathway') + assert isinstance(spring.pathway, LinearPathway) + assert spring.pathway == self.pathway + + assert hasattr(spring, 'equilibrium_length') + assert isinstance(spring.equilibrium_length, ExprType) + assert spring.equilibrium_length == expected_equilibrium_length + + assert hasattr(spring, 'force') + assert isinstance(spring.force, ExprType) + assert spring.force == force + + @pytest.mark.parametrize('linear_stiffness', [None, NonSympifyable()]) + def test_invalid_constructor_linear_stiffness_not_sympifyable(self, linear_stiffness): + with pytest.raises(SympifyError): + _ = DuffingSpring(linear_stiffness, self.nonlinear_stiffness, self.pathway, self.equilibrium_length) + + @pytest.mark.parametrize('nonlinear_stiffness', [None, NonSympifyable()]) + def test_invalid_constructor_nonlinear_stiffness_not_sympifyable(self, nonlinear_stiffness): + with pytest.raises(SympifyError): + _ = DuffingSpring(self.linear_stiffness, nonlinear_stiffness, self.pathway, self.equilibrium_length) + + def test_invalid_constructor_pathway_not_pathway_base(self): + with pytest.raises(TypeError): + _ = DuffingSpring(self.linear_stiffness, self.nonlinear_stiffness, NonSympifyable(), self.equilibrium_length) + + @pytest.mark.parametrize('equilibrium_length', [None, NonSympifyable()]) + def test_invalid_constructor_equilibrium_length_not_sympifyable(self, equilibrium_length): + with pytest.raises(SympifyError): + _ = DuffingSpring(self.linear_stiffness, self.nonlinear_stiffness, self.pathway, equilibrium_length) + + @pytest.mark.parametrize( + 'property_name, fixture_attr_name', + [ + ('linear_stiffness', 'linear_stiffness'), + ('nonlinear_stiffness', 'nonlinear_stiffness'), + ('pathway', 'pathway'), + ('equilibrium_length', 'equilibrium_length') + ] + ) + # Check if certain properties of DuffingSpring object are immutable after initialization + # Ensure that once DuffingSpring is created, its key properties cannot be changed + def test_properties_are_immutable(self, property_name, fixture_attr_name): + spring = DuffingSpring(self.linear_stiffness, self.nonlinear_stiffness, self.pathway, self.equilibrium_length) + with pytest.raises(AttributeError): + setattr(spring, property_name, getattr(self, fixture_attr_name)) + + @pytest.mark.parametrize( + 'equilibrium_length, expected', + [ + (0, 'DuffingSpring(beta, alpha, LinearPathway(pA, pB), equilibrium_length=0)'), + (Symbol('l'), 'DuffingSpring(beta, alpha, LinearPathway(pA, pB), equilibrium_length=l)'), + ] + ) + # Check the __repr__ method of DuffingSpring class + # Check if the actual string representation of DuffingSpring instance matches the expected string for each provided parameter values + def test_repr(self, equilibrium_length, expected): + spring = DuffingSpring(self.linear_stiffness, self.nonlinear_stiffness, self.pathway, equilibrium_length) + assert repr(spring) == expected + + def test_to_loads(self): + self.pB.set_pos(self.pA, self.q*self.N.x) + spring = DuffingSpring(self.linear_stiffness, self.nonlinear_stiffness, self.pathway, self.equilibrium_length) + + # Calculate the displacement from the equilibrium length + displacement = self.q - self.equilibrium_length + + # Make sure this matches the computation in DuffingSpring class + force = -self.linear_stiffness * displacement - self.nonlinear_stiffness * displacement**3 + + # The expected loads on pA and pB due to the spring + expected_loads = [Force(self.pA, force * self.N.x), Force(self.pB, -force * self.N.x)] + + # Compare expected loads to what is returned from DuffingSpring.to_loads() + calculated_loads = spring.to_loads() + for calculated, expected in zip(calculated_loads, expected_loads): + assert calculated.point == expected.point + for dim in self.N: # Assuming self.N is the reference frame + calculated_component = calculated.vector.dot(dim) + expected_component = expected.vector.dot(dim) + # Substitute all symbols with numeric values + substitutions = {self.q: 1, Symbol('l'): 1, Symbol('alpha'): 1, Symbol('beta'): 1} # Add other necessary symbols as needed + diff = (calculated_component - expected_component).subs(substitutions).evalf() + # Check if the absolute value of the difference is below a threshold + assert Abs(diff) < 1e-9, f"The forces do not match. Difference: {diff}" + +class TestCoulombKineticFriction: + @pytest.fixture(autouse=True) + def _block_on_surface(self): + """A block sliding on a surface. + + Notes + ===== + This test validates the correctness of the CoulombKineticFriction by simulating + a block sliding on a surface with the Coulomb kinetic friction force. + The test covers scenarios with both positive and negative velocities. + + """ + + # Mass, gravity constant, friction coefficient, coefficient of Stribeck friction, viscous_coefficient + self.m, self.g, self.mu_k, self.mu_s, self.v_s, self.sigma, self.F = symbols('m g mu_k mu_s v_s sigma F', real=True) + + def test_block_on_surface_default(self): + # General Case + q = dynamicsymbols('q') + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway) + expected_general = [Force(point=O, force=self.g * self.m * self.mu_k * q * sign(sqrt(q**2) * q.diff()/q)/sqrt(q**2) * N.x), + Force(point=P, force=-self.g * self.m * self.mu_k * q * sign(sqrt(q**2) * q.diff()/q)/sqrt(q**2) * N.x)] + + assert friction.to_loads() == expected_general + + # Positive + q = dynamicsymbols('q', positive=True) + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway) + expected_positive = [Force(point=O, force=self.g * self.m * self.mu_k * sign(q.diff()) * N.x), + Force(point=P, force=-self.g * self.m * self.mu_k * sign(q.diff()) * N.x)] + + assert friction.to_loads() == expected_positive + + # Negative + q = dynamicsymbols('q', positive=False) + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway) + expected_negative = [Force(point=O, force=self.g * self.m * self.mu_k * q * sign(sqrt(q**2) * q.diff()/q)/sqrt(q**2)*N.x), + Force(point=P, force=-self.g * self.m * self.mu_k * q * sign(sqrt(q**2) * q.diff()/q)/sqrt(q**2)*N.x)] + + assert friction.to_loads() == expected_negative + + def test_block_on_surface_viscous(self): + # General Case + q = dynamicsymbols('q') + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway, sigma=self.sigma) + expected_general = [Force(point=O, force=(self.g * self.m * self.mu_k * sign(sqrt(q**2) * q.diff()/q) + self.sigma * sqrt(q**2) * q.diff()/q) * q/sqrt(q**2) * N.x), + Force(point=P, force=(-self.g * self.m * self.mu_k * sign(sqrt(q**2) * q.diff()/q) - self.sigma * sqrt(q**2) * q.diff()/q) * q/sqrt(q**2) * N.x)] + + assert friction.to_loads() == expected_general + + # Positive + q = dynamicsymbols('q', positive=True) + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway, sigma=self.sigma) + expected_positive = [Force(point=O, force=(self.g * self.m * self.mu_k * sign(q.diff()) + self.sigma * q.diff()) * N.x), + Force(point=P, force=(-self.g * self.m * self.mu_k * sign(q.diff()) - self.sigma * q.diff()) * N.x)] + + assert friction.to_loads() == expected_positive + + # Negative + q = dynamicsymbols('q', positive=False) + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway, sigma=self.sigma) + expected_negative = [Force(point=O, force=(self.g * self.m * self.mu_k * sign(sqrt(q**2) * q.diff()/q) + self.sigma * sqrt(q**2) * q.diff()/q) * q/sqrt(q**2) * N.x), + Force(point=P, force=(-self.g * self.m * self.mu_k * sign(sqrt(q**2) * q.diff()/q) - self.sigma * sqrt(q**2) * q.diff()/q) * q/sqrt(q**2) * N.x)] + + assert friction.to_loads() == expected_negative + + def test_block_on_surface_stribeck(self): + # General Case + q = dynamicsymbols('q') + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway, v_s=self.v_s, mu_s=self.mu_s) + expected_general = [Force(point=O, force=(self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * q * sign(sqrt(q**2) * q.diff()/q)/sqrt(q**2) * N.x), + Force(point=P, force=- (self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * q * sign(sqrt(q**2) * q.diff()/q)/sqrt(q**2) * N.x)] + + assert friction.to_loads() == expected_general + + # Positive + q = dynamicsymbols('q', positive=True) + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway, v_s=self.v_s, mu_s=self.mu_s) + expected_positive = [Force(point=O, force=(self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * sign(q.diff()) * N.x), + Force(point=P, force=- (self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * sign(q.diff()) * N.x)] + + assert friction.to_loads() == expected_positive + + # Negative + q = dynamicsymbols('q', positive=False) + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway, v_s=self.v_s, mu_s=self.mu_s) + expected_negative = [Force(point=O, force=(self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * q * sign(sqrt(q**2) * q.diff()/q)/sqrt(q**2) * N.x), + Force(point=P, force=- (self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * q * sign(sqrt(q**2) * q.diff()/q)/sqrt(q**2) * N.x)] + + assert friction.to_loads() == expected_negative + + def test_block_on_surface_all(self): + # General Case + q = dynamicsymbols('q') + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway, v_s=self.v_s, sigma=self.sigma, mu_s=self.mu_s) + expected_general = [Force(point=O, force=(self.sigma * sqrt(q**2) * q.diff()/q + (self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * sign(sqrt(q**2) * q.diff()/q)) * q/sqrt(q**2) * N.x), + Force(point=P, force=(-self.sigma * sqrt(q**2) * q.diff()/q - (self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * sign(sqrt(q**2) * q.diff()/q)) * q/sqrt(q**2) * N.x)] + + assert friction.to_loads() == expected_general + + # Positive + q = dynamicsymbols('q', positive=True) + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway, v_s=self.v_s, sigma=self.sigma, mu_s=self.mu_s) + expected_positive = [Force(point=O, force=(self.sigma * q.diff() + (self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * sign(q.diff())) * N.x), + Force(point=P, force=(-self.sigma * q.diff() - (self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * sign(q.diff())) * N.x)] + + assert friction.to_loads() == expected_positive + + # Negative + q = dynamicsymbols('q', positive=False) + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction(self.mu_k, self.m * self.g, pathway, v_s=self.v_s, sigma=self.sigma, mu_s=self.mu_s) + expected_negative = [Force(point=O, force=(self.sigma * sqrt(q**2) * q.diff()/q + (self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * sign(sqrt(q**2) * q.diff()/q)) * q/sqrt(q**2) * N.x), + Force(point=P, force=(-self.sigma * sqrt(q**2) * q.diff()/q - (self.g * self.m * self.mu_k + (-self.g * self.m * self.mu_k + self.g * self.m * self.mu_s) * exp(-q.diff()**2/self.v_s**2)) * sign(sqrt(q**2) * q.diff()/q)) * q/sqrt(q**2) * N.x)] + + assert friction.to_loads() == expected_negative + + def test_normal_force_zero(self): + q = dynamicsymbols('q') + + N = ReferenceFrame('N') + O = Point('O') + P = O.locatenew('P', q * N.x) + O.set_vel(N, 0) + P.set_vel(N, q.diff() * N.x) + + pathway = LinearPathway(O, P) + friction = CoulombKineticFriction( + self.mu_k, + 0, + pathway + ) + assert friction.force == 0 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_body.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_body.py new file mode 100644 index 0000000000000000000000000000000000000000..2d59d747400652a0cbb081f4afc5ae4ebaa4db85 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_body.py @@ -0,0 +1,340 @@ +from sympy import (Symbol, symbols, sin, cos, Matrix, zeros, + simplify) +from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols, Dyadic +from sympy.physics.mechanics import inertia, Body +from sympy.testing.pytest import raises, warns_deprecated_sympy + + +def test_default(): + with warns_deprecated_sympy(): + body = Body('body') + assert body.name == 'body' + assert body.loads == [] + point = Point('body_masscenter') + point.set_vel(body.frame, 0) + com = body.masscenter + frame = body.frame + assert com.vel(frame) == point.vel(frame) + assert body.mass == Symbol('body_mass') + ixx, iyy, izz = symbols('body_ixx body_iyy body_izz') + ixy, iyz, izx = symbols('body_ixy body_iyz body_izx') + assert body.inertia == (inertia(body.frame, ixx, iyy, izz, ixy, iyz, izx), + body.masscenter) + + +def test_custom_rigid_body(): + # Body with RigidBody. + rigidbody_masscenter = Point('rigidbody_masscenter') + rigidbody_mass = Symbol('rigidbody_mass') + rigidbody_frame = ReferenceFrame('rigidbody_frame') + body_inertia = inertia(rigidbody_frame, 1, 0, 0) + with warns_deprecated_sympy(): + rigid_body = Body('rigidbody_body', rigidbody_masscenter, + rigidbody_mass, rigidbody_frame, body_inertia) + com = rigid_body.masscenter + frame = rigid_body.frame + rigidbody_masscenter.set_vel(rigidbody_frame, 0) + assert com.vel(frame) == rigidbody_masscenter.vel(frame) + assert com.pos_from(com) == rigidbody_masscenter.pos_from(com) + + assert rigid_body.mass == rigidbody_mass + assert rigid_body.inertia == (body_inertia, rigidbody_masscenter) + + assert rigid_body.is_rigidbody + + assert hasattr(rigid_body, 'masscenter') + assert hasattr(rigid_body, 'mass') + assert hasattr(rigid_body, 'frame') + assert hasattr(rigid_body, 'inertia') + + +def test_particle_body(): + # Body with Particle + particle_masscenter = Point('particle_masscenter') + particle_mass = Symbol('particle_mass') + particle_frame = ReferenceFrame('particle_frame') + with warns_deprecated_sympy(): + particle_body = Body('particle_body', particle_masscenter, + particle_mass, particle_frame) + com = particle_body.masscenter + frame = particle_body.frame + particle_masscenter.set_vel(particle_frame, 0) + assert com.vel(frame) == particle_masscenter.vel(frame) + assert com.pos_from(com) == particle_masscenter.pos_from(com) + + assert particle_body.mass == particle_mass + assert not hasattr(particle_body, "_inertia") + assert hasattr(particle_body, 'frame') + assert hasattr(particle_body, 'masscenter') + assert hasattr(particle_body, 'mass') + assert particle_body.inertia == (Dyadic(0), particle_body.masscenter) + assert particle_body.central_inertia == Dyadic(0) + assert not particle_body.is_rigidbody + + particle_body.central_inertia = inertia(particle_frame, 1, 1, 1) + assert particle_body.central_inertia == inertia(particle_frame, 1, 1, 1) + assert particle_body.is_rigidbody + + with warns_deprecated_sympy(): + particle_body = Body('particle_body', mass=particle_mass) + assert not particle_body.is_rigidbody + point = particle_body.masscenter.locatenew('point', particle_body.x) + point_inertia = particle_mass * inertia(particle_body.frame, 0, 1, 1) + particle_body.inertia = (point_inertia, point) + assert particle_body.inertia == (point_inertia, point) + assert particle_body.central_inertia == Dyadic(0) + assert particle_body.is_rigidbody + + +def test_particle_body_add_force(): + # Body with Particle + particle_masscenter = Point('particle_masscenter') + particle_mass = Symbol('particle_mass') + particle_frame = ReferenceFrame('particle_frame') + with warns_deprecated_sympy(): + particle_body = Body('particle_body', particle_masscenter, + particle_mass, particle_frame) + + a = Symbol('a') + force_vector = a * particle_body.frame.x + particle_body.apply_force(force_vector, particle_body.masscenter) + assert len(particle_body.loads) == 1 + point = particle_body.masscenter.locatenew( + particle_body._name + '_point0', 0) + point.set_vel(particle_body.frame, 0) + force_point = particle_body.loads[0][0] + + frame = particle_body.frame + assert force_point.vel(frame) == point.vel(frame) + assert force_point.pos_from(force_point) == point.pos_from(force_point) + + assert particle_body.loads[0][1] == force_vector + + +def test_body_add_force(): + # Body with RigidBody. + rigidbody_masscenter = Point('rigidbody_masscenter') + rigidbody_mass = Symbol('rigidbody_mass') + rigidbody_frame = ReferenceFrame('rigidbody_frame') + body_inertia = inertia(rigidbody_frame, 1, 0, 0) + with warns_deprecated_sympy(): + rigid_body = Body('rigidbody_body', rigidbody_masscenter, + rigidbody_mass, rigidbody_frame, body_inertia) + + l = Symbol('l') + Fa = Symbol('Fa') + point = rigid_body.masscenter.locatenew( + 'rigidbody_body_point0', + l * rigid_body.frame.x) + point.set_vel(rigid_body.frame, 0) + force_vector = Fa * rigid_body.frame.z + # apply_force with point + rigid_body.apply_force(force_vector, point) + assert len(rigid_body.loads) == 1 + force_point = rigid_body.loads[0][0] + frame = rigid_body.frame + assert force_point.vel(frame) == point.vel(frame) + assert force_point.pos_from(force_point) == point.pos_from(force_point) + assert rigid_body.loads[0][1] == force_vector + # apply_force without point + rigid_body.apply_force(force_vector) + assert len(rigid_body.loads) == 2 + assert rigid_body.loads[1][1] == force_vector + # passing something else than point + raises(TypeError, lambda: rigid_body.apply_force(force_vector, 0)) + raises(TypeError, lambda: rigid_body.apply_force(0)) + +def test_body_add_torque(): + with warns_deprecated_sympy(): + body = Body('body') + torque_vector = body.frame.x + body.apply_torque(torque_vector) + + assert len(body.loads) == 1 + assert body.loads[0] == (body.frame, torque_vector) + raises(TypeError, lambda: body.apply_torque(0)) + +def test_body_masscenter_vel(): + with warns_deprecated_sympy(): + A = Body('A') + N = ReferenceFrame('N') + with warns_deprecated_sympy(): + B = Body('B', frame=N) + A.masscenter.set_vel(N, N.z) + assert A.masscenter_vel(B) == N.z + assert A.masscenter_vel(N) == N.z + +def test_body_ang_vel(): + with warns_deprecated_sympy(): + A = Body('A') + N = ReferenceFrame('N') + with warns_deprecated_sympy(): + B = Body('B', frame=N) + A.frame.set_ang_vel(N, N.y) + assert A.ang_vel_in(B) == N.y + assert B.ang_vel_in(A) == -N.y + assert A.ang_vel_in(N) == N.y + +def test_body_dcm(): + with warns_deprecated_sympy(): + A = Body('A') + B = Body('B') + A.frame.orient_axis(B.frame, B.frame.z, 10) + assert A.dcm(B) == Matrix([[cos(10), sin(10), 0], [-sin(10), cos(10), 0], [0, 0, 1]]) + assert A.dcm(B.frame) == Matrix([[cos(10), sin(10), 0], [-sin(10), cos(10), 0], [0, 0, 1]]) + +def test_body_axis(): + N = ReferenceFrame('N') + with warns_deprecated_sympy(): + B = Body('B', frame=N) + assert B.x == N.x + assert B.y == N.y + assert B.z == N.z + +def test_apply_force_multiple_one_point(): + a, b = symbols('a b') + P = Point('P') + with warns_deprecated_sympy(): + B = Body('B') + f1 = a*B.x + f2 = b*B.y + B.apply_force(f1, P) + assert B.loads == [(P, f1)] + B.apply_force(f2, P) + assert B.loads == [(P, f1+f2)] + +def test_apply_force(): + f, g = symbols('f g') + q, x, v1, v2 = dynamicsymbols('q x v1 v2') + P1 = Point('P1') + P2 = Point('P2') + with warns_deprecated_sympy(): + B1 = Body('B1') + B2 = Body('B2') + N = ReferenceFrame('N') + + P1.set_vel(B1.frame, v1*B1.x) + P2.set_vel(B2.frame, v2*B2.x) + force = f*q*N.z # time varying force + + B1.apply_force(force, P1, B2, P2) #applying equal and opposite force on moving points + assert B1.loads == [(P1, force)] + assert B2.loads == [(P2, -force)] + + g1 = B1.mass*g*N.y + g2 = B2.mass*g*N.y + + B1.apply_force(g1) #applying gravity on B1 masscenter + B2.apply_force(g2) #applying gravity on B2 masscenter + + assert B1.loads == [(P1,force), (B1.masscenter, g1)] + assert B2.loads == [(P2, -force), (B2.masscenter, g2)] + + force2 = x*N.x + + B1.apply_force(force2, reaction_body=B2) #Applying time varying force on masscenter + + assert B1.loads == [(P1, force), (B1.masscenter, force2+g1)] + assert B2.loads == [(P2, -force), (B2.masscenter, -force2+g2)] + +def test_apply_torque(): + t = symbols('t') + q = dynamicsymbols('q') + with warns_deprecated_sympy(): + B1 = Body('B1') + B2 = Body('B2') + N = ReferenceFrame('N') + torque = t*q*N.x + + B1.apply_torque(torque, B2) #Applying equal and opposite torque + assert B1.loads == [(B1.frame, torque)] + assert B2.loads == [(B2.frame, -torque)] + + torque2 = t*N.y + B1.apply_torque(torque2) + assert B1.loads == [(B1.frame, torque+torque2)] + +def test_clear_load(): + a = symbols('a') + P = Point('P') + with warns_deprecated_sympy(): + B = Body('B') + force = a*B.z + B.apply_force(force, P) + assert B.loads == [(P, force)] + B.clear_loads() + assert B.loads == [] + +def test_remove_load(): + P1 = Point('P1') + P2 = Point('P2') + with warns_deprecated_sympy(): + B = Body('B') + f1 = B.x + f2 = B.y + B.apply_force(f1, P1) + B.apply_force(f2, P2) + assert B.loads == [(P1, f1), (P2, f2)] + B.remove_load(P2) + assert B.loads == [(P1, f1)] + B.apply_torque(f1.cross(f2)) + assert B.loads == [(P1, f1), (B.frame, f1.cross(f2))] + B.remove_load() + assert B.loads == [(P1, f1)] + +def test_apply_loads_on_multi_degree_freedom_holonomic_system(): + """Example based on: https://pydy.readthedocs.io/en/latest/examples/multidof-holonomic.html""" + with warns_deprecated_sympy(): + W = Body('W') #Wall + B = Body('B') #Block + P = Body('P') #Pendulum + b = Body('b') #bob + q1, q2 = dynamicsymbols('q1 q2') #generalized coordinates + k, c, g, kT = symbols('k c g kT') #constants + F, T = dynamicsymbols('F T') #Specified forces + + #Applying forces + B.apply_force(F*W.x) + W.apply_force(k*q1*W.x, reaction_body=B) #Spring force + W.apply_force(c*q1.diff()*W.x, reaction_body=B) #dampner + P.apply_force(P.mass*g*W.y) + b.apply_force(b.mass*g*W.y) + + #Applying torques + P.apply_torque(kT*q2*W.z, reaction_body=b) + P.apply_torque(T*W.z) + + assert B.loads == [(B.masscenter, (F - k*q1 - c*q1.diff())*W.x)] + assert P.loads == [(P.masscenter, P.mass*g*W.y), (P.frame, (T + kT*q2)*W.z)] + assert b.loads == [(b.masscenter, b.mass*g*W.y), (b.frame, -kT*q2*W.z)] + assert W.loads == [(W.masscenter, (c*q1.diff() + k*q1)*W.x)] + + +def test_parallel_axis(): + N = ReferenceFrame('N') + m, Ix, Iy, Iz, a, b = symbols('m, I_x, I_y, I_z, a, b') + Io = inertia(N, Ix, Iy, Iz) + # Test RigidBody + o = Point('o') + p = o.locatenew('p', a * N.x + b * N.y) + with warns_deprecated_sympy(): + R = Body('R', masscenter=o, frame=N, mass=m, central_inertia=Io) + Ip = R.parallel_axis(p) + Ip_expected = inertia(N, Ix + m * b**2, Iy + m * a**2, + Iz + m * (a**2 + b**2), ixy=-m * a * b) + assert Ip == Ip_expected + # Reference frame from which the parallel axis is viewed should not matter + A = ReferenceFrame('A') + A.orient_axis(N, N.z, 1) + assert simplify( + (R.parallel_axis(p, A) - Ip_expected).to_matrix(A)) == zeros(3, 3) + # Test Particle + o = Point('o') + p = o.locatenew('p', a * N.x + b * N.y) + with warns_deprecated_sympy(): + P = Body('P', masscenter=o, mass=m, frame=N) + Ip = P.parallel_axis(p, N) + Ip_expected = inertia(N, m * b ** 2, m * a ** 2, m * (a ** 2 + b ** 2), + ixy=-m * a * b) + assert not P.is_rigidbody + assert Ip == Ip_expected diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_functions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_functions.py new file mode 100644 index 0000000000000000000000000000000000000000..bae6b19b2807dca1632942bd3717e29d214eb269 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_functions.py @@ -0,0 +1,262 @@ +from sympy import sin, cos, tan, pi, symbols, Matrix, S, Function +from sympy.physics.mechanics import (Particle, Point, ReferenceFrame, + RigidBody) +from sympy.physics.mechanics import (angular_momentum, dynamicsymbols, + kinetic_energy, linear_momentum, + outer, potential_energy, msubs, + find_dynamicsymbols, Lagrangian) + +from sympy.physics.mechanics.functions import ( + center_of_mass, _validate_coordinates, _parse_linear_solver) +from sympy.testing.pytest import raises, warns_deprecated_sympy + + +q1, q2, q3, q4, q5 = symbols('q1 q2 q3 q4 q5') +N = ReferenceFrame('N') +A = N.orientnew('A', 'Axis', [q1, N.z]) +B = A.orientnew('B', 'Axis', [q2, A.x]) +C = B.orientnew('C', 'Axis', [q3, B.y]) + + +def test_linear_momentum(): + N = ReferenceFrame('N') + Ac = Point('Ac') + Ac.set_vel(N, 25 * N.y) + I = outer(N.x, N.x) + A = RigidBody('A', Ac, N, 20, (I, Ac)) + P = Point('P') + Pa = Particle('Pa', P, 1) + Pa.point.set_vel(N, 10 * N.x) + raises(TypeError, lambda: linear_momentum(A, A, Pa)) + raises(TypeError, lambda: linear_momentum(N, N, Pa)) + assert linear_momentum(N, A, Pa) == 10 * N.x + 500 * N.y + + +def test_angular_momentum_and_linear_momentum(): + """A rod with length 2l, centroidal inertia I, and mass M along with a + particle of mass m fixed to the end of the rod rotate with an angular rate + of omega about point O which is fixed to the non-particle end of the rod. + The rod's reference frame is A and the inertial frame is N.""" + m, M, l, I = symbols('m, M, l, I') + omega = dynamicsymbols('omega') + N = ReferenceFrame('N') + a = ReferenceFrame('a') + O = Point('O') + Ac = O.locatenew('Ac', l * N.x) + P = Ac.locatenew('P', l * N.x) + O.set_vel(N, 0 * N.x) + 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) + A = RigidBody('A', Ac, a, M, (I * outer(N.z, N.z), Ac)) + expected = 2 * m * omega * l * N.y + M * l * omega * N.y + assert linear_momentum(N, A, Pa) == expected + raises(TypeError, lambda: angular_momentum(N, N, A, Pa)) + raises(TypeError, lambda: angular_momentum(O, O, A, Pa)) + raises(TypeError, lambda: angular_momentum(O, N, O, Pa)) + expected = (I + M * l**2 + 4 * m * l**2) * omega * N.z + assert angular_momentum(O, N, A, Pa) == expected + + +def test_kinetic_energy(): + m, M, l1 = symbols('m M l1') + 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)) + raises(TypeError, lambda: kinetic_energy(Pa, Pa, A)) + raises(TypeError, lambda: kinetic_energy(N, N, A)) + assert 0 == (kinetic_energy(N, Pa, A) - (M*l1**2*omega**2/2 + + 2*l1**2*m*omega**2 + omega**2/2)).expand() + + +def test_potential_energy(): + 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)) + Pa.potential_energy = m * g * h + A.potential_energy = M * g * H + assert potential_energy(A, Pa) == m * g * h + M * g * H + + +def test_Lagrangian(): + M, m, g, h = symbols('M m g h') + N = ReferenceFrame('N') + O = Point('O') + O.set_vel(N, 0 * N.x) + P = O.locatenew('P', 1 * N.x) + P.set_vel(N, 10 * N.x) + Pa = Particle('Pa', P, 1) + Ac = O.locatenew('Ac', 2 * N.y) + Ac.set_vel(N, 5 * N.y) + a = ReferenceFrame('a') + a.set_ang_vel(N, 10 * N.z) + I = outer(N.z, N.z) + A = RigidBody('A', Ac, a, 20, (I, Ac)) + Pa.potential_energy = m * g * h + A.potential_energy = M * g * h + raises(TypeError, lambda: Lagrangian(A, A, Pa)) + raises(TypeError, lambda: Lagrangian(N, N, Pa)) + + +def test_msubs(): + a, b = symbols('a, b') + x, y, z = dynamicsymbols('x, y, z') + # Test simple substitution + expr = Matrix([[a*x + b, x*y.diff() + y], + [x.diff().diff(), z + sin(z.diff())]]) + sol = Matrix([[a + b, y], + [x.diff().diff(), 1]]) + sd = {x: 1, z: 1, z.diff(): 0, y.diff(): 0} + assert msubs(expr, sd) == sol + # Test smart substitution + expr = cos(x + y)*tan(x + y) + b*x.diff() + sd = {x: 0, y: pi/2, x.diff(): 1} + assert msubs(expr, sd, smart=True) == b + 1 + N = ReferenceFrame('N') + v = x*N.x + y*N.y + d = x*(N.x|N.x) + y*(N.y|N.y) + v_sol = 1*N.y + d_sol = 1*(N.y|N.y) + sd = {x: 0, y: 1} + assert msubs(v, sd) == v_sol + assert msubs(d, sd) == d_sol + + +def test_find_dynamicsymbols(): + a, b = symbols('a, b') + x, y, z = dynamicsymbols('x, y, z') + expr = Matrix([[a*x + b, x*y.diff() + y], + [x.diff().diff(), z + sin(z.diff())]]) + # Test finding all dynamicsymbols + sol = {x, y.diff(), y, x.diff().diff(), z, z.diff()} + assert find_dynamicsymbols(expr) == sol + # Test finding all but those in sym_list + exclude_list = [x, y, z] + sol = {y.diff(), x.diff().diff(), z.diff()} + assert find_dynamicsymbols(expr, exclude=exclude_list) == sol + # Test finding all dynamicsymbols in a vector with a given reference frame + d, e, f = dynamicsymbols('d, e, f') + A = ReferenceFrame('A') + v = d * A.x + e * A.y + f * A.z + sol = {d, e, f} + assert find_dynamicsymbols(v, reference_frame=A) == sol + # Test if a ValueError is raised on supplying only a vector as input + raises(ValueError, lambda: find_dynamicsymbols(v)) + + +# This function tests the center_of_mass() function +# that was added in PR #14758 to compute the center of +# mass of a system of bodies. +def test_center_of_mass(): + a = ReferenceFrame('a') + m = symbols('m', real=True) + p1 = Particle('p1', Point('p1_pt'), S.One) + p2 = Particle('p2', Point('p2_pt'), S(2)) + p3 = Particle('p3', Point('p3_pt'), S(3)) + p4 = Particle('p4', Point('p4_pt'), m) + b_f = ReferenceFrame('b_f') + b_cm = Point('b_cm') + mb = symbols('mb') + b = RigidBody('b', b_cm, b_f, mb, (outer(b_f.x, b_f.x), b_cm)) + p2.point.set_pos(p1.point, a.x) + p3.point.set_pos(p1.point, a.x + a.y) + p4.point.set_pos(p1.point, a.y) + b.masscenter.set_pos(p1.point, a.y + a.z) + point_o=Point('o') + point_o.set_pos(p1.point, center_of_mass(p1.point, p1, p2, p3, p4, b)) + expr = 5/(m + mb + 6)*a.x + (m + mb + 3)/(m + mb + 6)*a.y + mb/(m + mb + 6)*a.z + assert point_o.pos_from(p1.point)-expr == 0 + + +def test_validate_coordinates(): + q1, q2, q3, u1, u2, u3, ua1, ua2, ua3 = dynamicsymbols('q1:4 u1:4 ua1:4') + s1, s2, s3 = symbols('s1:4') + # Test normal + _validate_coordinates([q1, q2, q3], [u1, u2, u3], + u_auxiliary=[ua1, ua2, ua3]) + # Test not equal number of coordinates and speeds + _validate_coordinates([q1, q2]) + _validate_coordinates([q1, q2], [u1]) + _validate_coordinates(speeds=[u1, u2]) + # Test duplicate + _validate_coordinates([q1, q2, q2], [u1, u2, u3], check_duplicates=False) + raises(ValueError, lambda: _validate_coordinates( + [q1, q2, q2], [u1, u2, u3])) + _validate_coordinates([q1, q2, q3], [u1, u2, u2], check_duplicates=False) + raises(ValueError, lambda: _validate_coordinates( + [q1, q2, q3], [u1, u2, u2], check_duplicates=True)) + raises(ValueError, lambda: _validate_coordinates( + [q1, q2, q3], [q1, u2, u3], check_duplicates=True)) + _validate_coordinates([q1, q2, q3], [u1, u2, u3], check_duplicates=False, + u_auxiliary=[u1, ua2, ua2]) + raises(ValueError, lambda: _validate_coordinates( + [q1, q2, q3], [u1, u2, u3], u_auxiliary=[u1, ua2, ua3])) + raises(ValueError, lambda: _validate_coordinates( + [q1, q2, q3], [u1, u2, u3], u_auxiliary=[q1, ua2, ua3])) + raises(ValueError, lambda: _validate_coordinates( + [q1, q2, q3], [u1, u2, u3], u_auxiliary=[ua1, ua2, ua2])) + # Test is_dynamicsymbols + _validate_coordinates([q1 + q2, q3], is_dynamicsymbols=False) + raises(ValueError, lambda: _validate_coordinates([q1 + q2, q3])) + _validate_coordinates([s1, q1, q2], [0, u1, u2], is_dynamicsymbols=False) + raises(ValueError, lambda: _validate_coordinates( + [s1, q1, q2], [0, u1, u2], is_dynamicsymbols=True)) + _validate_coordinates([s1 + s2 + s3, q1], [0, u1], is_dynamicsymbols=False) + raises(ValueError, lambda: _validate_coordinates( + [s1 + s2 + s3, q1], [0, u1], is_dynamicsymbols=True)) + _validate_coordinates(u_auxiliary=[s1, ua1], is_dynamicsymbols=False) + raises(ValueError, lambda: _validate_coordinates(u_auxiliary=[s1, ua1])) + # Test normal function + t = dynamicsymbols._t + a = symbols('a') + f1, f2 = symbols('f1:3', cls=Function) + _validate_coordinates([f1(a), f2(a)], is_dynamicsymbols=False) + raises(ValueError, lambda: _validate_coordinates([f1(a), f2(a)])) + raises(ValueError, lambda: _validate_coordinates(speeds=[f1(a), f2(a)])) + dynamicsymbols._t = a + _validate_coordinates([f1(a), f2(a)]) + raises(ValueError, lambda: _validate_coordinates([f1(t), f2(t)])) + dynamicsymbols._t = t + + +def test_parse_linear_solver(): + A, b = Matrix(3, 3, symbols('a:9')), Matrix(3, 2, symbols('b:6')) + assert _parse_linear_solver(Matrix.LUsolve) == Matrix.LUsolve # Test callable + assert _parse_linear_solver('LU')(A, b) == Matrix.LUsolve(A, b) + + +def test_deprecated_moved_functions(): + from sympy.physics.mechanics.functions import ( + inertia, inertia_of_point_mass, gravity) + N = ReferenceFrame('N') + with warns_deprecated_sympy(): + assert inertia(N, 0, 1, 0, 1) == (N.x | N.y) + (N.y | N.x) + (N.y | N.y) + with warns_deprecated_sympy(): + assert inertia_of_point_mass(1, N.x + N.y, N) == ( + (N.x | N.x) + (N.y | N.y) + 2 * (N.z | N.z) - + (N.x | N.y) - (N.y | N.x)) + p = Particle('P') + with warns_deprecated_sympy(): + assert gravity(-2 * N.z, p) == [(p.masscenter, -2 * p.mass * N.z)] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_inertia.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_inertia.py new file mode 100644 index 0000000000000000000000000000000000000000..8d29e5f31868e539c4b50575af5180e5eb96f2cd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_inertia.py @@ -0,0 +1,71 @@ +from sympy import symbols +from sympy.testing.pytest import raises +from sympy.physics.mechanics import (inertia, inertia_of_point_mass, + Inertia, ReferenceFrame, Point) + + +def test_inertia_dyadic(): + N = ReferenceFrame('N') + ixx, iyy, izz = symbols('ixx iyy izz') + ixy, iyz, izx = symbols('ixy iyz izx') + assert inertia(N, ixx, iyy, izz) == (ixx * (N.x | N.x) + iyy * + (N.y | N.y) + izz * (N.z | N.z)) + assert inertia(N, 0, 0, 0) == 0 * (N.x | N.x) + raises(TypeError, lambda: inertia(0, 0, 0, 0)) + 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) + izz * (N.z | N.z)) + + +def test_inertia_of_point_mass(): + r, s, t, m = symbols('r s t m') + N = ReferenceFrame('N') + + px = r * N.x + I = inertia_of_point_mass(m, px, N) + assert I == m * r**2 * (N.y | N.y) + m * r**2 * (N.z | N.z) + + py = s * N.y + I = inertia_of_point_mass(m, py, N) + assert I == m * s**2 * (N.x | N.x) + m * s**2 * (N.z | N.z) + + pz = t * N.z + I = inertia_of_point_mass(m, pz, N) + assert I == m * t**2 * (N.x | N.x) + m * t**2 * (N.y | N.y) + + p = px + py + pz + I = inertia_of_point_mass(m, p, N) + assert I == (m * (s**2 + t**2) * (N.x | N.x) - + m * r * s * (N.x | N.y) - + m * r * t * (N.x | N.z) - + m * r * s * (N.y | N.x) + + m * (r**2 + t**2) * (N.y | N.y) - + m * s * t * (N.y | N.z) - + m * r * t * (N.z | N.x) - + m * s * t * (N.z | N.y) + + m * (r**2 + s**2) * (N.z | N.z)) + + +def test_inertia_object(): + N = ReferenceFrame('N') + O = Point('O') + ixx, iyy, izz = symbols('ixx iyy izz') + I_dyadic = ixx * (N.x | N.x) + iyy * (N.y | N.y) + izz * (N.z | N.z) + I = Inertia(inertia(N, ixx, iyy, izz), O) + assert isinstance(I, tuple) + assert I.__repr__() == ('Inertia(dyadic=ixx*(N.x|N.x) + iyy*(N.y|N.y) + ' + 'izz*(N.z|N.z), point=O)') + assert I.dyadic == I_dyadic + assert I.point == O + assert I[0] == I_dyadic + assert I[1] == O + assert I == (I_dyadic, O) # Test tuple equal + raises(TypeError, lambda: I != (O, I_dyadic)) # Incorrect tuple order + assert I == Inertia(O, I_dyadic) # Parse changed argument order + assert I == Inertia.from_inertia_scalars(O, N, ixx, iyy, izz) + # Test invalid tuple operations + raises(TypeError, lambda: I + (1, 2)) + raises(TypeError, lambda: (1, 2) + I) + raises(TypeError, lambda: I * 2) + raises(TypeError, lambda: 2 * I) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_joint.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_joint.py new file mode 100644 index 0000000000000000000000000000000000000000..271801b5b7290a4479ee61e1414741e4c4d6f966 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_joint.py @@ -0,0 +1,1240 @@ +from sympy.core.function import expand_mul +from sympy.core.numbers import pi +from sympy.core.singleton import S +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy import Matrix, simplify, eye, zeros +from sympy.core.symbol import symbols +from sympy.physics.mechanics import ( + dynamicsymbols, RigidBody, Particle, JointsMethod, PinJoint, PrismaticJoint, + CylindricalJoint, PlanarJoint, SphericalJoint, WeldJoint, Body) +from sympy.physics.mechanics.joint import Joint +from sympy.physics.vector import Vector, ReferenceFrame, Point +from sympy.testing.pytest import raises, warns_deprecated_sympy + + +t = dynamicsymbols._t # type: ignore + + +def _generate_body(interframe=False): + N = ReferenceFrame('N') + A = ReferenceFrame('A') + P = RigidBody('P', frame=N) + C = RigidBody('C', frame=A) + if interframe: + Pint, Cint = ReferenceFrame('P_int'), ReferenceFrame('C_int') + Pint.orient_axis(N, N.x, pi) + Cint.orient_axis(A, A.y, -pi / 2) + return N, A, P, C, Pint, Cint + return N, A, P, C + + +def test_Joint(): + parent = RigidBody('parent') + child = RigidBody('child') + raises(TypeError, lambda: Joint('J', parent, child)) + + +def test_coordinate_generation(): + q, u, qj, uj = dynamicsymbols('q u q_J u_J') + q0j, q1j, q2j, q3j, u0j, u1j, u2j, u3j = dynamicsymbols('q0:4_J u0:4_J') + q0, q1, q2, q3, u0, u1, u2, u3 = dynamicsymbols('q0:4 u0:4') + _, _, P, C = _generate_body() + # Using PinJoint to access Joint's coordinate generation method + J = PinJoint('J', P, C) + # Test single given + assert J._fill_coordinate_list(q, 1) == Matrix([q]) + assert J._fill_coordinate_list([u], 1) == Matrix([u]) + assert J._fill_coordinate_list([u], 1, offset=2) == Matrix([u]) + # Test None + assert J._fill_coordinate_list(None, 1) == Matrix([qj]) + assert J._fill_coordinate_list([None], 1) == Matrix([qj]) + assert J._fill_coordinate_list([q0, None, None], 3) == Matrix( + [q0, q1j, q2j]) + # Test autofill + assert J._fill_coordinate_list(None, 3) == Matrix([q0j, q1j, q2j]) + assert J._fill_coordinate_list([], 3) == Matrix([q0j, q1j, q2j]) + # Test offset + assert J._fill_coordinate_list([], 3, offset=1) == Matrix([q1j, q2j, q3j]) + assert J._fill_coordinate_list([q1, None, q3], 3, offset=1) == Matrix( + [q1, q2j, q3]) + assert J._fill_coordinate_list(None, 2, offset=2) == Matrix([q2j, q3j]) + # Test label + assert J._fill_coordinate_list(None, 1, 'u') == Matrix([uj]) + assert J._fill_coordinate_list([], 3, 'u') == Matrix([u0j, u1j, u2j]) + # Test single numbering + assert J._fill_coordinate_list(None, 1, number_single=True) == Matrix([q0j]) + assert J._fill_coordinate_list([], 1, 'u', 2, True) == Matrix([u2j]) + assert J._fill_coordinate_list([], 3, 'q') == Matrix([q0j, q1j, q2j]) + # Test invalid number of coordinates supplied + raises(ValueError, lambda: J._fill_coordinate_list([q0, q1], 1)) + raises(ValueError, lambda: J._fill_coordinate_list([u0, u1, None], 2, 'u')) + raises(ValueError, lambda: J._fill_coordinate_list([q0, q1], 3)) + # Test incorrect coordinate type + raises(TypeError, lambda: J._fill_coordinate_list([q0, symbols('q1')], 2)) + raises(TypeError, lambda: J._fill_coordinate_list([q0 + q1, q1], 2)) + # Test if derivative as generalized speed is allowed + _, _, P, C = _generate_body() + PinJoint('J', P, C, q1, q1.diff(t)) + # Test duplicate coordinates + _, _, P, C = _generate_body() + raises(ValueError, lambda: SphericalJoint('J', P, C, [q1j, None, None])) + raises(ValueError, lambda: SphericalJoint('J', P, C, speeds=[u0, u0, u1])) + + +def test_pin_joint(): + P = RigidBody('P') + C = RigidBody('C') + l, m = symbols('l m') + q, u = dynamicsymbols('q_J, u_J') + Pj = PinJoint('J', P, C) + assert Pj.name == 'J' + assert Pj.parent == P + assert Pj.child == C + assert Pj.coordinates == Matrix([q]) + assert Pj.speeds == Matrix([u]) + assert Pj.kdes == Matrix([u - q.diff(t)]) + assert Pj.joint_axis == P.frame.x + assert Pj.child_point.pos_from(C.masscenter) == Vector(0) + assert Pj.parent_point.pos_from(P.masscenter) == Vector(0) + assert Pj.parent_point.pos_from(Pj._child_point) == Vector(0) + assert C.masscenter.pos_from(P.masscenter) == Vector(0) + assert Pj.parent_interframe == P.frame + assert Pj.child_interframe == C.frame + assert Pj.__str__() == 'PinJoint: J parent: P child: C' + + P1 = RigidBody('P1') + C1 = RigidBody('C1') + Pint = ReferenceFrame('P_int') + Pint.orient_axis(P1.frame, P1.y, pi / 2) + J1 = PinJoint('J1', P1, C1, parent_point=l*P1.frame.x, + child_point=m*C1.frame.y, joint_axis=P1.frame.z, + parent_interframe=Pint) + assert J1._joint_axis == P1.frame.z + assert J1._child_point.pos_from(C1.masscenter) == m * C1.frame.y + assert J1._parent_point.pos_from(P1.masscenter) == l * P1.frame.x + assert J1._parent_point.pos_from(J1._child_point) == Vector(0) + assert (P1.masscenter.pos_from(C1.masscenter) == + -l*P1.frame.x + m*C1.frame.y) + assert J1.parent_interframe == Pint + assert J1.child_interframe == C1.frame + + q, u = dynamicsymbols('q, u') + N, A, P, C, Pint, Cint = _generate_body(True) + parent_point = P.masscenter.locatenew('parent_point', N.x + N.y) + child_point = C.masscenter.locatenew('child_point', C.y + C.z) + J = PinJoint('J', P, C, q, u, parent_point=parent_point, + child_point=child_point, parent_interframe=Pint, + child_interframe=Cint, joint_axis=N.z) + assert J.joint_axis == N.z + assert J.parent_point.vel(N) == 0 + assert J.parent_point == parent_point + assert J.child_point == child_point + assert J.child_point.pos_from(P.masscenter) == N.x + N.y + assert J.parent_point.pos_from(C.masscenter) == C.y + C.z + assert C.masscenter.pos_from(P.masscenter) == N.x + N.y - C.y - C.z + assert C.masscenter.vel(N).express(N) == (u * sin(q) - u * cos(q)) * N.x + ( + -u * sin(q) - u * cos(q)) * N.y + assert J.parent_interframe == Pint + assert J.child_interframe == Cint + + +def test_particle_compatibility(): + m, l = symbols('m l') + C_frame = ReferenceFrame('C') + P = Particle('P') + C = Particle('C', mass=m) + q, u = dynamicsymbols('q, u') + J = PinJoint('J', P, C, q, u, child_interframe=C_frame, + child_point=l * C_frame.y) + assert J.child_interframe == C_frame + assert J.parent_interframe.name == 'J_P_frame' + assert C.masscenter.pos_from(P.masscenter) == -l * C_frame.y + assert C_frame.dcm(J.parent_interframe) == Matrix([[1, 0, 0], + [0, cos(q), sin(q)], + [0, -sin(q), cos(q)]]) + assert C.masscenter.vel(J.parent_interframe) == -l * u * C_frame.z + # Test with specified joint axis + P_frame = ReferenceFrame('P') + C_frame = ReferenceFrame('C') + P = Particle('P') + C = Particle('C', mass=m) + q, u = dynamicsymbols('q, u') + J = PinJoint('J', P, C, q, u, parent_interframe=P_frame, + child_interframe=C_frame, child_point=l * C_frame.y, + joint_axis=P_frame.z) + assert J.joint_axis == J.parent_interframe.z + assert C_frame.dcm(J.parent_interframe) == Matrix([[cos(q), sin(q), 0], + [-sin(q), cos(q), 0], + [0, 0, 1]]) + assert P.masscenter.vel(J.parent_interframe) == 0 + assert C.masscenter.vel(J.parent_interframe) == l * u * C_frame.x + q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1:4 u1:4') + qdot_to_u = {qi.diff(t): ui for qi, ui in ((q1, u1), (q2, u2), (q3, u3))} + # Test compatibility for prismatic joint + P, C = Particle('P'), Particle('C') + J = PrismaticJoint('J', P, C, q, u) + assert J.parent_interframe.dcm(J.child_interframe) == eye(3) + assert C.masscenter.pos_from(P.masscenter) == q * J.parent_interframe.x + assert P.masscenter.vel(J.parent_interframe) == 0 + assert C.masscenter.vel(J.parent_interframe) == u * J.parent_interframe.x + # Test compatibility for cylindrical joint + P, C = Particle('P'), Particle('C') + P_frame = ReferenceFrame('P_frame') + J = CylindricalJoint('J', P, C, q1, q2, u1, u2, parent_interframe=P_frame, + parent_point=l * P_frame.x, joint_axis=P_frame.y) + assert J.parent_interframe.dcm(J.child_interframe) == Matrix([ + [cos(q1), 0, sin(q1)], [0, 1, 0], [-sin(q1), 0, cos(q1)]]) + assert C.masscenter.pos_from(P.masscenter) == l * P_frame.x + q2 * P_frame.y + assert C.masscenter.vel(J.parent_interframe) == u2 * P_frame.y + assert P.masscenter.vel(J.child_interframe).xreplace(qdot_to_u) == ( + -u2 * P_frame.y - l * u1 * P_frame.z) + # Test compatibility for planar joint + P, C = Particle('P'), Particle('C') + C_frame = ReferenceFrame('C_frame') + J = PlanarJoint('J', P, C, q1, [q2, q3], u1, [u2, u3], + child_interframe=C_frame, child_point=l * C_frame.z) + P_frame = J.parent_interframe + assert J.parent_interframe.dcm(J.child_interframe) == Matrix([ + [1, 0, 0], [0, cos(q1), -sin(q1)], [0, sin(q1), cos(q1)]]) + assert C.masscenter.pos_from(P.masscenter) == ( + -l * C_frame.z + q2 * P_frame.y + q3 * P_frame.z) + assert C.masscenter.vel(J.parent_interframe) == ( + l * u1 * C_frame.y + u2 * P_frame.y + u3 * P_frame.z) + # Test compatibility for weld joint + P, C = Particle('P'), Particle('C') + C_frame, P_frame = ReferenceFrame('C_frame'), ReferenceFrame('P_frame') + J = WeldJoint('J', P, C, parent_interframe=P_frame, + child_interframe=C_frame, parent_point=l * P_frame.x, + child_point=l * C_frame.y) + assert P_frame.dcm(C_frame) == eye(3) + assert C.masscenter.pos_from(P.masscenter) == l * P_frame.x - l * C_frame.y + assert C.masscenter.vel(J.parent_interframe) == 0 + + +def test_body_compatibility(): + m, l = symbols('m l') + C_frame = ReferenceFrame('C') + with warns_deprecated_sympy(): + P = Body('P') + C = Body('C', mass=m, frame=C_frame) + q, u = dynamicsymbols('q, u') + PinJoint('J', P, C, q, u, child_point=l * C_frame.y) + assert C.frame == C_frame + assert P.frame.name == 'P_frame' + assert C.masscenter.pos_from(P.masscenter) == -l * C.y + assert C.frame.dcm(P.frame) == Matrix([[1, 0, 0], + [0, cos(q), sin(q)], + [0, -sin(q), cos(q)]]) + assert C.masscenter.vel(P.frame) == -l * u * C.z + + +def test_pin_joint_double_pendulum(): + q1, q2 = dynamicsymbols('q1 q2') + u1, u2 = dynamicsymbols('u1 u2') + m, l = symbols('m l') + N = ReferenceFrame('N') + A = ReferenceFrame('A') + B = ReferenceFrame('B') + C = RigidBody('C', frame=N) # ceiling + PartP = RigidBody('P', frame=A, mass=m) + PartR = RigidBody('R', frame=B, mass=m) + + J1 = PinJoint('J1', C, PartP, speeds=u1, coordinates=q1, + child_point=-l*A.x, joint_axis=C.frame.z) + J2 = PinJoint('J2', PartP, PartR, speeds=u2, coordinates=q2, + child_point=-l*B.x, joint_axis=PartP.frame.z) + + # Check orientation + assert N.dcm(A) == Matrix([[cos(q1), -sin(q1), 0], + [sin(q1), cos(q1), 0], [0, 0, 1]]) + assert A.dcm(B) == Matrix([[cos(q2), -sin(q2), 0], + [sin(q2), cos(q2), 0], [0, 0, 1]]) + assert simplify(N.dcm(B)) == Matrix([[cos(q1 + q2), -sin(q1 + q2), 0], + [sin(q1 + q2), cos(q1 + q2), 0], + [0, 0, 1]]) + + # Check Angular Velocity + assert A.ang_vel_in(N) == u1 * N.z + assert B.ang_vel_in(A) == u2 * A.z + assert B.ang_vel_in(N) == u1 * N.z + u2 * A.z + + # Check kde + assert J1.kdes == Matrix([u1 - q1.diff(t)]) + assert J2.kdes == Matrix([u2 - q2.diff(t)]) + + # Check Linear Velocity + assert PartP.masscenter.vel(N) == l*u1*A.y + assert PartR.masscenter.vel(A) == l*u2*B.y + assert PartR.masscenter.vel(N) == l*u1*A.y + l*(u1 + u2)*B.y + + +def test_pin_joint_chaos_pendulum(): + mA, mB, lA, lB, h = symbols('mA, mB, lA, lB, h') + theta, phi, omega, alpha = dynamicsymbols('theta phi omega alpha') + N = ReferenceFrame('N') + A = ReferenceFrame('A') + B = ReferenceFrame('B') + lA = (lB - h / 2) / 2 + lC = (lB/2 + h/4) + rod = RigidBody('rod', frame=A, mass=mA) + plate = RigidBody('plate', mass=mB, frame=B) + C = RigidBody('C', frame=N) + J1 = PinJoint('J1', C, rod, coordinates=theta, speeds=omega, + child_point=lA*A.z, joint_axis=N.y) + J2 = PinJoint('J2', rod, plate, coordinates=phi, speeds=alpha, + parent_point=lC*A.z, joint_axis=A.z) + + # Check orientation + assert A.dcm(N) == Matrix([[cos(theta), 0, -sin(theta)], + [0, 1, 0], + [sin(theta), 0, cos(theta)]]) + assert A.dcm(B) == Matrix([[cos(phi), -sin(phi), 0], + [sin(phi), cos(phi), 0], + [0, 0, 1]]) + assert B.dcm(N) == Matrix([ + [cos(phi)*cos(theta), sin(phi), -sin(theta)*cos(phi)], + [-sin(phi)*cos(theta), cos(phi), sin(phi)*sin(theta)], + [sin(theta), 0, cos(theta)]]) + + # Check Angular Velocity + assert A.ang_vel_in(N) == omega*N.y + assert A.ang_vel_in(B) == -alpha*A.z + assert N.ang_vel_in(B) == -omega*N.y - alpha*A.z + + # Check kde + assert J1.kdes == Matrix([omega - theta.diff(t)]) + assert J2.kdes == Matrix([alpha - phi.diff(t)]) + + # Check pos of masscenters + assert C.masscenter.pos_from(rod.masscenter) == lA*A.z + assert rod.masscenter.pos_from(plate.masscenter) == - lC * A.z + + # Check Linear Velocities + assert rod.masscenter.vel(N) == (h/4 - lB/2)*omega*A.x + assert plate.masscenter.vel(N) == ((h/4 - lB/2)*omega + + (h/4 + lB/2)*omega)*A.x + + +def test_pin_joint_interframe(): + q, u = dynamicsymbols('q, u') + # Check not connected + N, A, P, C = _generate_body() + Pint, Cint = ReferenceFrame('Pint'), ReferenceFrame('Cint') + raises(ValueError, lambda: PinJoint('J', P, C, parent_interframe=Pint)) + raises(ValueError, lambda: PinJoint('J', P, C, child_interframe=Cint)) + # Check not fixed interframe + Pint.orient_axis(N, N.z, q) + Cint.orient_axis(A, A.z, q) + raises(ValueError, lambda: PinJoint('J', P, C, parent_interframe=Pint)) + raises(ValueError, lambda: PinJoint('J', P, C, child_interframe=Cint)) + # Check only parent_interframe + N, A, P, C = _generate_body() + Pint = ReferenceFrame('Pint') + Pint.orient_body_fixed(N, (pi / 4, pi, pi / 3), 'xyz') + PinJoint('J', P, C, q, u, parent_point=N.x, child_point=-C.y, + parent_interframe=Pint, joint_axis=Pint.x) + assert simplify(N.dcm(A)) - Matrix([ + [-1 / 2, sqrt(3) * cos(q) / 2, -sqrt(3) * sin(q) / 2], + [sqrt(6) / 4, sqrt(2) * (2 * sin(q) + cos(q)) / 4, + sqrt(2) * (-sin(q) + 2 * cos(q)) / 4], + [sqrt(6) / 4, sqrt(2) * (-2 * sin(q) + cos(q)) / 4, + -sqrt(2) * (sin(q) + 2 * cos(q)) / 4]]) == zeros(3) + assert A.ang_vel_in(N) == u * Pint.x + assert C.masscenter.pos_from(P.masscenter) == N.x + A.y + assert C.masscenter.vel(N) == u * A.z + assert P.masscenter.vel(Pint) == Vector(0) + assert C.masscenter.vel(Pint) == u * A.z + # Check only child_interframe + N, A, P, C = _generate_body() + Cint = ReferenceFrame('Cint') + Cint.orient_body_fixed(A, (2 * pi / 3, -pi, pi / 2), 'xyz') + PinJoint('J', P, C, q, u, parent_point=-N.z, child_point=C.x, + child_interframe=Cint, joint_axis=P.x + P.z) + assert simplify(N.dcm(A)) == Matrix([ + [-sqrt(2) * sin(q) / 2, + -sqrt(3) * (cos(q) - 1) / 4 - cos(q) / 4 - S(1) / 4, + sqrt(3) * (cos(q) + 1) / 4 - cos(q) / 4 + S(1) / 4], + [cos(q), (sqrt(2) + sqrt(6)) * -sin(q) / 4, + (-sqrt(2) + sqrt(6)) * sin(q) / 4], + [sqrt(2) * sin(q) / 2, + sqrt(3) * (cos(q) + 1) / 4 + cos(q) / 4 - S(1) / 4, + sqrt(3) * (1 - cos(q)) / 4 + cos(q) / 4 + S(1) / 4]]) + assert A.ang_vel_in(N) == sqrt(2) * u / 2 * N.x + sqrt(2) * u / 2 * N.z + assert C.masscenter.pos_from(P.masscenter) == - N.z - A.x + assert C.masscenter.vel(N).simplify() == ( + -sqrt(6) - sqrt(2)) * u / 4 * A.y + ( + -sqrt(2) + sqrt(6)) * u / 4 * A.z + assert C.masscenter.vel(Cint) == Vector(0) + # Check combination + N, A, P, C = _generate_body() + Pint, Cint = ReferenceFrame('Pint'), ReferenceFrame('Cint') + Pint.orient_body_fixed(N, (-pi / 2, pi, pi / 2), 'xyz') + Cint.orient_body_fixed(A, (2 * pi / 3, -pi, pi / 2), 'xyz') + PinJoint('J', P, C, q, u, parent_point=N.x - N.y, child_point=-C.z, + parent_interframe=Pint, child_interframe=Cint, + joint_axis=Pint.x + Pint.z) + assert simplify(N.dcm(A)) == Matrix([ + [cos(q), (sqrt(2) + sqrt(6)) * -sin(q) / 4, + (-sqrt(2) + sqrt(6)) * sin(q) / 4], + [-sqrt(2) * sin(q) / 2, + -sqrt(3) * (cos(q) + 1) / 4 - cos(q) / 4 + S(1) / 4, + sqrt(3) * (cos(q) - 1) / 4 - cos(q) / 4 - S(1) / 4], + [sqrt(2) * sin(q) / 2, + sqrt(3) * (cos(q) - 1) / 4 + cos(q) / 4 + S(1) / 4, + -sqrt(3) * (cos(q) + 1) / 4 + cos(q) / 4 - S(1) / 4]]) + assert A.ang_vel_in(N) == sqrt(2) * u / 2 * Pint.x + sqrt( + 2) * u / 2 * Pint.z + assert C.masscenter.pos_from(P.masscenter) == N.x - N.y + A.z + N_v_C = (-sqrt(2) + sqrt(6)) * u / 4 * A.x + assert C.masscenter.vel(N).simplify() == N_v_C + assert C.masscenter.vel(Pint).simplify() == N_v_C + assert C.masscenter.vel(Cint) == Vector(0) + + +def test_pin_joint_joint_axis(): + q, u = dynamicsymbols('q, u') + # Check parent as reference + N, A, P, C, Pint, Cint = _generate_body(True) + pin = PinJoint('J', P, C, q, u, parent_interframe=Pint, + child_interframe=Cint, joint_axis=P.y) + assert pin.joint_axis == P.y + assert N.dcm(A) == Matrix([[sin(q), 0, cos(q)], [0, -1, 0], + [cos(q), 0, -sin(q)]]) + # Check parent_interframe as reference + N, A, P, C, Pint, Cint = _generate_body(True) + pin = PinJoint('J', P, C, q, u, parent_interframe=Pint, + child_interframe=Cint, joint_axis=Pint.y) + assert pin.joint_axis == Pint.y + assert N.dcm(A) == Matrix([[-sin(q), 0, cos(q)], [0, -1, 0], + [cos(q), 0, sin(q)]]) + # Check combination of joint_axis with interframes supplied as vectors (2x) + N, A, P, C = _generate_body() + pin = PinJoint('J', P, C, q, u, parent_interframe=N.z, + child_interframe=-C.z, joint_axis=N.z) + assert pin.joint_axis == N.z + assert N.dcm(A) == Matrix([[-cos(q), -sin(q), 0], [-sin(q), cos(q), 0], + [0, 0, -1]]) + N, A, P, C = _generate_body() + pin = PinJoint('J', P, C, q, u, parent_interframe=N.z, + child_interframe=-C.z, joint_axis=N.x) + assert pin.joint_axis == N.x + assert N.dcm(A) == Matrix([[-1, 0, 0], [0, cos(q), sin(q)], + [0, sin(q), -cos(q)]]) + # Check time varying axis + N, A, P, C, Pint, Cint = _generate_body(True) + raises(ValueError, lambda: PinJoint('J', P, C, + joint_axis=cos(q) * N.x + sin(q) * N.y)) + # Check joint_axis provided in child frame + raises(ValueError, lambda: PinJoint('J', P, C, joint_axis=C.x)) + # Check some invalid combinations + raises(ValueError, lambda: PinJoint('J', P, C, joint_axis=P.x + C.y)) + raises(ValueError, lambda: PinJoint( + 'J', P, C, parent_interframe=Pint, child_interframe=Cint, + joint_axis=Pint.x + C.y)) + raises(ValueError, lambda: PinJoint( + 'J', P, C, parent_interframe=Pint, child_interframe=Cint, + joint_axis=P.x + Cint.y)) + # Check valid special combination + N, A, P, C, Pint, Cint = _generate_body(True) + PinJoint('J', P, C, parent_interframe=Pint, child_interframe=Cint, + joint_axis=Pint.x + P.y) + # Check invalid zero vector + raises(Exception, lambda: PinJoint( + 'J', P, C, parent_interframe=Pint, child_interframe=Cint, + joint_axis=Vector(0))) + raises(Exception, lambda: PinJoint( + 'J', P, C, parent_interframe=Pint, child_interframe=Cint, + joint_axis=P.y + Pint.y)) + + +def test_pin_joint_arbitrary_axis(): + q, u = dynamicsymbols('q_J, u_J') + + # When the bodies are attached though masscenters but axes are opposite. + N, A, P, C = _generate_body() + PinJoint('J', P, C, child_interframe=-A.x) + + assert (-A.x).angle_between(N.x) == 0 + assert -A.x.express(N) == N.x + assert A.dcm(N) == Matrix([[-1, 0, 0], + [0, -cos(q), -sin(q)], + [0, -sin(q), cos(q)]]) + assert A.ang_vel_in(N) == u*N.x + assert A.ang_vel_in(N).magnitude() == sqrt(u**2) + assert C.masscenter.pos_from(P.masscenter) == 0 + assert C.masscenter.pos_from(P.masscenter).express(N).simplify() == 0 + assert C.masscenter.vel(N) == 0 + + # When axes are different and parent joint is at masscenter but child joint + # is at a unit vector from child masscenter. + N, A, P, C = _generate_body() + PinJoint('J', P, C, child_interframe=A.y, child_point=A.x) + + assert A.y.angle_between(N.x) == 0 # Axis are aligned + assert A.y.express(N) == N.x + assert A.dcm(N) == Matrix([[0, -cos(q), -sin(q)], + [1, 0, 0], + [0, -sin(q), cos(q)]]) + assert A.ang_vel_in(N) == u*N.x + assert A.ang_vel_in(N).express(A) == u * A.y + assert A.ang_vel_in(N).magnitude() == sqrt(u**2) + assert A.ang_vel_in(N).cross(A.y) == 0 + assert C.masscenter.vel(N) == u*A.z + assert C.masscenter.pos_from(P.masscenter) == -A.x + assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() == + cos(q)*N.y + sin(q)*N.z) + assert C.masscenter.vel(N).angle_between(A.x) == pi/2 + + # Similar to previous case but wrt parent body + N, A, P, C = _generate_body() + PinJoint('J', P, C, parent_interframe=N.y, parent_point=N.x) + + assert N.y.angle_between(A.x) == 0 # Axis are aligned + assert N.y.express(A) == A.x + assert A.dcm(N) == Matrix([[0, 1, 0], + [-cos(q), 0, sin(q)], + [sin(q), 0, cos(q)]]) + assert A.ang_vel_in(N) == u*N.y + assert A.ang_vel_in(N).express(A) == u*A.x + assert A.ang_vel_in(N).magnitude() == sqrt(u**2) + angle = A.ang_vel_in(N).angle_between(A.x) + assert angle.xreplace({u: 1}) == 0 + assert C.masscenter.vel(N) == 0 + assert C.masscenter.pos_from(P.masscenter) == N.x + + # Both joint pos id defined but different axes + N, A, P, C = _generate_body() + PinJoint('J', P, C, parent_point=N.x, child_point=A.x, + child_interframe=A.x + A.y) + assert expand_mul(N.x.angle_between(A.x + A.y)) == 0 # Axis are aligned + assert (A.x + A.y).express(N).simplify() == sqrt(2)*N.x + assert simplify(A.dcm(N)) == Matrix([ + [sqrt(2)/2, -sqrt(2)*cos(q)/2, -sqrt(2)*sin(q)/2], + [sqrt(2)/2, sqrt(2)*cos(q)/2, sqrt(2)*sin(q)/2], + [0, -sin(q), cos(q)]]) + assert A.ang_vel_in(N) == u*N.x + assert (A.ang_vel_in(N).express(A).simplify() == + (u*A.x + u*A.y)/sqrt(2)) + assert A.ang_vel_in(N).magnitude() == sqrt(u**2) + angle = A.ang_vel_in(N).angle_between(A.x + A.y) + assert angle.xreplace({u: 1}) == 0 + assert C.masscenter.vel(N).simplify() == (u * A.z)/sqrt(2) + assert C.masscenter.pos_from(P.masscenter) == N.x - A.x + assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() == + (1 - sqrt(2)/2)*N.x + sqrt(2)*cos(q)/2*N.y + + sqrt(2)*sin(q)/2*N.z) + assert (C.masscenter.vel(N).express(N).simplify() == + -sqrt(2)*u*sin(q)/2*N.y + sqrt(2)*u*cos(q)/2*N.z) + assert C.masscenter.vel(N).angle_between(A.x) == pi/2 + + N, A, P, C = _generate_body() + PinJoint('J', P, C, parent_point=N.x, child_point=A.x, + child_interframe=A.x + A.y - A.z) + assert expand_mul(N.x.angle_between(A.x + A.y - A.z)) == 0 # Axis aligned + assert (A.x + A.y - A.z).express(N).simplify() == sqrt(3)*N.x + assert simplify(A.dcm(N)) == Matrix([ + [sqrt(3)/3, -sqrt(6)*sin(q + pi/4)/3, + sqrt(6)*cos(q + pi/4)/3], + [sqrt(3)/3, sqrt(6)*cos(q + pi/12)/3, + sqrt(6)*sin(q + pi/12)/3], + [-sqrt(3)/3, sqrt(6)*cos(q + 5*pi/12)/3, + sqrt(6)*sin(q + 5*pi/12)/3]]) + assert A.ang_vel_in(N) == u*N.x + assert A.ang_vel_in(N).express(A).simplify() == (u*A.x + u*A.y - + u*A.z)/sqrt(3) + assert A.ang_vel_in(N).magnitude() == sqrt(u**2) + angle = A.ang_vel_in(N).angle_between(A.x + A.y-A.z) + assert angle.xreplace({u: 1}).simplify() == 0 + assert C.masscenter.vel(N).simplify() == (u*A.y + u*A.z)/sqrt(3) + assert C.masscenter.pos_from(P.masscenter) == N.x - A.x + assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() == + (1 - sqrt(3)/3)*N.x + sqrt(6)*sin(q + pi/4)/3*N.y - + sqrt(6)*cos(q + pi/4)/3*N.z) + assert (C.masscenter.vel(N).express(N).simplify() == + sqrt(6)*u*cos(q + pi/4)/3*N.y + + sqrt(6)*u*sin(q + pi/4)/3*N.z) + assert C.masscenter.vel(N).angle_between(A.x) == pi/2 + + N, A, P, C = _generate_body() + m, n = symbols('m n') + PinJoint('J', P, C, parent_point=m * N.x, child_point=n * A.x, + child_interframe=A.x + A.y - A.z, + parent_interframe=N.x - N.y + N.z) + angle = (N.x - N.y + N.z).angle_between(A.x + A.y - A.z) + assert expand_mul(angle) == 0 # Axis are aligned + assert ((A.x-A.y+A.z).express(N).simplify() == + (-4*cos(q)/3 - S(1)/3)*N.x + (S(1)/3 - 4*sin(q + pi/6)/3)*N.y + + (4*cos(q + pi/3)/3 - S(1)/3)*N.z) + assert simplify(A.dcm(N)) == Matrix([ + [S(1)/3 - 2*cos(q)/3, -2*sin(q + pi/6)/3 - S(1)/3, + 2*cos(q + pi/3)/3 + S(1)/3], + [2*cos(q + pi/3)/3 + S(1)/3, 2*cos(q)/3 - S(1)/3, + 2*sin(q + pi/6)/3 + S(1)/3], + [-2*sin(q + pi/6)/3 - S(1)/3, 2*cos(q + pi/3)/3 + S(1)/3, + 2*cos(q)/3 - S(1)/3]]) + assert (A.ang_vel_in(N) - (u*N.x - u*N.y + u*N.z)/sqrt(3)).simplify() + assert A.ang_vel_in(N).express(A).simplify() == (u*A.x + u*A.y - + u*A.z)/sqrt(3) + assert A.ang_vel_in(N).magnitude() == sqrt(u**2) + angle = A.ang_vel_in(N).angle_between(A.x+A.y-A.z) + assert angle.xreplace({u: 1}).simplify() == 0 + assert (C.masscenter.vel(N).simplify() == + sqrt(3)*n*u/3*A.y + sqrt(3)*n*u/3*A.z) + assert C.masscenter.pos_from(P.masscenter) == m*N.x - n*A.x + assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() == + (m + n*(2*cos(q) - 1)/3)*N.x + n*(2*sin(q + pi/6) + + 1)/3*N.y - n*(2*cos(q + pi/3) + 1)/3*N.z) + assert (C.masscenter.vel(N).express(N).simplify() == + - 2*n*u*sin(q)/3*N.x + 2*n*u*cos(q + pi/6)/3*N.y + + 2*n*u*sin(q + pi/3)/3*N.z) + assert C.masscenter.vel(N).dot(N.x - N.y + N.z).simplify() == 0 + + +def test_create_aligned_frame_pi(): + N, A, P, C = _generate_body() + f = Joint._create_aligned_interframe(P, -P.x, P.x) + assert f.z == P.z + f = Joint._create_aligned_interframe(P, -P.y, P.y) + assert f.x == P.x + f = Joint._create_aligned_interframe(P, -P.z, P.z) + assert f.y == P.y + f = Joint._create_aligned_interframe(P, -P.x - P.y, P.x + P.y) + assert f.z == P.z + f = Joint._create_aligned_interframe(P, -P.y - P.z, P.y + P.z) + assert f.x == P.x + f = Joint._create_aligned_interframe(P, -P.x - P.z, P.x + P.z) + assert f.y == P.y + f = Joint._create_aligned_interframe(P, -P.x - P.y - P.z, P.x + P.y + P.z) + assert f.y - f.z == P.y - P.z + + +def test_pin_joint_axis(): + q, u = dynamicsymbols('q u') + # Test default joint axis + N, A, P, C, Pint, Cint = _generate_body(True) + J = PinJoint('J', P, C, q, u, parent_interframe=Pint, child_interframe=Cint) + assert J.joint_axis == Pint.x + # Test for the same joint axis expressed in different frames + N_R_A = Matrix([[0, sin(q), cos(q)], + [0, -cos(q), sin(q)], + [1, 0, 0]]) + N, A, P, C, Pint, Cint = _generate_body(True) + PinJoint('J', P, C, q, u, parent_interframe=Pint, child_interframe=Cint, + joint_axis=N.z) + assert N.dcm(A) == N_R_A + N, A, P, C, Pint, Cint = _generate_body(True) + PinJoint('J', P, C, q, u, parent_interframe=Pint, child_interframe=Cint, + joint_axis=-Pint.z) + assert N.dcm(A) == N_R_A + # Test time varying joint axis + N, A, P, C, Pint, Cint = _generate_body(True) + raises(ValueError, lambda: PinJoint('J', P, C, joint_axis=q * N.z)) + + +def test_locate_joint_pos(): + # Test Vector and default + N, A, P, C = _generate_body() + joint = PinJoint('J', P, C, parent_point=N.y + N.z) + assert joint.parent_point.name == 'J_P_joint' + assert joint.parent_point.pos_from(P.masscenter) == N.y + N.z + assert joint.child_point == C.masscenter + # Test Point objects + N, A, P, C = _generate_body() + parent_point = P.masscenter.locatenew('p', N.y + N.z) + joint = PinJoint('J', P, C, parent_point=parent_point, + child_point=C.masscenter) + assert joint.parent_point == parent_point + assert joint.child_point == C.masscenter + # Check invalid type + N, A, P, C = _generate_body() + raises(TypeError, + lambda: PinJoint('J', P, C, parent_point=N.x.to_matrix(N))) + # Test time varying positions + q = dynamicsymbols('q') + N, A, P, C = _generate_body() + raises(ValueError, lambda: PinJoint('J', P, C, parent_point=q * N.x)) + N, A, P, C = _generate_body() + child_point = C.masscenter.locatenew('p', q * A.y) + raises(ValueError, lambda: PinJoint('J', P, C, child_point=child_point)) + # Test undefined position + child_point = Point('p') + raises(ValueError, lambda: PinJoint('J', P, C, child_point=child_point)) + + +def test_locate_joint_frame(): + # Test rotated frame and default + N, A, P, C = _generate_body() + parent_interframe = ReferenceFrame('int_frame') + parent_interframe.orient_axis(N, N.z, 1) + joint = PinJoint('J', P, C, parent_interframe=parent_interframe) + assert joint.parent_interframe == parent_interframe + assert joint.parent_interframe.ang_vel_in(N) == 0 + assert joint.child_interframe == A + # Test time varying orientations + q = dynamicsymbols('q') + N, A, P, C = _generate_body() + parent_interframe = ReferenceFrame('int_frame') + parent_interframe.orient_axis(N, N.z, q) + raises(ValueError, + lambda: PinJoint('J', P, C, parent_interframe=parent_interframe)) + # Test undefined frame + N, A, P, C = _generate_body() + child_interframe = ReferenceFrame('int_frame') + child_interframe.orient_axis(N, N.z, 1) # Defined with respect to parent + raises(ValueError, + lambda: PinJoint('J', P, C, child_interframe=child_interframe)) + + +def test_prismatic_joint(): + _, _, P, C = _generate_body() + q, u = dynamicsymbols('q_S, u_S') + S = PrismaticJoint('S', P, C) + assert S.name == 'S' + assert S.parent == P + assert S.child == C + assert S.coordinates == Matrix([q]) + assert S.speeds == Matrix([u]) + assert S.kdes == Matrix([u - q.diff(t)]) + assert S.joint_axis == P.frame.x + assert S.child_point.pos_from(C.masscenter) == Vector(0) + assert S.parent_point.pos_from(P.masscenter) == Vector(0) + assert S.parent_point.pos_from(S.child_point) == - q * P.frame.x + assert P.masscenter.pos_from(C.masscenter) == - q * P.frame.x + assert C.masscenter.vel(P.frame) == u * P.frame.x + assert P.frame.ang_vel_in(C.frame) == 0 + assert C.frame.ang_vel_in(P.frame) == 0 + assert S.__str__() == 'PrismaticJoint: S parent: P child: C' + + N, A, P, C = _generate_body() + l, m = symbols('l m') + Pint = ReferenceFrame('P_int') + Pint.orient_axis(P.frame, P.y, pi / 2) + S = PrismaticJoint('S', P, C, parent_point=l * P.frame.x, + child_point=m * C.frame.y, joint_axis=P.frame.z, + parent_interframe=Pint) + + assert S.joint_axis == P.frame.z + assert S.child_point.pos_from(C.masscenter) == m * C.frame.y + assert S.parent_point.pos_from(P.masscenter) == l * P.frame.x + assert S.parent_point.pos_from(S.child_point) == - q * P.frame.z + assert P.masscenter.pos_from(C.masscenter) == - l * N.x - q * N.z + m * A.y + assert C.masscenter.vel(P.frame) == u * P.frame.z + assert P.masscenter.vel(Pint) == Vector(0) + assert C.frame.ang_vel_in(P.frame) == 0 + assert P.frame.ang_vel_in(C.frame) == 0 + + _, _, P, C = _generate_body() + Pint = ReferenceFrame('P_int') + Pint.orient_axis(P.frame, P.y, pi / 2) + S = PrismaticJoint('S', P, C, parent_point=l * P.frame.z, + child_point=m * C.frame.x, joint_axis=P.frame.z, + parent_interframe=Pint) + assert S.joint_axis == P.frame.z + assert S.child_point.pos_from(C.masscenter) == m * C.frame.x + assert S.parent_point.pos_from(P.masscenter) == l * P.frame.z + assert S.parent_point.pos_from(S.child_point) == - q * P.frame.z + assert P.masscenter.pos_from(C.masscenter) == (-l - q)*P.frame.z + m*C.frame.x + assert C.masscenter.vel(P.frame) == u * P.frame.z + assert C.frame.ang_vel_in(P.frame) == 0 + assert P.frame.ang_vel_in(C.frame) == 0 + + +def test_prismatic_joint_arbitrary_axis(): + q, u = dynamicsymbols('q_S, u_S') + + N, A, P, C = _generate_body() + PrismaticJoint('S', P, C, child_interframe=-A.x) + + assert (-A.x).angle_between(N.x) == 0 + assert -A.x.express(N) == N.x + assert A.dcm(N) == Matrix([[-1, 0, 0], [0, -1, 0], [0, 0, 1]]) + assert C.masscenter.pos_from(P.masscenter) == q * N.x + assert C.masscenter.pos_from(P.masscenter).express(A).simplify() == -q * A.x + assert C.masscenter.vel(N) == u * N.x + assert C.masscenter.vel(N).express(A) == -u * A.x + assert A.ang_vel_in(N) == 0 + assert N.ang_vel_in(A) == 0 + + #When axes are different and parent joint is at masscenter but child joint is at a unit vector from + #child masscenter. + N, A, P, C = _generate_body() + PrismaticJoint('S', P, C, child_interframe=A.y, child_point=A.x) + + assert A.y.angle_between(N.x) == 0 #Axis are aligned + assert A.y.express(N) == N.x + assert A.dcm(N) == Matrix([[0, -1, 0], [1, 0, 0], [0, 0, 1]]) + assert C.masscenter.vel(N) == u * N.x + assert C.masscenter.vel(N).express(A) == u * A.y + assert C.masscenter.pos_from(P.masscenter) == q*N.x - A.x + assert C.masscenter.pos_from(P.masscenter).express(N).simplify() == q*N.x + N.y + assert A.ang_vel_in(N) == 0 + assert N.ang_vel_in(A) == 0 + + #Similar to previous case but wrt parent body + N, A, P, C = _generate_body() + PrismaticJoint('S', P, C, parent_interframe=N.y, parent_point=N.x) + + assert N.y.angle_between(A.x) == 0 #Axis are aligned + assert N.y.express(A) == A.x + assert A.dcm(N) == Matrix([[0, 1, 0], [-1, 0, 0], [0, 0, 1]]) + assert C.masscenter.vel(N) == u * N.y + assert C.masscenter.vel(N).express(A) == u * A.x + assert C.masscenter.pos_from(P.masscenter) == N.x + q*N.y + assert A.ang_vel_in(N) == 0 + assert N.ang_vel_in(A) == 0 + + #Both joint pos is defined but different axes + N, A, P, C = _generate_body() + PrismaticJoint('S', P, C, parent_point=N.x, child_point=A.x, + child_interframe=A.x + A.y) + assert N.x.angle_between(A.x + A.y) == 0 #Axis are aligned + assert (A.x + A.y).express(N) == sqrt(2)*N.x + assert A.dcm(N) == Matrix([[sqrt(2)/2, -sqrt(2)/2, 0], [sqrt(2)/2, sqrt(2)/2, 0], [0, 0, 1]]) + assert C.masscenter.pos_from(P.masscenter) == (q + 1)*N.x - A.x + assert C.masscenter.pos_from(P.masscenter).express(N) == (q - sqrt(2)/2 + 1)*N.x + sqrt(2)/2*N.y + assert C.masscenter.vel(N).express(A) == u * (A.x + A.y)/sqrt(2) + assert C.masscenter.vel(N) == u*N.x + assert A.ang_vel_in(N) == 0 + assert N.ang_vel_in(A) == 0 + + N, A, P, C = _generate_body() + PrismaticJoint('S', P, C, parent_point=N.x, child_point=A.x, + child_interframe=A.x + A.y - A.z) + assert N.x.angle_between(A.x + A.y - A.z).simplify() == 0 #Axis are aligned + assert ((A.x + A.y - A.z).express(N) - sqrt(3)*N.x).simplify() == 0 + assert simplify(A.dcm(N)) == Matrix([[sqrt(3)/3, -sqrt(3)/3, sqrt(3)/3], + [sqrt(3)/3, sqrt(3)/6 + S(1)/2, S(1)/2 - sqrt(3)/6], + [-sqrt(3)/3, S(1)/2 - sqrt(3)/6, sqrt(3)/6 + S(1)/2]]) + assert C.masscenter.pos_from(P.masscenter) == (q + 1)*N.x - A.x + assert (C.masscenter.pos_from(P.masscenter).express(N) - + ((q - sqrt(3)/3 + 1)*N.x + sqrt(3)/3*N.y - sqrt(3)/3*N.z)).simplify() == 0 + assert C.masscenter.vel(N) == u*N.x + assert (C.masscenter.vel(N).express(A) - ( + sqrt(3)*u/3*A.x + sqrt(3)*u/3*A.y - sqrt(3)*u/3*A.z)).simplify() + assert A.ang_vel_in(N) == 0 + assert N.ang_vel_in(A) == 0 + + N, A, P, C = _generate_body() + m, n = symbols('m n') + PrismaticJoint('S', P, C, parent_point=m*N.x, child_point=n*A.x, + child_interframe=A.x + A.y - A.z, + parent_interframe=N.x - N.y + N.z) + # 0 angle means that the axis are aligned + assert (N.x-N.y+N.z).angle_between(A.x+A.y-A.z).simplify() == 0 + assert ((A.x+A.y-A.z).express(N) - (N.x - N.y + N.z)).simplify() == 0 + assert simplify(A.dcm(N)) == Matrix([[-S(1)/3, -S(2)/3, S(2)/3], + [S(2)/3, S(1)/3, S(2)/3], + [-S(2)/3, S(2)/3, S(1)/3]]) + assert (C.masscenter.pos_from(P.masscenter) - ( + (m + sqrt(3)*q/3)*N.x - sqrt(3)*q/3*N.y + sqrt(3)*q/3*N.z - n*A.x) + ).express(N).simplify() == 0 + assert (C.masscenter.pos_from(P.masscenter).express(N) - ( + (m + n/3 + sqrt(3)*q/3)*N.x + (2*n/3 - sqrt(3)*q/3)*N.y + + (-2*n/3 + sqrt(3)*q/3)*N.z)).simplify() == 0 + assert (C.masscenter.vel(N).express(N) - ( + sqrt(3)*u/3*N.x - sqrt(3)*u/3*N.y + sqrt(3)*u/3*N.z)).simplify() == 0 + assert (C.masscenter.vel(N).express(A) - + (sqrt(3)*u/3*A.x + sqrt(3)*u/3*A.y - sqrt(3)*u/3*A.z)).simplify() == 0 + assert A.ang_vel_in(N) == 0 + assert N.ang_vel_in(A) == 0 + + +def test_cylindrical_joint(): + N, A, P, C = _generate_body() + q0_def, q1_def, u0_def, u1_def = dynamicsymbols('q0:2_J, u0:2_J') + Cj = CylindricalJoint('J', P, C) + assert Cj.name == 'J' + assert Cj.parent == P + assert Cj.child == C + assert Cj.coordinates == Matrix([q0_def, q1_def]) + assert Cj.speeds == Matrix([u0_def, u1_def]) + assert Cj.rotation_coordinate == q0_def + assert Cj.translation_coordinate == q1_def + assert Cj.rotation_speed == u0_def + assert Cj.translation_speed == u1_def + assert Cj.kdes == Matrix([u0_def - q0_def.diff(t), u1_def - q1_def.diff(t)]) + assert Cj.joint_axis == N.x + assert Cj.child_point.pos_from(C.masscenter) == Vector(0) + assert Cj.parent_point.pos_from(P.masscenter) == Vector(0) + assert Cj.parent_point.pos_from(Cj._child_point) == -q1_def * N.x + assert C.masscenter.pos_from(P.masscenter) == q1_def * N.x + assert Cj.child_point.vel(N) == u1_def * N.x + assert A.ang_vel_in(N) == u0_def * N.x + assert Cj.parent_interframe == N + assert Cj.child_interframe == A + assert Cj.__str__() == 'CylindricalJoint: J parent: P child: C' + + q0, q1, u0, u1 = dynamicsymbols('q0:2, u0:2') + l, m = symbols('l, m') + N, A, P, C, Pint, Cint = _generate_body(True) + Cj = CylindricalJoint('J', P, C, rotation_coordinate=q0, rotation_speed=u0, + translation_speed=u1, parent_point=m * N.x, + child_point=l * A.y, parent_interframe=Pint, + child_interframe=Cint, joint_axis=2 * N.z) + assert Cj.coordinates == Matrix([q0, q1_def]) + assert Cj.speeds == Matrix([u0, u1]) + assert Cj.rotation_coordinate == q0 + assert Cj.translation_coordinate == q1_def + assert Cj.rotation_speed == u0 + assert Cj.translation_speed == u1 + assert Cj.kdes == Matrix([u0 - q0.diff(t), u1 - q1_def.diff(t)]) + assert Cj.joint_axis == 2 * N.z + assert Cj.child_point.pos_from(C.masscenter) == l * A.y + assert Cj.parent_point.pos_from(P.masscenter) == m * N.x + assert Cj.parent_point.pos_from(Cj._child_point) == -q1_def * N.z + assert C.masscenter.pos_from( + P.masscenter) == m * N.x + q1_def * N.z - l * A.y + assert C.masscenter.vel(N) == u1 * N.z - u0 * l * A.z + assert A.ang_vel_in(N) == u0 * N.z + + +def test_planar_joint(): + N, A, P, C = _generate_body() + q0_def, q1_def, q2_def = dynamicsymbols('q0:3_J') + u0_def, u1_def, u2_def = dynamicsymbols('u0:3_J') + Cj = PlanarJoint('J', P, C) + assert Cj.name == 'J' + assert Cj.parent == P + assert Cj.child == C + assert Cj.coordinates == Matrix([q0_def, q1_def, q2_def]) + assert Cj.speeds == Matrix([u0_def, u1_def, u2_def]) + assert Cj.rotation_coordinate == q0_def + assert Cj.planar_coordinates == Matrix([q1_def, q2_def]) + assert Cj.rotation_speed == u0_def + assert Cj.planar_speeds == Matrix([u1_def, u2_def]) + assert Cj.kdes == Matrix([u0_def - q0_def.diff(t), u1_def - q1_def.diff(t), + u2_def - q2_def.diff(t)]) + assert Cj.rotation_axis == N.x + assert Cj.planar_vectors == [N.y, N.z] + assert Cj.child_point.pos_from(C.masscenter) == Vector(0) + assert Cj.parent_point.pos_from(P.masscenter) == Vector(0) + r_P_C = q1_def * N.y + q2_def * N.z + assert Cj.parent_point.pos_from(Cj.child_point) == -r_P_C + assert C.masscenter.pos_from(P.masscenter) == r_P_C + assert Cj.child_point.vel(N) == u1_def * N.y + u2_def * N.z + assert A.ang_vel_in(N) == u0_def * N.x + assert Cj.parent_interframe == N + assert Cj.child_interframe == A + assert Cj.__str__() == 'PlanarJoint: J parent: P child: C' + + q0, q1, q2, u0, u1, u2 = dynamicsymbols('q0:3, u0:3') + l, m = symbols('l, m') + N, A, P, C, Pint, Cint = _generate_body(True) + Cj = PlanarJoint('J', P, C, rotation_coordinate=q0, + planar_coordinates=[q1, q2], planar_speeds=[u1, u2], + parent_point=m * N.x, child_point=l * A.y, + parent_interframe=Pint, child_interframe=Cint) + assert Cj.coordinates == Matrix([q0, q1, q2]) + assert Cj.speeds == Matrix([u0_def, u1, u2]) + assert Cj.rotation_coordinate == q0 + assert Cj.planar_coordinates == Matrix([q1, q2]) + assert Cj.rotation_speed == u0_def + assert Cj.planar_speeds == Matrix([u1, u2]) + assert Cj.kdes == Matrix([u0_def - q0.diff(t), u1 - q1.diff(t), + u2 - q2.diff(t)]) + assert Cj.rotation_axis == Pint.x + assert Cj.planar_vectors == [Pint.y, Pint.z] + assert Cj.child_point.pos_from(C.masscenter) == l * A.y + assert Cj.parent_point.pos_from(P.masscenter) == m * N.x + assert Cj.parent_point.pos_from(Cj.child_point) == q1 * N.y + q2 * N.z + assert C.masscenter.pos_from( + P.masscenter) == m * N.x - q1 * N.y - q2 * N.z - l * A.y + assert C.masscenter.vel(N) == -u1 * N.y - u2 * N.z + u0_def * l * A.x + assert A.ang_vel_in(N) == u0_def * N.x + + +def test_planar_joint_advanced(): + # Tests whether someone is able to just specify two normals, which will form + # the rotation axis seen from the parent and child body. + # This specific example is a block on a slope, which has that same slope of + # 30 degrees, so in the zero configuration the frames of the parent and + # child are actually aligned. + q0, q1, q2, u0, u1, u2 = dynamicsymbols('q0:3, u0:3') + l1, l2 = symbols('l1:3') + N, A, P, C = _generate_body() + J = PlanarJoint('J', P, C, q0, [q1, q2], u0, [u1, u2], + parent_point=l1 * N.z, + child_point=-l2 * C.z, + parent_interframe=N.z + N.y / sqrt(3), + child_interframe=A.z + A.y / sqrt(3)) + assert J.rotation_axis.express(N) == (N.z + N.y / sqrt(3)).normalize() + assert J.rotation_axis.express(A) == (A.z + A.y / sqrt(3)).normalize() + assert J.rotation_axis.angle_between(N.z) == pi / 6 + assert N.dcm(A).xreplace({q0: 0, q1: 0, q2: 0}) == eye(3) + N_R_A = Matrix([ + [cos(q0), -sqrt(3) * sin(q0) / 2, sin(q0) / 2], + [sqrt(3) * sin(q0) / 2, 3 * cos(q0) / 4 + 1 / 4, + sqrt(3) * (1 - cos(q0)) / 4], + [-sin(q0) / 2, sqrt(3) * (1 - cos(q0)) / 4, cos(q0) / 4 + 3 / 4]]) + # N.dcm(A) == N_R_A did not work + assert simplify(N.dcm(A) - N_R_A) == zeros(3) + + +def test_spherical_joint(): + N, A, P, C = _generate_body() + q0, q1, q2, u0, u1, u2 = dynamicsymbols('q0:3_S, u0:3_S') + S = SphericalJoint('S', P, C) + assert S.name == 'S' + assert S.parent == P + assert S.child == C + assert S.coordinates == Matrix([q0, q1, q2]) + assert S.speeds == Matrix([u0, u1, u2]) + assert S.kdes == Matrix([u0 - q0.diff(t), u1 - q1.diff(t), u2 - q2.diff(t)]) + assert S.child_point.pos_from(C.masscenter) == Vector(0) + assert S.parent_point.pos_from(P.masscenter) == Vector(0) + assert S.parent_point.pos_from(S.child_point) == Vector(0) + assert P.masscenter.pos_from(C.masscenter) == Vector(0) + assert C.masscenter.vel(N) == Vector(0) + assert N.ang_vel_in(A) == (-u0 * cos(q1) * cos(q2) - u1 * sin(q2)) * A.x + ( + u0 * sin(q2) * cos(q1) - u1 * cos(q2)) * A.y + ( + -u0 * sin(q1) - u2) * A.z + assert A.ang_vel_in(N) == (u0 * cos(q1) * cos(q2) + u1 * sin(q2)) * A.x + ( + -u0 * sin(q2) * cos(q1) + u1 * cos(q2)) * A.y + ( + u0 * sin(q1) + u2) * A.z + assert S.__str__() == 'SphericalJoint: S parent: P child: C' + assert S._rot_type == 'BODY' + assert S._rot_order == 123 + assert S._amounts is None + + +def test_spherical_joint_speeds_as_derivative_terms(): + # This tests checks whether the system remains valid if the user chooses to + # pass the derivative of the generalized coordinates as generalized speeds + q0, q1, q2 = dynamicsymbols('q0:3') + u0, u1, u2 = dynamicsymbols('q0:3', 1) + N, A, P, C = _generate_body() + S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2]) + assert S.coordinates == Matrix([q0, q1, q2]) + assert S.speeds == Matrix([u0, u1, u2]) + assert S.kdes == Matrix([0, 0, 0]) + assert N.ang_vel_in(A) == (-u0 * cos(q1) * cos(q2) - u1 * sin(q2)) * A.x + ( + u0 * sin(q2) * cos(q1) - u1 * cos(q2)) * A.y + ( + -u0 * sin(q1) - u2) * A.z + + +def test_spherical_joint_coords(): + q0s, q1s, q2s, u0s, u1s, u2s = dynamicsymbols('q0:3_S, u0:3_S') + q0, q1, q2, q3, u0, u1, u2, u4 = dynamicsymbols('q0:4, u0:4') + # Test coordinates as list + N, A, P, C = _generate_body() + S = SphericalJoint('S', P, C, [q0, q1, q2], [u0, u1, u2]) + assert S.coordinates == Matrix([q0, q1, q2]) + assert S.speeds == Matrix([u0, u1, u2]) + # Test coordinates as Matrix + N, A, P, C = _generate_body() + S = SphericalJoint('S', P, C, Matrix([q0, q1, q2]), + Matrix([u0, u1, u2])) + assert S.coordinates == Matrix([q0, q1, q2]) + assert S.speeds == Matrix([u0, u1, u2]) + # Test too few generalized coordinates + N, A, P, C = _generate_body() + raises(ValueError, + lambda: SphericalJoint('S', P, C, Matrix([q0, q1]), Matrix([u0]))) + # Test too many generalized coordinates + raises(ValueError, lambda: SphericalJoint( + 'S', P, C, Matrix([q0, q1, q2, q3]), Matrix([u0, u1, u2]))) + raises(ValueError, lambda: SphericalJoint( + 'S', P, C, Matrix([q0, q1, q2]), Matrix([u0, u1, u2, u4]))) + + +def test_spherical_joint_orient_body(): + q0, q1, q2, u0, u1, u2 = dynamicsymbols('q0:3, u0:3') + N_R_A = Matrix([ + [-sin(q1), -sin(q2) * cos(q1), cos(q1) * cos(q2)], + [-sin(q0) * cos(q1), sin(q0) * sin(q1) * sin(q2) - cos(q0) * cos(q2), + -sin(q0) * sin(q1) * cos(q2) - sin(q2) * cos(q0)], + [cos(q0) * cos(q1), -sin(q0) * cos(q2) - sin(q1) * sin(q2) * cos(q0), + -sin(q0) * sin(q2) + sin(q1) * cos(q0) * cos(q2)]]) + N_w_A = Matrix([[-u0 * sin(q1) - u2], + [-u0 * sin(q2) * cos(q1) + u1 * cos(q2)], + [u0 * cos(q1) * cos(q2) + u1 * sin(q2)]]) + N_v_Co = Matrix([ + [-sqrt(2) * (u0 * cos(q2 + pi / 4) * cos(q1) + u1 * sin(q2 + pi / 4))], + [-u0 * sin(q1) - u2], [-u0 * sin(q1) - u2]]) + # Test default rot_type='BODY', rot_order=123 + N, A, P, C, Pint, Cint = _generate_body(True) + S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2], + parent_point=N.x + N.y, child_point=-A.y + A.z, + parent_interframe=Pint, child_interframe=Cint, + rot_type='body', rot_order=123) + assert S._rot_type.upper() == 'BODY' + assert S._rot_order == 123 + assert simplify(N.dcm(A) - N_R_A) == zeros(3) + assert simplify(A.ang_vel_in(N).to_matrix(A) - N_w_A) == zeros(3, 1) + assert simplify(C.masscenter.vel(N).to_matrix(A)) == N_v_Co + # Test change of amounts + N, A, P, C, Pint, Cint = _generate_body(True) + S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2], + parent_point=N.x + N.y, child_point=-A.y + A.z, + parent_interframe=Pint, child_interframe=Cint, + rot_type='BODY', amounts=(q1, q0, q2), rot_order=123) + switch_order = lambda expr: expr.xreplace( + {q0: q1, q1: q0, q2: q2, u0: u1, u1: u0, u2: u2}) + assert S._rot_type.upper() == 'BODY' + assert S._rot_order == 123 + assert simplify(N.dcm(A) - switch_order(N_R_A)) == zeros(3) + assert simplify(A.ang_vel_in(N).to_matrix(A) - switch_order(N_w_A) + ) == zeros(3, 1) + assert simplify(C.masscenter.vel(N).to_matrix(A)) == switch_order(N_v_Co) + # Test different rot_order + N, A, P, C, Pint, Cint = _generate_body(True) + S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2], + parent_point=N.x + N.y, child_point=-A.y + A.z, + parent_interframe=Pint, child_interframe=Cint, + rot_type='BodY', rot_order='yxz') + assert S._rot_type.upper() == 'BODY' + assert S._rot_order == 'yxz' + assert simplify(N.dcm(A) - Matrix([ + [-sin(q0) * cos(q1), sin(q0) * sin(q1) * cos(q2) - sin(q2) * cos(q0), + sin(q0) * sin(q1) * sin(q2) + cos(q0) * cos(q2)], + [-sin(q1), -cos(q1) * cos(q2), -sin(q2) * cos(q1)], + [cos(q0) * cos(q1), -sin(q0) * sin(q2) - sin(q1) * cos(q0) * cos(q2), + sin(q0) * cos(q2) - sin(q1) * sin(q2) * cos(q0)]])) == zeros(3) + assert simplify(A.ang_vel_in(N).to_matrix(A) - Matrix([ + [u0 * sin(q1) - u2], [u0 * cos(q1) * cos(q2) - u1 * sin(q2)], + [u0 * sin(q2) * cos(q1) + u1 * cos(q2)]])) == zeros(3, 1) + assert simplify(C.masscenter.vel(N).to_matrix(A)) == Matrix([ + [-sqrt(2) * (u0 * sin(q2 + pi / 4) * cos(q1) + u1 * cos(q2 + pi / 4))], + [u0 * sin(q1) - u2], [u0 * sin(q1) - u2]]) + + +def test_spherical_joint_orient_space(): + q0, q1, q2, u0, u1, u2 = dynamicsymbols('q0:3, u0:3') + N_R_A = Matrix([ + [-sin(q0) * sin(q2) - sin(q1) * cos(q0) * cos(q2), + sin(q0) * sin(q1) * cos(q2) - sin(q2) * cos(q0), cos(q1) * cos(q2)], + [-sin(q0) * cos(q2) + sin(q1) * sin(q2) * cos(q0), + -sin(q0) * sin(q1) * sin(q2) - cos(q0) * cos(q2), -sin(q2) * cos(q1)], + [cos(q0) * cos(q1), -sin(q0) * cos(q1), sin(q1)]]) + N_w_A = Matrix([ + [u1 * sin(q0) - u2 * cos(q0) * cos(q1)], + [u1 * cos(q0) + u2 * sin(q0) * cos(q1)], [u0 - u2 * sin(q1)]]) + N_v_Co = Matrix([ + [u0 - u2 * sin(q1)], [u0 - u2 * sin(q1)], + [sqrt(2) * (-u1 * sin(q0 + pi / 4) + u2 * cos(q0 + pi / 4) * cos(q1))]]) + # Test default rot_type='BODY', rot_order=123 + N, A, P, C, Pint, Cint = _generate_body(True) + S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2], + parent_point=N.x + N.z, child_point=-A.x + A.y, + parent_interframe=Pint, child_interframe=Cint, + rot_type='space', rot_order=123) + assert S._rot_type.upper() == 'SPACE' + assert S._rot_order == 123 + assert simplify(N.dcm(A) - N_R_A) == zeros(3) + assert simplify(A.ang_vel_in(N).to_matrix(A)) == N_w_A + assert simplify(C.masscenter.vel(N).to_matrix(A)) == N_v_Co + # Test change of amounts + switch_order = lambda expr: expr.xreplace( + {q0: q1, q1: q0, q2: q2, u0: u1, u1: u0, u2: u2}) + N, A, P, C, Pint, Cint = _generate_body(True) + S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2], + parent_point=N.x + N.z, child_point=-A.x + A.y, + parent_interframe=Pint, child_interframe=Cint, + rot_type='SPACE', amounts=(q1, q0, q2), rot_order=123) + assert S._rot_type.upper() == 'SPACE' + assert S._rot_order == 123 + assert simplify(N.dcm(A) - switch_order(N_R_A)) == zeros(3) + assert simplify(A.ang_vel_in(N).to_matrix(A)) == switch_order(N_w_A) + assert simplify(C.masscenter.vel(N).to_matrix(A)) == switch_order(N_v_Co) + # Test different rot_order + N, A, P, C, Pint, Cint = _generate_body(True) + S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2], + parent_point=N.x + N.z, child_point=-A.x + A.y, + parent_interframe=Pint, child_interframe=Cint, + rot_type='SPaCe', rot_order='zxy') + assert S._rot_type.upper() == 'SPACE' + assert S._rot_order == 'zxy' + assert simplify(N.dcm(A) - Matrix([ + [-sin(q2) * cos(q1), -sin(q0) * cos(q2) + sin(q1) * sin(q2) * cos(q0), + sin(q0) * sin(q1) * sin(q2) + cos(q0) * cos(q2)], + [-sin(q1), -cos(q0) * cos(q1), -sin(q0) * cos(q1)], + [cos(q1) * cos(q2), -sin(q0) * sin(q2) - sin(q1) * cos(q0) * cos(q2), + -sin(q0) * sin(q1) * cos(q2) + sin(q2) * cos(q0)]])) + assert simplify(A.ang_vel_in(N).to_matrix(A) - Matrix([ + [-u0 + u2 * sin(q1)], [-u1 * sin(q0) + u2 * cos(q0) * cos(q1)], + [u1 * cos(q0) + u2 * sin(q0) * cos(q1)]])) == zeros(3, 1) + assert simplify(C.masscenter.vel(N).to_matrix(A) - Matrix([ + [u1 * cos(q0) + u2 * sin(q0) * cos(q1)], + [u1 * cos(q0) + u2 * sin(q0) * cos(q1)], + [u0 + u1 * sin(q0) - u2 * sin(q1) - + u2 * cos(q0) * cos(q1)]])) == zeros(3, 1) + + +def test_weld_joint(): + _, _, P, C = _generate_body() + W = WeldJoint('W', P, C) + assert W.name == 'W' + assert W.parent == P + assert W.child == C + assert W.coordinates == Matrix() + assert W.speeds == Matrix() + assert W.kdes == Matrix(1, 0, []).T + assert P.frame.dcm(C.frame) == eye(3) + assert W.child_point.pos_from(C.masscenter) == Vector(0) + assert W.parent_point.pos_from(P.masscenter) == Vector(0) + assert W.parent_point.pos_from(W.child_point) == Vector(0) + assert P.masscenter.pos_from(C.masscenter) == Vector(0) + assert C.masscenter.vel(P.frame) == Vector(0) + assert P.frame.ang_vel_in(C.frame) == 0 + assert C.frame.ang_vel_in(P.frame) == 0 + assert W.__str__() == 'WeldJoint: W parent: P child: C' + + N, A, P, C = _generate_body() + l, m = symbols('l m') + Pint = ReferenceFrame('P_int') + Pint.orient_axis(P.frame, P.y, pi / 2) + W = WeldJoint('W', P, C, parent_point=l * P.frame.x, + child_point=m * C.frame.y, parent_interframe=Pint) + + assert W.child_point.pos_from(C.masscenter) == m * C.frame.y + assert W.parent_point.pos_from(P.masscenter) == l * P.frame.x + assert W.parent_point.pos_from(W.child_point) == Vector(0) + assert P.masscenter.pos_from(C.masscenter) == - l * N.x + m * A.y + assert C.masscenter.vel(P.frame) == Vector(0) + assert P.masscenter.vel(Pint) == Vector(0) + assert C.frame.ang_vel_in(P.frame) == 0 + assert P.frame.ang_vel_in(C.frame) == 0 + assert P.x == A.z + + with warns_deprecated_sympy(): + JointsMethod(P, W) # Tests #10770 + + +def test_deprecated_parent_child_axis(): + q, u = dynamicsymbols('q_J, u_J') + N, A, P, C = _generate_body() + with warns_deprecated_sympy(): + PinJoint('J', P, C, child_axis=-A.x) + assert (-A.x).angle_between(N.x) == 0 + assert -A.x.express(N) == N.x + assert A.dcm(N) == Matrix([[-1, 0, 0], + [0, -cos(q), -sin(q)], + [0, -sin(q), cos(q)]]) + assert A.ang_vel_in(N) == u * N.x + assert A.ang_vel_in(N).magnitude() == sqrt(u ** 2) + + N, A, P, C = _generate_body() + with warns_deprecated_sympy(): + PrismaticJoint('J', P, C, parent_axis=P.x + P.y) + assert (A.x).angle_between(N.x + N.y) == 0 + assert A.x.express(N) == (N.x + N.y) / sqrt(2) + assert A.dcm(N) == Matrix([[sqrt(2) / 2, sqrt(2) / 2, 0], + [-sqrt(2) / 2, sqrt(2) / 2, 0], [0, 0, 1]]) + assert A.ang_vel_in(N) == Vector(0) + + +def test_deprecated_joint_pos(): + N, A, P, C = _generate_body() + with warns_deprecated_sympy(): + pin = PinJoint('J', P, C, parent_joint_pos=N.x + N.y, + child_joint_pos=C.y - C.z) + assert pin.parent_point.pos_from(P.masscenter) == N.x + N.y + assert pin.child_point.pos_from(C.masscenter) == C.y - C.z + + N, A, P, C = _generate_body() + with warns_deprecated_sympy(): + slider = PrismaticJoint('J', P, C, parent_joint_pos=N.z + N.y, + child_joint_pos=C.y - C.x) + assert slider.parent_point.pos_from(P.masscenter) == N.z + N.y + assert slider.child_point.pos_from(C.masscenter) == C.y - C.x diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_jointsmethod.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_jointsmethod.py new file mode 100644 index 0000000000000000000000000000000000000000..1b48eae06dadc627442fd4e42445450be0393e33 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_jointsmethod.py @@ -0,0 +1,249 @@ +from sympy.core.function import expand +from sympy.core.symbol import symbols +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.matrices.dense import Matrix +from sympy.simplify.trigsimp import trigsimp +from sympy.physics.mechanics import ( + PinJoint, JointsMethod, RigidBody, Particle, Body, KanesMethod, + PrismaticJoint, LagrangesMethod, inertia) +from sympy.physics.vector import dynamicsymbols, ReferenceFrame +from sympy.testing.pytest import raises, warns_deprecated_sympy +from sympy import zeros +from sympy.utilities.lambdify import lambdify +from sympy.solvers.solvers import solve + + +t = dynamicsymbols._t # type: ignore + + +def test_jointsmethod(): + with warns_deprecated_sympy(): + P = Body('P') + C = Body('C') + Pin = PinJoint('P1', P, C) + C_ixx, g = symbols('C_ixx g') + q, u = dynamicsymbols('q_P1, u_P1') + P.apply_force(g*P.y) + with warns_deprecated_sympy(): + method = JointsMethod(P, Pin) + assert method.frame == P.frame + assert method.bodies == [C, P] + assert method.loads == [(P.masscenter, g*P.frame.y)] + assert method.q == Matrix([q]) + assert method.u == Matrix([u]) + assert method.kdes == Matrix([u - q.diff()]) + soln = method.form_eoms() + assert soln == Matrix([[-C_ixx*u.diff()]]) + assert method.forcing_full == Matrix([[u], [0]]) + assert method.mass_matrix_full == Matrix([[1, 0], [0, C_ixx]]) + assert isinstance(method.method, KanesMethod) + + +def test_rigid_body_particle_compatibility(): + l, m, g = symbols('l m g') + C = RigidBody('C') + b = Particle('b', mass=m) + b_frame = ReferenceFrame('b_frame') + q, u = dynamicsymbols('q u') + P = PinJoint('P', C, b, coordinates=q, speeds=u, child_interframe=b_frame, + child_point=-l * b_frame.x, joint_axis=C.z) + with warns_deprecated_sympy(): + method = JointsMethod(C, P) + method.loads.append((b.masscenter, m * g * C.x)) + method.form_eoms() + rhs = method.rhs() + assert rhs[1] == -g*sin(q)/l + + +def test_jointmethod_duplicate_coordinates_speeds(): + with warns_deprecated_sympy(): + P = Body('P') + C = Body('C') + T = Body('T') + q, u = dynamicsymbols('q u') + P1 = PinJoint('P1', P, C, q) + P2 = PrismaticJoint('P2', C, T, q) + with warns_deprecated_sympy(): + raises(ValueError, lambda: JointsMethod(P, P1, P2)) + + P1 = PinJoint('P1', P, C, speeds=u) + P2 = PrismaticJoint('P2', C, T, speeds=u) + with warns_deprecated_sympy(): + raises(ValueError, lambda: JointsMethod(P, P1, P2)) + + P1 = PinJoint('P1', P, C, q, u) + P2 = PrismaticJoint('P2', C, T, q, u) + with warns_deprecated_sympy(): + raises(ValueError, lambda: JointsMethod(P, P1, P2)) + +def test_complete_simple_double_pendulum(): + q1, q2 = dynamicsymbols('q1 q2') + u1, u2 = dynamicsymbols('u1 u2') + m, l, g = symbols('m l g') + with warns_deprecated_sympy(): + C = Body('C') # ceiling + PartP = Body('P', mass=m) + PartR = Body('R', mass=m) + J1 = PinJoint('J1', C, PartP, speeds=u1, coordinates=q1, + child_point=-l*PartP.x, joint_axis=C.z) + J2 = PinJoint('J2', PartP, PartR, speeds=u2, coordinates=q2, + child_point=-l*PartR.x, joint_axis=PartP.z) + + PartP.apply_force(m*g*C.x) + PartR.apply_force(m*g*C.x) + + with warns_deprecated_sympy(): + method = JointsMethod(C, J1, J2) + method.form_eoms() + + assert expand(method.mass_matrix_full) == Matrix([[1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 2*l**2*m*cos(q2) + 3*l**2*m, l**2*m*cos(q2) + l**2*m], + [0, 0, l**2*m*cos(q2) + l**2*m, l**2*m]]) + assert trigsimp(method.forcing_full) == trigsimp(Matrix([[u1], [u2], [-g*l*m*(sin(q1 + q2) + sin(q1)) - + g*l*m*sin(q1) + l**2*m*(2*u1 + u2)*u2*sin(q2)], + [-g*l*m*sin(q1 + q2) - l**2*m*u1**2*sin(q2)]])) + +def test_two_dof_joints(): + q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2') + m, c1, c2, k1, k2 = symbols('m c1 c2 k1 k2') + with warns_deprecated_sympy(): + W = Body('W') + B1 = Body('B1', mass=m) + B2 = Body('B2', mass=m) + J1 = PrismaticJoint('J1', W, B1, coordinates=q1, speeds=u1) + J2 = PrismaticJoint('J2', B1, B2, coordinates=q2, speeds=u2) + W.apply_force(k1*q1*W.x, reaction_body=B1) + W.apply_force(c1*u1*W.x, reaction_body=B1) + B1.apply_force(k2*q2*W.x, reaction_body=B2) + B1.apply_force(c2*u2*W.x, reaction_body=B2) + with warns_deprecated_sympy(): + method = JointsMethod(W, J1, J2) + method.form_eoms() + MM = method.mass_matrix + forcing = method.forcing + rhs = MM.LUsolve(forcing) + assert expand(rhs[0]) == expand((-k1 * q1 - c1 * u1 + k2 * q2 + c2 * u2)/m) + assert expand(rhs[1]) == expand((k1 * q1 + c1 * u1 - 2 * k2 * q2 - 2 * + c2 * u2) / m) + +def test_simple_pedulum(): + l, m, g = symbols('l m g') + with warns_deprecated_sympy(): + C = Body('C') + b = Body('b', mass=m) + q = dynamicsymbols('q') + P = PinJoint('P', C, b, speeds=q.diff(t), coordinates=q, + child_point=-l * b.x, joint_axis=C.z) + b.potential_energy = - m * g * l * cos(q) + with warns_deprecated_sympy(): + method = JointsMethod(C, P) + method.form_eoms(LagrangesMethod) + rhs = method.rhs() + assert rhs[1] == -g*sin(q)/l + +def test_chaos_pendulum(): + #https://www.pydy.org/examples/chaos_pendulum.html + mA, mB, lA, lB, IAxx, IBxx, IByy, IBzz, g = symbols('mA, mB, lA, lB, IAxx, IBxx, IByy, IBzz, g') + theta, phi, omega, alpha = dynamicsymbols('theta phi omega alpha') + + A = ReferenceFrame('A') + B = ReferenceFrame('B') + + with warns_deprecated_sympy(): + rod = Body('rod', mass=mA, frame=A, + central_inertia=inertia(A, IAxx, IAxx, 0)) + plate = Body('plate', mass=mB, frame=B, + central_inertia=inertia(B, IBxx, IByy, IBzz)) + C = Body('C') + J1 = PinJoint('J1', C, rod, coordinates=theta, speeds=omega, + child_point=-lA * rod.z, joint_axis=C.y) + J2 = PinJoint('J2', rod, plate, coordinates=phi, speeds=alpha, + parent_point=(lB - lA) * rod.z, joint_axis=rod.z) + + rod.apply_force(mA*g*C.z) + plate.apply_force(mB*g*C.z) + + with warns_deprecated_sympy(): + method = JointsMethod(C, J1, J2) + method.form_eoms() + + MM = method.mass_matrix + forcing = method.forcing + rhs = MM.LUsolve(forcing) + xd = (-2 * IBxx * alpha * omega * sin(phi) * cos(phi) + 2 * IByy * alpha * omega * sin(phi) * + cos(phi) - g * lA * mA * sin(theta) - g * lB * mB * sin(theta)) / (IAxx + IBxx * + sin(phi)**2 + IByy * cos(phi)**2 + lA**2 * mA + lB**2 * mB) + assert (rhs[0] - xd).simplify() == 0 + xd = (IBxx - IByy) * omega**2 * sin(phi) * cos(phi) / IBzz + assert (rhs[1] - xd).simplify() == 0 + +def test_four_bar_linkage_with_manual_constraints(): + q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1:4, u1:4') + l1, l2, l3, l4, rho = symbols('l1:5, rho') + + N = ReferenceFrame('N') + inertias = [inertia(N, 0, 0, rho * l ** 3 / 12) for l in (l1, l2, l3, l4)] + with warns_deprecated_sympy(): + link1 = Body('Link1', frame=N, mass=rho * l1, + central_inertia=inertias[0]) + link2 = Body('Link2', mass=rho * l2, central_inertia=inertias[1]) + link3 = Body('Link3', mass=rho * l3, central_inertia=inertias[2]) + link4 = Body('Link4', mass=rho * l4, central_inertia=inertias[3]) + + joint1 = PinJoint( + 'J1', link1, link2, coordinates=q1, speeds=u1, joint_axis=link1.z, + parent_point=l1 / 2 * link1.x, child_point=-l2 / 2 * link2.x) + joint2 = PinJoint( + 'J2', link2, link3, coordinates=q2, speeds=u2, joint_axis=link2.z, + parent_point=l2 / 2 * link2.x, child_point=-l3 / 2 * link3.x) + joint3 = PinJoint( + 'J3', link3, link4, coordinates=q3, speeds=u3, joint_axis=link3.z, + parent_point=l3 / 2 * link3.x, child_point=-l4 / 2 * link4.x) + + loop = link4.masscenter.pos_from(link1.masscenter) \ + + l1 / 2 * link1.x + l4 / 2 * link4.x + + fh = Matrix([loop.dot(link1.x), loop.dot(link1.y)]) + + with warns_deprecated_sympy(): + method = JointsMethod(link1, joint1, joint2, joint3) + + t = dynamicsymbols._t + qdots = solve(method.kdes, [q1.diff(t), q2.diff(t), q3.diff(t)]) + fhd = fh.diff(t).subs(qdots) + + kane = KanesMethod(method.frame, q_ind=[q1], u_ind=[u1], + q_dependent=[q2, q3], u_dependent=[u2, u3], + kd_eqs=method.kdes, configuration_constraints=fh, + velocity_constraints=fhd, forcelist=method.loads, + bodies=method.bodies) + fr, frs = kane.kanes_equations() + assert fr == zeros(1) + + # Numerically check the mass- and forcing-matrix + p = Matrix([l1, l2, l3, l4, rho]) + q = Matrix([q1, q2, q3]) + u = Matrix([u1, u2, u3]) + eval_m = lambdify((q, p), kane.mass_matrix) + eval_f = lambdify((q, u, p), kane.forcing) + eval_fhd = lambdify((q, u, p), fhd) + + p_vals = [0.13, 0.24, 0.21, 0.34, 997] + q_vals = [2.1, 0.6655470375077588, 2.527408138024188] # Satisfies fh + u_vals = [0.2, -0.17963733938852067, 0.1309060540601612] # Satisfies fhd + mass_check = Matrix([[3.452709815256506e+01, 7.003948798374735e+00, + -4.939690970641498e+00], + [-2.203792703880936e-14, 2.071702479957077e-01, + 2.842917573033711e-01], + [-1.300000000000123e-01, -8.836934896046506e-03, + 1.864891330060847e-01]]) + forcing_check = Matrix([[-0.031211821321648], + [-0.00066022608181], + [0.001813559741243]]) + eps = 1e-10 + assert all(abs(x) < eps for x in eval_fhd(q_vals, u_vals, p_vals)) + assert all(abs(x) < eps for x in + (Matrix(eval_m(q_vals, p_vals)) - mass_check)) + assert all(abs(x) < eps for x in + (Matrix(eval_f(q_vals, u_vals, p_vals)) - forcing_check)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane.py new file mode 100644 index 0000000000000000000000000000000000000000..5f9310aae6d720c32615a86df5e488f46a513c76 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane.py @@ -0,0 +1,553 @@ +from sympy import solve +from sympy import (cos, expand, Matrix, sin, symbols, tan, sqrt, S, + zeros, eye) +from sympy.simplify.simplify import simplify +from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point, + RigidBody, KanesMethod, inertia, Particle, + dot, find_dynamicsymbols) +from sympy.testing.pytest import raises + + +def test_invalid_coordinates(): + # Simple pendulum, but use symbols instead of dynamicsymbols + l, m, g = symbols('l m g') + q, u = symbols('q u') # Generalized coordinate + kd = [q.diff(dynamicsymbols._t) - u] + N, O = ReferenceFrame('N'), Point('O') + O.set_vel(N, 0) + P = Particle('P', Point('P'), m) + P.point.set_pos(O, l * (sin(q) * N.x - cos(q) * N.y)) + F = (P.point, -m * g * N.y) + raises(ValueError, lambda: KanesMethod(N, [q], [u], kd, bodies=[P], + forcelist=[F])) + + +def test_one_dof(): + # This is for a 1 dof spring-mass-damper case. + # It is described in more detail in the KanesMethod docstring. + q, u = dynamicsymbols('q u') + qd, ud = dynamicsymbols('q u', 1) + m, c, k = symbols('m c k') + N = ReferenceFrame('N') + P = Point('P') + P.set_vel(N, u * N.x) + + kd = [qd - u] + FL = [(P, (-k * q - c * u) * N.x)] + pa = Particle('pa', P, m) + BL = [pa] + + KM = KanesMethod(N, [q], [u], kd) + KM.kanes_equations(BL, FL) + + assert KM.bodies == BL + assert KM.loads == FL + + MM = KM.mass_matrix + forcing = KM.forcing + rhs = MM.inv() * forcing + assert expand(rhs[0]) == expand(-(q * k + u * c) / m) + + assert simplify(KM.rhs() - + KM.mass_matrix_full.LUsolve(KM.forcing_full)) == zeros(2, 1) + + assert (KM.linearize(A_and_B=True, )[0] == Matrix([[0, 1], [-k/m, -c/m]])) + + +def test_two_dof(): + # This is for a 2 d.o.f., 2 particle spring-mass-damper. + # The first coordinate is the displacement of the first particle, and the + # second is the relative displacement between the first and second + # particles. Speeds are defined as the time derivatives of the particles. + q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2') + q1d, q2d, u1d, u2d = dynamicsymbols('q1 q2 u1 u2', 1) + m, c1, c2, k1, k2 = symbols('m c1 c2 k1 k2') + N = ReferenceFrame('N') + P1 = Point('P1') + P2 = Point('P2') + P1.set_vel(N, u1 * N.x) + P2.set_vel(N, (u1 + u2) * N.x) + # Note we multiply the kinematic equation by an arbitrary factor + # to test the implicit vs explicit kinematics attribute + kd = [q1d/2 - u1/2, 2*q2d - 2*u2] + + # Now we create the list of forces, then assign properties to each + # particle, then create a list of all particles. + FL = [(P1, (-k1 * q1 - c1 * u1 + k2 * q2 + c2 * u2) * N.x), (P2, (-k2 * + q2 - c2 * u2) * N.x)] + pa1 = Particle('pa1', P1, m) + pa2 = Particle('pa2', P2, m) + BL = [pa1, pa2] + + # Finally we create the KanesMethod object, specify the inertial frame, + # pass relevant information, and form Fr & Fr*. Then we calculate the mass + # matrix and forcing terms, and finally solve for the udots. + KM = KanesMethod(N, q_ind=[q1, q2], u_ind=[u1, u2], kd_eqs=kd) + KM.kanes_equations(BL, FL) + MM = KM.mass_matrix + forcing = KM.forcing + rhs = MM.inv() * forcing + assert expand(rhs[0]) == expand((-k1 * q1 - c1 * u1 + k2 * q2 + c2 * u2)/m) + assert expand(rhs[1]) == expand((k1 * q1 + c1 * u1 - 2 * k2 * q2 - 2 * + c2 * u2) / m) + + # Check that the explicit form is the default and kinematic mass matrix is identity + assert KM.explicit_kinematics + assert KM.mass_matrix_kin == eye(2) + + # Check that for the implicit form the mass matrix is not identity + KM.explicit_kinematics = False + assert KM.mass_matrix_kin == Matrix([[S(1)/2, 0], [0, 2]]) + + # Check that whether using implicit or explicit kinematics the RHS + # equations are consistent with the matrix form + for explicit_kinematics in [False, True]: + KM.explicit_kinematics = explicit_kinematics + assert simplify(KM.rhs() - + KM.mass_matrix_full.LUsolve(KM.forcing_full)) == zeros(4, 1) + + # Make sure an error is raised if nonlinear kinematic differential + # equations are supplied. + kd = [q1d - u1**2, sin(q2d) - cos(u2)] + raises(ValueError, lambda: KanesMethod(N, q_ind=[q1, q2], + u_ind=[u1, u2], kd_eqs=kd)) + +def test_pend(): + q, u = dynamicsymbols('q u') + qd, ud = dynamicsymbols('q u', 1) + m, l, g = symbols('m l g') + N = ReferenceFrame('N') + P = Point('P') + P.set_vel(N, -l * u * sin(q) * N.x + l * u * cos(q) * N.y) + kd = [qd - u] + + FL = [(P, m * g * N.x)] + pa = Particle('pa', P, m) + BL = [pa] + + KM = KanesMethod(N, [q], [u], kd) + KM.kanes_equations(BL, FL) + MM = KM.mass_matrix + forcing = KM.forcing + rhs = MM.inv() * forcing + rhs.simplify() + assert expand(rhs[0]) == expand(-g / l * sin(q)) + assert simplify(KM.rhs() - + KM.mass_matrix_full.LUsolve(KM.forcing_full)) == zeros(2, 1) + + +def test_rolling_disc(): + # Rolling Disc Example + # Here the rolling disc 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). + 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') + + # 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]) + w_R_N_qd = R.ang_vel_in(N) + R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) + + # 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) + + # This is a simple way to form the inertia dyadic. + I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) + + # Kinematic differential equations; how the generalized coordinate time + # derivatives relate to generalized speeds. + kd = [dot(R.ang_vel_in(N) - w_R_N_qd, uv) for uv in L] + + # Creation of the force list; it is the gravitational force at the mass + # center 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 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) + KM.kanes_equations(BodyList, ForceList) + MM = KM.mass_matrix + forcing = KM.forcing + rhs = MM.inv() * forcing + kdd = KM.kindiffdict() + rhs = rhs.subs(kdd) + rhs.simplify() + assert rhs.expand() == Matrix([(6*u2*u3*r - u3**2*r*tan(q2) + + 4*g*sin(q2))/(5*r), -2*u1*u3/3, u1*(-2*u2 + u3*tan(q2))]).expand() + assert simplify(KM.rhs() - + KM.mass_matrix_full.LUsolve(KM.forcing_full)) == zeros(6, 1) + + # This code tests our output vs. benchmark values. When r=g=m=1, the + # critical speed (where all eigenvalues of the linearized equations are 0) + # is 1 / sqrt(3) for the upright case. + A = KM.linearize(A_and_B=True)[0] + A_upright = A.subs({r: 1, g: 1, m: 1}).subs({q1: 0, q2: 0, q3: 0, u1: 0, u3: 0}) + import sympy + assert sympy.sympify(A_upright.subs({u2: 1 / sqrt(3)})).eigenvals() == {S.Zero: 6} + + +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') + 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) + r, m, g = symbols('r m g') + + 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]) + w_R_N_qd = R.ang_vel_in(N) + R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) + + C = Point('C') + C.set_vel(N, u4 * L.x + u5 * (Y.z ^ L.x)) + Dmc = C.locatenew('Dmc', r * L.z) + Dmc.v2pt_theory(C, N, R) + Dmc.a2pt_theory(C, N, R) + + I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) + + kd = [dot(R.ang_vel_in(N) - w_R_N_qd, uv) for uv in L] + + ForceList = [(Dmc, - m * g * Y.z), (C, f1 * L.x + f2 * (Y.z ^ L.x))] + BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) + BodyList = [BodyD] + + KM = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3, u4, u5], + kd_eqs=kd) + (fr, frstar) = KM.kanes_equations(BodyList, ForceList) + 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(BodyList, ForceList) + fr2 = fr2.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5: 0}) + frstar2 = frstar2.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5: 0}) + + frstar.simplify() + frstar2.simplify() + + assert (fr - fr2).expand() == Matrix([0, 0, 0, 0, 0]) + assert (frstar - frstar2).expand() == Matrix([0, 0, 0, 0, 0]) + + +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') + + # Declaring the Generalized coordinates and speeds + q1, q2 = dynamicsymbols('q1 q2') + q1d, q2d = dynamicsymbols('q1 q2', 1) + u1, u2 = dynamicsymbols('u1 u2') + u1d, u2d = dynamicsymbols('u1 u2', 1) + + # Creating reference frames + N = ReferenceFrame('N') + A = ReferenceFrame('A') + + A.orient(N, 'Axis', [-q2, N.z]) + A.set_ang_vel(N, -u2 * N.z) + + # Origin of Newtonian reference frame + O = Point('O') + + # 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) + 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) + Pendulum = RigidBody('Pendulum', Ao, A, mA, (inertia(A, Ix, Iy, Iz), C)) + + # kinematical differential equations + + kindiffs = [q1d - u1, q2d - u2] + + bodyList = [Cart, Pendulum] + + forceList = [(Ao, -N.y * gravity * mA), + (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(bodyList, forceList) + mm = km.mass_matrix_full + assert mm[3, 3] == Iz + +def test_input_format(): + # 1 dof problem from test_one_dof + q, u = dynamicsymbols('q u') + qd, ud = dynamicsymbols('q u', 1) + m, c, k = symbols('m c k') + N = ReferenceFrame('N') + P = Point('P') + P.set_vel(N, u * N.x) + + kd = [qd - u] + FL = [(P, (-k * q - c * u) * N.x)] + pa = Particle('pa', P, m) + BL = [pa] + + KM = KanesMethod(N, [q], [u], kd) + # test for input format kane.kanes_equations((body1, body2, particle1)) + assert KM.kanes_equations(BL)[0] == Matrix([0]) + # test for input format kane.kanes_equations(bodies=(body1, body 2), loads=(load1,load2)) + assert KM.kanes_equations(bodies=BL, loads=None)[0] == Matrix([0]) + # test for input format kane.kanes_equations(bodies=(body1, body 2), loads=None) + assert KM.kanes_equations(BL, loads=None)[0] == Matrix([0]) + # test for input format kane.kanes_equations(bodies=(body1, body 2)) + assert KM.kanes_equations(BL)[0] == Matrix([0]) + # test for input format kane.kanes_equations(bodies=(body1, body2), loads=[]) + assert KM.kanes_equations(BL, [])[0] == Matrix([0]) + # test for error raised when a wrong force list (in this case a string) is provided + raises(ValueError, lambda: KM._form_fr('bad input')) + + # 1 dof problem from test_one_dof with FL & BL in instance + KM = KanesMethod(N, [q], [u], kd, bodies=BL, forcelist=FL) + assert KM.kanes_equations()[0] == Matrix([-c*u - k*q]) + + # 2 dof problem from test_two_dof + q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2') + q1d, q2d, u1d, u2d = dynamicsymbols('q1 q2 u1 u2', 1) + m, c1, c2, k1, k2 = symbols('m c1 c2 k1 k2') + N = ReferenceFrame('N') + P1 = Point('P1') + P2 = Point('P2') + P1.set_vel(N, u1 * N.x) + P2.set_vel(N, (u1 + u2) * N.x) + kd = [q1d - u1, q2d - u2] + + FL = ((P1, (-k1 * q1 - c1 * u1 + k2 * q2 + c2 * u2) * N.x), (P2, (-k2 * + q2 - c2 * u2) * N.x)) + pa1 = Particle('pa1', P1, m) + pa2 = Particle('pa2', P2, m) + BL = (pa1, pa2) + + KM = KanesMethod(N, q_ind=[q1, q2], u_ind=[u1, u2], kd_eqs=kd) + # test for input format + # kane.kanes_equations((body1, body2), (load1, load2)) + KM.kanes_equations(BL, FL) + MM = KM.mass_matrix + forcing = KM.forcing + rhs = MM.inv() * forcing + assert expand(rhs[0]) == expand((-k1 * q1 - c1 * u1 + k2 * q2 + c2 * u2)/m) + assert expand(rhs[1]) == expand((k1 * q1 + c1 * u1 - 2 * k2 * q2 - 2 * + c2 * u2) / m) + + +def test_implicit_kinematics(): + # Test that implicit kinematics can handle complicated + # equations that explicit form struggles with + # See https://github.com/sympy/sympy/issues/22626 + + # Inertial frame + NED = ReferenceFrame('NED') + NED_o = Point('NED_o') + NED_o.set_vel(NED, 0) + + # body frame + q_att = dynamicsymbols('lambda_0:4', real=True) + B = NED.orientnew('B', 'Quaternion', q_att) + + # Generalized coordinates + q_pos = dynamicsymbols('B_x:z') + B_cm = NED_o.locatenew('B_cm', q_pos[0]*B.x + q_pos[1]*B.y + q_pos[2]*B.z) + + q_ind = q_att[1:] + q_pos + q_dep = [q_att[0]] + + kinematic_eqs = [] + + # Generalized velocities + B_ang_vel = B.ang_vel_in(NED) + P, Q, R = dynamicsymbols('P Q R') + B.set_ang_vel(NED, P*B.x + Q*B.y + R*B.z) + + B_ang_vel_kd = (B.ang_vel_in(NED) - B_ang_vel).simplify() + + # Equating the two gives us the kinematic equation + kinematic_eqs += [ + B_ang_vel_kd & B.x, + B_ang_vel_kd & B.y, + B_ang_vel_kd & B.z + ] + + B_cm_vel = B_cm.vel(NED) + U, V, W = dynamicsymbols('U V W') + B_cm.set_vel(NED, U*B.x + V*B.y + W*B.z) + + # Compute the velocity of the point using the two methods + B_ref_vel_kd = (B_cm.vel(NED) - B_cm_vel) + + # taking dot product with unit vectors to get kinematic equations + # relating body coordinates and velocities + + # Note, there is a choice to dot with NED.xyz here. That makes + # the implicit form have some bigger terms but is still fine, the + # explicit form still struggles though + kinematic_eqs += [ + B_ref_vel_kd & B.x, + B_ref_vel_kd & B.y, + B_ref_vel_kd & B.z, + ] + + u_ind = [U, V, W, P, Q, R] + + # constraints + q_att_vec = Matrix(q_att) + config_cons = [(q_att_vec.T*q_att_vec)[0] - 1] #unit norm + kinematic_eqs = kinematic_eqs + [(q_att_vec.T * q_att_vec.diff())[0]] + + try: + KM = KanesMethod(NED, q_ind, u_ind, + q_dependent= q_dep, + kd_eqs = kinematic_eqs, + configuration_constraints = config_cons, + velocity_constraints= [], + u_dependent= [], #no dependent speeds + u_auxiliary = [], # No auxiliary speeds + explicit_kinematics = False # implicit kinematics + ) + except Exception as e: + raise e + + # mass and inertia dyadic relative to CM + M_B = symbols('M_B') + J_B = inertia(B, *[S(f'J_B_{ax}')*(1 if ax[0] == ax[1] else -1) + for ax in ['xx', 'yy', 'zz', 'xy', 'yz', 'xz']]) + J_B = J_B.subs({S('J_B_xy'): 0, S('J_B_yz'): 0}) + RB = RigidBody('RB', B_cm, B, M_B, (J_B, B_cm)) + + rigid_bodies = [RB] + # Forces + force_list = [ + #gravity pointing down + (RB.masscenter, RB.mass*S('g')*NED.z), + #generic forces and torques in body frame(inputs) + (RB.frame, dynamicsymbols('T_z')*B.z), + (RB.masscenter, dynamicsymbols('F_z')*B.z) + ] + + KM.kanes_equations(rigid_bodies, force_list) + + # Expecting implicit form to be less than 5% of the flops + n_ops_implicit = sum( + [x.count_ops() for x in KM.forcing_full] + + [x.count_ops() for x in KM.mass_matrix_full] + ) + # Save implicit kinematic matrices to use later + mass_matrix_kin_implicit = KM.mass_matrix_kin + forcing_kin_implicit = KM.forcing_kin + + KM.explicit_kinematics = True + n_ops_explicit = sum( + [x.count_ops() for x in KM.forcing_full] + + [x.count_ops() for x in KM.mass_matrix_full] + ) + forcing_kin_explicit = KM.forcing_kin + + assert n_ops_implicit / n_ops_explicit < .05 + + # Ideally we would check that implicit and explicit equations give the same result as done in test_one_dof + # But the whole raison-d'etre of the implicit equations is to deal with problems such + # as this one where the explicit form is too complicated to handle, especially the angular part + # (i.e. tests would be too slow) + # Instead, we check that the kinematic equations are correct using more fundamental tests: + # + # (1) that we recover the kinematic equations we have provided + assert (mass_matrix_kin_implicit * KM.q.diff() - forcing_kin_implicit) == Matrix(kinematic_eqs) + + # (2) that rate of quaternions matches what 'textbook' solutions give + # Note that we just use the explicit kinematics for the linear velocities + # as they are not as complicated as the angular ones + qdot_candidate = forcing_kin_explicit + + quat_dot_textbook = Matrix([ + [0, -P, -Q, -R], + [P, 0, R, -Q], + [Q, -R, 0, P], + [R, Q, -P, 0], + ]) * q_att_vec / 2 + + # Again, if we don't use this "textbook" solution + # sympy will struggle to deal with the terms related to quaternion rates + # due to the number of operations involved + qdot_candidate[-1] = quat_dot_textbook[0] # lambda_0, note the [-1] as sympy's Kane puts the dependent coordinate last + qdot_candidate[0] = quat_dot_textbook[1] # lambda_1 + qdot_candidate[1] = quat_dot_textbook[2] # lambda_2 + qdot_candidate[2] = quat_dot_textbook[3] # lambda_3 + + # sub the config constraint in the candidate solution and compare to the implicit rhs + lambda_0_sol = solve(config_cons[0], q_att_vec[0])[1] + lhs_candidate = simplify(mass_matrix_kin_implicit * qdot_candidate).subs({q_att_vec[0]: lambda_0_sol}) + assert lhs_candidate == forcing_kin_implicit + +def test_issue_24887(): + # Spherical pendulum + g, l, m, c = symbols('g l m c') + q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1:4 u1:4') + N = ReferenceFrame('N') + A = ReferenceFrame('A') + A.orient_body_fixed(N, (q1, q2, q3), 'zxy') + N_w_A = A.ang_vel_in(N) + # A.set_ang_vel(N, u1 * A.x + u2 * A.y + u3 * A.z) + kdes = [N_w_A.dot(A.x) - u1, N_w_A.dot(A.y) - u2, N_w_A.dot(A.z) - u3] + O = Point('O') + O.set_vel(N, 0) + Po = O.locatenew('Po', -l * A.y) + Po.set_vel(A, 0) + P = Particle('P', Po, m) + kane = KanesMethod(N, [q1, q2, q3], [u1, u2, u3], kdes, bodies=[P], + forcelist=[(Po, -m * g * N.y)]) + kane.kanes_equations() + expected_md = m * l ** 2 * Matrix([[1, 0, 0], [0, 0, 0], [0, 0, 1]]) + expected_fd = Matrix([ + [l*m*(g*(sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3)) - l*u2*u3)], + [0], [l*m*(-g*(sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1)) + l*u1*u2)]]) + assert find_dynamicsymbols(kane.forcing).issubset({q1, q2, q3, u1, u2, u3}) + assert simplify(kane.mass_matrix - expected_md) == zeros(3, 3) + assert simplify(kane.forcing - expected_fd) == zeros(3, 1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane2.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane2.py new file mode 100644 index 0000000000000000000000000000000000000000..e55866672aec0adcd951e772964a4ed205b56405 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane2.py @@ -0,0 +1,464 @@ +from sympy import cos, Matrix, sin, zeros, tan, pi, symbols +from sympy.simplify.simplify import simplify +from sympy.simplify.trigsimp import trigsimp +from sympy.solvers.solvers import solve +from sympy.physics.mechanics import (cross, dot, dynamicsymbols, + find_dynamicsymbols, KanesMethod, inertia, + inertia_of_point_mass, 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, manual 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 = dict(zip(ud, [0.]*len(ud))) + ua = dynamicsymbols('ua:3') + ua_zero = dict(zip(ua, [0.]*len(ua))) # noqa:F841 + + # 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) # noqa:F841 + + # 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]) # noqa:F841 + + # 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(zip(u[3:], u_dep)) + + # 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(bodyList, forceList) + frstar_steady = frstar.subs(ud_zero).subs(u_dep_dict).subs(steady_conditions)\ + .subs({q[3]: -r*cos(q[1])}).expand() + kdd = kane.kindiffdict() + + assert Matrix(Fr_c).expand() == fr.expand() + assert Matrix(Fr_star_c.subs(kdd)).expand() == frstar.expand() + # These Matrices have some Integer(0) and some Float(0). Running under + # SymEngine gives different types of zero. + assert (simplify(Matrix(Fr_star_steady).expand()).xreplace({0:0.0}) == + simplify(frstar_steady.expand()).xreplace({0:0.0})) + + syms_in_forcing = find_dynamicsymbols(kane.forcing) + for qdi in qd: + assert qdi not in syms_in_forcing + + +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 = [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(bodies, forces) + 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]) + t = trigsimp(fr_star.subs(vc_map).subs({u3: 0})).doit().expand() + assert ((fr_star_expected - t).expand() == zeros(3, 1)) + + # 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(bodies2, forces) + + t = trigsimp(fr_star2.subs(vc_map).subs({u3: 0})).doit() + assert (fr_star_expected - t).expand() == zeros(3, 1) + +def test_sub_qdot(): + # This test solves exercises 8.12, 8.17 from Kane 1985 and defines + # some velocities in terms of q, qdot. + + ## --- Declare symbols --- + q1, q2, q3 = dynamicsymbols('q1:4') + q1d, q2d, q3d = dynamicsymbols('q1:4', level=1) + u1, u2, u3 = dynamicsymbols('u1:4') + 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') + IA22, IA23, IA33 = symbols('IA22 IA23 IA33') + Q1, Q2, Q3 = symbols('Q1 Q2 Q3') + + # --- 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]) + + ## --- 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 w/o 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) + # 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 [pS_star, pQ, 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) + + # --- relate qdot, u --- + # the velocities of B^, C^ are zero since B, C are assumed to roll w/o slip + kde = [dot(p.vel(F), A.y) for p in [pB_hat, pC_hat]] + kde += [u1 - q1d] + kde_map = solve(kde, [q1d, q2d, q3d]) + for k, v in list(kde_map.items()): + kde_map[k.diff(t)] = v.diff(t) + + # 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)) + + ## --- use kanes method --- + km = KanesMethod(F, [q1, q2, q3], [u1, u2], kd_eqs=kde, u_auxiliary=[u3]) + + forces = [(pS_star, -M*g*F.x), (pQ, Q1*A.x + Q2*A.y + Q3*A.z)] + bodies = [rbA, rbB, rbC] + + # Q2 = -u_prime * u2 * Q1 / sqrt(u2**2 + f**2 * u1**2) + # -u_prime * R * u2 / sqrt(u2**2 + f**2 * u1**2) = R / Q1 * Q2 + fr_expected = Matrix([ + f*Q3 + M*g*e*sin(theta)*cos(q1), + Q2 + M*g*sin(theta)*sin(q1), + e*M*g*cos(theta) - Q1*f - Q2*R]) + #Q1 * (f - u_prime * R * u2 / sqrt(u2**2 + f**2 * u1**2)))]) + 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]) + + fr, fr_star = km.kanes_equations(bodies, forces) + assert (fr.expand() == fr_expected.expand()) + assert ((fr_star_expected - trigsimp(fr_star)).expand() == zeros(3, 1)) + +def test_sub_qdot2(): + # This test solves exercises 8.3 from Kane 1985 and defines + # all velocities in terms of q, qdot. We check that the generalized active + # forces are correctly computed if u terms are only defined in the + # kinematic differential equations. + # + # This functionality was added in PR 8948. Without qdot/u substitution, the + # KanesMethod constructor will fail during the constraint initialization as + # the B matrix will be poorly formed and inversion of the dependent part + # will fail. + + g, m, Px, Py, Pz, R, t = symbols('g m Px Py Pz R t') + q = dynamicsymbols('q:5') + qd = dynamicsymbols('q:5', level=1) + u = dynamicsymbols('u:5') + + ## Define inertial, intermediate, and rigid body reference frames + A = ReferenceFrame('A') + B_prime = A.orientnew('B_prime', 'Axis', [q[0], A.z]) + B = B_prime.orientnew('B', 'Axis', [pi/2 - q[1], B_prime.x]) + C = B.orientnew('C', 'Axis', [q[2], B.z]) + + ## Define points of interest and their velocities + pO = Point('O') + pO.set_vel(A, 0) + + # R is the point in plane H that comes into contact with disk C. + pR = pO.locatenew('R', q[3]*A.x + q[4]*A.y) + pR.set_vel(A, pR.pos_from(pO).diff(t, A)) + pR.set_vel(B, 0) + + # C^ is the point in disk C that comes into contact with plane H. + pC_hat = pR.locatenew('C^', 0) + pC_hat.set_vel(C, 0) + + # C* is the point at the center of disk C. + pCs = pC_hat.locatenew('C*', R*B.y) + pCs.set_vel(C, 0) + pCs.set_vel(B, 0) + + # calculate velocites of points C* and C^ in frame A + pCs.v2pt_theory(pR, A, B) # points C* and R are fixed in frame B + pC_hat.v2pt_theory(pCs, A, C) # points C* and C^ are fixed in frame C + + ## Define forces on each point of the system + R_C_hat = Px*A.x + Py*A.y + Pz*A.z + R_Cs = -m*g*A.z + forces = [(pC_hat, R_C_hat), (pCs, R_Cs)] + + ## Define kinematic differential equations + # let ui = omega_C_A & bi (i = 1, 2, 3) + # u4 = qd4, u5 = qd5 + u_expr = [C.ang_vel_in(A) & uv for uv in B] + u_expr += qd[3:] + kde = [ui - e for ui, e in zip(u, u_expr)] + km1 = KanesMethod(A, q, u, kde) + fr1, _ = km1.kanes_equations([], forces) + + ## Calculate generalized active forces if we impose the condition that the + # disk C is rolling without slipping + u_indep = u[:3] + u_dep = list(set(u) - set(u_indep)) + vc = [pC_hat.vel(A) & uv for uv in [A.x, A.y]] + km2 = KanesMethod(A, q, u_indep, kde, + u_dependent=u_dep, velocity_constraints=vc) + fr2, _ = km2.kanes_equations([], forces) + + fr1_expected = Matrix([ + -R*g*m*sin(q[1]), + -R*(Px*cos(q[0]) + Py*sin(q[0]))*tan(q[1]), + R*(Px*cos(q[0]) + Py*sin(q[0])), + Px, + Py]) + fr2_expected = Matrix([ + -R*g*m*sin(q[1]), + 0, + 0]) + assert (trigsimp(fr1.expand()) == trigsimp(fr1_expected.expand())) + assert (trigsimp(fr2.expand()) == trigsimp(fr2_expected.expand())) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane3.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane3.py new file mode 100644 index 0000000000000000000000000000000000000000..438759451cfb142c488b9b5c67ac269b668cac68 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane3.py @@ -0,0 +1,315 @@ +from sympy.core.numbers import pi +from sympy.core.symbol import symbols +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import acos, sin, cos +from sympy.matrices.dense import Matrix +from sympy.physics.mechanics import (ReferenceFrame, dynamicsymbols, + KanesMethod, inertia, Point, RigidBody, + dot) +from sympy.testing.pytest import slow + + +@slow +def test_bicycle(): + # Code to get equations of motion for a bicycle modeled as in: + # J.P Meijaard, Jim M Papadopoulos, Andy Ruina and A.L Schwab. Linearized + # dynamics equations for the balance and steer of a bicycle: a benchmark + # and review. Proceedings of The Royal Society (2007) 463, 1955-1982 + # doi: 10.1098/rspa.2007.1857 + + # 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 aide debugging. + + # Declare Coordinates & Speeds + # Simple definitions for qdots - qd = u + # Speeds are: + # - u1: yaw frame ang. rate + # - u2: roll frame ang. rate + # - u3: rear wheel frame ang. rate (spinning motion) + # - u4: frame ang. rate (pitching motion) + # - u5: steering frame ang. rate + # - u6: 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) + + # Declare System's Parameters + 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 mass center -> frame mass center + + # frame/fork connection -> fork mass center + front wheel mass center -> + # 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 previously defined points, using the 2 - point + # theorem (written out by hand here). Accelerations again are calculated + # automatically when first needed. + WR_cont.set_vel(N, 0) + WR_mc.v2pt_theory(WR_cont, N, WR) + Steer.v2pt_theory(WR_mc, N, Frame) + Frame_mc.v2pt_theory(WR_mc, N, Frame) + Fork_mc.v2pt_theory(Steer, N, Fork) + WF_mc.v2pt_theory(Steer, N, Fork) + WF_cont.v2pt_theory(WF_mc, N, WF) + + # Sets the inertias of each body. Uses the inertia frame to construct the + # inertia dyadics. Wheel inertias are only defined by principle 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) + + # 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 lineraization process. + + conlist_coord = [WF_cont.pos_from(WR_cont) & Y.z] + + # The force list; each body has the appropriate gravitational force applied + # at its mass center. + 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, as are the speeds. The kinematic + # differential equation are also entered here. Here the dependent speeds + # are specified, in the same order they were provided in earlier, along + # with the non-holonomic constraints. The dependent coordinate is also + # provided, with the holonomic constraint. Again, this is only provided + # for the linearization process. + + KM = KanesMethod(N, q_ind=[q1, q2, q5], + q_dependent=[q4], configuration_constraints=conlist_coord, + u_ind=[u2, u3, u5], + u_dependent=[u1, u4, u6], velocity_constraints=conlist_speed, + kd_eqs=kd, + constraint_solver="CRAMER") + (fr, frstar) = KM.kanes_equations(BL, FL) + + # This is the start of entering in the numerical values from the benchmark + # paper to validate the eigen values of the linearized equations from this + # model to the reference eigen values. 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 = (pi / 2 - pi / 10).evalf() + TrailPaper = 0.08 + rake = (-(TrailPaper*sin(HTA)-(PaperRadFront*cos(HTA)))).evalf() + PaperWb = 1.02 + PaperFrameCgX = 0.3 + PaperFrameCgZ = 0.9 + PaperForkCgX = 0.9 + PaperForkCgZ = 0.7 + FrameLength = (PaperWb*sin(HTA)-(rake-(PaperRadFront-PaperRadRear)*cos(HTA))).evalf() + FrameCGNorm = ((PaperFrameCgZ - PaperRadRear-(PaperFrameCgX/sin(HTA))*cos(HTA))*sin(HTA)).evalf() + FrameCGPar = (PaperFrameCgX / sin(HTA) + (PaperFrameCgZ - PaperRadRear - PaperFrameCgX / sin(HTA) * cos(HTA)) * cos(HTA)).evalf() + tempa = (PaperForkCgZ - PaperRadFront) + tempb = (PaperWb-PaperForkCgX) + tempc = (sqrt(tempa**2+tempb**2)).evalf() + PaperForkL = (PaperWb*cos(HTA)-(PaperRadFront-PaperRadRear)*sin(HTA)).evalf() + ForkCGNorm = (rake+(tempc * sin(pi/2-HTA-acos(tempa/tempc)))).evalf() + ForkCGPar = (tempc * cos((pi/2-HTA)-acos(tempa/tempc))-PaperForkL).evalf() + + # 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 = symbols('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} + + # 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 + # centripital 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. + + A, B, _ = KM.linearize( + A_and_B=True, + op_point={ + # Operating points for the accelerations are required for the + # linearizer to eliminate u' terms showing up in the coefficient + # matrices. + u1.diff(): 0, + u2.diff(): 0, + u3.diff(): 0, + u4.diff(): 0, + u5.diff(): 0, + u6.diff(): 0, + u1: 0, + u2: 0, + u3: v / PaperRadRear, + u4: 0, + u5: 0, + u6: v / PaperRadFront, + q1: 0, + q2: 0, + q4: 0, + q5: 0, + }, + linear_solver="CRAMER", + ) + # 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. + A_s = A.xreplace(val_dict) + B_s = B.xreplace(val_dict) + + A_s = A_s.evalf() + B_s = B_s.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. + A = A_s.extract([1, 2, 3, 5], [1, 2, 3, 5]) + + # Precomputed for comparison + Res = Matrix([[ 0, 0, 1.0, 0], + [ 0, 0, 0, 1.0], + [9.48977444677355, -0.891197738059089*v**2 - 0.571523173729245, -0.105522449805691*v, -0.330515398992311*v], + [11.7194768719633, -1.97171508499972*v**2 + 30.9087533932407, 3.67680523332152*v, -3.08486552743311*v]]) + + # Actual eigenvalue comparison + eps = 1.e-12 + for i in range(6): + error = Res.subs(v, i) - A.subs(v, i) + assert all(abs(x) < eps for x in error) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane4.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane4.py new file mode 100644 index 0000000000000000000000000000000000000000..a44dd2d407056ea36669268d478780fc581def51 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane4.py @@ -0,0 +1,115 @@ +from sympy import (cos, sin, Matrix, symbols) +from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point, + KanesMethod, Particle) + +def test_replace_qdots_in_force(): + # Test PR 16700 "Replaces qdots with us in force-list in kanes.py" + # The new functionality allows one to specify forces in qdots which will + # automatically be replaced with u:s which are defined by the kde supplied + # to KanesMethod. The test case is the double pendulum with interacting + # forces in the example of chapter 4.7 "CONTRIBUTING INTERACTION FORCES" + # in Ref. [1]. Reference list at end test function. + + q1, q2 = dynamicsymbols('q1, q2') + qd1, qd2 = dynamicsymbols('q1, q2', level=1) + u1, u2 = dynamicsymbols('u1, u2') + + l, m = symbols('l, m') + + N = ReferenceFrame('N') # Inertial frame + A = N.orientnew('A', 'Axis', (q1, N.z)) # Rod A frame + B = A.orientnew('B', 'Axis', (q2, N.z)) # Rod B frame + + O = Point('O') # Origo + O.set_vel(N, 0) + + P = O.locatenew('P', ( l * A.x )) # Point @ end of rod A + P.v2pt_theory(O, N, A) + + Q = P.locatenew('Q', ( l * B.x )) # Point @ end of rod B + Q.v2pt_theory(P, N, B) + + Ap = Particle('Ap', P, m) + Bp = Particle('Bp', Q, m) + + # The forces are specified below. sigma is the torsional spring stiffness + # and delta is the viscous damping coefficient acting between the two + # bodies. Here, we specify the viscous damper as function of qdots prior + # forming the kde. In more complex systems it not might be obvious which + # kde is most efficient, why it is convenient to specify viscous forces in + # qdots independently of the kde. + sig, delta = symbols('sigma, delta') + Ta = (sig * q2 + delta * qd2) * N.z + forces = [(A, Ta), (B, -Ta)] + + # Try different kdes. + kde1 = [u1 - qd1, u2 - qd2] + kde2 = [u1 - qd1, u2 - (qd1 + qd2)] + + KM1 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde1) + fr1, fstar1 = KM1.kanes_equations([Ap, Bp], forces) + + KM2 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde2) + fr2, fstar2 = KM2.kanes_equations([Ap, Bp], forces) + + # Check EOM for KM2: + # Mass and force matrix from p.6 in Ref. [2] with added forces from + # example of chapter 4.7 in [1] and without gravity. + forcing_matrix_expected = Matrix( [ [ m * l**2 * sin(q2) * u2**2 + sig * q2 + + delta * (u2 - u1)], + [ m * l**2 * sin(q2) * -u1**2 - sig * q2 + - delta * (u2 - u1)] ] ) + mass_matrix_expected = Matrix( [ [ 2 * m * l**2, m * l**2 * cos(q2) ], + [ m * l**2 * cos(q2), m * l**2 ] ] ) + + assert (KM2.mass_matrix.expand() == mass_matrix_expected.expand()) + assert (KM2.forcing.expand() == forcing_matrix_expected.expand()) + + # Check fr1 with reference fr_expected from [1] with u:s instead of qdots. + fr1_expected = Matrix([ 0, -(sig*q2 + delta * u2) ]) + assert fr1.expand() == fr1_expected.expand() + + # Check fr2 + fr2_expected = Matrix([sig * q2 + delta * (u2 - u1), + - sig * q2 - delta * (u2 - u1)]) + assert fr2.expand() == fr2_expected.expand() + + # Specifying forces in u:s should stay the same: + Ta = (sig * q2 + delta * u2) * N.z + forces = [(A, Ta), (B, -Ta)] + KM1 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde1) + fr1, fstar1 = KM1.kanes_equations([Ap, Bp], forces) + + assert fr1.expand() == fr1_expected.expand() + + Ta = (sig * q2 + delta * (u2-u1)) * N.z + forces = [(A, Ta), (B, -Ta)] + KM2 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde2) + fr2, fstar2 = KM2.kanes_equations([Ap, Bp], forces) + + assert fr2.expand() == fr2_expected.expand() + + # Test if we have a qubic qdot force: + Ta = (sig * q2 + delta * qd2**3) * N.z + forces = [(A, Ta), (B, -Ta)] + + KM1 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde1) + fr1, fstar1 = KM1.kanes_equations([Ap, Bp], forces) + + fr1_cubic_expected = Matrix([ 0, -(sig*q2 + delta * u2**3) ]) + + assert fr1.expand() == fr1_cubic_expected.expand() + + KM2 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde2) + fr2, fstar2 = KM2.kanes_equations([Ap, Bp], forces) + + fr2_cubic_expected = Matrix([sig * q2 + delta * (u2 - u1)**3, + - sig * q2 - delta * (u2 - u1)**3]) + + assert fr2.expand() == fr2_cubic_expected.expand() + + # References: + # [1] T.R. Kane, D. a Levinson, Dynamics Theory and Applications, 2005. + # [2] Arun K Banerjee, Flexible Multibody Dynamics:Efficient Formulations + # and Applications, John Wiley and Sons, Ltd, 2016. + # doi:http://dx.doi.org/10.1002/9781119015635. diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane5.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane5.py new file mode 100644 index 0000000000000000000000000000000000000000..1d0f863e8fa0f46bcd8ae729a1a8852b702bdafa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_kane5.py @@ -0,0 +1,128 @@ +from sympy import (zeros, Matrix, symbols, lambdify, sqrt, pi, + simplify) +from sympy.physics.mechanics import (dynamicsymbols, cross, inertia, RigidBody, + ReferenceFrame, KanesMethod) + + +def _create_rolling_disc(): + # Define symbols and coordinates + t = dynamicsymbols._t + q1, q2, q3, q4, q5, u1, u2, u3, u4, u5 = dynamicsymbols('q1:6 u1:6') + g, r, m = symbols('g r m') + # Define bodies and frames + ground = RigidBody('ground') + disc = RigidBody('disk', mass=m) + disc.inertia = (m * r ** 2 / 4 * inertia(disc.frame, 1, 2, 1), + disc.masscenter) + ground.masscenter.set_vel(ground.frame, 0) + disc.masscenter.set_vel(disc.frame, 0) + int_frame = ReferenceFrame('int_frame') + # Orient frames + int_frame.orient_body_fixed(ground.frame, (q1, q2, 0), 'zxy') + disc.frame.orient_axis(int_frame, int_frame.y, q3) + g_w_d = disc.frame.ang_vel_in(ground.frame) + disc.frame.set_ang_vel(ground.frame, + u1 * disc.x + u2 * disc.y + u3 * disc.z) + # Define points + cp = ground.masscenter.locatenew('contact_point', + q4 * ground.x + q5 * ground.y) + cp.set_vel(ground.frame, u4 * ground.x + u5 * ground.y) + disc.masscenter.set_pos(cp, r * int_frame.z) + disc.masscenter.set_vel(ground.frame, cross( + disc.frame.ang_vel_in(ground.frame), disc.masscenter.pos_from(cp))) + # Define kinematic differential equations + kdes = [g_w_d.dot(disc.x) - u1, g_w_d.dot(disc.y) - u2, + g_w_d.dot(disc.z) - u3, q4.diff(t) - u4, q5.diff(t) - u5] + # Define nonholonomic constraints + v0 = cp.vel(ground.frame) + cross( + disc.frame.ang_vel_in(int_frame), cp.pos_from(disc.masscenter)) + fnh = [v0.dot(ground.x), v0.dot(ground.y)] + # Define loads + loads = [(disc.masscenter, -disc.mass * g * ground.z)] + bodies = [disc] + return { + 'frame': ground.frame, + 'q_ind': [q1, q2, q3, q4, q5], + 'u_ind': [u1, u2, u3], + 'u_dep': [u4, u5], + 'kdes': kdes, + 'fnh': fnh, + 'bodies': bodies, + 'loads': loads + } + + +def _verify_rolling_disc_numerically(kane, all_zero=False): + q, u, p = dynamicsymbols('q1:6'), dynamicsymbols('u1:6'), symbols('g r m') + eval_sys = lambdify((q, u, p), (kane.mass_matrix_full, kane.forcing_full), + cse=True) + solve_sys = lambda q, u, p: Matrix.LUsolve( + *(Matrix(mat) for mat in eval_sys(q, u, p))) + solve_u_dep = lambdify((q, u[:3], p), kane._Ars * Matrix(u[:3]), cse=True) + eps = 1e-10 + p_vals = (9.81, 0.26, 3.43) + # First numeric test + q_vals = (0.3, 0.1, 1.97, -0.35, 2.27) + u_vals = [-0.2, 1.3, 0.15] + u_vals.extend(solve_u_dep(q_vals, u_vals, p_vals)[:2, 0]) + expected = Matrix([ + 0.126603940595934, 0.215942571601660, 1.28736069604936, + 0.319764288376543, 0.0989146857254898, -0.925848952664489, + -0.0181350656532944, 2.91695398184589, -0.00992793421754526, + 0.0412861634829171]) + assert all(abs(x) < eps for x in + (solve_sys(q_vals, u_vals, p_vals) - expected)) + # Second numeric test + q_vals = (3.97, -0.28, 8.2, -0.35, 2.27) + u_vals = [-0.25, -2.2, 0.62] + u_vals.extend(solve_u_dep(q_vals, u_vals, p_vals)[:2, 0]) + expected = Matrix([ + 0.0259159090798597, 0.668041660387416, -2.19283799213811, + 0.385441810852219, 0.420109283790573, 1.45030568179066, + -0.0110924422400793, -8.35617840186040, -0.154098542632173, + -0.146102664410010]) + assert all(abs(x) < eps for x in + (solve_sys(q_vals, u_vals, p_vals) - expected)) + if all_zero: + q_vals = (0, 0, 0, 0, 0) + u_vals = (0, 0, 0, 0, 0) + assert solve_sys(q_vals, u_vals, p_vals) == zeros(10, 1) + + +def test_kane_rolling_disc_lu(): + props = _create_rolling_disc() + kane = KanesMethod(props['frame'], props['q_ind'], props['u_ind'], + props['kdes'], u_dependent=props['u_dep'], + velocity_constraints=props['fnh'], + bodies=props['bodies'], forcelist=props['loads'], + explicit_kinematics=False, constraint_solver='LU') + kane.kanes_equations() + _verify_rolling_disc_numerically(kane) + + +def test_kane_rolling_disc_kdes_callable(): + props = _create_rolling_disc() + kane = KanesMethod( + props['frame'], props['q_ind'], props['u_ind'], props['kdes'], + u_dependent=props['u_dep'], velocity_constraints=props['fnh'], + bodies=props['bodies'], forcelist=props['loads'], + explicit_kinematics=False, + kd_eqs_solver=lambda A, b: simplify(A.LUsolve(b))) + q, u, p = dynamicsymbols('q1:6'), dynamicsymbols('u1:6'), symbols('g r m') + qd = dynamicsymbols('q1:6', 1) + eval_kdes = lambdify((q, qd, u, p), tuple(kane.kindiffdict().items())) + eps = 1e-10 + # Test with only zeros. If 'LU' would be used this would result in nan. + p_vals = (9.81, 0.25, 3.5) + zero_vals = (0, 0, 0, 0, 0) + assert all(abs(qdi - fui) < eps for qdi, fui in + eval_kdes(zero_vals, zero_vals, zero_vals, p_vals)) + # Test with some arbitrary values + q_vals = tuple(map(float, (pi / 6, pi / 3, pi / 2, 0.42, 0.62))) + qd_vals = tuple(map(float, (4, 1 / 3, 4 - 2 * sqrt(3), + 0.25 * (2 * sqrt(3) - 3), + 0.25 * (2 - sqrt(3))))) + u_vals = tuple(map(float, (-2, 4, 1 / 3, 0.25 * (-3 + 2 * sqrt(3)), + 0.25 * (-sqrt(3) + 2)))) + assert all(abs(qdi - fui) < eps for qdi, fui in + eval_kdes(q_vals, qd_vals, u_vals, p_vals)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_lagrange.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_lagrange.py new file mode 100644 index 0000000000000000000000000000000000000000..81552bc7a4d0f6766dc46dcd47b7c7b1b0151b3f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_lagrange.py @@ -0,0 +1,247 @@ +from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point, + RigidBody, LagrangesMethod, Particle, + inertia, Lagrangian) +from sympy.core.function import (Derivative, Function) +from sympy.core.numbers import pi +from sympy.core.symbol import symbols +from sympy.functions.elementary.trigonometric import (cos, sin, tan) +from sympy.matrices.dense import Matrix +from sympy.simplify.simplify import simplify +from sympy.testing.pytest import raises + + +def test_invalid_coordinates(): + # Simple pendulum, but use symbol instead of dynamicsymbol + l, m, g = symbols('l m g') + q = symbols('q') # Generalized coordinate + N, O = ReferenceFrame('N'), Point('O') + O.set_vel(N, 0) + P = Particle('P', Point('P'), m) + P.point.set_pos(O, l * (sin(q) * N.x - cos(q) * N.y)) + P.potential_energy = m * g * P.point.pos_from(O).dot(N.y) + L = Lagrangian(N, P) + raises(ValueError, lambda: LagrangesMethod(L, [q], bodies=P)) + + +def test_disc_on_an_incline_plane(): + # Disc rolling on an inclined plane + # First the generalized coordinates are created. The mass center of the + # disc is located from top vertex of the inclined plane by the generalized + # coordinate 'y'. The orientation of the disc is defined by the angle + # 'theta'. The mass of the disc is 'm' and its radius is 'R'. The length of + # the inclined path is 'l', the angle of inclination is 'alpha'. 'g' is the + # gravitational constant. + y, theta = dynamicsymbols('y theta') + yd, thetad = dynamicsymbols('y theta', 1) + m, g, R, l, alpha = symbols('m g R l alpha') + + # 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]) + B = A.orientnew('B', 'Axis', [-theta, A.z]) + + # Creating the disc 'D'; we create the point that represents the mass + # center of the disc and set its velocity. The inertia dyadic of the disc + # is created. Finally, we create the disc. + Do = Point('Do') + Do.set_vel(N, yd * A.x) + I = m * R**2/2 * B.z | B.z + D = RigidBody('D', Do, B, m, (I, Do)) + + # To construct the Lagrangian, 'L', of the disc, we determine its kinetic + # and potential energies, T and U, respectively. L is defined as the + # difference between T and U. + D.potential_energy = m * g * (l - y) * sin(alpha) + L = Lagrangian(N, D) + + # We then create the list of generalized coordinates and constraint + # equations. The constraint arises due to the disc rolling without slip on + # on the inclined path. We then invoke the 'LagrangesMethod' class and + # supply it the necessary arguments and generate the equations of motion. + # The'rhs' method solves for the q_double_dots (i.e. the second derivative + # with respect to time of the generalized coordinates and the lagrange + # multipliers. + q = [y, theta] + hol_coneqs = [y - R * theta] + m = LagrangesMethod(L, q, hol_coneqs=hol_coneqs) + m.form_lagranges_equations() + rhs = m.rhs() + rhs.simplify() + assert rhs[2] == 2*g*sin(alpha)/3 + + +def test_simp_pen(): + # This tests that the equations generated by LagrangesMethod are identical + # to those obtained by hand calculations. The system under consideration is + # the simple pendulum. + # We begin by creating the generalized coordinates as per the requirements + # of LagrangesMethod. Also we created the associate symbols + # that characterize the system: 'm' is the mass of the bob, l is the length + # of the massless rigid rod connecting the bob to a point O fixed in the + # inertial frame. + q, u = dynamicsymbols('q u') + qd, ud = dynamicsymbols('q u ', 1) + l, m, g = symbols('l m g') + + # We then create the inertial frame and a frame attached to the massless + # string following which we define the inertial angular velocity of the + # string. + N = ReferenceFrame('N') + A = N.orientnew('A', 'Axis', [q, N.z]) + A.set_ang_vel(N, qd * N.z) + + # Next, we create the point O and fix it in the inertial frame. We then + # locate the point P to which the bob is attached. Its corresponding + # velocity is then determined by the 'two point formula'. + O = Point('O') + O.set_vel(N, 0) + P = O.locatenew('P', l * A.x) + P.v2pt_theory(O, N, A) + + # The 'Particle' which represents the bob is then created and its + # Lagrangian generated. + Pa = Particle('Pa', P, m) + Pa.potential_energy = - m * g * l * cos(q) + L = Lagrangian(N, Pa) + + # The 'LagrangesMethod' class is invoked to obtain equations of motion. + lm = LagrangesMethod(L, [q]) + lm.form_lagranges_equations() + RHS = lm.rhs() + assert RHS[1] == -g*sin(q)/l + + +def test_nonminimal_pendulum(): + q1, q2 = dynamicsymbols('q1:3') + q1d, q2d = dynamicsymbols('q1:3', level=1) + L, m, t = symbols('L, m, t') + g = 9.8 + # Compose World Frame + N = ReferenceFrame('N') + pN = Point('N*') + pN.set_vel(N, 0) + # Create point P, the pendulum mass + P = pN.locatenew('P1', q1*N.x + q2*N.y) + P.set_vel(N, P.pos_from(pN).dt(N)) + pP = Particle('pP', P, m) + # Constraint Equations + f_c = Matrix([q1**2 + q2**2 - L**2]) + # Calculate the lagrangian, and form the equations of motion + Lag = Lagrangian(N, pP) + LM = LagrangesMethod(Lag, [q1, q2], hol_coneqs=f_c, + forcelist=[(P, m*g*N.x)], frame=N) + LM.form_lagranges_equations() + # Check solution + lam1 = LM.lam_vec[0, 0] + eom_sol = Matrix([[m*Derivative(q1, t, t) - 9.8*m + 2*lam1*q1], + [m*Derivative(q2, t, t) + 2*lam1*q2]]) + assert LM.eom == eom_sol + # Check multiplier solution + lam_sol = Matrix([(19.6*q1 + 2*q1d**2 + 2*q2d**2)/(4*q1**2/m + 4*q2**2/m)]) + assert simplify(LM.solve_multipliers(sol_type='Matrix')) == simplify(lam_sol) + + +def test_dub_pen(): + + # The system considered is the double pendulum. Like in the + # test of the simple pendulum above, we begin by creating the generalized + # coordinates and the simple generalized speeds and accelerations which + # will be used later. Following this we create frames and points necessary + # for the kinematics. The procedure isn't explicitly explained as this is + # similar to the simple pendulum. Also this is documented on the pydy.org + # website. + q1, q2 = dynamicsymbols('q1 q2') + q1d, q2d = dynamicsymbols('q1 q2', 1) + q1dd, q2dd = dynamicsymbols('q1 q2', 2) + u1, u2 = dynamicsymbols('u1 u2') + u1d, u2d = dynamicsymbols('u1 u2', 1) + l, m, g = symbols('l m g') + + N = ReferenceFrame('N') + A = N.orientnew('A', 'Axis', [q1, N.z]) + B = N.orientnew('B', 'Axis', [q2, N.z]) + + A.set_ang_vel(N, q1d * A.z) + B.set_ang_vel(N, q2d * A.z) + + O = Point('O') + P = O.locatenew('P', l * A.x) + R = P.locatenew('R', l * B.x) + + O.set_vel(N, 0) + P.v2pt_theory(O, N, A) + R.v2pt_theory(P, N, B) + + ParP = Particle('ParP', P, m) + ParR = Particle('ParR', R, m) + + ParP.potential_energy = - m * g * l * cos(q1) + ParR.potential_energy = - m * g * l * cos(q1) - m * g * l * cos(q2) + L = Lagrangian(N, ParP, ParR) + lm = LagrangesMethod(L, [q1, q2], bodies=[ParP, ParR]) + lm.form_lagranges_equations() + + 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) - 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) - lm.eom[1]) == 0 + assert lm.bodies == [ParP, ParR] + + +def test_rolling_disc(): + # Rolling Disc Example + # 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 need to describe this system, along with the + # disc's mass and radius, and the local gravity. + 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) + + # Forming the inertia dyadic. + I = inertia(L, m/4 * r**2, m/2 * r**2, m/4 * r**2) + BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) + + # Finally we form the equations of motion, using the same steps we did + # before. Supply the Lagrangian, the generalized speeds. + BodyD.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].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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_lagrange2.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_lagrange2.py new file mode 100644 index 0000000000000000000000000000000000000000..7602df157e9beb13db1dbb68a2980765cdc49bf2 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_lagrange2.py @@ -0,0 +1,46 @@ +from sympy import symbols +from sympy.physics.mechanics import dynamicsymbols +from sympy.physics.mechanics import ReferenceFrame, Point, Particle +from sympy.physics.mechanics import LagrangesMethod, Lagrangian + +### This test asserts that a system with more than one external forces +### is accurately formed with Lagrange method (see issue #8626) + +def test_lagrange_2forces(): + ### Equations for two damped springs in series with two forces + + ### generalized coordinates + q1, q2 = dynamicsymbols('q1, q2') + ### generalized speeds + q1d, q2d = dynamicsymbols('q1, q2', 1) + + ### Mass, spring strength, friction coefficient + m, k, nu = symbols('m, k, nu') + + N = ReferenceFrame('N') + O = Point('O') + + ### Two points + P1 = O.locatenew('P1', q1 * N.x) + P1.set_vel(N, q1d * N.x) + P2 = O.locatenew('P1', q2 * N.x) + P2.set_vel(N, q2d * N.x) + + pP1 = Particle('pP1', P1, m) + pP1.potential_energy = k * q1**2 / 2 + + pP2 = Particle('pP2', P2, m) + pP2.potential_energy = k * (q1 - q2)**2 / 2 + + #### Friction forces + forcelist = [(P1, - nu * q1d * N.x), + (P2, - nu * q2d * N.x)] + lag = Lagrangian(N, pP1, pP2) + + l_method = LagrangesMethod(lag, (q1, q2), forcelist=forcelist, frame=N) + l_method.form_lagranges_equations() + + eq1 = l_method.eom[0] + assert eq1.diff(q1d) == nu + eq2 = l_method.eom[1] + assert eq2.diff(q2d) == nu diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_linearity_of_velocity_constraints.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_linearity_of_velocity_constraints.py new file mode 100644 index 0000000000000000000000000000000000000000..33c9e7ec070a3e6db2a6e26697d670964b0a32b9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_linearity_of_velocity_constraints.py @@ -0,0 +1,41 @@ +from sympy import symbols, sin, cos +from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point, + KanesMethod) +from sympy.testing import pytest +from sympy.solvers.solveset import NonlinearError + +def test_linearity_of_motion_constraints(): + # Test that an error is raised by KanesMethod if nonlinear velocity + # constraints are supplied. + # It is a simple pendulum. + t = dynamicsymbols._t + N, A = ReferenceFrame('N'), ReferenceFrame('A') + O, P = Point('O'), Point('P') + O.set_vel(N, 0) + + l = symbols('l') + q, x, y, u, ux, uy = dynamicsymbols('q x y u ux uy') + + A.orient_axis(N, q, N.z) + A.set_ang_vel(N, u * N.z) + P.set_pos(O, -l * A.y) + P.v2pt_theory(O, N, A) + + kd = [u - q.diff(t), ux - x.diff(t), uy - y.diff(t)] + config_constr = [x - l * sin(q), y - l * cos(q)] + + q_ind = [q] + q_dep = [x, y] + u_ind = [u] + u_dep = [ux, uy] + + # Make sure an error is raised if nonlinear velocity constraints are + # supplied. + speed_constr = [ux - l * q.diff(t) * cos(q), sin(uy) + + l * q.diff(t) * sin(q)] + + with pytest.raises(NonlinearError): + KanesMethod(N, q_ind=q_ind, q_dependent=q_dep, u_ind=u_ind, + u_dependent=u_dep, kd_eqs=kd, + configuration_constraints=config_constr, + velocity_constraints=speed_constr) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_linearize.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_linearize.py new file mode 100644 index 0000000000000000000000000000000000000000..ec62b960b71d7fce5a5504478431ca23eb371fe0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_linearize.py @@ -0,0 +1,372 @@ +from sympy import symbols, Matrix, cos, sin, atan, sqrt, Rational +from sympy.core.sympify import sympify +from sympy.simplify.simplify import simplify +from sympy.solvers.solvers import solve +from sympy.physics.mechanics import dynamicsymbols, ReferenceFrame, Point,\ + dot, cross, inertia, KanesMethod, Particle, RigidBody, Lagrangian,\ + LagrangesMethod +from sympy.testing.pytest import slow + + +@slow +def test_linearize_rolling_disc_kane(): + # Symbols for time and constant parameters + t, r, m, g, v = symbols('t r m g v') + + # Configuration variables and their time derivatives + q1, q2, q3, q4, q5, q6 = q = dynamicsymbols('q1:7') + q1d, q2d, q3d, q4d, q5d, q6d = qd = [qi.diff(t) for qi in q] + + # Generalized speeds and their time derivatives + u = dynamicsymbols('u:6') + u1, u2, u3, u4, u5, u6 = u = dynamicsymbols('u1:7') + u1d, u2d, u3d, u4d, u5d, u6d = [ui.diff(t) for ui in u] + + # Reference frames + N = ReferenceFrame('N') # Inertial frame + NO = Point('NO') # Inertial origin + A = N.orientnew('A', 'Axis', [q1, N.z]) # Yaw intermediate frame + B = A.orientnew('B', 'Axis', [q2, A.x]) # Lean intermediate frame + C = B.orientnew('C', 'Axis', [q3, B.y]) # Disc fixed frame + CO = NO.locatenew('CO', q4*N.x + q5*N.y + q6*N.z) # Disc center + + # Disc angular velocity in N expressed using time derivatives of coordinates + w_c_n_qd = C.ang_vel_in(N) + w_b_n_qd = B.ang_vel_in(N) + + # Inertial angular velocity and angular acceleration of disc fixed frame + C.set_ang_vel(N, u1*B.x + u2*B.y + u3*B.z) + + # Disc center velocity in N expressed using time derivatives of coordinates + v_co_n_qd = CO.pos_from(NO).dt(N) + + # Disc center velocity in N expressed using generalized speeds + CO.set_vel(N, u4*C.x + u5*C.y + u6*C.z) + + # Disc Ground Contact Point + P = CO.locatenew('P', r*B.z) + P.v2pt_theory(CO, N, C) + + # Configuration constraint + f_c = Matrix([q6 - dot(CO.pos_from(P), N.z)]) + + # Velocity level constraints + f_v = Matrix([dot(P.vel(N), uv) for uv in C]) + + # Kinematic differential equations + kindiffs = Matrix([dot(w_c_n_qd - C.ang_vel_in(N), uv) for uv in B] + + [dot(v_co_n_qd - CO.vel(N), uv) for uv in N]) + qdots = solve(kindiffs, qd) + + # Set angular velocity of remaining frames + B.set_ang_vel(N, w_b_n_qd.subs(qdots)) + C.set_ang_acc(N, C.ang_vel_in(N).dt(B) + cross(B.ang_vel_in(N), C.ang_vel_in(N))) + + # Active forces + F_CO = m*g*A.z + + # Create inertia dyadic of disc C about point CO + I = (m * r**2) / 4 + J = (m * r**2) / 2 + I_C_CO = inertia(C, I, J, I) + + Disc = RigidBody('Disc', CO, C, m, (I_C_CO, CO)) + BL = [Disc] + FL = [(CO, F_CO)] + KM = KanesMethod(N, [q1, q2, q3, q4, q5], [u1, u2, u3], kd_eqs=kindiffs, + q_dependent=[q6], configuration_constraints=f_c, + u_dependent=[u4, u5, u6], velocity_constraints=f_v) + (fr, fr_star) = KM.kanes_equations(BL, FL) + + # Test generalized form equations + linearizer = KM.to_linearizer() + assert linearizer.f_c == f_c + assert linearizer.f_v == f_v + assert linearizer.f_a == f_v.diff(t).subs(KM.kindiffdict()) + sol = solve(linearizer.f_0 + linearizer.f_1, qd) + for qi in qdots.keys(): + assert sol[qi] == qdots[qi] + assert simplify(linearizer.f_2 + linearizer.f_3 - fr - fr_star) == Matrix([0, 0, 0]) + + # Perform the linearization + # Precomputed operating point + q_op = {q6: -r*cos(q2)} + u_op = {u1: 0, + u2: sin(q2)*q1d + q3d, + u3: cos(q2)*q1d, + u4: -r*(sin(q2)*q1d + q3d)*cos(q3), + u5: 0, + u6: -r*(sin(q2)*q1d + q3d)*sin(q3)} + qd_op = {q2d: 0, + q4d: -r*(sin(q2)*q1d + q3d)*cos(q1), + q5d: -r*(sin(q2)*q1d + q3d)*sin(q1), + q6d: 0} + ud_op = {u1d: 4*g*sin(q2)/(5*r) + sin(2*q2)*q1d**2/2 + 6*cos(q2)*q1d*q3d/5, + u2d: 0, + u3d: 0, + u4d: r*(sin(q2)*sin(q3)*q1d*q3d + sin(q3)*q3d**2), + u5d: r*(4*g*sin(q2)/(5*r) + sin(2*q2)*q1d**2/2 + 6*cos(q2)*q1d*q3d/5), + u6d: -r*(sin(q2)*cos(q3)*q1d*q3d + cos(q3)*q3d**2)} + + A, B = linearizer.linearize(op_point=[q_op, u_op, qd_op, ud_op], A_and_B=True, simplify=True) + + upright_nominal = {q1d: 0, q2: 0, m: 1, r: 1, g: 1} + + # Precomputed solution + A_sol = Matrix([[0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], + [sin(q1)*q3d, 0, 0, 0, 0, -sin(q1), -cos(q1), 0], + [-cos(q1)*q3d, 0, 0, 0, 0, cos(q1), -sin(q1), 0], + [0, Rational(4, 5), 0, 0, 0, 0, 0, 6*q3d/5], + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, -2*q3d, 0, 0]]) + B_sol = Matrix([]) + + # Check that linearization is correct + assert A.subs(upright_nominal) == A_sol + assert B.subs(upright_nominal) == B_sol + + # Check eigenvalues at critical speed are all zero: + assert sympify(A.subs(upright_nominal).subs(q3d, 1/sqrt(3))).eigenvals() == {0: 8} + + # Check whether alternative solvers work + # symengine doesn't support method='GJ' + linearizer = KM.to_linearizer(linear_solver='GJ') + A, B = linearizer.linearize(op_point=[q_op, u_op, qd_op, ud_op], + A_and_B=True, simplify=True) + assert A.subs(upright_nominal) == A_sol + assert B.subs(upright_nominal) == B_sol + +def test_linearize_pendulum_kane_minimal(): + q1 = dynamicsymbols('q1') # angle of pendulum + u1 = dynamicsymbols('u1') # Angular velocity + q1d = dynamicsymbols('q1', 1) # Angular velocity + L, m, t = symbols('L, m, t') + g = 9.8 + + # Compose world frame + N = ReferenceFrame('N') + pN = Point('N*') + pN.set_vel(N, 0) + + # A.x is along the pendulum + A = N.orientnew('A', 'axis', [q1, N.z]) + A.set_ang_vel(N, u1*N.z) + + # Locate point P relative to the origin N* + P = pN.locatenew('P', L*A.x) + P.v2pt_theory(pN, N, A) + pP = Particle('pP', P, m) + + # Create Kinematic Differential Equations + kde = Matrix([q1d - u1]) + + # Input the force resultant at P + R = m*g*N.x + + # Solve for eom with kanes method + KM = KanesMethod(N, q_ind=[q1], u_ind=[u1], kd_eqs=kde) + (fr, frstar) = KM.kanes_equations([pP], [(P, R)]) + + # Linearize + A, B, inp_vec = KM.linearize(A_and_B=True, simplify=True) + + assert A == Matrix([[0, 1], [-9.8*cos(q1)/L, 0]]) + assert B == Matrix([]) + +def test_linearize_pendulum_kane_nonminimal(): + # Create generalized coordinates and speeds for this non-minimal realization + # q1, q2 = N.x and N.y coordinates of pendulum + # u1, u2 = N.x and N.y velocities of pendulum + q1, q2 = dynamicsymbols('q1:3') + q1d, q2d = dynamicsymbols('q1:3', level=1) + u1, u2 = dynamicsymbols('u1:3') + u1d, u2d = dynamicsymbols('u1:3', level=1) + L, m, t = symbols('L, m, t') + g = 9.8 + + # Compose world frame + N = ReferenceFrame('N') + pN = Point('N*') + pN.set_vel(N, 0) + + # A.x is along the pendulum + theta1 = atan(q2/q1) + A = N.orientnew('A', 'axis', [theta1, N.z]) + + # Locate the pendulum mass + P = pN.locatenew('P1', q1*N.x + q2*N.y) + pP = Particle('pP', P, m) + + # Calculate the kinematic differential equations + kde = Matrix([q1d - u1, + q2d - u2]) + dq_dict = solve(kde, [q1d, q2d]) + + # Set velocity of point P + P.set_vel(N, P.pos_from(pN).dt(N).subs(dq_dict)) + + # Configuration constraint is length of pendulum + f_c = Matrix([P.pos_from(pN).magnitude() - L]) + + # Velocity constraint is that the velocity in the A.x direction is + # always zero (the pendulum is never getting longer). + f_v = Matrix([P.vel(N).express(A).dot(A.x)]) + f_v.simplify() + + # Acceleration constraints is the time derivative of the velocity constraint + f_a = f_v.diff(t) + f_a.simplify() + + # Input the force resultant at P + R = m*g*N.x + + # Derive the equations of motion using the KanesMethod class. + KM = KanesMethod(N, q_ind=[q2], u_ind=[u2], q_dependent=[q1], + u_dependent=[u1], configuration_constraints=f_c, + velocity_constraints=f_v, acceleration_constraints=f_a, kd_eqs=kde) + (fr, frstar) = KM.kanes_equations([pP], [(P, R)]) + + # Set the operating point to be straight down, and non-moving + q_op = {q1: L, q2: 0} + u_op = {u1: 0, u2: 0} + ud_op = {u1d: 0, u2d: 0} + + A, B, inp_vec = KM.linearize(op_point=[q_op, u_op, ud_op], A_and_B=True, + simplify=True) + + assert A.expand() == Matrix([[0, 1], [-9.8/L, 0]]) + assert B == Matrix([]) + + + # symengine doesn't support method='GJ' + A, B, inp_vec = KM.linearize(op_point=[q_op, u_op, ud_op], A_and_B=True, + simplify=True, linear_solver='GJ') + + assert A.expand() == Matrix([[0, 1], [-9.8/L, 0]]) + assert B == Matrix([]) + + A, B, inp_vec = KM.linearize(op_point=[q_op, u_op, ud_op], + A_and_B=True, + simplify=True, + linear_solver=lambda A, b: A.LUsolve(b)) + + assert A.expand() == Matrix([[0, 1], [-9.8/L, 0]]) + assert B == Matrix([]) + + +def test_linearize_pendulum_lagrange_minimal(): + q1 = dynamicsymbols('q1') # angle of pendulum + q1d = dynamicsymbols('q1', 1) # Angular velocity + L, m, t = symbols('L, m, t') + g = 9.8 + + # Compose world frame + N = ReferenceFrame('N') + pN = Point('N*') + pN.set_vel(N, 0) + + # A.x is along the pendulum + A = N.orientnew('A', 'axis', [q1, N.z]) + A.set_ang_vel(N, q1d*N.z) + + # Locate point P relative to the origin N* + P = pN.locatenew('P', L*A.x) + P.v2pt_theory(pN, N, A) + pP = Particle('pP', P, m) + + # Solve for eom with Lagranges method + Lag = Lagrangian(N, pP) + LM = LagrangesMethod(Lag, [q1], forcelist=[(P, m*g*N.x)], frame=N) + LM.form_lagranges_equations() + + # Linearize + A, B, inp_vec = LM.linearize([q1], [q1d], A_and_B=True) + + assert simplify(A) == Matrix([[0, 1], [-9.8*cos(q1)/L, 0]]) + assert B == Matrix([]) + + # Check an alternative solver + A, B, inp_vec = LM.linearize([q1], [q1d], A_and_B=True, linear_solver='GJ') + + assert simplify(A) == Matrix([[0, 1], [-9.8*cos(q1)/L, 0]]) + assert B == Matrix([]) + + +def test_linearize_pendulum_lagrange_nonminimal(): + q1, q2 = dynamicsymbols('q1:3') + q1d, q2d = dynamicsymbols('q1:3', level=1) + L, m, t = symbols('L, m, t') + g = 9.8 + # Compose World Frame + N = ReferenceFrame('N') + pN = Point('N*') + pN.set_vel(N, 0) + # A.x is along the pendulum + theta1 = atan(q2/q1) + A = N.orientnew('A', 'axis', [theta1, N.z]) + # Create point P, the pendulum mass + P = pN.locatenew('P1', q1*N.x + q2*N.y) + P.set_vel(N, P.pos_from(pN).dt(N)) + pP = Particle('pP', P, m) + # Constraint Equations + f_c = Matrix([q1**2 + q2**2 - L**2]) + # Calculate the lagrangian, and form the equations of motion + Lag = Lagrangian(N, pP) + LM = LagrangesMethod(Lag, [q1, q2], hol_coneqs=f_c, forcelist=[(P, m*g*N.x)], frame=N) + LM.form_lagranges_equations() + # Compose operating point + op_point = {q1: L, q2: 0, q1d: 0, q2d: 0, q1d.diff(t): 0, q2d.diff(t): 0} + # Solve for multiplier operating point + lam_op = LM.solve_multipliers(op_point=op_point) + op_point.update(lam_op) + # Perform the Linearization + A, B, inp_vec = LM.linearize([q2], [q2d], [q1], [q1d], + op_point=op_point, A_and_B=True) + assert simplify(A) == Matrix([[0, 1], [-9.8/L, 0]]) + assert B == Matrix([]) + + # Check if passing a function to linear_solver works + A, B, inp_vec = LM.linearize([q2], [q2d], [q1], [q1d], op_point=op_point, + A_and_B=True, linear_solver=lambda A, b: + A.LUsolve(b)) + assert simplify(A) == Matrix([[0, 1], [-9.8/L, 0]]) + assert B == Matrix([]) + +def test_linearize_rolling_disc_lagrange(): + q1, q2, q3 = q = dynamicsymbols('q1 q2 q3') + q1d, q2d, q3d = qd = dynamicsymbols('q1 q2 q3', 1) + r, m, g = symbols('r m g') + + 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]) + + C = Point('C') + C.set_vel(N, 0) + Dmc = C.locatenew('Dmc', r * L.z) + Dmc.v2pt_theory(C, N, R) + + I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) + BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) + BodyD.potential_energy = - m * g * r * cos(q2) + + Lag = Lagrangian(N, BodyD) + l = LagrangesMethod(Lag, q) + l.form_lagranges_equations() + + # Linearize about steady-state upright rolling + op_point = {q1: 0, q2: 0, q3: 0, + q1d: 0, q2d: 0, + q1d.diff(): 0, q2d.diff(): 0, q3d.diff(): 0} + A = l.linearize(q_ind=q, qd_ind=qd, op_point=op_point, A_and_B=True)[0] + sol = Matrix([[0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, -6*q3d, 0], + [0, -4*g/(5*r), 0, 6*q3d/5, 0, 0], + [0, 0, 0, 0, 0, 0]]) + + assert A == sol diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_loads.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_loads.py new file mode 100644 index 0000000000000000000000000000000000000000..8aa0cec14887f0778fc1e60e7ff33830ceef72d3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_loads.py @@ -0,0 +1,86 @@ +from pytest import raises + +from sympy import symbols +from sympy.physics.mechanics import (RigidBody, Particle, ReferenceFrame, Point, + outer, dynamicsymbols, Force, Torque) +from sympy.physics.mechanics.loads import gravity, _parse_load + + +def test_force_default(): + N = ReferenceFrame('N') + Po = Point('Po') + f1 = Force(Po, N.x) + assert f1.point == Po + assert f1.force == N.x + assert f1.__repr__() == 'Force(point=Po, force=N.x)' + # Test tuple behaviour + assert isinstance(f1, tuple) + assert f1[0] == Po + assert f1[1] == N.x + assert f1 == (Po, N.x) + assert f1 != (N.x, Po) + assert f1 != (Po, N.x + N.y) + assert f1 != (Point('Co'), N.x) + # Test body as input + P = Particle('P', Po) + f2 = Force(P, N.x) + assert f1 == f2 + + +def test_torque_default(): + N = ReferenceFrame('N') + f1 = Torque(N, N.x) + assert f1.frame == N + assert f1.torque == N.x + assert f1.__repr__() == 'Torque(frame=N, torque=N.x)' + # Test tuple behaviour + assert isinstance(f1, tuple) + assert f1[0] == N + assert f1[1] == N.x + assert f1 == (N, N.x) + assert f1 != (N.x, N) + assert f1 != (N, N.x + N.y) + assert f1 != (ReferenceFrame('A'), N.x) + # Test body as input + rb = RigidBody('P', frame=N) + f2 = Torque(rb, N.x) + assert f1 == f2 + + +def test_gravity(): + N = ReferenceFrame('N') + m, M, g = symbols('m M g') + F1, F2 = dynamicsymbols('F1 F2') + po = Point('po') + pa = Particle('pa', po, m) + A = ReferenceFrame('A') + P = Point('P') + I = outer(A.x, A.x) + B = RigidBody('B', P, A, M, (I, P)) + forceList = [(po, F1), (P, F2)] + forceList.extend(gravity(g * N.y, pa, B)) + l = [(po, F1), (P, F2), (po, g * m * N.y), (P, g * M * N.y)] + + for i in range(len(l)): + for j in range(len(l[i])): + assert forceList[i][j] == l[i][j] + + +def test_parse_loads(): + N = ReferenceFrame('N') + po = Point('po') + assert _parse_load(Force(po, N.z)) == (po, N.z) + assert _parse_load(Torque(N, N.x)) == (N, N.x) + f1 = _parse_load((po, N.x)) # Test whether a force is recognized + assert isinstance(f1, Force) + assert f1 == Force(po, N.x) + t1 = _parse_load((N, N.y)) # Test whether a torque is recognized + assert isinstance(t1, Torque) + assert t1 == Torque(N, N.y) + # Bodies should be undetermined (even in case of a Particle) + raises(ValueError, lambda: _parse_load((Particle('pa', po), N.x))) + raises(ValueError, lambda: _parse_load((RigidBody('pa', po, N), N.x))) + # Invalid tuple length + raises(ValueError, lambda: _parse_load((po, N.x, po, N.x))) + # Invalid type + raises(TypeError, lambda: _parse_load([po, N.x])) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_method.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_method.py new file mode 100644 index 0000000000000000000000000000000000000000..4a8fd5fb50c3178f5a5cdab1e80423df8b52f525 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_method.py @@ -0,0 +1,5 @@ +from sympy.physics.mechanics.method import _Methods +from sympy.testing.pytest import raises + +def test_method(): + raises(TypeError, lambda: _Methods()) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_models.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_models.py new file mode 100644 index 0000000000000000000000000000000000000000..2b3d3ae89b44d774ead1a3ea641a8274ba951638 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_models.py @@ -0,0 +1,117 @@ +import sympy.physics.mechanics.models as models +from sympy import (cos, sin, Matrix, symbols, zeros) +from sympy.simplify.simplify import simplify +from sympy.physics.mechanics import (dynamicsymbols) + + +def test_multi_mass_spring_damper_inputs(): + + c0, k0, m0 = symbols("c0 k0 m0") + g = symbols("g") + v0, x0, f0 = dynamicsymbols("v0 x0 f0") + + kane1 = models.multi_mass_spring_damper(1) + massmatrix1 = Matrix([[m0]]) + forcing1 = Matrix([[-c0*v0 - k0*x0]]) + assert simplify(massmatrix1 - kane1.mass_matrix) == Matrix([0]) + assert simplify(forcing1 - kane1.forcing) == Matrix([0]) + + kane2 = models.multi_mass_spring_damper(1, True) + massmatrix2 = Matrix([[m0]]) + forcing2 = Matrix([[-c0*v0 + g*m0 - k0*x0]]) + assert simplify(massmatrix2 - kane2.mass_matrix) == Matrix([0]) + assert simplify(forcing2 - kane2.forcing) == Matrix([0]) + + kane3 = models.multi_mass_spring_damper(1, True, True) + massmatrix3 = Matrix([[m0]]) + forcing3 = Matrix([[-c0*v0 + g*m0 - k0*x0 + f0]]) + assert simplify(massmatrix3 - kane3.mass_matrix) == Matrix([0]) + assert simplify(forcing3 - kane3.forcing) == Matrix([0]) + + kane4 = models.multi_mass_spring_damper(1, False, True) + massmatrix4 = Matrix([[m0]]) + forcing4 = Matrix([[-c0*v0 - k0*x0 + f0]]) + assert simplify(massmatrix4 - kane4.mass_matrix) == Matrix([0]) + assert simplify(forcing4 - kane4.forcing) == Matrix([0]) + + +def test_multi_mass_spring_damper_higher_order(): + c0, k0, m0 = symbols("c0 k0 m0") + c1, k1, m1 = symbols("c1 k1 m1") + c2, k2, m2 = symbols("c2 k2 m2") + v0, x0 = dynamicsymbols("v0 x0") + v1, x1 = dynamicsymbols("v1 x1") + v2, x2 = dynamicsymbols("v2 x2") + + kane1 = models.multi_mass_spring_damper(3) + massmatrix1 = Matrix([[m0 + m1 + m2, m1 + m2, m2], + [m1 + m2, m1 + m2, m2], + [m2, m2, m2]]) + forcing1 = Matrix([[-c0*v0 - k0*x0], + [-c1*v1 - k1*x1], + [-c2*v2 - k2*x2]]) + assert simplify(massmatrix1 - kane1.mass_matrix) == zeros(3) + assert simplify(forcing1 - kane1.forcing) == Matrix([0, 0, 0]) + + +def test_n_link_pendulum_on_cart_inputs(): + l0, m0 = symbols("l0 m0") + m1 = symbols("m1") + g = symbols("g") + q0, q1, F, T1 = dynamicsymbols("q0 q1 F T1") + u0, u1 = dynamicsymbols("u0 u1") + + kane1 = models.n_link_pendulum_on_cart(1) + massmatrix1 = Matrix([[m0 + m1, -l0*m1*cos(q1)], + [-l0*m1*cos(q1), l0**2*m1]]) + forcing1 = Matrix([[-l0*m1*u1**2*sin(q1) + F], [g*l0*m1*sin(q1)]]) + assert simplify(massmatrix1 - kane1.mass_matrix) == zeros(2) + assert simplify(forcing1 - kane1.forcing) == Matrix([0, 0]) + + kane2 = models.n_link_pendulum_on_cart(1, False) + massmatrix2 = Matrix([[m0 + m1, -l0*m1*cos(q1)], + [-l0*m1*cos(q1), l0**2*m1]]) + forcing2 = Matrix([[-l0*m1*u1**2*sin(q1)], [g*l0*m1*sin(q1)]]) + assert simplify(massmatrix2 - kane2.mass_matrix) == zeros(2) + assert simplify(forcing2 - kane2.forcing) == Matrix([0, 0]) + + kane3 = models.n_link_pendulum_on_cart(1, False, True) + massmatrix3 = Matrix([[m0 + m1, -l0*m1*cos(q1)], + [-l0*m1*cos(q1), l0**2*m1]]) + forcing3 = Matrix([[-l0*m1*u1**2*sin(q1)], [g*l0*m1*sin(q1) + T1]]) + assert simplify(massmatrix3 - kane3.mass_matrix) == zeros(2) + assert simplify(forcing3 - kane3.forcing) == Matrix([0, 0]) + + kane4 = models.n_link_pendulum_on_cart(1, True, False) + massmatrix4 = Matrix([[m0 + m1, -l0*m1*cos(q1)], + [-l0*m1*cos(q1), l0**2*m1]]) + forcing4 = Matrix([[-l0*m1*u1**2*sin(q1) + F], [g*l0*m1*sin(q1)]]) + assert simplify(massmatrix4 - kane4.mass_matrix) == zeros(2) + assert simplify(forcing4 - kane4.forcing) == Matrix([0, 0]) + + +def test_n_link_pendulum_on_cart_higher_order(): + l0, m0 = symbols("l0 m0") + l1, m1 = symbols("l1 m1") + m2 = symbols("m2") + g = symbols("g") + q0, q1, q2 = dynamicsymbols("q0 q1 q2") + u0, u1, u2 = dynamicsymbols("u0 u1 u2") + F, T1 = dynamicsymbols("F T1") + + kane1 = models.n_link_pendulum_on_cart(2) + massmatrix1 = Matrix([[m0 + m1 + m2, -l0*m1*cos(q1) - l0*m2*cos(q1), + -l1*m2*cos(q2)], + [-l0*m1*cos(q1) - l0*m2*cos(q1), l0**2*m1 + l0**2*m2, + l0*l1*m2*(sin(q1)*sin(q2) + cos(q1)*cos(q2))], + [-l1*m2*cos(q2), + l0*l1*m2*(sin(q1)*sin(q2) + cos(q1)*cos(q2)), + l1**2*m2]]) + forcing1 = Matrix([[-l0*m1*u1**2*sin(q1) - l0*m2*u1**2*sin(q1) - + l1*m2*u2**2*sin(q2) + F], + [g*l0*m1*sin(q1) + g*l0*m2*sin(q1) - + l0*l1*m2*(sin(q1)*cos(q2) - sin(q2)*cos(q1))*u2**2], + [g*l1*m2*sin(q2) - l0*l1*m2*(-sin(q1)*cos(q2) + + sin(q2)*cos(q1))*u1**2]]) + assert simplify(massmatrix1 - kane1.mass_matrix) == zeros(3) + assert simplify(forcing1 - kane1.forcing) == Matrix([0, 0, 0]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_particle.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_particle.py new file mode 100644 index 0000000000000000000000000000000000000000..8eec80275b532055eacaf2339a276c0fd19b330a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_particle.py @@ -0,0 +1,78 @@ +from sympy import symbols +from sympy.physics.mechanics import Point, Particle, ReferenceFrame, inertia +from sympy.physics.mechanics.body_base import BodyBase +from sympy.testing.pytest import raises, warns_deprecated_sympy + + +def test_particle_default(): + # Test default + p = Particle('P') + assert p.name == 'P' + assert p.mass == symbols('P_mass') + assert p.masscenter.name == 'P_masscenter' + assert p.potential_energy == 0 + assert p.__str__() == 'P' + assert p.__repr__() == ("Particle('P', masscenter=P_masscenter, " + "mass=P_mass)") + raises(AttributeError, lambda: p.frame) + + +def test_particle(): + # Test initializing with parameters + m, m2, v1, v2, v3, r, g, h = symbols('m m2 v1 v2 v3 r g h') + P = Point('P') + P2 = Point('P2') + p = Particle('pa', P, m) + assert isinstance(p, BodyBase) + assert p.mass == m + assert p.point == P + # Test the mass setter + p.mass = m2 + assert p.mass == m2 + # Test the point setter + p.point = P2 + assert p.point == P2 + # Test the linear momentum function + N = ReferenceFrame('N') + O = Point('O') + P2.set_pos(O, r * N.y) + P2.set_vel(N, v1 * N.x) + raises(TypeError, lambda: Particle(P, P, m)) + raises(TypeError, lambda: Particle('pa', m, m)) + assert p.linear_momentum(N) == m2 * v1 * N.x + assert p.angular_momentum(O, N) == -m2 * r * v1 * N.z + P2.set_vel(N, v2 * N.y) + assert p.linear_momentum(N) == m2 * v2 * N.y + assert p.angular_momentum(O, N) == 0 + P2.set_vel(N, v3 * N.z) + assert p.linear_momentum(N) == m2 * v3 * N.z + assert p.angular_momentum(O, N) == m2 * r * v3 * N.x + P2.set_vel(N, v1 * N.x + v2 * N.y + v3 * N.z) + assert p.linear_momentum(N) == m2 * (v1 * N.x + v2 * N.y + v3 * N.z) + assert p.angular_momentum(O, N) == m2 * r * (v3 * N.x - v1 * N.z) + p.potential_energy = m * g * h + assert p.potential_energy == m * g * h + # 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] + + +def test_parallel_axis(): + N = ReferenceFrame('N') + m, a, b = symbols('m, a, b') + o = Point('o') + p = o.locatenew('p', a * N.x + b * N.y) + P = Particle('P', o, m) + Ip = P.parallel_axis(p, N) + Ip_expected = inertia(N, m * b ** 2, m * a ** 2, m * (a ** 2 + b ** 2), + ixy=-m * a * b) + assert Ip == Ip_expected + + +def test_deprecated_set_potential_energy(): + m, g, h = symbols('m g h') + P = Point('P') + p = Particle('pa', P, m) + with warns_deprecated_sympy(): + p.set_potential_energy(m * g * h) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_pathway.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_pathway.py new file mode 100644 index 0000000000000000000000000000000000000000..49dc4bd4d61300745833f9d32f3a91d9054c4839 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_pathway.py @@ -0,0 +1,691 @@ +"""Tests for the ``sympy.physics.mechanics.pathway.py`` module.""" + +import pytest + +from sympy import ( + Rational, + Symbol, + cos, + pi, + sin, + sqrt, +) +from sympy.physics.mechanics import ( + Force, + LinearPathway, + ObstacleSetPathway, + PathwayBase, + Point, + ReferenceFrame, + WrappingCylinder, + WrappingGeometryBase, + WrappingPathway, + WrappingSphere, + dynamicsymbols, +) +from sympy.simplify.simplify import simplify + + +def _simplify_loads(loads): + return [ + load.__class__(load.location, load.vector.simplify()) + for load in loads + ] + + +class TestLinearPathway: + + def test_is_pathway_base_subclass(self): + assert issubclass(LinearPathway, PathwayBase) + + @staticmethod + @pytest.mark.parametrize( + 'args, kwargs', + [ + ((Point('pA'), Point('pB')), {}), + ] + ) + def test_valid_constructor(args, kwargs): + pointA, pointB = args + instance = LinearPathway(*args, **kwargs) + assert isinstance(instance, LinearPathway) + assert hasattr(instance, 'attachments') + assert len(instance.attachments) == 2 + assert instance.attachments[0] is pointA + assert instance.attachments[1] is pointB + assert isinstance(instance.attachments[0], Point) + assert instance.attachments[0].name == 'pA' + assert isinstance(instance.attachments[1], Point) + assert instance.attachments[1].name == 'pB' + + @staticmethod + @pytest.mark.parametrize( + 'attachments', + [ + (Point('pA'), ), + (Point('pA'), Point('pB'), Point('pZ')), + ] + ) + def test_invalid_attachments_incorrect_number(attachments): + with pytest.raises(ValueError): + _ = LinearPathway(*attachments) + + @staticmethod + @pytest.mark.parametrize( + 'attachments', + [ + (None, Point('pB')), + (Point('pA'), None), + ] + ) + def test_invalid_attachments_not_point(attachments): + with pytest.raises(TypeError): + _ = LinearPathway(*attachments) + + @pytest.fixture(autouse=True) + def _linear_pathway_fixture(self): + self.N = ReferenceFrame('N') + self.pA = Point('pA') + self.pB = Point('pB') + self.pathway = LinearPathway(self.pA, self.pB) + self.q1 = dynamicsymbols('q1') + self.q2 = dynamicsymbols('q2') + self.q3 = dynamicsymbols('q3') + self.q1d = dynamicsymbols('q1', 1) + self.q2d = dynamicsymbols('q2', 1) + self.q3d = dynamicsymbols('q3', 1) + self.F = Symbol('F') + + def test_properties_are_immutable(self): + instance = LinearPathway(self.pA, self.pB) + with pytest.raises(AttributeError): + instance.attachments = None + with pytest.raises(TypeError): + instance.attachments[0] = None + with pytest.raises(TypeError): + instance.attachments[1] = None + + def test_repr(self): + pathway = LinearPathway(self.pA, self.pB) + expected = 'LinearPathway(pA, pB)' + assert repr(pathway) == expected + + def test_static_pathway_length(self): + self.pB.set_pos(self.pA, 2*self.N.x) + assert self.pathway.length == 2 + + def test_static_pathway_extension_velocity(self): + self.pB.set_pos(self.pA, 2*self.N.x) + assert self.pathway.extension_velocity == 0 + + def test_static_pathway_to_loads(self): + self.pB.set_pos(self.pA, 2*self.N.x) + expected = [ + (self.pA, - self.F*self.N.x), + (self.pB, self.F*self.N.x), + ] + assert self.pathway.to_loads(self.F) == expected + + def test_2D_pathway_length(self): + self.pB.set_pos(self.pA, 2*self.q1*self.N.x) + expected = 2*sqrt(self.q1**2) + assert self.pathway.length == expected + + def test_2D_pathway_extension_velocity(self): + self.pB.set_pos(self.pA, 2*self.q1*self.N.x) + expected = 2*sqrt(self.q1**2)*self.q1d/self.q1 + assert self.pathway.extension_velocity == expected + + def test_2D_pathway_to_loads(self): + self.pB.set_pos(self.pA, 2*self.q1*self.N.x) + expected = [ + (self.pA, - self.F*(self.q1 / sqrt(self.q1**2))*self.N.x), + (self.pB, self.F*(self.q1 / sqrt(self.q1**2))*self.N.x), + ] + assert self.pathway.to_loads(self.F) == expected + + def test_3D_pathway_length(self): + self.pB.set_pos( + self.pA, + self.q1*self.N.x - self.q2*self.N.y + 2*self.q3*self.N.z, + ) + expected = sqrt(self.q1**2 + self.q2**2 + 4*self.q3**2) + assert simplify(self.pathway.length - expected) == 0 + + def test_3D_pathway_extension_velocity(self): + self.pB.set_pos( + self.pA, + self.q1*self.N.x - self.q2*self.N.y + 2*self.q3*self.N.z, + ) + length = sqrt(self.q1**2 + self.q2**2 + 4*self.q3**2) + expected = ( + self.q1*self.q1d/length + + self.q2*self.q2d/length + + 4*self.q3*self.q3d/length + ) + assert simplify(self.pathway.extension_velocity - expected) == 0 + + def test_3D_pathway_to_loads(self): + self.pB.set_pos( + self.pA, + self.q1*self.N.x - self.q2*self.N.y + 2*self.q3*self.N.z, + ) + length = sqrt(self.q1**2 + self.q2**2 + 4*self.q3**2) + pO_force = ( + - self.F*self.q1*self.N.x/length + + self.F*self.q2*self.N.y/length + - 2*self.F*self.q3*self.N.z/length + ) + pI_force = ( + self.F*self.q1*self.N.x/length + - self.F*self.q2*self.N.y/length + + 2*self.F*self.q3*self.N.z/length + ) + expected = [ + (self.pA, pO_force), + (self.pB, pI_force), + ] + assert self.pathway.to_loads(self.F) == expected + + +class TestObstacleSetPathway: + + def test_is_pathway_base_subclass(self): + assert issubclass(ObstacleSetPathway, PathwayBase) + + @staticmethod + @pytest.mark.parametrize( + 'num_attachments, attachments', + [ + (3, [Point(name) for name in ('pO', 'pA', 'pI')]), + (4, [Point(name) for name in ('pO', 'pA', 'pB', 'pI')]), + (5, [Point(name) for name in ('pO', 'pA', 'pB', 'pC', 'pI')]), + (6, [Point(name) for name in ('pO', 'pA', 'pB', 'pC', 'pD', 'pI')]), + ] + ) + def test_valid_constructor(num_attachments, attachments): + instance = ObstacleSetPathway(*attachments) + assert isinstance(instance, ObstacleSetPathway) + assert hasattr(instance, 'attachments') + assert len(instance.attachments) == num_attachments + for attachment in instance.attachments: + assert isinstance(attachment, Point) + + @staticmethod + @pytest.mark.parametrize( + 'attachments', + [[Point('pO')], [Point('pO'), Point('pI')]], + ) + def test_invalid_constructor_attachments_incorrect_number(attachments): + with pytest.raises(ValueError): + _ = ObstacleSetPathway(*attachments) + + @staticmethod + @pytest.mark.parametrize( + 'attachments', + [ + (None, Point('pA'), Point('pI')), + (Point('pO'), None, Point('pI')), + (Point('pO'), Point('pA'), None), + ] + ) + def test_invalid_constructor_attachments_not_point(attachments): + with pytest.raises(TypeError): + _ = WrappingPathway(*attachments) # type: ignore + + def test_properties_are_immutable(self): + pathway = ObstacleSetPathway(Point('pO'), Point('pA'), Point('pI')) + with pytest.raises(AttributeError): + pathway.attachments = None # type: ignore + with pytest.raises(TypeError): + pathway.attachments[0] = None # type: ignore + with pytest.raises(TypeError): + pathway.attachments[1] = None # type: ignore + with pytest.raises(TypeError): + pathway.attachments[-1] = None # type: ignore + + @staticmethod + @pytest.mark.parametrize( + 'attachments, expected', + [ + ( + [Point(name) for name in ('pO', 'pA', 'pI')], + 'ObstacleSetPathway(pO, pA, pI)' + ), + ( + [Point(name) for name in ('pO', 'pA', 'pB', 'pI')], + 'ObstacleSetPathway(pO, pA, pB, pI)' + ), + ( + [Point(name) for name in ('pO', 'pA', 'pB', 'pC', 'pI')], + 'ObstacleSetPathway(pO, pA, pB, pC, pI)' + ), + ] + ) + def test_repr(attachments, expected): + pathway = ObstacleSetPathway(*attachments) + assert repr(pathway) == expected + + @pytest.fixture(autouse=True) + def _obstacle_set_pathway_fixture(self): + self.N = ReferenceFrame('N') + self.pO = Point('pO') + self.pI = Point('pI') + self.pA = Point('pA') + self.pB = Point('pB') + self.q = dynamicsymbols('q') + self.qd = dynamicsymbols('q', 1) + self.F = Symbol('F') + + def test_static_pathway_length(self): + self.pA.set_pos(self.pO, self.N.x) + self.pB.set_pos(self.pO, self.N.y) + self.pI.set_pos(self.pO, self.N.z) + pathway = ObstacleSetPathway(self.pO, self.pA, self.pB, self.pI) + assert pathway.length == 1 + 2 * sqrt(2) + + def test_static_pathway_extension_velocity(self): + self.pA.set_pos(self.pO, self.N.x) + self.pB.set_pos(self.pO, self.N.y) + self.pI.set_pos(self.pO, self.N.z) + pathway = ObstacleSetPathway(self.pO, self.pA, self.pB, self.pI) + assert pathway.extension_velocity == 0 + + def test_static_pathway_to_loads(self): + self.pA.set_pos(self.pO, self.N.x) + self.pB.set_pos(self.pO, self.N.y) + self.pI.set_pos(self.pO, self.N.z) + pathway = ObstacleSetPathway(self.pO, self.pA, self.pB, self.pI) + expected = [ + Force(self.pO, -self.F * self.N.x), + Force(self.pA, self.F * self.N.x), + Force(self.pA, self.F * sqrt(2) / 2 * (self.N.x - self.N.y)), + Force(self.pB, self.F * sqrt(2) / 2 * (self.N.y - self.N.x)), + Force(self.pB, self.F * sqrt(2) / 2 * (self.N.y - self.N.z)), + Force(self.pI, self.F * sqrt(2) / 2 * (self.N.z - self.N.y)), + ] + assert pathway.to_loads(self.F) == expected + + def test_2D_pathway_length(self): + self.pA.set_pos(self.pO, -(self.N.x + self.N.y)) + self.pB.set_pos( + self.pO, cos(self.q) * self.N.x - (sin(self.q) + 1) * self.N.y + ) + self.pI.set_pos( + self.pO, sin(self.q) * self.N.x + (cos(self.q) - 1) * self.N.y + ) + pathway = ObstacleSetPathway(self.pO, self.pA, self.pB, self.pI) + expected = 2 * sqrt(2) + sqrt(2 + 2*cos(self.q)) + assert (pathway.length - expected).simplify() == 0 + + def test_2D_pathway_extension_velocity(self): + self.pA.set_pos(self.pO, -(self.N.x + self.N.y)) + self.pB.set_pos( + self.pO, cos(self.q) * self.N.x - (sin(self.q) + 1) * self.N.y + ) + self.pI.set_pos( + self.pO, sin(self.q) * self.N.x + (cos(self.q) - 1) * self.N.y + ) + pathway = ObstacleSetPathway(self.pO, self.pA, self.pB, self.pI) + expected = - (sqrt(2) * sin(self.q) * self.qd) / (2 * sqrt(cos(self.q) + 1)) + assert (pathway.extension_velocity - expected).simplify() == 0 + + def test_2D_pathway_to_loads(self): + self.pA.set_pos(self.pO, -(self.N.x + self.N.y)) + self.pB.set_pos( + self.pO, cos(self.q) * self.N.x - (sin(self.q) + 1) * self.N.y + ) + self.pI.set_pos( + self.pO, sin(self.q) * self.N.x + (cos(self.q) - 1) * self.N.y + ) + pathway = ObstacleSetPathway(self.pO, self.pA, self.pB, self.pI) + pO_pA_force_vec = sqrt(2) / 2 * (self.N.x + self.N.y) + pA_pB_force_vec = ( + - sqrt(2 * cos(self.q) + 2) / 2 * self.N.x + + sqrt(2) * sin(self.q) / (2 * sqrt(cos(self.q) + 1)) * self.N.y + ) + pB_pI_force_vec = cos(self.q + pi/4) * self.N.x - sin(self.q + pi/4) * self.N.y + expected = [ + Force(self.pO, self.F * pO_pA_force_vec), + Force(self.pA, -self.F * pO_pA_force_vec), + Force(self.pA, self.F * pA_pB_force_vec), + Force(self.pB, -self.F * pA_pB_force_vec), + Force(self.pB, self.F * pB_pI_force_vec), + Force(self.pI, -self.F * pB_pI_force_vec), + ] + assert _simplify_loads(pathway.to_loads(self.F)) == expected + + +class TestWrappingPathway: + + def test_is_pathway_base_subclass(self): + assert issubclass(WrappingPathway, PathwayBase) + + @pytest.fixture(autouse=True) + def _wrapping_pathway_fixture(self): + self.pA = Point('pA') + self.pB = Point('pB') + self.r = Symbol('r', positive=True) + self.pO = Point('pO') + self.N = ReferenceFrame('N') + self.ax = self.N.z + self.sphere = WrappingSphere(self.r, self.pO) + self.cylinder = WrappingCylinder(self.r, self.pO, self.ax) + self.pathway = WrappingPathway(self.pA, self.pB, self.cylinder) + self.F = Symbol('F') + + def test_valid_constructor(self): + instance = WrappingPathway(self.pA, self.pB, self.cylinder) + assert isinstance(instance, WrappingPathway) + assert hasattr(instance, 'attachments') + assert len(instance.attachments) == 2 + assert isinstance(instance.attachments[0], Point) + assert instance.attachments[0] == self.pA + assert isinstance(instance.attachments[1], Point) + assert instance.attachments[1] == self.pB + assert hasattr(instance, 'geometry') + assert isinstance(instance.geometry, WrappingGeometryBase) + assert instance.geometry == self.cylinder + + @pytest.mark.parametrize( + 'attachments', + [ + (Point('pA'), ), + (Point('pA'), Point('pB'), Point('pZ')), + ] + ) + def test_invalid_constructor_attachments_incorrect_number(self, attachments): + with pytest.raises(TypeError): + _ = WrappingPathway(*attachments, self.cylinder) + + @staticmethod + @pytest.mark.parametrize( + 'attachments', + [ + (None, Point('pB')), + (Point('pA'), None), + ] + ) + def test_invalid_constructor_attachments_not_point(attachments): + with pytest.raises(TypeError): + _ = WrappingPathway(*attachments) + + def test_invalid_constructor_geometry_is_not_supplied(self): + with pytest.raises(TypeError): + _ = WrappingPathway(self.pA, self.pB) + + @pytest.mark.parametrize( + 'geometry', + [ + Symbol('r'), + dynamicsymbols('q'), + ReferenceFrame('N'), + ReferenceFrame('N').x, + ] + ) + def test_invalid_geometry_not_geometry(self, geometry): + with pytest.raises(TypeError): + _ = WrappingPathway(self.pA, self.pB, geometry) + + def test_attachments_property_is_immutable(self): + with pytest.raises(TypeError): + self.pathway.attachments[0] = self.pB + with pytest.raises(TypeError): + self.pathway.attachments[1] = self.pA + + def test_geometry_property_is_immutable(self): + with pytest.raises(AttributeError): + self.pathway.geometry = None + + def test_repr(self): + expected = ( + f'WrappingPathway(pA, pB, ' + f'geometry={self.cylinder!r})' + ) + assert repr(self.pathway) == expected + + @staticmethod + def _expand_pos_to_vec(pos, frame): + return sum(mag*unit for (mag, unit) in zip(pos, frame)) + + @pytest.mark.parametrize( + 'pA_vec, pB_vec, factor', + [ + ((1, 0, 0), (0, 1, 0), pi/2), + ((0, 1, 0), (sqrt(2)/2, -sqrt(2)/2, 0), 3*pi/4), + ((1, 0, 0), (Rational(1, 2), sqrt(3)/2, 0), pi/3), + ] + ) + def test_static_pathway_on_sphere_length(self, pA_vec, pB_vec, factor): + pA_vec = self._expand_pos_to_vec(pA_vec, self.N) + pB_vec = self._expand_pos_to_vec(pB_vec, self.N) + self.pA.set_pos(self.pO, self.r*pA_vec) + self.pB.set_pos(self.pO, self.r*pB_vec) + pathway = WrappingPathway(self.pA, self.pB, self.sphere) + expected = factor*self.r + assert simplify(pathway.length - expected) == 0 + + @pytest.mark.parametrize( + 'pA_vec, pB_vec, factor', + [ + ((1, 0, 0), (0, 1, 0), Rational(1, 2)*pi), + ((1, 0, 0), (-1, 0, 0), pi), + ((-1, 0, 0), (1, 0, 0), pi), + ((0, 1, 0), (sqrt(2)/2, -sqrt(2)/2, 0), 5*pi/4), + ((1, 0, 0), (Rational(1, 2), sqrt(3)/2, 0), pi/3), + ( + (0, 1, 0), + (sqrt(2)*Rational(1, 2), -sqrt(2)*Rational(1, 2), 1), + sqrt(1 + (Rational(5, 4)*pi)**2), + ), + ( + (1, 0, 0), + (Rational(1, 2), sqrt(3)*Rational(1, 2), 1), + sqrt(1 + (Rational(1, 3)*pi)**2), + ), + ] + ) + def test_static_pathway_on_cylinder_length(self, pA_vec, pB_vec, factor): + pA_vec = self._expand_pos_to_vec(pA_vec, self.N) + pB_vec = self._expand_pos_to_vec(pB_vec, self.N) + self.pA.set_pos(self.pO, self.r*pA_vec) + self.pB.set_pos(self.pO, self.r*pB_vec) + pathway = WrappingPathway(self.pA, self.pB, self.cylinder) + expected = factor*sqrt(self.r**2) + assert simplify(pathway.length - expected) == 0 + + @pytest.mark.parametrize( + 'pA_vec, pB_vec', + [ + ((1, 0, 0), (0, 1, 0)), + ((0, 1, 0), (sqrt(2)*Rational(1, 2), -sqrt(2)*Rational(1, 2), 0)), + ((1, 0, 0), (Rational(1, 2), sqrt(3)*Rational(1, 2), 0)), + ] + ) + def test_static_pathway_on_sphere_extension_velocity(self, pA_vec, pB_vec): + pA_vec = self._expand_pos_to_vec(pA_vec, self.N) + pB_vec = self._expand_pos_to_vec(pB_vec, self.N) + self.pA.set_pos(self.pO, self.r*pA_vec) + self.pB.set_pos(self.pO, self.r*pB_vec) + pathway = WrappingPathway(self.pA, self.pB, self.sphere) + assert pathway.extension_velocity == 0 + + @pytest.mark.parametrize( + 'pA_vec, pB_vec', + [ + ((1, 0, 0), (0, 1, 0)), + ((1, 0, 0), (-1, 0, 0)), + ((-1, 0, 0), (1, 0, 0)), + ((0, 1, 0), (sqrt(2)/2, -sqrt(2)/2, 0)), + ((1, 0, 0), (Rational(1, 2), sqrt(3)/2, 0)), + ((0, 1, 0), (sqrt(2)*Rational(1, 2), -sqrt(2)/2, 1)), + ((1, 0, 0), (Rational(1, 2), sqrt(3)/2, 1)), + ] + ) + def test_static_pathway_on_cylinder_extension_velocity(self, pA_vec, pB_vec): + pA_vec = self._expand_pos_to_vec(pA_vec, self.N) + pB_vec = self._expand_pos_to_vec(pB_vec, self.N) + self.pA.set_pos(self.pO, self.r*pA_vec) + self.pB.set_pos(self.pO, self.r*pB_vec) + pathway = WrappingPathway(self.pA, self.pB, self.cylinder) + assert pathway.extension_velocity == 0 + + @pytest.mark.parametrize( + 'pA_vec, pB_vec, pA_vec_expected, pB_vec_expected, pO_vec_expected', + ( + ((1, 0, 0), (0, 1, 0), (0, 1, 0), (1, 0, 0), (-1, -1, 0)), + ( + (0, 1, 0), + (sqrt(2)/2, -sqrt(2)/2, 0), + (1, 0, 0), + (sqrt(2)/2, sqrt(2)/2, 0), + (-1 - sqrt(2)/2, -sqrt(2)/2, 0) + ), + ( + (1, 0, 0), + (Rational(1, 2), sqrt(3)/2, 0), + (0, 1, 0), + (sqrt(3)/2, -Rational(1, 2), 0), + (-sqrt(3)/2, Rational(1, 2) - 1, 0), + ), + ) + ) + def test_static_pathway_on_sphere_to_loads( + self, + pA_vec, + pB_vec, + pA_vec_expected, + pB_vec_expected, + pO_vec_expected, + ): + pA_vec = self._expand_pos_to_vec(pA_vec, self.N) + pB_vec = self._expand_pos_to_vec(pB_vec, self.N) + self.pA.set_pos(self.pO, self.r*pA_vec) + self.pB.set_pos(self.pO, self.r*pB_vec) + pathway = WrappingPathway(self.pA, self.pB, self.sphere) + + pA_vec_expected = sum( + mag*unit for (mag, unit) in zip(pA_vec_expected, self.N) + ) + pB_vec_expected = sum( + mag*unit for (mag, unit) in zip(pB_vec_expected, self.N) + ) + pO_vec_expected = sum( + mag*unit for (mag, unit) in zip(pO_vec_expected, self.N) + ) + expected = [ + Force(self.pA, self.F*(self.r**3/sqrt(self.r**6))*pA_vec_expected), + Force(self.pB, self.F*(self.r**3/sqrt(self.r**6))*pB_vec_expected), + Force(self.pO, self.F*(self.r**3/sqrt(self.r**6))*pO_vec_expected), + ] + assert pathway.to_loads(self.F) == expected + + @pytest.mark.parametrize( + 'pA_vec, pB_vec, pA_vec_expected, pB_vec_expected, pO_vec_expected', + ( + ((1, 0, 0), (0, 1, 0), (0, 1, 0), (1, 0, 0), (-1, -1, 0)), + ((1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, 1, 0), (0, -2, 0)), + ((-1, 0, 0), (1, 0, 0), (0, -1, 0), (0, -1, 0), (0, 2, 0)), + ( + (0, 1, 0), + (sqrt(2)/2, -sqrt(2)/2, 0), + (-1, 0, 0), + (-sqrt(2)/2, -sqrt(2)/2, 0), + (1 + sqrt(2)/2, sqrt(2)/2, 0) + ), + ( + (1, 0, 0), + (Rational(1, 2), sqrt(3)/2, 0), + (0, 1, 0), + (sqrt(3)/2, -Rational(1, 2), 0), + (-sqrt(3)/2, Rational(1, 2) - 1, 0), + ), + ( + (1, 0, 0), + (sqrt(2)/2, sqrt(2)/2, 0), + (0, 1, 0), + (sqrt(2)/2, -sqrt(2)/2, 0), + (-sqrt(2)/2, sqrt(2)/2 - 1, 0), + ), + ((0, 1, 0), (0, 1, 1), (0, 0, 1), (0, 0, -1), (0, 0, 0)), + ( + (0, 1, 0), + (sqrt(2)/2, -sqrt(2)/2, 1), + (-5*pi/sqrt(16 + 25*pi**2), 0, 4/sqrt(16 + 25*pi**2)), + ( + -5*sqrt(2)*pi/(2*sqrt(16 + 25*pi**2)), + -5*sqrt(2)*pi/(2*sqrt(16 + 25*pi**2)), + -4/sqrt(16 + 25*pi**2), + ), + ( + 5*(sqrt(2) + 2)*pi/(2*sqrt(16 + 25*pi**2)), + 5*sqrt(2)*pi/(2*sqrt(16 + 25*pi**2)), + 0, + ), + ), + ) + ) + def test_static_pathway_on_cylinder_to_loads( + self, + pA_vec, + pB_vec, + pA_vec_expected, + pB_vec_expected, + pO_vec_expected, + ): + pA_vec = self._expand_pos_to_vec(pA_vec, self.N) + pB_vec = self._expand_pos_to_vec(pB_vec, self.N) + self.pA.set_pos(self.pO, self.r*pA_vec) + self.pB.set_pos(self.pO, self.r*pB_vec) + pathway = WrappingPathway(self.pA, self.pB, self.cylinder) + + pA_force_expected = self.F*self._expand_pos_to_vec(pA_vec_expected, + self.N) + pB_force_expected = self.F*self._expand_pos_to_vec(pB_vec_expected, + self.N) + pO_force_expected = self.F*self._expand_pos_to_vec(pO_vec_expected, + self.N) + expected = [ + Force(self.pA, pA_force_expected), + Force(self.pB, pB_force_expected), + Force(self.pO, pO_force_expected), + ] + assert _simplify_loads(pathway.to_loads(self.F)) == expected + + def test_2D_pathway_on_cylinder_length(self): + q = dynamicsymbols('q') + pA_pos = self.r*self.N.x + pB_pos = self.r*(cos(q)*self.N.x + sin(q)*self.N.y) + self.pA.set_pos(self.pO, pA_pos) + self.pB.set_pos(self.pO, pB_pos) + expected = self.r*sqrt(q**2) + assert simplify(self.pathway.length - expected) == 0 + + def test_2D_pathway_on_cylinder_extension_velocity(self): + q = dynamicsymbols('q') + qd = dynamicsymbols('q', 1) + pA_pos = self.r*self.N.x + pB_pos = self.r*(cos(q)*self.N.x + sin(q)*self.N.y) + self.pA.set_pos(self.pO, pA_pos) + self.pB.set_pos(self.pO, pB_pos) + expected = self.r*(sqrt(q**2)/q)*qd + assert simplify(self.pathway.extension_velocity - expected) == 0 + + def test_2D_pathway_on_cylinder_to_loads(self): + q = dynamicsymbols('q') + pA_pos = self.r*self.N.x + pB_pos = self.r*(cos(q)*self.N.x + sin(q)*self.N.y) + self.pA.set_pos(self.pO, pA_pos) + self.pB.set_pos(self.pO, pB_pos) + + pA_force = self.F*self.N.y + pB_force = self.F*(sin(q)*self.N.x - cos(q)*self.N.y) + pO_force = self.F*(-sin(q)*self.N.x + (cos(q) - 1)*self.N.y) + expected = [ + Force(self.pA, pA_force), + Force(self.pB, pB_force), + Force(self.pO, pO_force), + ] + + loads = _simplify_loads(self.pathway.to_loads(self.F)) + assert loads == expected diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_rigidbody.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_rigidbody.py new file mode 100644 index 0000000000000000000000000000000000000000..78161e0c9fc33be6e3d274034b67278c8ceee8fd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_rigidbody.py @@ -0,0 +1,184 @@ +from sympy.physics.mechanics import Point, ReferenceFrame, Dyadic, RigidBody +from sympy.physics.mechanics import dynamicsymbols, outer, inertia, Inertia +from sympy.physics.mechanics import inertia_of_point_mass +from sympy import expand, zeros, simplify, symbols +from sympy.testing.pytest import raises, warns_deprecated_sympy + + +def test_rigidbody_default(): + # Test default + b = RigidBody('B') + I = inertia(b.frame, *symbols('B_ixx B_iyy B_izz B_ixy B_iyz B_izx')) + assert b.name == 'B' + assert b.mass == symbols('B_mass') + assert b.masscenter.name == 'B_masscenter' + assert b.inertia == (I, b.masscenter) + assert b.central_inertia == I + assert b.frame.name == 'B_frame' + assert b.__str__() == 'B' + assert b.__repr__() == ( + "RigidBody('B', masscenter=B_masscenter, frame=B_frame, mass=B_mass, " + "inertia=Inertia(dyadic=B_ixx*(B_frame.x|B_frame.x) + " + "B_ixy*(B_frame.x|B_frame.y) + B_izx*(B_frame.x|B_frame.z) + " + "B_ixy*(B_frame.y|B_frame.x) + B_iyy*(B_frame.y|B_frame.y) + " + "B_iyz*(B_frame.y|B_frame.z) + B_izx*(B_frame.z|B_frame.x) + " + "B_iyz*(B_frame.z|B_frame.y) + B_izz*(B_frame.z|B_frame.z), " + "point=B_masscenter))") + + +def test_rigidbody(): + m, m2, v1, v2, v3, omega = symbols('m m2 v1 v2 v3 omega') + A = ReferenceFrame('A') + A2 = ReferenceFrame('A2') + P = Point('P') + P2 = Point('P2') + I = Dyadic(0) + I2 = Dyadic(0) + B = RigidBody('B', P, A, m, (I, P)) + assert B.mass == m + assert B.frame == A + assert B.masscenter == P + assert B.inertia == (I, B.masscenter) + + B.mass = m2 + B.frame = A2 + B.masscenter = P2 + B.inertia = (I2, B.masscenter) + raises(TypeError, lambda: RigidBody(P, P, A, m, (I, P))) + raises(TypeError, lambda: RigidBody('B', P, P, m, (I, P))) + raises(TypeError, lambda: RigidBody('B', P, A, m, (P, P))) + raises(TypeError, lambda: RigidBody('B', P, A, m, (I, I))) + assert B.__str__() == 'B' + assert B.mass == m2 + assert B.frame == A2 + assert B.masscenter == P2 + assert B.inertia == (I2, B.masscenter) + assert isinstance(B.inertia, Inertia) + + # Testing linear momentum function assuming A2 is the inertial frame + 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) + Inertia_tuple = (I, P) + B = RigidBody('B', P, b, M, Inertia_tuple) + P.set_vel(N, v * b.x) + assert B.angular_momentum(P, N) == omega * b.x + O = Point('O') + O.set_vel(N, v * b.x) + P.set_pos(O, r * b.y) + assert B.angular_momentum(O, N) == omega * b.x - M*v*r*b.z + B.potential_energy = M * g * h + assert B.potential_energy == M * g * h + assert expand(2 * B.kinetic_energy(N)) == omega**2 + M * v**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) + P.v2pt_theory(O, A, B) + 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) + + +def test_pendulum_angular_momentum(): + """Consider a pendulum of length OA = 2a, of mass m as a rigid body of + center of mass G (OG = a) which turn around (O,z). The angle between the + reference frame R and the rod is q. The inertia of the body is I = + (G,0,ma^2/3,ma^2/3). """ + + m, a = symbols('m, a') + q = dynamicsymbols('q') + + R = ReferenceFrame('R') + R1 = R.orientnew('R1', 'Axis', [q, R.z]) + R1.set_ang_vel(R, q.diff() * R.z) + + I = inertia(R1, 0, m * a**2 / 3, m * a**2 / 3) + + O = Point('O') + + A = O.locatenew('A', 2*a * R1.x) + G = O.locatenew('G', a * R1.x) + + S = RigidBody('S', G, R1, m, (I, G)) + + O.set_vel(R, 0) + A.v2pt_theory(O, R, R1) + G.v2pt_theory(O, R, R1) + + assert (4 * m * a**2 / 3 * q.diff() * R.z - + S.angular_momentum(O, R).express(R)) == 0 + + +def test_rigidbody_inertia(): + N = ReferenceFrame('N') + m, Ix, Iy, Iz, a, b = symbols('m, I_x, I_y, I_z, a, b') + Io = inertia(N, Ix, Iy, Iz) + o = Point('o') + p = o.locatenew('p', a * N.x + b * N.y) + R = RigidBody('R', o, N, m, (Io, p)) + I_check = inertia(N, Ix - b ** 2 * m, Iy - a ** 2 * m, + Iz - m * (a ** 2 + b ** 2), m * a * b) + assert isinstance(R.inertia, Inertia) + assert R.inertia == (Io, p) + assert R.central_inertia == I_check + R.central_inertia = Io + assert R.inertia == (Io, o) + assert R.central_inertia == Io + R.inertia = (Io, p) + assert R.inertia == (Io, p) + assert R.central_inertia == I_check + # parse Inertia object + R.inertia = Inertia(Io, o) + assert R.inertia == (Io, o) + + +def test_parallel_axis(): + N = ReferenceFrame('N') + m, Ix, Iy, Iz, a, b = symbols('m, I_x, I_y, I_z, a, b') + Io = inertia(N, Ix, Iy, Iz) + o = Point('o') + p = o.locatenew('p', a * N.x + b * N.y) + R = RigidBody('R', o, N, m, (Io, o)) + Ip = R.parallel_axis(p) + Ip_expected = inertia(N, Ix + m * b**2, Iy + m * a**2, + Iz + m * (a**2 + b**2), ixy=-m * a * b) + assert Ip == Ip_expected + # Reference frame from which the parallel axis is viewed should not matter + A = ReferenceFrame('A') + A.orient_axis(N, N.z, 1) + assert simplify( + (R.parallel_axis(p, A) - Ip_expected).to_matrix(A)) == zeros(3, 3) + + +def test_deprecated_set_potential_energy(): + m, g, h = symbols('m g h') + A = ReferenceFrame('A') + P = Point('P') + I = Dyadic(0) + B = RigidBody('B', P, A, m, (I, P)) + with warns_deprecated_sympy(): + B.set_potential_energy(m*g*h) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_system.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_system.py new file mode 100644 index 0000000000000000000000000000000000000000..6fdac1ea10e9f71f8cf999cc5069da7567f67adf --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_system.py @@ -0,0 +1,245 @@ +from sympy import symbols, Matrix, atan, zeros +from sympy.simplify.simplify import simplify +from sympy.physics.mechanics import (dynamicsymbols, Particle, Point, + ReferenceFrame, SymbolicSystem) +from sympy.testing.pytest import raises + +# This class is going to be tested using a simple pendulum set up in x and y +# coordinates +x, y, u, v, lam = dynamicsymbols('x y u v lambda') +m, l, g = symbols('m l g') + +# Set up the different forms the equations can take +# [1] Explicit form where the kinematics and dynamics are combined +# x' = F(x, t, r, p) +# +# [2] Implicit form where the kinematics and dynamics are combined +# M(x, p) x' = F(x, t, r, p) +# +# [3] Implicit form where the kinematics and dynamics are separate +# M(q, p) u' = F(q, u, t, r, p) +# q' = G(q, u, t, r, p) +dyn_implicit_mat = Matrix([[1, 0, -x/m], + [0, 1, -y/m], + [0, 0, l**2/m]]) + +dyn_implicit_rhs = Matrix([0, 0, u**2 + v**2 - g*y]) + +comb_implicit_mat = Matrix([[1, 0, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, -x/m], + [0, 0, 0, 1, -y/m], + [0, 0, 0, 0, l**2/m]]) + +comb_implicit_rhs = Matrix([u, v, 0, 0, u**2 + v**2 - g*y]) + +kin_explicit_rhs = Matrix([u, v]) + +comb_explicit_rhs = comb_implicit_mat.LUsolve(comb_implicit_rhs) + +# Set up a body and load to pass into the system +theta = atan(x/y) +N = ReferenceFrame('N') +A = N.orientnew('A', 'Axis', [theta, N.z]) +O = Point('O') +P = O.locatenew('P', l * A.x) + +Pa = Particle('Pa', P, m) + +bodies = [Pa] +loads = [(P, g * m * N.x)] + +# Set up some output equations to be given to SymbolicSystem +# Change to make these fit the pendulum +PE = symbols("PE") +out_eqns = {PE: m*g*(l+y)} + +# Set up remaining arguments that can be passed to SymbolicSystem +alg_con = [2] +alg_con_full = [4] +coordinates = (x, y, lam) +speeds = (u, v) +states = (x, y, u, v, lam) +coord_idxs = (0, 1) +speed_idxs = (2, 3) + + +def test_form_1(): + symsystem1 = SymbolicSystem(states, comb_explicit_rhs, + alg_con=alg_con_full, output_eqns=out_eqns, + coord_idxs=coord_idxs, speed_idxs=speed_idxs, + bodies=bodies, loads=loads) + + assert symsystem1.coordinates == Matrix([x, y]) + assert symsystem1.speeds == Matrix([u, v]) + assert symsystem1.states == Matrix([x, y, u, v, lam]) + + assert symsystem1.alg_con == [4] + + inter = comb_explicit_rhs + assert simplify(symsystem1.comb_explicit_rhs - inter) == zeros(5, 1) + + assert set(symsystem1.dynamic_symbols()) == {y, v, lam, u, x} + assert type(symsystem1.dynamic_symbols()) == tuple + assert set(symsystem1.constant_symbols()) == {l, g, m} + assert type(symsystem1.constant_symbols()) == tuple + + assert symsystem1.output_eqns == out_eqns + + assert symsystem1.bodies == (Pa,) + assert symsystem1.loads == ((P, g * m * N.x),) + + +def test_form_2(): + symsystem2 = SymbolicSystem(coordinates, comb_implicit_rhs, speeds=speeds, + mass_matrix=comb_implicit_mat, + alg_con=alg_con_full, output_eqns=out_eqns, + bodies=bodies, loads=loads) + + assert symsystem2.coordinates == Matrix([x, y, lam]) + assert symsystem2.speeds == Matrix([u, v]) + assert symsystem2.states == Matrix([x, y, lam, u, v]) + + assert symsystem2.alg_con == [4] + + inter = comb_implicit_rhs + assert simplify(symsystem2.comb_implicit_rhs - inter) == zeros(5, 1) + assert simplify(symsystem2.comb_implicit_mat-comb_implicit_mat) == zeros(5) + + assert set(symsystem2.dynamic_symbols()) == {y, v, lam, u, x} + assert type(symsystem2.dynamic_symbols()) == tuple + assert set(symsystem2.constant_symbols()) == {l, g, m} + assert type(symsystem2.constant_symbols()) == tuple + + inter = comb_explicit_rhs + symsystem2.compute_explicit_form() + assert simplify(symsystem2.comb_explicit_rhs - inter) == zeros(5, 1) + + + assert symsystem2.output_eqns == out_eqns + + assert symsystem2.bodies == (Pa,) + assert symsystem2.loads == ((P, g * m * N.x),) + + +def test_form_3(): + symsystem3 = SymbolicSystem(states, dyn_implicit_rhs, + mass_matrix=dyn_implicit_mat, + coordinate_derivatives=kin_explicit_rhs, + alg_con=alg_con, coord_idxs=coord_idxs, + speed_idxs=speed_idxs, bodies=bodies, + loads=loads) + + assert symsystem3.coordinates == Matrix([x, y]) + assert symsystem3.speeds == Matrix([u, v]) + assert symsystem3.states == Matrix([x, y, u, v, lam]) + + assert symsystem3.alg_con == [4] + + inter1 = kin_explicit_rhs + inter2 = dyn_implicit_rhs + assert simplify(symsystem3.kin_explicit_rhs - inter1) == zeros(2, 1) + assert simplify(symsystem3.dyn_implicit_mat - dyn_implicit_mat) == zeros(3) + assert simplify(symsystem3.dyn_implicit_rhs - inter2) == zeros(3, 1) + + inter = comb_implicit_rhs + assert simplify(symsystem3.comb_implicit_rhs - inter) == zeros(5, 1) + assert simplify(symsystem3.comb_implicit_mat-comb_implicit_mat) == zeros(5) + + inter = comb_explicit_rhs + symsystem3.compute_explicit_form() + assert simplify(symsystem3.comb_explicit_rhs - inter) == zeros(5, 1) + + assert set(symsystem3.dynamic_symbols()) == {y, v, lam, u, x} + assert type(symsystem3.dynamic_symbols()) == tuple + assert set(symsystem3.constant_symbols()) == {l, g, m} + assert type(symsystem3.constant_symbols()) == tuple + + assert symsystem3.output_eqns == {} + + assert symsystem3.bodies == (Pa,) + assert symsystem3.loads == ((P, g * m * N.x),) + + +def test_property_attributes(): + symsystem = SymbolicSystem(states, comb_explicit_rhs, + alg_con=alg_con_full, output_eqns=out_eqns, + coord_idxs=coord_idxs, speed_idxs=speed_idxs, + bodies=bodies, loads=loads) + + with raises(AttributeError): + symsystem.bodies = 42 + with raises(AttributeError): + symsystem.coordinates = 42 + with raises(AttributeError): + symsystem.dyn_implicit_rhs = 42 + with raises(AttributeError): + symsystem.comb_implicit_rhs = 42 + with raises(AttributeError): + symsystem.loads = 42 + with raises(AttributeError): + symsystem.dyn_implicit_mat = 42 + with raises(AttributeError): + symsystem.comb_implicit_mat = 42 + with raises(AttributeError): + symsystem.kin_explicit_rhs = 42 + with raises(AttributeError): + symsystem.comb_explicit_rhs = 42 + with raises(AttributeError): + symsystem.speeds = 42 + with raises(AttributeError): + symsystem.states = 42 + with raises(AttributeError): + symsystem.alg_con = 42 + + +def test_not_specified_errors(): + """This test will cover errors that arise from trying to access attributes + that were not specified upon object creation or were specified on creation + and the user tries to recalculate them.""" + # Trying to access form 2 when form 1 given + # Trying to access form 3 when form 2 given + + symsystem1 = SymbolicSystem(states, comb_explicit_rhs) + + with raises(AttributeError): + symsystem1.comb_implicit_mat + with raises(AttributeError): + symsystem1.comb_implicit_rhs + with raises(AttributeError): + symsystem1.dyn_implicit_mat + with raises(AttributeError): + symsystem1.dyn_implicit_rhs + with raises(AttributeError): + symsystem1.kin_explicit_rhs + with raises(AttributeError): + symsystem1.compute_explicit_form() + + symsystem2 = SymbolicSystem(coordinates, comb_implicit_rhs, speeds=speeds, + mass_matrix=comb_implicit_mat) + + with raises(AttributeError): + symsystem2.dyn_implicit_mat + with raises(AttributeError): + symsystem2.dyn_implicit_rhs + with raises(AttributeError): + symsystem2.kin_explicit_rhs + + # Attribute error when trying to access coordinates and speeds when only the + # states were given. + with raises(AttributeError): + symsystem1.coordinates + with raises(AttributeError): + symsystem1.speeds + + # Attribute error when trying to access bodies and loads when they are not + # given + with raises(AttributeError): + symsystem1.bodies + with raises(AttributeError): + symsystem1.loads + + # Attribute error when trying to access comb_explicit_rhs before it was + # calculated + with raises(AttributeError): + symsystem2.comb_explicit_rhs diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_system_class.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_system_class.py new file mode 100644 index 0000000000000000000000000000000000000000..924cb8272c27c4f978aa4c3b1999f6ac56e47335 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_system_class.py @@ -0,0 +1,831 @@ +import pytest + +from sympy.core.symbol import symbols +from sympy.core.sympify import sympify +from sympy.functions.elementary.trigonometric import cos, sin +from sympy.matrices.dense import eye, zeros +from sympy.matrices.immutable import ImmutableMatrix +from sympy.physics.mechanics import ( + Force, KanesMethod, LagrangesMethod, Particle, PinJoint, Point, + PrismaticJoint, ReferenceFrame, RigidBody, Torque, TorqueActuator, System, + dynamicsymbols) +from sympy.simplify.simplify import simplify +from sympy.solvers.solvers import solve + +t = dynamicsymbols._t # type: ignore +q = dynamicsymbols('q:6') # type: ignore +qd = dynamicsymbols('q:6', 1) # type: ignore +u = dynamicsymbols('u:6') # type: ignore +ua = dynamicsymbols('ua:3') # type: ignore + + +class TestSystemBase: + @pytest.fixture() + def _empty_system_setup(self): + self.system = System(ReferenceFrame('frame'), Point('fixed_point')) + + def _empty_system_check(self, exclude=()): + matrices = ('q_ind', 'q_dep', 'q', 'u_ind', 'u_dep', 'u', 'u_aux', + 'kdes', 'holonomic_constraints', 'nonholonomic_constraints') + tuples = ('loads', 'bodies', 'joints', 'actuators') + for attr in matrices: + if attr not in exclude: + assert getattr(self.system, attr)[:] == [] + for attr in tuples: + if attr not in exclude: + assert getattr(self.system, attr) == () + if 'eom_method' not in exclude: + assert self.system.eom_method is None + + def _create_filled_system(self, with_speeds=True): + self.system = System(ReferenceFrame('frame'), Point('fixed_point')) + u = dynamicsymbols('u:6') if with_speeds else qd + self.bodies = symbols('rb1:5', cls=RigidBody) + self.joints = ( + PinJoint('J1', self.bodies[0], self.bodies[1], q[0], u[0]), + PrismaticJoint('J2', self.bodies[1], self.bodies[2], q[1], u[1]), + PinJoint('J3', self.bodies[2], self.bodies[3], q[2], u[2]) + ) + self.system.add_joints(*self.joints) + self.system.add_coordinates(q[3], independent=[False]) + self.system.add_speeds(u[3], independent=False) + if with_speeds: + self.system.add_kdes(u[3] - qd[3]) + self.system.add_auxiliary_speeds(ua[0], ua[1]) + self.system.add_holonomic_constraints(q[2] - q[0] + q[1]) + self.system.add_nonholonomic_constraints(u[3] - qd[1] + u[2]) + self.system.u_ind = u[:2] + self.system.u_dep = u[2:4] + self.q_ind, self.q_dep = self.system.q_ind[:], self.system.q_dep[:] + self.u_ind, self.u_dep = self.system.u_ind[:], self.system.u_dep[:] + self.kdes = self.system.kdes[:] + self.hc = self.system.holonomic_constraints[:] + self.vc = self.system.velocity_constraints[:] + self.nhc = self.system.nonholonomic_constraints[:] + + @pytest.fixture() + def _filled_system_setup(self): + self._create_filled_system(with_speeds=True) + + @pytest.fixture() + def _filled_system_setup_no_speeds(self): + self._create_filled_system(with_speeds=False) + + def _filled_system_check(self, exclude=()): + assert 'q_ind' in exclude or self.system.q_ind[:] == q[:3] + assert 'q_dep' in exclude or self.system.q_dep[:] == [q[3]] + assert 'q' in exclude or self.system.q[:] == q[:4] + assert 'u_ind' in exclude or self.system.u_ind[:] == u[:2] + assert 'u_dep' in exclude or self.system.u_dep[:] == u[2:4] + assert 'u' in exclude or self.system.u[:] == u[:4] + assert 'u_aux' in exclude or self.system.u_aux[:] == ua[:2] + assert 'kdes' in exclude or self.system.kdes[:] == [ + ui - qdi for ui, qdi in zip(u[:4], qd[:4])] + assert ('holonomic_constraints' in exclude or + self.system.holonomic_constraints[:] == [q[2] - q[0] + q[1]]) + assert ('nonholonomic_constraints' in exclude or + self.system.nonholonomic_constraints[:] == [u[3] - qd[1] + u[2]] + ) + assert ('velocity_constraints' in exclude or + self.system.velocity_constraints[:] == [ + qd[2] - qd[0] + qd[1], u[3] - qd[1] + u[2]]) + assert ('bodies' in exclude or + self.system.bodies == tuple(self.bodies)) + assert ('joints' in exclude or + self.system.joints == tuple(self.joints)) + + @pytest.fixture() + def _moving_point_mass(self, _empty_system_setup): + self.system.q_ind = q[0] + self.system.u_ind = u[0] + self.system.kdes = u[0] - q[0].diff(t) + p = Particle('p', mass=symbols('m')) + self.system.add_bodies(p) + p.masscenter.set_pos(self.system.fixed_point, q[0] * self.system.x) + + +class TestSystem(TestSystemBase): + def test_empty_system(self, _empty_system_setup): + self._empty_system_check() + self.system.validate_system() + + def test_filled_system(self, _filled_system_setup): + self._filled_system_check() + self.system.validate_system() + + @pytest.mark.parametrize('frame', [None, ReferenceFrame('frame')]) + @pytest.mark.parametrize('fixed_point', [None, Point('fixed_point')]) + def test_init(self, frame, fixed_point): + if fixed_point is None and frame is None: + self.system = System() + else: + self.system = System(frame, fixed_point) + if fixed_point is None: + assert self.system.fixed_point.name == 'inertial_point' + else: + assert self.system.fixed_point == fixed_point + if frame is None: + assert self.system.frame.name == 'inertial_frame' + else: + assert self.system.frame == frame + self._empty_system_check() + assert isinstance(self.system.q_ind, ImmutableMatrix) + assert isinstance(self.system.q_dep, ImmutableMatrix) + assert isinstance(self.system.q, ImmutableMatrix) + assert isinstance(self.system.u_ind, ImmutableMatrix) + assert isinstance(self.system.u_dep, ImmutableMatrix) + assert isinstance(self.system.u, ImmutableMatrix) + assert isinstance(self.system.kdes, ImmutableMatrix) + assert isinstance(self.system.holonomic_constraints, ImmutableMatrix) + assert isinstance(self.system.nonholonomic_constraints, ImmutableMatrix) + + def test_from_newtonian_rigid_body(self): + rb = RigidBody('body') + self.system = System.from_newtonian(rb) + assert self.system.fixed_point == rb.masscenter + assert self.system.frame == rb.frame + self._empty_system_check(exclude=('bodies',)) + self.system.bodies = (rb,) + + def test_from_newtonian_particle(self): + pt = Particle('particle') + with pytest.raises(TypeError): + System.from_newtonian(pt) + + @pytest.mark.parametrize('args, kwargs, exp_q_ind, exp_q_dep, exp_q', [ + (q[:3], {}, q[:3], [], q[:3]), + (q[:3], {'independent': True}, q[:3], [], q[:3]), + (q[:3], {'independent': False}, [], q[:3], q[:3]), + (q[:3], {'independent': [True, False, True]}, [q[0], q[2]], [q[1]], + [q[0], q[2], q[1]]), + ]) + def test_coordinates(self, _empty_system_setup, args, kwargs, + exp_q_ind, exp_q_dep, exp_q): + # Test add_coordinates + self.system.add_coordinates(*args, **kwargs) + assert self.system.q_ind[:] == exp_q_ind + assert self.system.q_dep[:] == exp_q_dep + assert self.system.q[:] == exp_q + self._empty_system_check(exclude=('q_ind', 'q_dep', 'q')) + # Test setter for q_ind and q_dep + self.system.q_ind = exp_q_ind + self.system.q_dep = exp_q_dep + assert self.system.q_ind[:] == exp_q_ind + assert self.system.q_dep[:] == exp_q_dep + assert self.system.q[:] == exp_q + self._empty_system_check(exclude=('q_ind', 'q_dep', 'q')) + + @pytest.mark.parametrize('func', ['add_coordinates', 'add_speeds']) + @pytest.mark.parametrize('args, kwargs', [ + ((q[0], q[5]), {}), + ((u[0], u[5]), {}), + ((q[0],), {'independent': False}), + ((u[0],), {'independent': False}), + ((u[0], q[5]), {}), + ((symbols('a'), q[5]), {}), + ]) + def test_coordinates_speeds_invalid(self, _filled_system_setup, func, args, + kwargs): + with pytest.raises(ValueError): + getattr(self.system, func)(*args, **kwargs) + self._filled_system_check() + + @pytest.mark.parametrize('args, kwargs, exp_u_ind, exp_u_dep, exp_u', [ + (u[:3], {}, u[:3], [], u[:3]), + (u[:3], {'independent': True}, u[:3], [], u[:3]), + (u[:3], {'independent': False}, [], u[:3], u[:3]), + (u[:3], {'independent': [True, False, True]}, [u[0], u[2]], [u[1]], + [u[0], u[2], u[1]]), + ]) + def test_speeds(self, _empty_system_setup, args, kwargs, exp_u_ind, + exp_u_dep, exp_u): + # Test add_speeds + self.system.add_speeds(*args, **kwargs) + assert self.system.u_ind[:] == exp_u_ind + assert self.system.u_dep[:] == exp_u_dep + assert self.system.u[:] == exp_u + self._empty_system_check(exclude=('u_ind', 'u_dep', 'u')) + # Test setter for u_ind and u_dep + self.system.u_ind = exp_u_ind + self.system.u_dep = exp_u_dep + assert self.system.u_ind[:] == exp_u_ind + assert self.system.u_dep[:] == exp_u_dep + assert self.system.u[:] == exp_u + self._empty_system_check(exclude=('u_ind', 'u_dep', 'u')) + + @pytest.mark.parametrize('args, kwargs, exp_u_aux', [ + (ua[:3], {}, ua[:3]), + ]) + def test_auxiliary_speeds(self, _empty_system_setup, args, kwargs, + exp_u_aux): + # Test add_speeds + self.system.add_auxiliary_speeds(*args, **kwargs) + assert self.system.u_aux[:] == exp_u_aux + self._empty_system_check(exclude=('u_aux',)) + # Test setter for u_ind and u_dep + self.system.u_aux = exp_u_aux + assert self.system.u_aux[:] == exp_u_aux + self._empty_system_check(exclude=('u_aux',)) + + @pytest.mark.parametrize('args, kwargs', [ + ((ua[2], q[0]), {}), + ((ua[2], u[1]), {}), + ((ua[0], ua[2]), {}), + ((symbols('a'), ua[2]), {}), + ]) + def test_auxiliary_invalid(self, _filled_system_setup, args, kwargs): + with pytest.raises(ValueError): + self.system.add_auxiliary_speeds(*args, **kwargs) + self._filled_system_check() + + @pytest.mark.parametrize('prop, add_func, args, kwargs', [ + ('q_ind', 'add_coordinates', (q[0],), {}), + ('q_dep', 'add_coordinates', (q[3],), {'independent': False}), + ('u_ind', 'add_speeds', (u[0],), {}), + ('u_dep', 'add_speeds', (u[3],), {'independent': False}), + ('u_aux', 'add_auxiliary_speeds', (ua[2],), {}), + ('kdes', 'add_kdes', (qd[0] - u[0],), {}), + ('holonomic_constraints', 'add_holonomic_constraints', + (q[0] - q[1],), {}), + ('nonholonomic_constraints', 'add_nonholonomic_constraints', + (u[0] - u[1],), {}), + ('bodies', 'add_bodies', (RigidBody('body'),), {}), + ('loads', 'add_loads', (Force(Point('P'), ReferenceFrame('N').x),), {}), + ('actuators', 'add_actuators', (TorqueActuator( + symbols('T'), ReferenceFrame('N').x, ReferenceFrame('A')),), {}), + ]) + def test_add_after_reset(self, _filled_system_setup, prop, add_func, args, + kwargs): + setattr(self.system, prop, ()) + exclude = (prop, 'q', 'u') + if prop in ('holonomic_constraints', 'nonholonomic_constraints'): + exclude += ('velocity_constraints',) + self._filled_system_check(exclude=exclude) + assert list(getattr(self.system, prop)[:]) == [] + getattr(self.system, add_func)(*args, **kwargs) + assert list(getattr(self.system, prop)[:]) == list(args) + + @pytest.mark.parametrize('prop, add_func, value, error', [ + ('q_ind', 'add_coordinates', symbols('a'), ValueError), + ('q_dep', 'add_coordinates', symbols('a'), ValueError), + ('u_ind', 'add_speeds', symbols('a'), ValueError), + ('u_dep', 'add_speeds', symbols('a'), ValueError), + ('u_aux', 'add_auxiliary_speeds', symbols('a'), ValueError), + ('kdes', 'add_kdes', 7, TypeError), + ('holonomic_constraints', 'add_holonomic_constraints', 7, TypeError), + ('nonholonomic_constraints', 'add_nonholonomic_constraints', 7, + TypeError), + ('bodies', 'add_bodies', symbols('a'), TypeError), + ('loads', 'add_loads', symbols('a'), TypeError), + ('actuators', 'add_actuators', symbols('a'), TypeError), + ]) + def test_type_error(self, _filled_system_setup, prop, add_func, value, + error): + with pytest.raises(error): + getattr(self.system, add_func)(value) + with pytest.raises(error): + setattr(self.system, prop, value) + self._filled_system_check() + + @pytest.mark.parametrize('args, kwargs, exp_kdes', [ + ((), {}, [ui - qdi for ui, qdi in zip(u[:4], qd[:4])]), + ((u[4] - qd[4], u[5] - qd[5]), {}, + [ui - qdi for ui, qdi in zip(u[:6], qd[:6])]), + ]) + def test_kdes(self, _filled_system_setup, args, kwargs, exp_kdes): + # Test add_speeds + self.system.add_kdes(*args, **kwargs) + self._filled_system_check(exclude=('kdes',)) + assert self.system.kdes[:] == exp_kdes + # Test setter for kdes + self.system.kdes = exp_kdes + self._filled_system_check(exclude=('kdes',)) + assert self.system.kdes[:] == exp_kdes + + @pytest.mark.parametrize('args, kwargs', [ + ((u[0] - qd[0], u[4] - qd[4]), {}), + ((-(u[0] - qd[0]), u[4] - qd[4]), {}), + (([u[0] - u[0], u[4] - qd[4]]), {}), + ]) + def test_kdes_invalid(self, _filled_system_setup, args, kwargs): + with pytest.raises(ValueError): + self.system.add_kdes(*args, **kwargs) + self._filled_system_check() + + @pytest.mark.parametrize('args, kwargs, exp_con', [ + ((), {}, [q[2] - q[0] + q[1]]), + ((q[4] - q[5], q[5] + q[3]), {}, + [q[2] - q[0] + q[1], q[4] - q[5], q[5] + q[3]]), + ]) + def test_holonomic_constraints(self, _filled_system_setup, args, kwargs, + exp_con): + exclude = ('holonomic_constraints', 'velocity_constraints') + exp_vel_con = [c.diff(t) for c in exp_con] + self.nhc + # Test add_holonomic_constraints + self.system.add_holonomic_constraints(*args, **kwargs) + self._filled_system_check(exclude=exclude) + assert self.system.holonomic_constraints[:] == exp_con + assert self.system.velocity_constraints[:] == exp_vel_con + # Test setter for holonomic_constraints + self.system.holonomic_constraints = exp_con + self._filled_system_check(exclude=exclude) + assert self.system.holonomic_constraints[:] == exp_con + assert self.system.velocity_constraints[:] == exp_vel_con + + @pytest.mark.parametrize('args, kwargs', [ + ((q[2] - q[0] + q[1], q[4] - q[3]), {}), + ((-(q[2] - q[0] + q[1]), q[4] - q[3]), {}), + ((q[0] - q[0], q[4] - q[3]), {}), + ]) + def test_holonomic_constraints_invalid(self, _filled_system_setup, args, + kwargs): + with pytest.raises(ValueError): + self.system.add_holonomic_constraints(*args, **kwargs) + self._filled_system_check() + + @pytest.mark.parametrize('args, kwargs, exp_con', [ + ((), {}, [u[3] - qd[1] + u[2]]), + ((u[4] - u[5], u[5] + u[3]), {}, + [u[3] - qd[1] + u[2], u[4] - u[5], u[5] + u[3]]), + ]) + def test_nonholonomic_constraints(self, _filled_system_setup, args, kwargs, + exp_con): + exclude = ('nonholonomic_constraints', 'velocity_constraints') + exp_vel_con = self.vc[:len(self.hc)] + exp_con + # Test add_nonholonomic_constraints + self.system.add_nonholonomic_constraints(*args, **kwargs) + self._filled_system_check(exclude=exclude) + assert self.system.nonholonomic_constraints[:] == exp_con + assert self.system.velocity_constraints[:] == exp_vel_con + # Test setter for nonholonomic_constraints + self.system.nonholonomic_constraints = exp_con + self._filled_system_check(exclude=exclude) + assert self.system.nonholonomic_constraints[:] == exp_con + assert self.system.velocity_constraints[:] == exp_vel_con + + @pytest.mark.parametrize('args, kwargs', [ + ((u[3] - qd[1] + u[2], u[4] - u[3]), {}), + ((-(u[3] - qd[1] + u[2]), u[4] - u[3]), {}), + ((u[0] - u[0], u[4] - u[3]), {}), + (([u[0] - u[0], u[4] - u[3]]), {}), + ]) + def test_nonholonomic_constraints_invalid(self, _filled_system_setup, args, + kwargs): + with pytest.raises(ValueError): + self.system.add_nonholonomic_constraints(*args, **kwargs) + self._filled_system_check() + + @pytest.mark.parametrize('constraints, expected', [ + ([], []), + (qd[2] - qd[0] + qd[1], [qd[2] - qd[0] + qd[1]]), + ([qd[2] + qd[1], u[2] - u[1]], [qd[2] + qd[1], u[2] - u[1]]), + ]) + def test_velocity_constraints_overwrite(self, _filled_system_setup, + constraints, expected): + self.system.velocity_constraints = constraints + self._filled_system_check(exclude=('velocity_constraints',)) + assert self.system.velocity_constraints[:] == expected + + def test_velocity_constraints_back_to_auto(self, _filled_system_setup): + self.system.velocity_constraints = qd[3] - qd[2] + self._filled_system_check(exclude=('velocity_constraints',)) + assert self.system.velocity_constraints[:] == [qd[3] - qd[2]] + self.system.velocity_constraints = None + self._filled_system_check() + + def test_bodies(self, _filled_system_setup): + rb1, rb2 = RigidBody('rb1'), RigidBody('rb2') + p1, p2 = Particle('p1'), Particle('p2') + self.system.add_bodies(rb1, p1) + assert self.system.bodies == (*self.bodies, rb1, p1) + self.system.add_bodies(p2) + assert self.system.bodies == (*self.bodies, rb1, p1, p2) + self.system.bodies = [] + assert self.system.bodies == () + self.system.bodies = p2 + assert self.system.bodies == (p2,) + symb = symbols('symb') + pytest.raises(TypeError, lambda: self.system.add_bodies(symb)) + pytest.raises(ValueError, lambda: self.system.add_bodies(p2)) + with pytest.raises(TypeError): + self.system.bodies = (rb1, rb2, p1, p2, symb) + assert self.system.bodies == (p2,) + + def test_add_loads(self): + system = System() + N, A = ReferenceFrame('N'), ReferenceFrame('A') + rb1 = RigidBody('rb1', frame=N) + mc1 = Point('mc1') + p1 = Particle('p1', mc1) + system.add_loads(Torque(rb1, N.x), (mc1, A.x), Force(p1, A.x)) + assert system.loads == ((N, N.x), (mc1, A.x), (mc1, A.x)) + system.loads = [(A, A.x)] + assert system.loads == ((A, A.x),) + pytest.raises(ValueError, lambda: system.add_loads((N, N.x, N.y))) + with pytest.raises(TypeError): + system.loads = (N, N.x) + assert system.loads == ((A, A.x),) + + def test_add_actuators(self): + system = System() + N, A = ReferenceFrame('N'), ReferenceFrame('A') + act1 = TorqueActuator(symbols('T1'), N.x, N) + act2 = TorqueActuator(symbols('T2'), N.y, N, A) + system.add_actuators(act1) + assert system.actuators == (act1,) + assert system.loads == () + system.actuators = (act2,) + assert system.actuators == (act2,) + + def test_add_joints(self): + q1, q2, q3, q4, u1, u2, u3 = dynamicsymbols('q1:5 u1:4') + rb1, rb2, rb3, rb4, rb5 = symbols('rb1:6', cls=RigidBody) + J1 = PinJoint('J1', rb1, rb2, q1, u1) + J2 = PrismaticJoint('J2', rb2, rb3, q2, u2) + J3 = PinJoint('J3', rb3, rb4, q3, u3) + J_lag = PinJoint('J_lag', rb4, rb5, q4, q4.diff(t)) + system = System() + system.add_joints(J1) + assert system.joints == (J1,) + assert system.bodies == (rb1, rb2) + assert system.q_ind == ImmutableMatrix([q1]) + assert system.u_ind == ImmutableMatrix([u1]) + assert system.kdes == ImmutableMatrix([u1 - q1.diff(t)]) + system.add_bodies(rb4) + system.add_coordinates(q3) + system.add_kdes(u3 - q3.diff(t)) + system.add_joints(J3) + assert system.joints == (J1, J3) + assert system.bodies == (rb1, rb2, rb4, rb3) + assert system.q_ind == ImmutableMatrix([q1, q3]) + assert system.u_ind == ImmutableMatrix([u1, u3]) + assert system.kdes == ImmutableMatrix( + [u1 - q1.diff(t), u3 - q3.diff(t)]) + system.add_kdes(-(u2 - q2.diff(t))) + system.add_joints(J2) + assert system.joints == (J1, J3, J2) + assert system.bodies == (rb1, rb2, rb4, rb3) + assert system.q_ind == ImmutableMatrix([q1, q3, q2]) + assert system.u_ind == ImmutableMatrix([u1, u3, u2]) + assert system.kdes == ImmutableMatrix([u1 - q1.diff(t), u3 - q3.diff(t), + -(u2 - q2.diff(t))]) + system.add_joints(J_lag) + assert system.joints == (J1, J3, J2, J_lag) + assert system.bodies == (rb1, rb2, rb4, rb3, rb5) + assert system.q_ind == ImmutableMatrix([q1, q3, q2, q4]) + assert system.u_ind == ImmutableMatrix([u1, u3, u2, q4.diff(t)]) + assert system.kdes == ImmutableMatrix([u1 - q1.diff(t), u3 - q3.diff(t), + -(u2 - q2.diff(t))]) + assert system.q_dep[:] == [] + assert system.u_dep[:] == [] + pytest.raises(ValueError, lambda: system.add_joints(J2)) + pytest.raises(TypeError, lambda: system.add_joints(rb1)) + + def test_joints_setter(self, _filled_system_setup): + self.system.joints = self.joints[1:] + assert self.system.joints == self.joints[1:] + self._filled_system_check(exclude=('joints',)) + self.system.q_ind = () + self.system.u_ind = () + self.system.joints = self.joints + self._filled_system_check() + + @pytest.mark.parametrize('name, joint_index', [ + ('J1', 0), + ('J2', 1), + ('not_existing', None), + ]) + def test_get_joint(self, _filled_system_setup, name, joint_index): + joint = self.system.get_joint(name) + if joint_index is None: + assert joint is None + else: + assert joint == self.joints[joint_index] + + @pytest.mark.parametrize('name, body_index', [ + ('rb1', 0), + ('rb3', 2), + ('not_existing', None), + ]) + def test_get_body(self, _filled_system_setup, name, body_index): + body = self.system.get_body(name) + if body_index is None: + assert body is None + else: + assert body == self.bodies[body_index] + + @pytest.mark.parametrize('eom_method', [KanesMethod, LagrangesMethod]) + def test_form_eoms_calls_subclass(self, _moving_point_mass, eom_method): + class MyMethod(eom_method): + pass + + self.system.form_eoms(eom_method=MyMethod) + assert isinstance(self.system.eom_method, MyMethod) + + @pytest.mark.parametrize('kwargs, expected', [ + ({}, ImmutableMatrix([[-1, 0], [0, symbols('m')]])), + ({'explicit_kinematics': True}, ImmutableMatrix([[1, 0], + [0, symbols('m')]])), + ]) + def test_system_kane_form_eoms_kwargs(self, _moving_point_mass, kwargs, + expected): + self.system.form_eoms(**kwargs) + assert self.system.mass_matrix_full == expected + + @pytest.mark.parametrize('kwargs, mm, gm', [ + ({}, ImmutableMatrix([[1, 0], [0, symbols('m')]]), + ImmutableMatrix([q[0].diff(t), 0])), + ]) + def test_system_lagrange_form_eoms_kwargs(self, _moving_point_mass, kwargs, + mm, gm): + self.system.form_eoms(eom_method=LagrangesMethod, **kwargs) + assert self.system.mass_matrix_full == mm + assert self.system.forcing_full == gm + + @pytest.mark.parametrize('eom_method, kwargs, error', [ + (KanesMethod, {'non_existing_kwarg': 1}, TypeError), + (LagrangesMethod, {'non_existing_kwarg': 1}, TypeError), + (KanesMethod, {'bodies': []}, ValueError), + (KanesMethod, {'kd_eqs': []}, ValueError), + (LagrangesMethod, {'bodies': []}, ValueError), + (LagrangesMethod, {'Lagrangian': 1}, ValueError), + ]) + def test_form_eoms_kwargs_errors(self, _empty_system_setup, eom_method, + kwargs, error): + self.system.q_ind = q[0] + p = Particle('p', mass=symbols('m')) + self.system.add_bodies(p) + p.masscenter.set_pos(self.system.fixed_point, q[0] * self.system.x) + with pytest.raises(error): + self.system.form_eoms(eom_method=eom_method, **kwargs) + + +class TestValidateSystem(TestSystemBase): + @pytest.mark.parametrize('valid_method, invalid_method, with_speeds', [ + (KanesMethod, LagrangesMethod, True), + (LagrangesMethod, KanesMethod, False) + ]) + def test_only_valid(self, valid_method, invalid_method, with_speeds): + self._create_filled_system(with_speeds=with_speeds) + self.system.validate_system(valid_method) + # Test Lagrange should fail due to the usage of generalized speeds + with pytest.raises(ValueError): + self.system.validate_system(invalid_method) + + @pytest.mark.parametrize('method, with_speeds', [ + (KanesMethod, True), (LagrangesMethod, False)]) + def test_missing_joint_coordinate(self, method, with_speeds): + self._create_filled_system(with_speeds=with_speeds) + self.system.q_ind = self.q_ind[1:] + self.system.u_ind = self.u_ind[:-1] + self.system.kdes = self.kdes[:-1] + pytest.raises(ValueError, lambda: self.system.validate_system(method)) + + def test_missing_joint_speed(self, _filled_system_setup): + self.system.q_ind = self.q_ind[:-1] + self.system.u_ind = self.u_ind[1:] + self.system.kdes = self.kdes[:-1] + pytest.raises(ValueError, lambda: self.system.validate_system()) + + def test_missing_joint_kdes(self, _filled_system_setup): + self.system.kdes = self.kdes[1:] + pytest.raises(ValueError, lambda: self.system.validate_system()) + + def test_negative_joint_kdes(self, _filled_system_setup): + self.system.kdes = [-self.kdes[0]] + self.kdes[1:] + self.system.validate_system() + + @pytest.mark.parametrize('method, with_speeds', [ + (KanesMethod, True), (LagrangesMethod, False)]) + def test_missing_holonomic_constraint(self, method, with_speeds): + self._create_filled_system(with_speeds=with_speeds) + self.system.holonomic_constraints = [] + self.system.nonholonomic_constraints = self.nhc + [ + self.u_ind[1] - self.u_dep[0] + self.u_ind[0]] + pytest.raises(ValueError, lambda: self.system.validate_system(method)) + self.system.q_dep = [] + self.system.q_ind = self.q_ind + self.q_dep + self.system.validate_system(method) + + def test_missing_nonholonomic_constraint(self, _filled_system_setup): + self.system.nonholonomic_constraints = [] + pytest.raises(ValueError, lambda: self.system.validate_system()) + self.system.u_dep = self.u_dep[1] + self.system.u_ind = self.u_ind + [self.u_dep[0]] + self.system.validate_system() + + def test_number_of_coordinates_speeds(self, _filled_system_setup): + # Test more speeds than coordinates + self.system.u_ind = self.u_ind + [u[5]] + self.system.kdes = self.kdes + [u[5] - qd[5]] + self.system.validate_system() + # Test more coordinates than speeds + self.system.q_ind = self.q_ind + self.system.u_ind = self.u_ind[:-1] + self.system.kdes = self.kdes[:-1] + pytest.raises(ValueError, lambda: self.system.validate_system()) + + def test_number_of_kdes(self, _filled_system_setup): + # Test wrong number of kdes + self.system.kdes = self.kdes[:-1] + pytest.raises(ValueError, lambda: self.system.validate_system()) + self.system.kdes = self.kdes + [u[2] + u[1] - qd[2]] + pytest.raises(ValueError, lambda: self.system.validate_system()) + + def test_duplicates(self, _filled_system_setup): + # This is basically a redundant feature, which should never fail + self.system.validate_system(check_duplicates=True) + + def test_speeds_in_lagrange(self, _filled_system_setup_no_speeds): + self.system.u_ind = u[:len(self.u_ind)] + with pytest.raises(ValueError): + self.system.validate_system(LagrangesMethod) + self.system.u_ind = [] + self.system.validate_system(LagrangesMethod) + self.system.u_aux = ua + with pytest.raises(ValueError): + self.system.validate_system(LagrangesMethod) + self.system.u_aux = [] + self.system.validate_system(LagrangesMethod) + self.system.add_joints( + PinJoint('Ju', RigidBody('rbu1'), RigidBody('rbu2'))) + self.system.u_ind = [] + with pytest.raises(ValueError): + self.system.validate_system(LagrangesMethod) + + +class TestSystemExamples: + def test_cart_pendulum_kanes(self): + # This example is the same as in the top documentation of System + # Added a spring to the cart + g, l, mc, mp, k = symbols('g l mc mp k') + F, qp, qc, up, uc = dynamicsymbols('F qp qc up uc') + rail = RigidBody('rail') + cart = RigidBody('cart', mass=mc) + bob = Particle('bob', mass=mp) + bob_frame = ReferenceFrame('bob_frame') + system = System.from_newtonian(rail) + assert system.bodies == (rail,) + assert system.frame == rail.frame + assert system.fixed_point == rail.masscenter + slider = PrismaticJoint('slider', rail, cart, qc, uc, joint_axis=rail.x) + pin = PinJoint('pin', cart, bob, qp, up, joint_axis=cart.z, + child_interframe=bob_frame, child_point=l * bob_frame.y) + system.add_joints(slider, pin) + assert system.joints == (slider, pin) + assert system.get_joint('slider') == slider + assert system.get_body('bob') == bob + system.apply_uniform_gravity(-g * system.y) + system.add_loads((cart.masscenter, F * rail.x)) + system.add_actuators(TorqueActuator(k * qp, cart.z, bob_frame, cart)) + system.validate_system() + system.form_eoms() + assert isinstance(system.eom_method, KanesMethod) + assert (simplify(system.mass_matrix - ImmutableMatrix( + [[mp + mc, mp * l * cos(qp)], [mp * l * cos(qp), mp * l ** 2]])) + == zeros(2, 2)) + assert (simplify(system.forcing - ImmutableMatrix([ + [mp * l * up ** 2 * sin(qp) + F], + [-mp * g * l * sin(qp) + k * qp]])) == zeros(2, 1)) + + system.add_holonomic_constraints( + sympify(bob.masscenter.pos_from(rail.masscenter).dot(system.x))) + assert system.eom_method is None + system.q_ind, system.q_dep = qp, qc + system.u_ind, system.u_dep = up, uc + system.validate_system() + + # Computed solution based on manually solving the constraints + subs = {qc: -l * sin(qp), + uc: -l * cos(qp) * up, + uc.diff(t): l * (up ** 2 * sin(qp) - up.diff(t) * cos(qp))} + upd_expected = ( + (-g * mp * sin(qp) + k * qp / l + l * mc * sin(2 * qp) * up ** 2 / 2 + - l * mp * sin(2 * qp) * up ** 2 / 2 - F * cos(qp)) / + (l * (mc * cos(qp) ** 2 + mp * sin(qp) ** 2))) + upd_sol = tuple(solve(system.form_eoms().xreplace(subs), + up.diff(t)).values())[0] + assert simplify(upd_sol - upd_expected) == 0 + assert isinstance(system.eom_method, KanesMethod) + + # Test other output + Mk = -ImmutableMatrix([[0, 1], [1, 0]]) + gk = -ImmutableMatrix([uc, up]) + Md = ImmutableMatrix([[-l ** 2 * mp * cos(qp) ** 2 + l ** 2 * mp, + l * mp * cos(qp) - l * (mc + mp) * cos(qp)], + [l * cos(qp), 1]]) + gd = ImmutableMatrix( + [[-g * l * mp * sin(qp) + k * qp - l ** 2 * mp * up ** 2 * sin(qp) * + cos(qp) - l * F * cos(qp)], [l * up ** 2 * sin(qp)]]) + Mm = (Mk.row_join(zeros(2, 2))).col_join(zeros(2, 2).row_join(Md)) + gm = gk.col_join(gd) + assert simplify(system.mass_matrix - Md) == zeros(2, 2) + assert simplify(system.forcing - gd) == zeros(2, 1) + assert simplify(system.mass_matrix_full - Mm) == zeros(4, 4) + assert simplify(system.forcing_full - gm) == zeros(4, 1) + + def test_cart_pendulum_lagrange(self): + # Lagrange version of test_cart_pendulus_kanes + # Added a spring to the cart + g, l, mc, mp, k = symbols('g l mc mp k') + F, qp, qc = dynamicsymbols('F qp qc') + qpd, qcd = dynamicsymbols('qp qc', 1) + rail = RigidBody('rail') + cart = RigidBody('cart', mass=mc) + bob = Particle('bob', mass=mp) + bob_frame = ReferenceFrame('bob_frame') + system = System.from_newtonian(rail) + assert system.bodies == (rail,) + assert system.frame == rail.frame + assert system.fixed_point == rail.masscenter + slider = PrismaticJoint('slider', rail, cart, qc, qcd, + joint_axis=rail.x) + pin = PinJoint('pin', cart, bob, qp, qpd, joint_axis=cart.z, + child_interframe=bob_frame, child_point=l * bob_frame.y) + system.add_joints(slider, pin) + assert system.joints == (slider, pin) + assert system.get_joint('slider') == slider + assert system.get_body('bob') == bob + for body in system.bodies: + body.potential_energy = body.mass * g * body.masscenter.pos_from( + system.fixed_point).dot(system.y) + system.add_loads((cart.masscenter, F * rail.x)) + system.add_actuators(TorqueActuator(k * qp, cart.z, bob_frame, cart)) + system.validate_system(LagrangesMethod) + system.form_eoms(LagrangesMethod) + assert (simplify(system.mass_matrix - ImmutableMatrix( + [[mp + mc, mp * l * cos(qp)], [mp * l * cos(qp), mp * l ** 2]])) + == zeros(2, 2)) + assert (simplify(system.forcing - ImmutableMatrix([ + [mp * l * qpd ** 2 * sin(qp) + F], [-mp * g * l * sin(qp) + k * qp]] + )) == zeros(2, 1)) + + system.add_holonomic_constraints( + sympify(bob.masscenter.pos_from(rail.masscenter).dot(system.x))) + assert system.eom_method is None + system.q_ind, system.q_dep = qp, qc + + # Computed solution based on manually solving the constraints + subs = {qc: -l * sin(qp), + qcd: -l * cos(qp) * qpd, + qcd.diff(t): l * (qpd ** 2 * sin(qp) - qpd.diff(t) * cos(qp))} + qpdd_expected = ( + (-g * mp * sin(qp) + k * qp / l + l * mc * sin(2 * qp) * qpd ** 2 / + 2 - l * mp * sin(2 * qp) * qpd ** 2 / 2 - F * cos(qp)) / + (l * (mc * cos(qp) ** 2 + mp * sin(qp) ** 2))) + eoms = system.form_eoms(LagrangesMethod) + lam1 = system.eom_method.lam_vec[0] + lam1_sol = system.eom_method.solve_multipliers()[lam1] + qpdd_sol = solve(eoms[0].xreplace({lam1: lam1_sol}).xreplace(subs), + qpd.diff(t))[0] + assert simplify(qpdd_sol - qpdd_expected) == 0 + assert isinstance(system.eom_method, LagrangesMethod) + + # Test other output + Md = ImmutableMatrix([[l ** 2 * mp, l * mp * cos(qp), -l * cos(qp)], + [l * mp * cos(qp), mc + mp, -1]]) + gd = ImmutableMatrix( + [[-g * l * mp * sin(qp) + k * qp], + [l * mp * sin(qp) * qpd ** 2 + F]]) + Mm = (eye(2).row_join(zeros(2, 3))).col_join(zeros(3, 2).row_join( + Md.col_join(ImmutableMatrix([l * cos(qp), 1, 0]).T))) + gm = ImmutableMatrix([qpd, qcd] + gd[:] + [l * sin(qp) * qpd ** 2]) + assert simplify(system.mass_matrix - Md) == zeros(2, 3) + assert simplify(system.forcing - gd) == zeros(2, 1) + assert simplify(system.mass_matrix_full - Mm) == zeros(5, 5) + assert simplify(system.forcing_full - gm) == zeros(5, 1) + + def test_box_on_ground(self): + # Particle sliding on ground with friction. The applied force is assumed + # to be positive and to be higher than the friction force. + g, m, mu = symbols('g m mu') + q, u, ua = dynamicsymbols('q u ua') + N, F = dynamicsymbols('N F', positive=True) + P = Particle("P", mass=m) + system = System() + system.add_bodies(P) + P.masscenter.set_pos(system.fixed_point, q * system.x) + P.masscenter.set_vel(system.frame, u * system.x + ua * system.y) + system.q_ind, system.u_ind, system.u_aux = [q], [u], [ua] + system.kdes = [q.diff(t) - u] + system.apply_uniform_gravity(-g * system.y) + system.add_loads( + Force(P, N * system.y), + Force(P, F * system.x - mu * N * system.x)) + system.validate_system() + system.form_eoms() + + # Test other output + Mk = ImmutableMatrix([1]) + gk = ImmutableMatrix([u]) + Md = ImmutableMatrix([m]) + gd = ImmutableMatrix([F - mu * N]) + Mm = (Mk.row_join(zeros(1, 1))).col_join(zeros(1, 1).row_join(Md)) + gm = gk.col_join(gd) + aux_eqs = ImmutableMatrix([N - m * g]) + assert simplify(system.mass_matrix - Md) == zeros(1, 1) + assert simplify(system.forcing - gd) == zeros(1, 1) + assert simplify(system.mass_matrix_full - Mm) == zeros(2, 2) + assert simplify(system.forcing_full - gm) == zeros(2, 1) + assert simplify(system.eom_method.auxiliary_eqs - aux_eqs + ) == zeros(1, 1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_wrapping_geometry.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_wrapping_geometry.py new file mode 100644 index 0000000000000000000000000000000000000000..30c3ae71db5da75238ebb3d4cc53e11a29a72e5d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/tests/test_wrapping_geometry.py @@ -0,0 +1,363 @@ +"""Tests for the ``sympy.physics.mechanics.wrapping_geometry.py`` module.""" + +import pytest + +from sympy import ( + Integer, + Rational, + S, + Symbol, + acos, + cos, + pi, + sin, + sqrt, +) +from sympy.core.relational import Eq +from sympy.physics.mechanics import ( + Point, + ReferenceFrame, + WrappingCylinder, + WrappingSphere, + dynamicsymbols, +) +from sympy.simplify.simplify import simplify + + +r = Symbol('r', positive=True) +x = Symbol('x') +q = dynamicsymbols('q') +N = ReferenceFrame('N') + + +class TestWrappingSphere: + + @staticmethod + def test_valid_constructor(): + r = Symbol('r', positive=True) + pO = Point('pO') + sphere = WrappingSphere(r, pO) + assert isinstance(sphere, WrappingSphere) + assert hasattr(sphere, 'radius') + assert sphere.radius == r + assert hasattr(sphere, 'point') + assert sphere.point == pO + + @staticmethod + @pytest.mark.parametrize('position', [S.Zero, Integer(2)*r*N.x]) + def test_geodesic_length_point_not_on_surface_invalid(position): + r = Symbol('r', positive=True) + pO = Point('pO') + sphere = WrappingSphere(r, pO) + + p1 = Point('p1') + p1.set_pos(pO, position) + p2 = Point('p2') + p2.set_pos(pO, position) + + error_msg = r'point .* does not lie on the surface of' + with pytest.raises(ValueError, match=error_msg): + sphere.geodesic_length(p1, p2) + + @staticmethod + @pytest.mark.parametrize( + 'position_1, position_2, expected', + [ + (r*N.x, r*N.x, S.Zero), + (r*N.x, r*N.y, S.Half*pi*r), + (r*N.x, r*-N.x, pi*r), + (r*-N.x, r*N.x, pi*r), + (r*N.x, r*sqrt(2)*S.Half*(N.x + N.y), Rational(1, 4)*pi*r), + ( + r*sqrt(2)*S.Half*(N.x + N.y), + r*sqrt(3)*Rational(1, 3)*(N.x + N.y + N.z), + r*acos(sqrt(6)*Rational(1, 3)), + ), + ] + ) + def test_geodesic_length(position_1, position_2, expected): + r = Symbol('r', positive=True) + pO = Point('pO') + sphere = WrappingSphere(r, pO) + + p1 = Point('p1') + p1.set_pos(pO, position_1) + p2 = Point('p2') + p2.set_pos(pO, position_2) + + assert simplify(Eq(sphere.geodesic_length(p1, p2), expected)) + + @staticmethod + @pytest.mark.parametrize( + 'position_1, position_2, vector_1, vector_2', + [ + (r * N.x, r * N.y, N.y, N.x), + (r * N.x, -r * N.y, -N.y, N.x), + ( + r * N.y, + sqrt(2)/2 * r * N.x - sqrt(2)/2 * r * N.y, + N.x, + sqrt(2)/2 * N.x + sqrt(2)/2 * N.y, + ), + ( + r * N.x, + r / 2 * N.x + sqrt(3)/2 * r * N.y, + N.y, + sqrt(3)/2 * N.x - 1/2 * N.y, + ), + ( + r * N.x, + sqrt(2)/2 * r * N.x + sqrt(2)/2 * r * N.y, + N.y, + sqrt(2)/2 * N.x - sqrt(2)/2 * N.y, + ), + ] + ) + def test_geodesic_end_vectors(position_1, position_2, vector_1, vector_2): + r = Symbol('r', positive=True) + pO = Point('pO') + sphere = WrappingSphere(r, pO) + + p1 = Point('p1') + p1.set_pos(pO, position_1) + p2 = Point('p2') + p2.set_pos(pO, position_2) + + expected = (vector_1, vector_2) + + assert sphere.geodesic_end_vectors(p1, p2) == expected + + @staticmethod + @pytest.mark.parametrize( + 'position', + [r * N.x, r * cos(q) * N.x + r * sin(q) * N.y] + ) + def test_geodesic_end_vectors_invalid_coincident(position): + r = Symbol('r', positive=True) + pO = Point('pO') + sphere = WrappingSphere(r, pO) + + p1 = Point('p1') + p1.set_pos(pO, position) + p2 = Point('p2') + p2.set_pos(pO, position) + + with pytest.raises(ValueError): + _ = sphere.geodesic_end_vectors(p1, p2) + + @staticmethod + @pytest.mark.parametrize( + 'position_1, position_2', + [ + (r * N.x, -r * N.x), + (-r * N.y, r * N.y), + ( + r * cos(q) * N.x + r * sin(q) * N.y, + -r * cos(q) * N.x - r * sin(q) * N.y, + ) + ] + ) + def test_geodesic_end_vectors_invalid_diametrically_opposite( + position_1, + position_2, + ): + r = Symbol('r', positive=True) + pO = Point('pO') + sphere = WrappingSphere(r, pO) + + p1 = Point('p1') + p1.set_pos(pO, position_1) + p2 = Point('p2') + p2.set_pos(pO, position_2) + + with pytest.raises(ValueError): + _ = sphere.geodesic_end_vectors(p1, p2) + + +class TestWrappingCylinder: + + @staticmethod + def test_valid_constructor(): + N = ReferenceFrame('N') + r = Symbol('r', positive=True) + pO = Point('pO') + cylinder = WrappingCylinder(r, pO, N.x) + assert isinstance(cylinder, WrappingCylinder) + assert hasattr(cylinder, 'radius') + assert cylinder.radius == r + assert hasattr(cylinder, 'point') + assert cylinder.point == pO + assert hasattr(cylinder, 'axis') + assert cylinder.axis == N.x + + @staticmethod + @pytest.mark.parametrize( + 'position, expected', + [ + (S.Zero, False), + (r*N.y, True), + (r*N.z, True), + (r*(N.y + N.z).normalize(), True), + (Integer(2)*r*N.y, False), + (r*(N.x + N.y), True), + (r*(Integer(2)*N.x + N.y), True), + (Integer(2)*N.x + r*(Integer(2)*N.y + N.z).normalize(), True), + (r*(cos(q)*N.y + sin(q)*N.z), True) + ] + ) + def test_point_is_on_surface(position, expected): + r = Symbol('r', positive=True) + pO = Point('pO') + cylinder = WrappingCylinder(r, pO, N.x) + + p1 = Point('p1') + p1.set_pos(pO, position) + + assert cylinder.point_on_surface(p1) is expected + + @staticmethod + @pytest.mark.parametrize('position', [S.Zero, Integer(2)*r*N.y]) + def test_geodesic_length_point_not_on_surface_invalid(position): + r = Symbol('r', positive=True) + pO = Point('pO') + cylinder = WrappingCylinder(r, pO, N.x) + + p1 = Point('p1') + p1.set_pos(pO, position) + p2 = Point('p2') + p2.set_pos(pO, position) + + error_msg = r'point .* does not lie on the surface of' + with pytest.raises(ValueError, match=error_msg): + cylinder.geodesic_length(p1, p2) + + @staticmethod + @pytest.mark.parametrize( + 'axis, position_1, position_2, expected', + [ + (N.x, r*N.y, r*N.y, S.Zero), + (N.x, r*N.y, N.x + r*N.y, S.One), + (N.x, r*N.y, -x*N.x + r*N.y, sqrt(x**2)), + (-N.x, r*N.y, x*N.x + r*N.y, sqrt(x**2)), + (N.x, r*N.y, r*N.z, S.Half*pi*sqrt(r**2)), + (-N.x, r*N.y, r*N.z, Integer(3)*S.Half*pi*sqrt(r**2)), + (N.x, r*N.z, r*N.y, Integer(3)*S.Half*pi*sqrt(r**2)), + (-N.x, r*N.z, r*N.y, S.Half*pi*sqrt(r**2)), + (N.x, r*N.y, r*(cos(q)*N.y + sin(q)*N.z), sqrt(r**2*q**2)), + ( + -N.x, r*N.y, + r*(cos(q)*N.y + sin(q)*N.z), + sqrt(r**2*(Integer(2)*pi - q)**2), + ), + ] + ) + def test_geodesic_length(axis, position_1, position_2, expected): + r = Symbol('r', positive=True) + pO = Point('pO') + cylinder = WrappingCylinder(r, pO, axis) + + p1 = Point('p1') + p1.set_pos(pO, position_1) + p2 = Point('p2') + p2.set_pos(pO, position_2) + + assert simplify(Eq(cylinder.geodesic_length(p1, p2), expected)) + + @staticmethod + @pytest.mark.parametrize( + 'axis, position_1, position_2, vector_1, vector_2', + [ + (N.z, r * N.x, r * N.y, N.y, N.x), + (N.z, r * N.x, -r * N.x, N.y, N.y), + (N.z, -r * N.x, r * N.x, -N.y, -N.y), + (-N.z, r * N.x, -r * N.x, -N.y, -N.y), + (-N.z, -r * N.x, r * N.x, N.y, N.y), + (N.z, r * N.x, -r * N.y, N.y, -N.x), + ( + N.z, + r * N.y, + sqrt(2)/2 * r * N.x - sqrt(2)/2 * r * N.y, + - N.x, + - sqrt(2)/2 * N.x - sqrt(2)/2 * N.y, + ), + ( + N.z, + r * N.x, + r / 2 * N.x + sqrt(3)/2 * r * N.y, + N.y, + sqrt(3)/2 * N.x - 1/2 * N.y, + ), + ( + N.z, + r * N.x, + sqrt(2)/2 * r * N.x + sqrt(2)/2 * r * N.y, + N.y, + sqrt(2)/2 * N.x - sqrt(2)/2 * N.y, + ), + ( + N.z, + r * N.x, + r * N.x + N.z, + N.z, + -N.z, + ), + ( + N.z, + r * N.x, + r * N.y + pi/2 * r * N.z, + sqrt(2)/2 * N.y + sqrt(2)/2 * N.z, + sqrt(2)/2 * N.x - sqrt(2)/2 * N.z, + ), + ( + N.z, + r * N.x, + r * cos(q) * N.x + r * sin(q) * N.y, + N.y, + sin(q) * N.x - cos(q) * N.y, + ), + ] + ) + def test_geodesic_end_vectors( + axis, + position_1, + position_2, + vector_1, + vector_2, + ): + r = Symbol('r', positive=True) + pO = Point('pO') + cylinder = WrappingCylinder(r, pO, axis) + + p1 = Point('p1') + p1.set_pos(pO, position_1) + p2 = Point('p2') + p2.set_pos(pO, position_2) + + expected = (vector_1, vector_2) + end_vectors = tuple( + end_vector.simplify() + for end_vector in cylinder.geodesic_end_vectors(p1, p2) + ) + + assert end_vectors == expected + + @staticmethod + @pytest.mark.parametrize( + 'axis, position', + [ + (N.z, r * N.x), + (N.z, r * cos(q) * N.x + r * sin(q) * N.y + N.z), + ] + ) + def test_geodesic_end_vectors_invalid_coincident(axis, position): + r = Symbol('r', positive=True) + pO = Point('pO') + cylinder = WrappingCylinder(r, pO, axis) + + p1 = Point('p1') + p1.set_pos(pO, position) + p2 = Point('p2') + p2.set_pos(pO, position) + + with pytest.raises(ValueError): + _ = cylinder.geodesic_end_vectors(p1, p2) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/wrapping_geometry.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/wrapping_geometry.py new file mode 100644 index 0000000000000000000000000000000000000000..47ed3c1c463499b024afb9e31cfa2ecd77534132 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/mechanics/wrapping_geometry.py @@ -0,0 +1,641 @@ +"""Geometry objects for use by wrapping pathways.""" + +from abc import ABC, abstractmethod + +from sympy import Integer, acos, pi, sqrt, sympify, tan +from sympy.core.relational import Eq +from sympy.functions.elementary.trigonometric import atan2 +from sympy.polys.polytools import cancel +from sympy.physics.vector import Vector, dot +from sympy.simplify.simplify import trigsimp + + +__all__ = [ + 'WrappingGeometryBase', + 'WrappingCylinder', + 'WrappingSphere', +] + + +class WrappingGeometryBase(ABC): + """Abstract base class for all geometry classes to inherit from. + + Notes + ===== + + Instances of this class cannot be directly instantiated by users. However, + it can be used to created custom geometry types through subclassing. + + """ + + @property + @abstractmethod + def point(cls): + """The point with which the geometry is associated.""" + pass + + @abstractmethod + def point_on_surface(self, point): + """Returns ``True`` if a point is on the geometry's surface. + + Parameters + ========== + point : Point + The point for which it's to be ascertained if it's on the + geometry's surface or not. + + """ + pass + + @abstractmethod + def geodesic_length(self, point_1, point_2): + """Returns the shortest distance between two points on a geometry's + surface. + + Parameters + ========== + + point_1 : Point + The point from which the geodesic length should be calculated. + point_2 : Point + The point to which the geodesic length should be calculated. + + """ + pass + + @abstractmethod + def geodesic_end_vectors(self, point_1, point_2): + """The vectors parallel to the geodesic at the two end points. + + Parameters + ========== + + point_1 : Point + The point from which the geodesic originates. + point_2 : Point + The point at which the geodesic terminates. + + """ + pass + + def __repr__(self): + """Default representation of a geometry object.""" + return f'{self.__class__.__name__}()' + + +class WrappingSphere(WrappingGeometryBase): + """A solid spherical object. + + Explanation + =========== + + A wrapping geometry that allows for circular arcs to be defined between + pairs of points. These paths are always geodetic (the shortest possible). + + Examples + ======== + + To create a ``WrappingSphere`` instance, a ``Symbol`` denoting its radius + and ``Point`` at which its center will be located are needed: + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import Point, WrappingSphere + >>> r = symbols('r') + >>> pO = Point('pO') + + A sphere with radius ``r`` centered on ``pO`` can be instantiated with: + + >>> WrappingSphere(r, pO) + WrappingSphere(radius=r, point=pO) + + Parameters + ========== + + radius : Symbol + Radius of the sphere. This symbol must represent a value that is + positive and constant, i.e. it cannot be a dynamic symbol, nor can it + be an expression. + point : Point + A point at which the sphere is centered. + + See Also + ======== + + WrappingCylinder: Cylindrical geometry where the wrapping direction can be + defined. + + """ + + def __init__(self, radius, point): + """Initializer for ``WrappingSphere``. + + Parameters + ========== + + radius : Symbol + The radius of the sphere. + point : Point + A point on which the sphere is centered. + + """ + self.radius = radius + self.point = point + + @property + def radius(self): + """Radius of the sphere.""" + return self._radius + + @radius.setter + def radius(self, radius): + self._radius = radius + + @property + def point(self): + """A point on which the sphere is centered.""" + return self._point + + @point.setter + def point(self, point): + self._point = point + + def point_on_surface(self, point): + """Returns ``True`` if a point is on the sphere's surface. + + Parameters + ========== + + point : Point + The point for which it's to be ascertained if it's on the sphere's + surface or not. This point's position relative to the sphere's + center must be a simple expression involving the radius of the + sphere, otherwise this check will likely not work. + + """ + point_vector = point.pos_from(self.point) + if isinstance(point_vector, Vector): + point_radius_squared = dot(point_vector, point_vector) + else: + point_radius_squared = point_vector**2 + return Eq(point_radius_squared, self.radius**2) == True + + def geodesic_length(self, point_1, point_2): + r"""Returns the shortest distance between two points on the sphere's + surface. + + Explanation + =========== + + The geodesic length, i.e. the shortest arc along the surface of a + sphere, connecting two points can be calculated using the formula: + + .. math:: + + l = \arccos\left(\mathbf{v}_1 \cdot \mathbf{v}_2\right) + + where $\mathbf{v}_1$ and $\mathbf{v}_2$ are the unit vectors from the + sphere's center to the first and second points on the sphere's surface + respectively. Note that the actual path that the geodesic will take is + undefined when the two points are directly opposite one another. + + Examples + ======== + + A geodesic length can only be calculated between two points on the + sphere's surface. Firstly, a ``WrappingSphere`` instance must be + created along with two points that will lie on its surface: + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import (Point, ReferenceFrame, + ... WrappingSphere) + >>> N = ReferenceFrame('N') + >>> r = symbols('r') + >>> pO = Point('pO') + >>> pO.set_vel(N, 0) + >>> sphere = WrappingSphere(r, pO) + >>> p1 = Point('p1') + >>> p2 = Point('p2') + + Let's assume that ``p1`` lies at a distance of ``r`` in the ``N.x`` + direction from ``pO`` and that ``p2`` is located on the sphere's + surface in the ``N.y + N.z`` direction from ``pO``. These positions can + be set with: + + >>> p1.set_pos(pO, r*N.x) + >>> p1.pos_from(pO) + r*N.x + >>> p2.set_pos(pO, r*(N.y + N.z).normalize()) + >>> p2.pos_from(pO) + sqrt(2)*r/2*N.y + sqrt(2)*r/2*N.z + + The geodesic length, which is in this case is a quarter of the sphere's + circumference, can be calculated using the ``geodesic_length`` method: + + >>> sphere.geodesic_length(p1, p2) + pi*r/2 + + If the ``geodesic_length`` method is passed an argument, the ``Point`` + that doesn't lie on the sphere's surface then a ``ValueError`` is + raised because it's not possible to calculate a value in this case. + + Parameters + ========== + + point_1 : Point + Point from which the geodesic length should be calculated. + point_2 : Point + Point to which the geodesic length should be calculated. + + """ + for point in (point_1, point_2): + if not self.point_on_surface(point): + msg = ( + f'Geodesic length cannot be calculated as point {point} ' + f'with radius {point.pos_from(self.point).magnitude()} ' + f'from the sphere\'s center {self.point} does not lie on ' + f'the surface of {self} with radius {self.radius}.' + ) + raise ValueError(msg) + point_1_vector = point_1.pos_from(self.point).normalize() + point_2_vector = point_2.pos_from(self.point).normalize() + central_angle = acos(point_2_vector.dot(point_1_vector)) + geodesic_length = self.radius*central_angle + return geodesic_length + + def geodesic_end_vectors(self, point_1, point_2): + """The vectors parallel to the geodesic at the two end points. + + Parameters + ========== + + point_1 : Point + The point from which the geodesic originates. + point_2 : Point + The point at which the geodesic terminates. + + """ + pA, pB = point_1, point_2 + pO = self.point + pA_vec = pA.pos_from(pO) + pB_vec = pB.pos_from(pO) + + if pA_vec.cross(pB_vec) == 0: + msg = ( + f'Can\'t compute geodesic end vectors for the pair of points ' + f'{pA} and {pB} on a sphere {self} as they are diametrically ' + f'opposed, thus the geodesic is not defined.' + ) + raise ValueError(msg) + + return ( + pA_vec.cross(pB.pos_from(pA)).cross(pA_vec).normalize(), + pB_vec.cross(pA.pos_from(pB)).cross(pB_vec).normalize(), + ) + + def __repr__(self): + """Representation of a ``WrappingSphere``.""" + return ( + f'{self.__class__.__name__}(radius={self.radius}, ' + f'point={self.point})' + ) + + +class WrappingCylinder(WrappingGeometryBase): + """A solid (infinite) cylindrical object. + + Explanation + =========== + + A wrapping geometry that allows for circular arcs to be defined between + pairs of points. These paths are always geodetic (the shortest possible) in + the sense that they will be a straight line on the unwrapped cylinder's + surface. However, it is also possible for a direction to be specified, i.e. + paths can be influenced such that they either wrap along the shortest side + or the longest side of the cylinder. To define these directions, rotations + are in the positive direction following the right-hand rule. + + Examples + ======== + + To create a ``WrappingCylinder`` instance, a ``Symbol`` denoting its + radius, a ``Vector`` defining its axis, and a ``Point`` through which its + axis passes are needed: + + >>> from sympy import symbols + >>> from sympy.physics.mechanics import (Point, ReferenceFrame, + ... WrappingCylinder) + >>> N = ReferenceFrame('N') + >>> r = symbols('r') + >>> pO = Point('pO') + >>> ax = N.x + + A cylinder with radius ``r``, and axis parallel to ``N.x`` passing through + ``pO`` can be instantiated with: + + >>> WrappingCylinder(r, pO, ax) + WrappingCylinder(radius=r, point=pO, axis=N.x) + + Parameters + ========== + + radius : Symbol + The radius of the cylinder. + point : Point + A point through which the cylinder's axis passes. + axis : Vector + The axis along which the cylinder is aligned. + + See Also + ======== + + WrappingSphere: Spherical geometry where the wrapping direction is always + geodetic. + + """ + + def __init__(self, radius, point, axis): + """Initializer for ``WrappingCylinder``. + + Parameters + ========== + + radius : Symbol + The radius of the cylinder. This symbol must represent a value that + is positive and constant, i.e. it cannot be a dynamic symbol. + point : Point + A point through which the cylinder's axis passes. + axis : Vector + The axis along which the cylinder is aligned. + + """ + self.radius = radius + self.point = point + self.axis = axis + + @property + def radius(self): + """Radius of the cylinder.""" + return self._radius + + @radius.setter + def radius(self, radius): + self._radius = radius + + @property + def point(self): + """A point through which the cylinder's axis passes.""" + return self._point + + @point.setter + def point(self, point): + self._point = point + + @property + def axis(self): + """Axis along which the cylinder is aligned.""" + return self._axis + + @axis.setter + def axis(self, axis): + self._axis = axis.normalize() + + def point_on_surface(self, point): + """Returns ``True`` if a point is on the cylinder's surface. + + Parameters + ========== + + point : Point + The point for which it's to be ascertained if it's on the + cylinder's surface or not. This point's position relative to the + cylinder's axis must be a simple expression involving the radius of + the sphere, otherwise this check will likely not work. + + """ + relative_position = point.pos_from(self.point) + parallel = relative_position.dot(self.axis) * self.axis + point_vector = relative_position - parallel + if isinstance(point_vector, Vector): + point_radius_squared = dot(point_vector, point_vector) + else: + point_radius_squared = point_vector**2 + return Eq(trigsimp(point_radius_squared), self.radius**2) == True + + def geodesic_length(self, point_1, point_2): + """The shortest distance between two points on a geometry's surface. + + Explanation + =========== + + The geodesic length, i.e. the shortest arc along the surface of a + cylinder, connecting two points. It can be calculated using Pythagoras' + theorem. The first short side is the distance between the two points on + the cylinder's surface parallel to the cylinder's axis. The second + short side is the arc of a circle between the two points of the + cylinder's surface perpendicular to the cylinder's axis. The resulting + hypotenuse is the geodesic length. + + Examples + ======== + + A geodesic length can only be calculated between two points on the + cylinder's surface. Firstly, a ``WrappingCylinder`` instance must be + created along with two points that will lie on its surface: + + >>> from sympy import symbols, cos, sin + >>> from sympy.physics.mechanics import (Point, ReferenceFrame, + ... WrappingCylinder, dynamicsymbols) + >>> N = ReferenceFrame('N') + >>> r = symbols('r') + >>> pO = Point('pO') + >>> pO.set_vel(N, 0) + >>> cylinder = WrappingCylinder(r, pO, N.x) + >>> p1 = Point('p1') + >>> p2 = Point('p2') + + Let's assume that ``p1`` is located at ``N.x + r*N.y`` relative to + ``pO`` and that ``p2`` is located at ``r*(cos(q)*N.y + sin(q)*N.z)`` + relative to ``pO``, where ``q(t)`` is a generalized coordinate + specifying the angle rotated around the ``N.x`` axis according to the + right-hand rule where ``N.y`` is zero. These positions can be set with: + + >>> q = dynamicsymbols('q') + >>> p1.set_pos(pO, N.x + r*N.y) + >>> p1.pos_from(pO) + N.x + r*N.y + >>> p2.set_pos(pO, r*(cos(q)*N.y + sin(q)*N.z).normalize()) + >>> p2.pos_from(pO).simplify() + r*cos(q(t))*N.y + r*sin(q(t))*N.z + + The geodesic length, which is in this case a is the hypotenuse of a + right triangle where the other two side lengths are ``1`` (parallel to + the cylinder's axis) and ``r*q(t)`` (parallel to the cylinder's cross + section), can be calculated using the ``geodesic_length`` method: + + >>> cylinder.geodesic_length(p1, p2).simplify() + sqrt(r**2*q(t)**2 + 1) + + If the ``geodesic_length`` method is passed an argument ``Point`` that + doesn't lie on the sphere's surface then a ``ValueError`` is raised + because it's not possible to calculate a value in this case. + + Parameters + ========== + + point_1 : Point + Point from which the geodesic length should be calculated. + point_2 : Point + Point to which the geodesic length should be calculated. + + """ + for point in (point_1, point_2): + if not self.point_on_surface(point): + msg = ( + f'Geodesic length cannot be calculated as point {point} ' + f'with radius {point.pos_from(self.point).magnitude()} ' + f'from the cylinder\'s center {self.point} does not lie on ' + f'the surface of {self} with radius {self.radius} and axis ' + f'{self.axis}.' + ) + raise ValueError(msg) + + relative_position = point_2.pos_from(point_1) + parallel_length = relative_position.dot(self.axis) + + point_1_relative_position = point_1.pos_from(self.point) + point_1_perpendicular_vector = ( + point_1_relative_position + - point_1_relative_position.dot(self.axis)*self.axis + ).normalize() + + point_2_relative_position = point_2.pos_from(self.point) + point_2_perpendicular_vector = ( + point_2_relative_position + - point_2_relative_position.dot(self.axis)*self.axis + ).normalize() + + central_angle = _directional_atan( + cancel(point_1_perpendicular_vector + .cross(point_2_perpendicular_vector) + .dot(self.axis)), + cancel(point_1_perpendicular_vector.dot(point_2_perpendicular_vector)), + ) + + planar_arc_length = self.radius*central_angle + geodesic_length = sqrt(parallel_length**2 + planar_arc_length**2) + return geodesic_length + + def geodesic_end_vectors(self, point_1, point_2): + """The vectors parallel to the geodesic at the two end points. + + Parameters + ========== + + point_1 : Point + The point from which the geodesic originates. + point_2 : Point + The point at which the geodesic terminates. + + """ + point_1_from_origin_point = point_1.pos_from(self.point) + point_2_from_origin_point = point_2.pos_from(self.point) + + if point_1_from_origin_point == point_2_from_origin_point: + msg = ( + f'Cannot compute geodesic end vectors for coincident points ' + f'{point_1} and {point_2} as no geodesic exists.' + ) + raise ValueError(msg) + + point_1_parallel = point_1_from_origin_point.dot(self.axis) * self.axis + point_2_parallel = point_2_from_origin_point.dot(self.axis) * self.axis + point_1_normal = (point_1_from_origin_point - point_1_parallel) + point_2_normal = (point_2_from_origin_point - point_2_parallel) + + if point_1_normal == point_2_normal: + point_1_perpendicular = Vector(0) + point_2_perpendicular = Vector(0) + else: + point_1_perpendicular = self.axis.cross(point_1_normal).normalize() + point_2_perpendicular = -self.axis.cross(point_2_normal).normalize() + + geodesic_length = self.geodesic_length(point_1, point_2) + relative_position = point_2.pos_from(point_1) + parallel_length = relative_position.dot(self.axis) + planar_arc_length = sqrt(geodesic_length**2 - parallel_length**2) + + point_1_vector = ( + planar_arc_length * point_1_perpendicular + + parallel_length * self.axis + ).normalize() + point_2_vector = ( + planar_arc_length * point_2_perpendicular + - parallel_length * self.axis + ).normalize() + + return (point_1_vector, point_2_vector) + + def __repr__(self): + """Representation of a ``WrappingCylinder``.""" + return ( + f'{self.__class__.__name__}(radius={self.radius}, ' + f'point={self.point}, axis={self.axis})' + ) + + +def _directional_atan(numerator, denominator): + """Compute atan in a directional sense as required for geodesics. + + Explanation + =========== + + To be able to control the direction of the geodesic length along the + surface of a cylinder a dedicated arctangent function is needed that + properly handles the directionality of different case. This function + ensures that the central angle is always positive but shifting the case + where ``atan2`` would return a negative angle to be centered around + ``2*pi``. + + Notes + ===== + + This function only handles very specific cases, i.e. the ones that are + expected to be encountered when calculating symbolic geodesics on uniformly + curved surfaces. As such, ``NotImplemented`` errors can be raised in many + cases. This function is named with a leader underscore to indicate that it + only aims to provide very specific functionality within the private scope + of this module. + + """ + + if numerator.is_number and denominator.is_number: + angle = atan2(numerator, denominator) + if angle < 0: + angle += 2 * pi + elif numerator.is_number: + msg = ( + f'Cannot compute a directional atan when the numerator {numerator} ' + f'is numeric and the denominator {denominator} is symbolic.' + ) + raise NotImplementedError(msg) + elif denominator.is_number: + msg = ( + f'Cannot compute a directional atan when the numerator {numerator} ' + f'is symbolic and the denominator {denominator} is numeric.' + ) + raise NotImplementedError(msg) + else: + ratio = sympify(trigsimp(numerator / denominator)) + if isinstance(ratio, tan): + angle = ratio.args[0] + elif ( + ratio.is_Mul + and ratio.args[0] == Integer(-1) + and isinstance(ratio.args[1], tan) + ): + angle = 2 * pi - ratio.args[1].args[0] + else: + msg = f'Cannot compute a directional atan for the value {ratio}.' + raise NotImplementedError(msg) + + return angle diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d2d83d452fd30e718546c0eac26fe03bbef59c06 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__init__.py @@ -0,0 +1,38 @@ +__all__ = [ + 'TWave', + + 'RayTransferMatrix', 'FreeSpace', 'FlatRefraction', 'CurvedRefraction', + 'FlatMirror', 'CurvedMirror', 'ThinLens', 'GeometricRay', 'BeamParameter', + 'waist2rayleigh', 'rayleigh2waist', 'geometric_conj_ab', + 'geometric_conj_af', 'geometric_conj_bf', 'gaussian_conj', + 'conjugate_gauss_beams', + + 'Medium', + + 'refraction_angle', 'deviation', 'fresnel_coefficients', 'brewster_angle', + 'critical_angle', 'lens_makers_formula', 'mirror_formula', 'lens_formula', + 'hyperfocal_distance', 'transverse_magnification', + + 'jones_vector', 'stokes_vector', 'jones_2_stokes', 'linear_polarizer', + 'phase_retarder', 'half_wave_retarder', 'quarter_wave_retarder', + 'transmissive_filter', 'reflective_filter', 'mueller_matrix', + 'polarizing_beam_splitter', +] +from .waves import TWave + +from .gaussopt import (RayTransferMatrix, FreeSpace, FlatRefraction, + CurvedRefraction, FlatMirror, CurvedMirror, ThinLens, GeometricRay, + BeamParameter, waist2rayleigh, rayleigh2waist, geometric_conj_ab, + geometric_conj_af, geometric_conj_bf, gaussian_conj, + conjugate_gauss_beams) + +from .medium import Medium + +from .utils import (refraction_angle, deviation, fresnel_coefficients, + brewster_angle, critical_angle, lens_makers_formula, mirror_formula, + lens_formula, hyperfocal_distance, transverse_magnification) + +from .polarization import (jones_vector, stokes_vector, jones_2_stokes, + linear_polarizer, phase_retarder, half_wave_retarder, + quarter_wave_retarder, transmissive_filter, reflective_filter, + mueller_matrix, polarizing_beam_splitter) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d4a5466d4262e7c990053b679d9a61de58590ef4 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/gaussopt.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/gaussopt.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db7f61a6c35a32bb76977208ee6a4f159ea9bf90 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/gaussopt.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/medium.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/medium.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f35a18ee60d71cbda21f9c0e230fcac40e324a78 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/medium.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/polarization.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/polarization.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7cafe11213aa7ec459a82fc10a5aabfbf8d7de95 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/polarization.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/utils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e56155194a8d51c0b727ee3403d6fc8c7b70a447 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/utils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/waves.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/waves.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..884c230345fb98aeb6020ccf8b03981aca77c48d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/__pycache__/waves.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/gaussopt.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/gaussopt.py new file mode 100644 index 0000000000000000000000000000000000000000..d9e8ef555d60e3204341cdc65cdd05fb02b2f196 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/gaussopt.py @@ -0,0 +1,923 @@ +""" +Gaussian optics. + +The module implements: + +- Ray transfer matrices for geometrical and gaussian optics. + + See RayTransferMatrix, GeometricRay and BeamParameter + +- Conjugation relations for geometrical and gaussian optics. + + See geometric_conj*, gauss_conj and conjugate_gauss_beams + +The conventions for the distances are as follows: + +focal distance + positive for convergent lenses +object distance + positive for real objects +image distance + positive for real images +""" + +__all__ = [ + 'RayTransferMatrix', + 'FreeSpace', + 'FlatRefraction', + 'CurvedRefraction', + 'FlatMirror', + 'CurvedMirror', + 'ThinLens', + 'GeometricRay', + 'BeamParameter', + 'waist2rayleigh', + 'rayleigh2waist', + 'geometric_conj_ab', + 'geometric_conj_af', + 'geometric_conj_bf', + 'gaussian_conj', + 'conjugate_gauss_beams', +] + + +from sympy.core.expr import Expr +from sympy.core.numbers import (I, pi) +from sympy.core.sympify import sympify +from sympy.functions.elementary.complexes import (im, re) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import atan2 +from sympy.matrices.dense import Matrix, MutableDenseMatrix +from sympy.polys.rationaltools import together +from sympy.utilities.misc import filldedent + +### +# A, B, C, D matrices +### + + +class RayTransferMatrix(MutableDenseMatrix): + """ + Base class for a Ray Transfer Matrix. + + It should be used if there is not already a more specific subclass mentioned + in See Also. + + Parameters + ========== + + parameters : + A, B, C and D or 2x2 matrix (Matrix(2, 2, [A, B, C, D])) + + Examples + ======== + + >>> from sympy.physics.optics import RayTransferMatrix, ThinLens + >>> from sympy import Symbol, Matrix + + >>> mat = RayTransferMatrix(1, 2, 3, 4) + >>> mat + Matrix([ + [1, 2], + [3, 4]]) + + >>> RayTransferMatrix(Matrix([[1, 2], [3, 4]])) + Matrix([ + [1, 2], + [3, 4]]) + + >>> mat.A + 1 + + >>> f = Symbol('f') + >>> lens = ThinLens(f) + >>> lens + Matrix([ + [ 1, 0], + [-1/f, 1]]) + + >>> lens.C + -1/f + + See Also + ======== + + GeometricRay, BeamParameter, + FreeSpace, FlatRefraction, CurvedRefraction, + FlatMirror, CurvedMirror, ThinLens + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Ray_transfer_matrix_analysis + """ + + def __new__(cls, *args): + + 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): + temp = args[0] + else: + raise ValueError(filldedent(''' + Expecting 2x2 Matrix or the 4 elements of + the Matrix but got %s''' % str(args))) + return Matrix.__new__(cls, temp) + + def __mul__(self, other): + if isinstance(other, RayTransferMatrix): + return RayTransferMatrix(Matrix(self)*Matrix(other)) + elif isinstance(other, GeometricRay): + return GeometricRay(Matrix(self)*Matrix(other)) + elif isinstance(other, BeamParameter): + temp = Matrix(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))) + else: + return Matrix.__mul__(self, other) + + @property + def A(self): + """ + The A parameter of the Matrix. + + Examples + ======== + + >>> from sympy.physics.optics import RayTransferMatrix + >>> mat = RayTransferMatrix(1, 2, 3, 4) + >>> mat.A + 1 + """ + return self[0, 0] + + @property + def B(self): + """ + The B parameter of the Matrix. + + Examples + ======== + + >>> from sympy.physics.optics import RayTransferMatrix + >>> mat = RayTransferMatrix(1, 2, 3, 4) + >>> mat.B + 2 + """ + return self[0, 1] + + @property + def C(self): + """ + The C parameter of the Matrix. + + Examples + ======== + + >>> from sympy.physics.optics import RayTransferMatrix + >>> mat = RayTransferMatrix(1, 2, 3, 4) + >>> mat.C + 3 + """ + return self[1, 0] + + @property + def D(self): + """ + The D parameter of the Matrix. + + Examples + ======== + + >>> from sympy.physics.optics import RayTransferMatrix + >>> mat = RayTransferMatrix(1, 2, 3, 4) + >>> mat.D + 4 + """ + return self[1, 1] + + +class FreeSpace(RayTransferMatrix): + """ + Ray Transfer Matrix for free space. + + Parameters + ========== + + distance + + See Also + ======== + + RayTransferMatrix + + Examples + ======== + + >>> from sympy.physics.optics import FreeSpace + >>> from sympy import symbols + >>> d = symbols('d') + >>> FreeSpace(d) + 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. + + Parameters + ========== + + n1 : + Refractive index of one medium. + n2 : + Refractive index of other medium. + + See Also + ======== + + RayTransferMatrix + + Examples + ======== + + >>> from sympy.physics.optics import FlatRefraction + >>> from sympy import symbols + >>> n1, n2 = symbols('n1 n2') + >>> FlatRefraction(n1, n2) + Matrix([ + [1, 0], + [0, n1/n2]]) + """ + def __new__(cls, n1, n2): + n1, n2 = map(sympify, (n1, n2)) + return RayTransferMatrix.__new__(cls, 1, 0, 0, n1/n2) + + +class CurvedRefraction(RayTransferMatrix): + """ + Ray Transfer Matrix for refraction on curved interface. + + Parameters + ========== + + R : + Radius of curvature (positive for concave). + n1 : + Refractive index of one medium. + n2 : + Refractive index of other medium. + + See Also + ======== + + RayTransferMatrix + + Examples + ======== + + >>> from sympy.physics.optics import CurvedRefraction + >>> from sympy import symbols + >>> R, n1, n2 = symbols('R n1 n2') + >>> CurvedRefraction(R, n1, n2) + Matrix([ + [ 1, 0], + [(n1 - n2)/(R*n2), n1/n2]]) + """ + def __new__(cls, R, n1, n2): + R, n1, n2 = map(sympify, (R, n1, n2)) + return RayTransferMatrix.__new__(cls, 1, 0, (n1 - n2)/R/n2, n1/n2) + + +class FlatMirror(RayTransferMatrix): + """ + Ray Transfer Matrix for reflection. + + See Also + ======== + + RayTransferMatrix + + Examples + ======== + + >>> from sympy.physics.optics import FlatMirror + >>> FlatMirror() + 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. + + Parameters + ========== + + R : radius of curvature (positive for concave) + + See Also + ======== + + RayTransferMatrix + + Examples + ======== + + >>> from sympy.physics.optics import CurvedMirror + >>> from sympy import symbols + >>> R = symbols('R') + >>> CurvedMirror(R) + 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. + + Parameters + ========== + + f : + The focal distance. + + See Also + ======== + + RayTransferMatrix + + Examples + ======== + + >>> from sympy.physics.optics import ThinLens + >>> from sympy import symbols + >>> f = symbols('f') + >>> ThinLens(f) + Matrix([ + [ 1, 0], + [-1/f, 1]]) + """ + def __new__(cls, f): + f = sympify(f) + return RayTransferMatrix.__new__(cls, 1, 0, -1/f, 1) + + +### +# Representation for geometric ray +### + +class GeometricRay(MutableDenseMatrix): + """ + Representation for a geometric ray in the Ray Transfer Matrix formalism. + + Parameters + ========== + + h : height, and + angle : angle, or + matrix : a 2x1 matrix (Matrix(2, 1, [height, angle])) + + Examples + ======== + + >>> from sympy.physics.optics import GeometricRay, FreeSpace + >>> from sympy import symbols, Matrix + >>> d, h, angle = symbols('d, h, angle') + + >>> GeometricRay(h, angle) + Matrix([ + [ h], + [angle]]) + + >>> FreeSpace(d)*GeometricRay(h, angle) + Matrix([ + [angle*d + h], + [ angle]]) + + >>> GeometricRay( Matrix( ((h,), (angle,)) ) ) + Matrix([ + [ h], + [angle]]) + + See Also + ======== + + RayTransferMatrix + + """ + + def __new__(cls, *args): + if len(args) == 1 and isinstance(args[0], Matrix) \ + and args[0].shape == (2, 1): + temp = args[0] + elif len(args) == 2: + temp = ((args[0],), (args[1],)) + else: + raise ValueError(filldedent(''' + Expecting 2x1 Matrix or the 2 elements of + the Matrix but got %s''' % str(args))) + return Matrix.__new__(cls, temp) + + @property + def height(self): + """ + The distance from the optical axis. + + Examples + ======== + + >>> from sympy.physics.optics import GeometricRay + >>> from sympy import symbols + >>> h, angle = symbols('h, angle') + >>> gRay = GeometricRay(h, angle) + >>> gRay.height + h + """ + return self[0] + + @property + def angle(self): + """ + The angle with the optical axis. + + Examples + ======== + + >>> from sympy.physics.optics import GeometricRay + >>> from sympy import symbols + >>> h, angle = symbols('h, angle') + >>> gRay = GeometricRay(h, angle) + >>> gRay.angle + angle + """ + return self[1] + + +### +# Representation for gauss beam +### + +class BeamParameter(Expr): + """ + Representation for a gaussian ray in the Ray Transfer Matrix formalism. + + Parameters + ========== + + wavelen : the wavelength, + z : the distance to waist, and + w : the waist, or + z_r : the rayleigh range. + n : the refractive index of medium. + + Examples + ======== + + >>> from sympy.physics.optics import BeamParameter + >>> p = BeamParameter(530e-9, 1, w=1e-3) + >>> p.q + 1 + 1.88679245283019*I*pi + + >>> p.q.n() + 1.0 + 5.92753330865999*I + >>> p.w_0.n() + 0.00100000000000000 + >>> p.z_r.n() + 5.92753330865999 + + >>> from sympy.physics.optics import FreeSpace + >>> fs = FreeSpace(10) + >>> p1 = fs*p + >>> p.w.n() + 0.00101413072159615 + >>> p1.w.n() + 0.00210803120913829 + + See Also + ======== + + RayTransferMatrix + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Complex_beam_parameter + .. [2] https://en.wikipedia.org/wiki/Gaussian_beam + """ + #TODO A class Complex may be implemented. The BeamParameter may + # subclass it. See: + # https://groups.google.com/d/topic/sympy/7XkU07NRBEs/discussion + + def __new__(cls, wavelen, z, z_r=None, w=None, n=1): + wavelen = sympify(wavelen) + z = sympify(z) + n = sympify(n) + + if z_r is not None and w is None: + z_r = sympify(z_r) + elif w is not None and z_r is None: + z_r = waist2rayleigh(sympify(w), wavelen, n) + elif z_r is None and w is None: + raise ValueError('Must specify one of w and z_r.') + + return Expr.__new__(cls, wavelen, z, z_r, n) + + @property + def wavelen(self): + return self.args[0] + + @property + def z(self): + return self.args[1] + + @property + def z_r(self): + return self.args[2] + + @property + def n(self): + return self.args[3] + + @property + def q(self): + """ + The complex parameter representing the beam. + + Examples + ======== + + >>> from sympy.physics.optics import BeamParameter + >>> p = BeamParameter(530e-9, 1, w=1e-3) + >>> p.q + 1 + 1.88679245283019*I*pi + """ + return self.z + I*self.z_r + + @property + def radius(self): + """ + The radius of curvature of the phase front. + + Examples + ======== + + >>> from sympy.physics.optics import BeamParameter + >>> p = BeamParameter(530e-9, 1, w=1e-3) + >>> p.radius + 1 + 3.55998576005696*pi**2 + """ + return self.z*(1 + (self.z_r/self.z)**2) + + @property + def w(self): + """ + The radius of the beam w(z), at any position z along the beam. + The beam radius at `1/e^2` intensity (axial value). + + See Also + ======== + + w_0 : + The minimal radius of beam. + + Examples + ======== + + >>> from sympy.physics.optics import BeamParameter + >>> p = BeamParameter(530e-9, 1, w=1e-3) + >>> p.w + 0.001*sqrt(0.2809/pi**2 + 1) + """ + return self.w_0*sqrt(1 + (self.z/self.z_r)**2) + + @property + def w_0(self): + """ + The minimal radius of beam at `1/e^2` intensity (peak value). + + See Also + ======== + + w : the beam radius at `1/e^2` intensity (axial value). + + Examples + ======== + + >>> from sympy.physics.optics import BeamParameter + >>> p = BeamParameter(530e-9, 1, w=1e-3) + >>> p.w_0 + 0.00100000000000000 + """ + return sqrt(self.z_r/(pi*self.n)*self.wavelen) + + @property + def divergence(self): + """ + Half of the total angular spread. + + Examples + ======== + + >>> from sympy.physics.optics import BeamParameter + >>> p = BeamParameter(530e-9, 1, w=1e-3) + >>> p.divergence + 0.00053/pi + """ + return self.wavelen/pi/self.w_0 + + @property + def gouy(self): + """ + The Gouy phase. + + Examples + ======== + + >>> from sympy.physics.optics import BeamParameter + >>> p = BeamParameter(530e-9, 1, w=1e-3) + >>> p.gouy + atan(0.53/pi) + """ + return atan2(self.z, self.z_r) + + @property + def waist_approximation_limit(self): + """ + The minimal waist for which the gauss beam approximation is valid. + + Explanation + =========== + + The gauss beam is a solution to the paraxial equation. For curvatures + that are too great it is not a valid approximation. + + Examples + ======== + + >>> from sympy.physics.optics import BeamParameter + >>> p = BeamParameter(530e-9, 1, w=1e-3) + >>> p.waist_approximation_limit + 1.06e-6/pi + """ + return 2*self.wavelen/pi + + +### +# Utilities +### + +def waist2rayleigh(w, wavelen, n=1): + """ + Calculate the rayleigh range from the waist of a gaussian beam. + + See Also + ======== + + rayleigh2waist, BeamParameter + + Examples + ======== + + >>> from sympy.physics.optics import waist2rayleigh + >>> from sympy import symbols + >>> w, wavelen = symbols('w wavelen') + >>> waist2rayleigh(w, wavelen) + pi*w**2/wavelen + """ + w, wavelen = map(sympify, (w, wavelen)) + return w**2*n*pi/wavelen + + +def rayleigh2waist(z_r, wavelen): + """Calculate the waist from the rayleigh range of a gaussian beam. + + See Also + ======== + + waist2rayleigh, BeamParameter + + Examples + ======== + + >>> from sympy.physics.optics import rayleigh2waist + >>> from sympy import symbols + >>> z_r, wavelen = symbols('z_r wavelen') + >>> rayleigh2waist(z_r, wavelen) + sqrt(wavelen*z_r)/sqrt(pi) + """ + z_r, wavelen = map(sympify, (z_r, wavelen)) + return sqrt(z_r/pi*wavelen) + + +def geometric_conj_ab(a, b): + """ + Conjugation relation for geometrical beams under paraxial conditions. + + Explanation + =========== + + Takes the distances to the optical element and returns the needed + focal distance. + + See Also + ======== + + geometric_conj_af, geometric_conj_bf + + Examples + ======== + + >>> from sympy.physics.optics import geometric_conj_ab + >>> from sympy import symbols + >>> a, b = symbols('a b') + >>> geometric_conj_ab(a, b) + a*b/(a + b) + """ + a, b = map(sympify, (a, b)) + if a.is_infinite or b.is_infinite: + return a if b.is_infinite else b + else: + return a*b/(a + b) + + +def geometric_conj_af(a, f): + """ + Conjugation relation for geometrical beams under paraxial conditions. + + Explanation + =========== + + Takes the object distance (for geometric_conj_af) or the image distance + (for geometric_conj_bf) to the optical element and the focal distance. + Then it returns the other distance needed for conjugation. + + See Also + ======== + + geometric_conj_ab + + Examples + ======== + + >>> from sympy.physics.optics.gaussopt import geometric_conj_af, geometric_conj_bf + >>> from sympy import symbols + >>> a, b, f = symbols('a b f') + >>> geometric_conj_af(a, f) + a*f/(a - f) + >>> geometric_conj_bf(b, f) + b*f/(b - f) + """ + a, f = 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. + + Parameters + ========== + + s_in : + The distance to optical element from the waist. + z_r_in : + The rayleigh range of the incident beam. + f : + The focal length of the optical element. + + Returns + ======= + + a tuple containing (s_out, z_r_out, m) + s_out : + The distance between the new waist and the optical element. + z_r_out : + The rayleigh range of the emergent beam. + m : + The ration between the new and the old waists. + + Examples + ======== + + >>> from sympy.physics.optics import gaussian_conj + >>> from sympy import symbols + >>> s_in, z_r_in, f = symbols('s_in z_r_in f') + + >>> gaussian_conj(s_in, z_r_in, f)[0] + 1/(-1/(s_in + z_r_in**2/(-f + s_in)) + 1/f) + + >>> gaussian_conj(s_in, z_r_in, f)[1] + z_r_in/(1 - s_in**2/f**2 + z_r_in**2/f**2) + + >>> 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 = 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. + + Parameters + ========== + + wavelen : + The wavelength of the beam. + waist_in and waist_out : + The waists to be conjugated. + f : + The focal distance of the element used in the conjugation. + + Returns + ======= + + a tuple containing (s_in, s_out, f) + s_in : + The distance before the optical element. + s_out : + The distance after the optical element. + f : + The focal distance of the optical element. + + Examples + ======== + + >>> from sympy.physics.optics import conjugate_gauss_beams + >>> from sympy import symbols, factor + >>> l, w_i, w_o, f = symbols('l w_i w_o f') + + >>> conjugate_gauss_beams(l, w_i, w_o, f=f)[0] + f*(1 - sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2))) + + >>> 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 + + >>> conjugate_gauss_beams(l, w_i, w_o, f=f)[2] + f + """ + #TODO add the other possible arguments + wavelen, waist_in, waist_out = map(sympify, (wavelen, waist_in, waist_out)) + m = waist_out / waist_in + z = waist2rayleigh(waist_in, wavelen) + if len(kwargs) != 1: + raise ValueError("The function expects only one named argument") + elif 'dist' in kwargs: + raise NotImplementedError(filldedent(''' + Currently only focal length is supported as a parameter''')) + elif 'f' in kwargs: + f = sympify(kwargs['f']) + s_in = f * (1 - sqrt(1/m**2 - z**2/f**2)) + s_out = gaussian_conj(s_in, z, f)[0] + elif 's_in' in kwargs: + raise NotImplementedError(filldedent(''' + Currently only focal length is supported as a parameter''')) + else: + raise ValueError(filldedent(''' + The functions expects the focal length as a named argument''')) + return (s_in, s_out, f) + +#TODO +#def plot_beam(): +# """Plot the beam radius as it propagates in space.""" +# pass + +#TODO +#def plot_beam_conjugation(): +# """ +# Plot the intersection of two beams. +# +# Represents the conjugation relation. +# +# See Also +# ======== +# +# conjugate_gauss_beams +# """ +# pass diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/medium.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/medium.py new file mode 100644 index 0000000000000000000000000000000000000000..764b68caad5865b8f3cee028a14cfa304796b4c0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/medium.py @@ -0,0 +1,253 @@ +""" +**Contains** + +* Medium +""" +from sympy.physics.units import second, meter, kilogram, ampere + +__all__ = ['Medium'] + +from sympy.core.basic import Basic +from sympy.core.symbol import Str +from sympy.core.sympify import _sympify +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.physics.units import speed_of_light, u0, e0 + + +c = speed_of_light.convert_to(meter/second) +_e0mksa = e0.convert_to(ampere**2*second**4/(kilogram*meter**3)) +_u0mksa = u0.convert_to(meter*kilogram/(ampere**2*second**2)) + + +class Medium(Basic): + + """ + This class represents an optical medium. The prime reason to implement this is + to facilitate refraction, Fermat's principle, etc. + + Explanation + =========== + + An optical medium is a material through which electromagnetic waves propagate. + The permittivity and permeability of the medium define how electromagnetic + waves propagate in it. + + + Parameters + ========== + + name: string + The display name of the Medium. + + permittivity: Sympifyable + Electric permittivity of the space. + + permeability: Sympifyable + Magnetic permeability of the space. + + n: Sympifyable + Index of refraction of the medium. + + + Examples + ======== + + >>> from sympy.abc import epsilon, mu + >>> from sympy.physics.optics import Medium + >>> m1 = Medium('m1') + >>> m2 = Medium('m2', epsilon, mu) + >>> m1.intrinsic_impedance + 149896229*pi*kilogram*meter**2/(1250000*ampere**2*second**3) + >>> m2.refractive_index + 299792458*meter*sqrt(epsilon*mu)/second + + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Optical_medium + + """ + + def __new__(cls, name, permittivity=None, permeability=None, n=None): + if not isinstance(name, Str): + name = Str(name) + + permittivity = _sympify(permittivity) if permittivity is not None else permittivity + permeability = _sympify(permeability) if permeability is not None else permeability + n = _sympify(n) if n is not None else n + + if n is not None: + if permittivity is not None and permeability is None: + permeability = n**2/(c**2*permittivity) + return MediumPP(name, permittivity, permeability) + elif permeability is not None and permittivity is None: + permittivity = n**2/(c**2*permeability) + return MediumPP(name, permittivity, permeability) + elif permittivity is not None and permittivity is not None: + raise ValueError("Specifying all of permittivity, permeability, and n is not allowed") + else: + return MediumN(name, n) + elif permittivity is not None and permeability is not None: + return MediumPP(name, permittivity, permeability) + elif permittivity is None and permeability is None: + return MediumPP(name, _e0mksa, _u0mksa) + else: + raise ValueError("Arguments are underspecified. Either specify n or any two of permittivity, " + "permeability, and n") + + @property + def name(self): + return self.args[0] + + @property + def speed(self): + """ + Returns speed of the electromagnetic wave travelling in the medium. + + Examples + ======== + + >>> from sympy.physics.optics import Medium + >>> m = Medium('m') + >>> m.speed + 299792458*meter/second + >>> m2 = Medium('m2', n=1) + >>> m.speed == m2.speed + True + + """ + return c / self.n + + @property + def refractive_index(self): + """ + Returns refractive index of the medium. + + Examples + ======== + + >>> from sympy.physics.optics import Medium + >>> m = Medium('m') + >>> m.refractive_index + 1 + + """ + return (c/self.speed) + + +class MediumN(Medium): + + """ + Represents an optical medium for which only the refractive index is known. + Useful for simple ray optics. + + This class should never be instantiated directly. + Instead it should be instantiated indirectly by instantiating Medium with + only n specified. + + Examples + ======== + >>> from sympy.physics.optics import Medium + >>> m = Medium('m', n=2) + >>> m + MediumN(Str('m'), 2) + """ + + def __new__(cls, name, n): + obj = super(Medium, cls).__new__(cls, name, n) + return obj + + @property + def n(self): + return self.args[1] + + +class MediumPP(Medium): + """ + Represents an optical medium for which the permittivity and permeability are known. + + This class should never be instantiated directly. Instead it should be + instantiated indirectly by instantiating Medium with any two of + permittivity, permeability, and n specified, or by not specifying any + of permittivity, permeability, or n, in which case default values for + permittivity and permeability will be used. + + Examples + ======== + >>> from sympy.physics.optics import Medium + >>> from sympy.abc import epsilon, mu + >>> m1 = Medium('m1', permittivity=epsilon, permeability=mu) + >>> m1 + MediumPP(Str('m1'), epsilon, mu) + >>> m2 = Medium('m2') + >>> m2 + MediumPP(Str('m2'), 625000*ampere**2*second**4/(22468879468420441*pi*kilogram*meter**3), pi*kilogram*meter/(2500000*ampere**2*second**2)) + """ + + + def __new__(cls, name, permittivity, permeability): + obj = super(Medium, cls).__new__(cls, name, permittivity, permeability) + return obj + + @property + def intrinsic_impedance(self): + """ + Returns intrinsic impedance of the medium. + + Explanation + =========== + + The intrinsic impedance of a medium is the ratio of the + transverse components of the electric and magnetic fields + of the electromagnetic wave travelling in the medium. + In a region with no electrical conductivity it simplifies + to the square root of ratio of magnetic permeability to + electric permittivity. + + Examples + ======== + + >>> from sympy.physics.optics import Medium + >>> m = Medium('m') + >>> m.intrinsic_impedance + 149896229*pi*kilogram*meter**2/(1250000*ampere**2*second**3) + + """ + return sqrt(self.permeability / self.permittivity) + + @property + def permittivity(self): + """ + Returns electric permittivity of the medium. + + Examples + ======== + + >>> from sympy.physics.optics import Medium + >>> m = Medium('m') + >>> m.permittivity + 625000*ampere**2*second**4/(22468879468420441*pi*kilogram*meter**3) + + """ + return self.args[1] + + @property + def permeability(self): + """ + Returns magnetic permeability of the medium. + + Examples + ======== + + >>> from sympy.physics.optics import Medium + >>> m = Medium('m') + >>> m.permeability + pi*kilogram*meter/(2500000*ampere**2*second**2) + + """ + return self.args[2] + + @property + def n(self): + return c*sqrt(self.permittivity*self.permeability) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/polarization.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/polarization.py new file mode 100644 index 0000000000000000000000000000000000000000..0bdb546548ad082ef38f5f0c159d7eadd38f6d30 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/polarization.py @@ -0,0 +1,732 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +The module implements routines to model the polarization of optical fields +and can be used to calculate the effects of polarization optical elements on +the fields. + +- Jones vectors. + +- Stokes vectors. + +- Jones matrices. + +- Mueller matrices. + +Examples +======== + +We calculate a generic Jones vector: + +>>> from sympy import symbols, pprint, zeros, simplify +>>> from sympy.physics.optics.polarization import (jones_vector, stokes_vector, +... half_wave_retarder, polarizing_beam_splitter, jones_2_stokes) + +>>> psi, chi, p, I0 = symbols("psi, chi, p, I0", real=True) +>>> x0 = jones_vector(psi, chi) +>>> pprint(x0, use_unicode=True) +⎡-ⅈ⋅sin(χ)⋅sin(ψ) + cos(χ)⋅cos(ψ)⎤ +⎢ ⎥ +⎣ⅈ⋅sin(χ)⋅cos(ψ) + sin(ψ)⋅cos(χ) ⎦ + +And the more general Stokes vector: + +>>> s0 = stokes_vector(psi, chi, p, I0) +>>> pprint(s0, use_unicode=True) +⎡ I₀ ⎤ +⎢ ⎥ +⎢I₀⋅p⋅cos(2⋅χ)⋅cos(2⋅ψ)⎥ +⎢ ⎥ +⎢I₀⋅p⋅sin(2⋅ψ)⋅cos(2⋅χ)⎥ +⎢ ⎥ +⎣ I₀⋅p⋅sin(2⋅χ) ⎦ + +We calculate how the Jones vector is modified by a half-wave plate: + +>>> alpha = symbols("alpha", real=True) +>>> HWP = half_wave_retarder(alpha) +>>> x1 = simplify(HWP*x0) + +We calculate the very common operation of passing a beam through a half-wave +plate and then through a polarizing beam-splitter. We do this by putting this +Jones vector as the first entry of a two-Jones-vector state that is transformed +by a 4x4 Jones matrix modelling the polarizing beam-splitter to get the +transmitted and reflected Jones vectors: + +>>> PBS = polarizing_beam_splitter() +>>> X1 = zeros(4, 1) +>>> X1[:2, :] = x1 +>>> X2 = PBS*X1 +>>> transmitted_port = X2[:2, :] +>>> reflected_port = X2[2:, :] + +This allows us to calculate how the power in both ports depends on the initial +polarization: + +>>> transmitted_power = jones_2_stokes(transmitted_port)[0] +>>> reflected_power = jones_2_stokes(reflected_port)[0] +>>> print(transmitted_power) +cos(-2*alpha + chi + psi)**2/2 + cos(2*alpha + chi - psi)**2/2 + + +>>> print(reflected_power) +sin(-2*alpha + chi + psi)**2/2 + sin(2*alpha + chi - psi)**2/2 + +Please see the description of the individual functions for further +details and examples. + +References +========== + +.. [1] https://en.wikipedia.org/wiki/Jones_calculus +.. [2] https://en.wikipedia.org/wiki/Mueller_calculus +.. [3] https://en.wikipedia.org/wiki/Stokes_parameters + +""" + +from sympy.core.numbers import (I, pi) +from sympy.functions.elementary.complexes import (Abs, im, re) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.matrices.dense import Matrix +from sympy.simplify.simplify import simplify +from sympy.physics.quantum import TensorProduct + + +def jones_vector(psi, chi): + """A Jones vector corresponding to a polarization ellipse with `psi` tilt, + and `chi` circularity. + + Parameters + ========== + + psi : numeric type or SymPy Symbol + The tilt of the polarization relative to the `x` axis. + + chi : numeric type or SymPy Symbol + The angle adjacent to the mayor axis of the polarization ellipse. + + + Returns + ======= + + Matrix : + A Jones vector. + + Examples + ======== + + The axes on the Poincaré sphere. + + >>> from sympy import pprint, symbols, pi + >>> from sympy.physics.optics.polarization import jones_vector + >>> psi, chi = symbols("psi, chi", real=True) + + A general Jones vector. + + >>> pprint(jones_vector(psi, chi), use_unicode=True) + ⎡-ⅈ⋅sin(χ)⋅sin(ψ) + cos(χ)⋅cos(ψ)⎤ + ⎢ ⎥ + ⎣ⅈ⋅sin(χ)⋅cos(ψ) + sin(ψ)⋅cos(χ) ⎦ + + Horizontal polarization. + + >>> pprint(jones_vector(0, 0), use_unicode=True) + ⎡1⎤ + ⎢ ⎥ + ⎣0⎦ + + Vertical polarization. + + >>> pprint(jones_vector(pi/2, 0), use_unicode=True) + ⎡0⎤ + ⎢ ⎥ + ⎣1⎦ + + Diagonal polarization. + + >>> pprint(jones_vector(pi/4, 0), use_unicode=True) + ⎡√2⎤ + ⎢──⎥ + ⎢2 ⎥ + ⎢ ⎥ + ⎢√2⎥ + ⎢──⎥ + ⎣2 ⎦ + + Anti-diagonal polarization. + + >>> pprint(jones_vector(-pi/4, 0), use_unicode=True) + ⎡ √2 ⎤ + ⎢ ── ⎥ + ⎢ 2 ⎥ + ⎢ ⎥ + ⎢-√2 ⎥ + ⎢────⎥ + ⎣ 2 ⎦ + + Right-hand circular polarization. + + >>> pprint(jones_vector(0, pi/4), use_unicode=True) + ⎡ √2 ⎤ + ⎢ ── ⎥ + ⎢ 2 ⎥ + ⎢ ⎥ + ⎢√2⋅ⅈ⎥ + ⎢────⎥ + ⎣ 2 ⎦ + + Left-hand circular polarization. + + >>> pprint(jones_vector(0, -pi/4), use_unicode=True) + ⎡ √2 ⎤ + ⎢ ── ⎥ + ⎢ 2 ⎥ + ⎢ ⎥ + ⎢-√2⋅ⅈ ⎥ + ⎢──────⎥ + ⎣ 2 ⎦ + + """ + return Matrix([-I*sin(chi)*sin(psi) + cos(chi)*cos(psi), + I*sin(chi)*cos(psi) + sin(psi)*cos(chi)]) + + +def stokes_vector(psi, chi, p=1, I=1): + """A Stokes vector corresponding to a polarization ellipse with ``psi`` + tilt, and ``chi`` circularity. + + Parameters + ========== + + psi : numeric type or SymPy Symbol + The tilt of the polarization relative to the ``x`` axis. + chi : numeric type or SymPy Symbol + The angle adjacent to the mayor axis of the polarization ellipse. + p : numeric type or SymPy Symbol + The degree of polarization. + I : numeric type or SymPy Symbol + The intensity of the field. + + + Returns + ======= + + Matrix : + A Stokes vector. + + Examples + ======== + + The axes on the Poincaré sphere. + + >>> from sympy import pprint, symbols, pi + >>> from sympy.physics.optics.polarization import stokes_vector + >>> psi, chi, p, I = symbols("psi, chi, p, I", real=True) + >>> pprint(stokes_vector(psi, chi, p, I), use_unicode=True) + ⎡ I ⎤ + ⎢ ⎥ + ⎢I⋅p⋅cos(2⋅χ)⋅cos(2⋅ψ)⎥ + ⎢ ⎥ + ⎢I⋅p⋅sin(2⋅ψ)⋅cos(2⋅χ)⎥ + ⎢ ⎥ + ⎣ I⋅p⋅sin(2⋅χ) ⎦ + + + Horizontal polarization + + >>> pprint(stokes_vector(0, 0), use_unicode=True) + ⎡1⎤ + ⎢ ⎥ + ⎢1⎥ + ⎢ ⎥ + ⎢0⎥ + ⎢ ⎥ + ⎣0⎦ + + Vertical polarization + + >>> pprint(stokes_vector(pi/2, 0), use_unicode=True) + ⎡1 ⎤ + ⎢ ⎥ + ⎢-1⎥ + ⎢ ⎥ + ⎢0 ⎥ + ⎢ ⎥ + ⎣0 ⎦ + + Diagonal polarization + + >>> pprint(stokes_vector(pi/4, 0), use_unicode=True) + ⎡1⎤ + ⎢ ⎥ + ⎢0⎥ + ⎢ ⎥ + ⎢1⎥ + ⎢ ⎥ + ⎣0⎦ + + Anti-diagonal polarization + + >>> pprint(stokes_vector(-pi/4, 0), use_unicode=True) + ⎡1 ⎤ + ⎢ ⎥ + ⎢0 ⎥ + ⎢ ⎥ + ⎢-1⎥ + ⎢ ⎥ + ⎣0 ⎦ + + Right-hand circular polarization + + >>> pprint(stokes_vector(0, pi/4), use_unicode=True) + ⎡1⎤ + ⎢ ⎥ + ⎢0⎥ + ⎢ ⎥ + ⎢0⎥ + ⎢ ⎥ + ⎣1⎦ + + Left-hand circular polarization + + >>> pprint(stokes_vector(0, -pi/4), use_unicode=True) + ⎡1 ⎤ + ⎢ ⎥ + ⎢0 ⎥ + ⎢ ⎥ + ⎢0 ⎥ + ⎢ ⎥ + ⎣-1⎦ + + Unpolarized light + + >>> pprint(stokes_vector(0, 0, 0), use_unicode=True) + ⎡1⎤ + ⎢ ⎥ + ⎢0⎥ + ⎢ ⎥ + ⎢0⎥ + ⎢ ⎥ + ⎣0⎦ + + """ + S0 = I + S1 = I*p*cos(2*psi)*cos(2*chi) + S2 = I*p*sin(2*psi)*cos(2*chi) + S3 = I*p*sin(2*chi) + return Matrix([S0, S1, S2, S3]) + + +def jones_2_stokes(e): + """Return the Stokes vector for a Jones vector ``e``. + + Parameters + ========== + + e : SymPy Matrix + A Jones vector. + + Returns + ======= + + SymPy Matrix + A Jones vector. + + Examples + ======== + + The axes on the Poincaré sphere. + + >>> from sympy import pprint, pi + >>> from sympy.physics.optics.polarization import jones_vector + >>> from sympy.physics.optics.polarization import jones_2_stokes + >>> H = jones_vector(0, 0) + >>> V = jones_vector(pi/2, 0) + >>> D = jones_vector(pi/4, 0) + >>> A = jones_vector(-pi/4, 0) + >>> R = jones_vector(0, pi/4) + >>> L = jones_vector(0, -pi/4) + >>> pprint([jones_2_stokes(e) for e in [H, V, D, A, R, L]], + ... use_unicode=True) + ⎡⎡1⎤ ⎡1 ⎤ ⎡1⎤ ⎡1 ⎤ ⎡1⎤ ⎡1 ⎤⎤ + ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ + ⎢⎢1⎥ ⎢-1⎥ ⎢0⎥ ⎢0 ⎥ ⎢0⎥ ⎢0 ⎥⎥ + ⎢⎢ ⎥, ⎢ ⎥, ⎢ ⎥, ⎢ ⎥, ⎢ ⎥, ⎢ ⎥⎥ + ⎢⎢0⎥ ⎢0 ⎥ ⎢1⎥ ⎢-1⎥ ⎢0⎥ ⎢0 ⎥⎥ + ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ + ⎣⎣0⎦ ⎣0 ⎦ ⎣0⎦ ⎣0 ⎦ ⎣1⎦ ⎣-1⎦⎦ + + """ + ex, ey = e + return Matrix([Abs(ex)**2 + Abs(ey)**2, + Abs(ex)**2 - Abs(ey)**2, + 2*re(ex*ey.conjugate()), + -2*im(ex*ey.conjugate())]) + + +def linear_polarizer(theta=0): + """A linear polarizer Jones matrix with transmission axis at + an angle ``theta``. + + Parameters + ========== + + theta : numeric type or SymPy Symbol + The angle of the transmission axis relative to the horizontal plane. + + Returns + ======= + + SymPy Matrix + A Jones matrix representing the polarizer. + + Examples + ======== + + A generic polarizer. + + >>> from sympy import pprint, symbols + >>> from sympy.physics.optics.polarization import linear_polarizer + >>> theta = symbols("theta", real=True) + >>> J = linear_polarizer(theta) + >>> pprint(J, use_unicode=True) + ⎡ 2 ⎤ + ⎢ cos (θ) sin(θ)⋅cos(θ)⎥ + ⎢ ⎥ + ⎢ 2 ⎥ + ⎣sin(θ)⋅cos(θ) sin (θ) ⎦ + + + """ + M = Matrix([[cos(theta)**2, sin(theta)*cos(theta)], + [sin(theta)*cos(theta), sin(theta)**2]]) + return M + + +def phase_retarder(theta=0, delta=0): + """A phase retarder Jones matrix with retardance ``delta`` at angle ``theta``. + + Parameters + ========== + + theta : numeric type or SymPy Symbol + The angle of the fast axis relative to the horizontal plane. + delta : numeric type or SymPy Symbol + The phase difference between the fast and slow axes of the + transmitted light. + + Returns + ======= + + SymPy Matrix : + A Jones matrix representing the retarder. + + Examples + ======== + + A generic retarder. + + >>> from sympy import pprint, symbols + >>> from sympy.physics.optics.polarization import phase_retarder + >>> theta, delta = symbols("theta, delta", real=True) + >>> R = phase_retarder(theta, delta) + >>> pprint(R, use_unicode=True) + ⎡ -ⅈ⋅δ -ⅈ⋅δ ⎤ + ⎢ ───── ───── ⎥ + ⎢⎛ ⅈ⋅δ 2 2 ⎞ 2 ⎛ ⅈ⋅δ⎞ 2 ⎥ + ⎢⎝ℯ ⋅sin (θ) + cos (θ)⎠⋅ℯ ⎝1 - ℯ ⎠⋅ℯ ⋅sin(θ)⋅cos(θ)⎥ + ⎢ ⎥ + ⎢ -ⅈ⋅δ -ⅈ⋅δ ⎥ + ⎢ ───── ─────⎥ + ⎢⎛ ⅈ⋅δ⎞ 2 ⎛ ⅈ⋅δ 2 2 ⎞ 2 ⎥ + ⎣⎝1 - ℯ ⎠⋅ℯ ⋅sin(θ)⋅cos(θ) ⎝ℯ ⋅cos (θ) + sin (θ)⎠⋅ℯ ⎦ + + """ + R = Matrix([[cos(theta)**2 + exp(I*delta)*sin(theta)**2, + (1-exp(I*delta))*cos(theta)*sin(theta)], + [(1-exp(I*delta))*cos(theta)*sin(theta), + sin(theta)**2 + exp(I*delta)*cos(theta)**2]]) + return R*exp(-I*delta/2) + + +def half_wave_retarder(theta): + """A half-wave retarder Jones matrix at angle ``theta``. + + Parameters + ========== + + theta : numeric type or SymPy Symbol + The angle of the fast axis relative to the horizontal plane. + + Returns + ======= + + SymPy Matrix + A Jones matrix representing the retarder. + + Examples + ======== + + A generic half-wave plate. + + >>> from sympy import pprint, symbols + >>> from sympy.physics.optics.polarization import half_wave_retarder + >>> theta= symbols("theta", real=True) + >>> HWP = half_wave_retarder(theta) + >>> pprint(HWP, use_unicode=True) + ⎡ ⎛ 2 2 ⎞ ⎤ + ⎢-ⅈ⋅⎝- sin (θ) + cos (θ)⎠ -2⋅ⅈ⋅sin(θ)⋅cos(θ) ⎥ + ⎢ ⎥ + ⎢ ⎛ 2 2 ⎞⎥ + ⎣ -2⋅ⅈ⋅sin(θ)⋅cos(θ) -ⅈ⋅⎝sin (θ) - cos (θ)⎠⎦ + + """ + return phase_retarder(theta, pi) + + +def quarter_wave_retarder(theta): + """A quarter-wave retarder Jones matrix at angle ``theta``. + + Parameters + ========== + + theta : numeric type or SymPy Symbol + The angle of the fast axis relative to the horizontal plane. + + Returns + ======= + + SymPy Matrix + A Jones matrix representing the retarder. + + Examples + ======== + + A generic quarter-wave plate. + + >>> from sympy import pprint, symbols + >>> from sympy.physics.optics.polarization import quarter_wave_retarder + >>> theta= symbols("theta", real=True) + >>> QWP = quarter_wave_retarder(theta) + >>> pprint(QWP, use_unicode=True) + ⎡ -ⅈ⋅π -ⅈ⋅π ⎤ + ⎢ ───── ───── ⎥ + ⎢⎛ 2 2 ⎞ 4 4 ⎥ + ⎢⎝ⅈ⋅sin (θ) + cos (θ)⎠⋅ℯ (1 - ⅈ)⋅ℯ ⋅sin(θ)⋅cos(θ)⎥ + ⎢ ⎥ + ⎢ -ⅈ⋅π -ⅈ⋅π ⎥ + ⎢ ───── ─────⎥ + ⎢ 4 ⎛ 2 2 ⎞ 4 ⎥ + ⎣(1 - ⅈ)⋅ℯ ⋅sin(θ)⋅cos(θ) ⎝sin (θ) + ⅈ⋅cos (θ)⎠⋅ℯ ⎦ + + """ + return phase_retarder(theta, pi/2) + + +def transmissive_filter(T): + """An attenuator Jones matrix with transmittance ``T``. + + Parameters + ========== + + T : numeric type or SymPy Symbol + The transmittance of the attenuator. + + Returns + ======= + + SymPy Matrix + A Jones matrix representing the filter. + + Examples + ======== + + A generic filter. + + >>> from sympy import pprint, symbols + >>> from sympy.physics.optics.polarization import transmissive_filter + >>> T = symbols("T", real=True) + >>> NDF = transmissive_filter(T) + >>> pprint(NDF, use_unicode=True) + ⎡√T 0 ⎤ + ⎢ ⎥ + ⎣0 √T⎦ + + """ + return Matrix([[sqrt(T), 0], [0, sqrt(T)]]) + + +def reflective_filter(R): + """A reflective filter Jones matrix with reflectance ``R``. + + Parameters + ========== + + R : numeric type or SymPy Symbol + The reflectance of the filter. + + Returns + ======= + + SymPy Matrix + A Jones matrix representing the filter. + + Examples + ======== + + A generic filter. + + >>> from sympy import pprint, symbols + >>> from sympy.physics.optics.polarization import reflective_filter + >>> R = symbols("R", real=True) + >>> pprint(reflective_filter(R), use_unicode=True) + ⎡√R 0 ⎤ + ⎢ ⎥ + ⎣0 -√R⎦ + + """ + return Matrix([[sqrt(R), 0], [0, -sqrt(R)]]) + + +def mueller_matrix(J): + """The Mueller matrix corresponding to Jones matrix `J`. + + Parameters + ========== + + J : SymPy Matrix + A Jones matrix. + + Returns + ======= + + SymPy Matrix + The corresponding Mueller matrix. + + Examples + ======== + + Generic optical components. + + >>> from sympy import pprint, symbols + >>> from sympy.physics.optics.polarization import (mueller_matrix, + ... linear_polarizer, half_wave_retarder, quarter_wave_retarder) + >>> theta = symbols("theta", real=True) + + A linear_polarizer + + >>> pprint(mueller_matrix(linear_polarizer(theta)), use_unicode=True) + ⎡ cos(2⋅θ) sin(2⋅θ) ⎤ + ⎢ 1/2 ──────── ──────── 0⎥ + ⎢ 2 2 ⎥ + ⎢ ⎥ + ⎢cos(2⋅θ) cos(4⋅θ) 1 sin(4⋅θ) ⎥ + ⎢──────── ──────── + ─ ──────── 0⎥ + ⎢ 2 4 4 4 ⎥ + ⎢ ⎥ + ⎢sin(2⋅θ) sin(4⋅θ) 1 cos(4⋅θ) ⎥ + ⎢──────── ──────── ─ - ──────── 0⎥ + ⎢ 2 4 4 4 ⎥ + ⎢ ⎥ + ⎣ 0 0 0 0⎦ + + A half-wave plate + + >>> pprint(mueller_matrix(half_wave_retarder(theta)), use_unicode=True) + ⎡1 0 0 0 ⎤ + ⎢ ⎥ + ⎢ 4 2 ⎥ + ⎢0 8⋅sin (θ) - 8⋅sin (θ) + 1 sin(4⋅θ) 0 ⎥ + ⎢ ⎥ + ⎢ 4 2 ⎥ + ⎢0 sin(4⋅θ) - 8⋅sin (θ) + 8⋅sin (θ) - 1 0 ⎥ + ⎢ ⎥ + ⎣0 0 0 -1⎦ + + A quarter-wave plate + + >>> pprint(mueller_matrix(quarter_wave_retarder(theta)), use_unicode=True) + ⎡1 0 0 0 ⎤ + ⎢ ⎥ + ⎢ cos(4⋅θ) 1 sin(4⋅θ) ⎥ + ⎢0 ──────── + ─ ──────── -sin(2⋅θ)⎥ + ⎢ 2 2 2 ⎥ + ⎢ ⎥ + ⎢ sin(4⋅θ) 1 cos(4⋅θ) ⎥ + ⎢0 ──────── ─ - ──────── cos(2⋅θ) ⎥ + ⎢ 2 2 2 ⎥ + ⎢ ⎥ + ⎣0 sin(2⋅θ) -cos(2⋅θ) 0 ⎦ + + """ + A = Matrix([[1, 0, 0, 1], + [1, 0, 0, -1], + [0, 1, 1, 0], + [0, -I, I, 0]]) + + return simplify(A*TensorProduct(J, J.conjugate())*A.inv()) + + +def polarizing_beam_splitter(Tp=1, Rs=1, Ts=0, Rp=0, phia=0, phib=0): + r"""A polarizing beam splitter Jones matrix at angle `theta`. + + Parameters + ========== + + J : SymPy Matrix + A Jones matrix. + Tp : numeric type or SymPy Symbol + The transmissivity of the P-polarized component. + Rs : numeric type or SymPy Symbol + The reflectivity of the S-polarized component. + Ts : numeric type or SymPy Symbol + The transmissivity of the S-polarized component. + Rp : numeric type or SymPy Symbol + The reflectivity of the P-polarized component. + phia : numeric type or SymPy Symbol + The phase difference between transmitted and reflected component for + output mode a. + phib : numeric type or SymPy Symbol + The phase difference between transmitted and reflected component for + output mode b. + + + Returns + ======= + + SymPy Matrix + A 4x4 matrix representing the PBS. This matrix acts on a 4x1 vector + whose first two entries are the Jones vector on one of the PBS ports, + and the last two entries the Jones vector on the other port. + + Examples + ======== + + Generic polarizing beam-splitter. + + >>> from sympy import pprint, symbols + >>> from sympy.physics.optics.polarization import polarizing_beam_splitter + >>> Ts, Rs, Tp, Rp = symbols(r"Ts, Rs, Tp, Rp", positive=True) + >>> phia, phib = symbols("phi_a, phi_b", real=True) + >>> PBS = polarizing_beam_splitter(Tp, Rs, Ts, Rp, phia, phib) + >>> pprint(PBS, use_unicode=False) + [ ____ ____ ] + [ \/ Tp 0 I*\/ Rp 0 ] + [ ] + [ ____ ____ I*phi_a] + [ 0 \/ Ts 0 -I*\/ Rs *e ] + [ ] + [ ____ ____ ] + [I*\/ Rp 0 \/ Tp 0 ] + [ ] + [ ____ I*phi_b ____ ] + [ 0 -I*\/ Rs *e 0 \/ Ts ] + + """ + PBS = Matrix([[sqrt(Tp), 0, I*sqrt(Rp), 0], + [0, sqrt(Ts), 0, -I*sqrt(Rs)*exp(I*phia)], + [I*sqrt(Rp), 0, sqrt(Tp), 0], + [0, -I*sqrt(Rs)*exp(I*phib), 0, sqrt(Ts)]]) + return PBS diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8db36c4d79f74d5f9ae67c52fc1d44ef28ef2e95 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_gaussopt.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_gaussopt.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc067dfd5ecb68d3886c1f69391ac4b98c59ec8b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_gaussopt.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_medium.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_medium.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a515594433aa7351a5a1bdddb3008d5dd2ef545 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_medium.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_polarization.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_polarization.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ac71359c161d93a308888f123d491736ca33a3b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_polarization.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_utils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..081a897a495e5ab519493cdf7a733de60bb9492c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_utils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_waves.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_waves.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34c7401ba811743eea4c9862c432e0f8d95f64c8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/__pycache__/test_waves.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_gaussopt.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_gaussopt.py new file mode 100644 index 0000000000000000000000000000000000000000..5271f3cbb69cf5de861ff332d36418b79daeb1b5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_gaussopt.py @@ -0,0 +1,102 @@ +from sympy.core.evalf import N +from sympy.core.numbers import (Float, I, oo, pi) +from sympy.core.symbol import symbols +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import atan2 +from sympy.matrices.dense import Matrix +from sympy.polys.polytools import factor + +from sympy.physics.optics import (BeamParameter, CurvedMirror, + CurvedRefraction, FlatMirror, FlatRefraction, FreeSpace, GeometricRay, + RayTransferMatrix, ThinLens, conjugate_gauss_beams, + 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]]) ) + 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') + lens = ThinLens(f) + 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 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] + + 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 + + p = BeamParameter(530e-9, 1, w=1e-3) + assert streq(p.q, 1 + 1.88679245283019*I*pi) + assert streq(N(p.q), 1.0 + 5.92753330865999*I) + assert streq(N(p.w_0), Float(0.00100000000000000)) + assert streq(N(p.z_r), Float(5.92753330865999)) + fs = FreeSpace(10) + p1 = fs*p + assert streq(N(p.w), Float(0.00101413072159615)) + assert streq(N(p1.w), Float(0.00210803120913829)) + + w, wavelen = symbols('w wavelen') + assert waist2rayleigh(w, wavelen) == pi*w**2/wavelen + z_r, wavelen = symbols('z_r wavelen') + assert rayleigh2waist(z_r, wavelen) == sqrt(wavelen*z_r)/sqrt(pi) + + a, b, f = symbols('a b f') + assert geometric_conj_ab(a, b) == a*b/(a + b) + assert geometric_conj_af(a, f) == a*f/(a - f) + assert geometric_conj_bf(b, f) == b*f/(b - f) + assert geometric_conj_ab(oo, b) == b + 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) + + 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)[2] == f + + z, l, w_0 = symbols('z l w_0', positive=True) + p = BeamParameter(l, z, w=w_0) + assert p.radius == z*(pi**2*w_0**4/(l**2*z**2) + 1) + assert p.w == w_0*sqrt(l**2*z**2/(pi**2*w_0**4) + 1) + assert p.w_0 == w_0 + assert p.divergence == l/(pi*w_0) + assert p.gouy == atan2(z, pi*w_0**2/l) + assert p.waist_approximation_limit == 2*l/pi + + p = BeamParameter(530e-9, 1, w=1e-3, n=2) + assert streq(p.q, 1 + 3.77358490566038*I*pi) + assert streq(N(p.z_r), Float(11.8550666173200)) + assert streq(N(p.w_0), Float(0.00100000000000000)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_medium.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_medium.py new file mode 100644 index 0000000000000000000000000000000000000000..dfbb485f5b8e401f38c7f1cfa573f960a2479d7b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_medium.py @@ -0,0 +1,48 @@ +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.physics.optics import Medium +from sympy.abc import epsilon, mu, n +from sympy.physics.units import speed_of_light, u0, e0, m, kg, s, A + +from sympy.testing.pytest import raises + +c = speed_of_light.convert_to(m/s) +e0 = e0.convert_to(A**2*s**4/(kg*m**3)) +u0 = u0.convert_to(m*kg/(A**2*s**2)) + + +def test_medium(): + m1 = Medium('m1') + assert m1.intrinsic_impedance == sqrt(u0/e0) + assert m1.speed == 1/sqrt(e0*u0) + assert m1.refractive_index == c*sqrt(e0*u0) + assert m1.permittivity == e0 + assert m1.permeability == u0 + m2 = Medium('m2', epsilon, mu) + assert m2.intrinsic_impedance == sqrt(mu/epsilon) + assert m2.speed == 1/sqrt(epsilon*mu) + assert m2.refractive_index == c*sqrt(epsilon*mu) + assert m2.permittivity == epsilon + assert m2.permeability == mu + # Increasing electric permittivity and magnetic permeability + # by small amount from its value in vacuum. + m3 = Medium('m3', 9.0*10**(-12)*s**4*A**2/(m**3*kg), 1.45*10**(-6)*kg*m/(A**2*s**2)) + assert m3.refractive_index > m1.refractive_index + assert m3 != m1 + # Decreasing electric permittivity and magnetic permeability + # by small amount from its value in vacuum. + m4 = Medium('m4', 7.0*10**(-12)*s**4*A**2/(m**3*kg), 1.15*10**(-6)*kg*m/(A**2*s**2)) + assert m4.refractive_index < m1.refractive_index + m5 = Medium('m5', permittivity=710*10**(-12)*s**4*A**2/(m**3*kg), n=1.33) + assert abs(m5.intrinsic_impedance - 6.24845417765552*kg*m**2/(A**2*s**3)) \ + < 1e-12*kg*m**2/(A**2*s**3) + assert abs(m5.speed - 225407863.157895*m/s) < 1e-6*m/s + assert abs(m5.refractive_index - 1.33000000000000) < 1e-12 + assert abs(m5.permittivity - 7.1e-10*A**2*s**4/(kg*m**3)) \ + < 1e-20*A**2*s**4/(kg*m**3) + assert abs(m5.permeability - 2.77206575232851e-8*kg*m/(A**2*s**2)) \ + < 1e-20*kg*m/(A**2*s**2) + m6 = Medium('m6', None, mu, n) + assert m6.permittivity == n**2/(c**2*mu) + # test for equality of refractive indices + assert Medium('m7').refractive_index == Medium('m8', e0, u0).refractive_index + raises(ValueError, lambda:Medium('m9', e0, u0, 2)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_polarization.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_polarization.py new file mode 100644 index 0000000000000000000000000000000000000000..99c595d82a4a296066d5075f6182895a8de54d91 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_polarization.py @@ -0,0 +1,57 @@ +from sympy.physics.optics.polarization import (jones_vector, stokes_vector, + jones_2_stokes, linear_polarizer, phase_retarder, half_wave_retarder, + quarter_wave_retarder, transmissive_filter, reflective_filter, + mueller_matrix, polarizing_beam_splitter) +from sympy.core.numbers import (I, pi) +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import exp +from sympy.matrices.dense import Matrix + + +def test_polarization(): + assert jones_vector(0, 0) == Matrix([1, 0]) + assert jones_vector(pi/2, 0) == Matrix([0, 1]) + ################################################################# + assert stokes_vector(0, 0) == Matrix([1, 1, 0, 0]) + assert stokes_vector(pi/2, 0) == Matrix([1, -1, 0, 0]) + ################################################################# + H = jones_vector(0, 0) + V = jones_vector(pi/2, 0) + D = jones_vector(pi/4, 0) + A = jones_vector(-pi/4, 0) + R = jones_vector(0, pi/4) + L = jones_vector(0, -pi/4) + + res = [Matrix([1, 1, 0, 0]), + Matrix([1, -1, 0, 0]), + Matrix([1, 0, 1, 0]), + Matrix([1, 0, -1, 0]), + Matrix([1, 0, 0, 1]), + Matrix([1, 0, 0, -1])] + + assert [jones_2_stokes(e) for e in [H, V, D, A, R, L]] == res + ################################################################# + assert linear_polarizer(0) == Matrix([[1, 0], [0, 0]]) + ################################################################# + delta = symbols("delta", real=True) + res = Matrix([[exp(-I*delta/2), 0], [0, exp(I*delta/2)]]) + assert phase_retarder(0, delta) == res + ################################################################# + assert half_wave_retarder(0) == Matrix([[-I, 0], [0, I]]) + ################################################################# + res = Matrix([[exp(-I*pi/4), 0], [0, I*exp(-I*pi/4)]]) + assert quarter_wave_retarder(0) == res + ################################################################# + assert transmissive_filter(1) == Matrix([[1, 0], [0, 1]]) + ################################################################# + assert reflective_filter(1) == Matrix([[1, 0], [0, -1]]) + + res = Matrix([[S(1)/2, S(1)/2, 0, 0], + [S(1)/2, S(1)/2, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0]]) + assert mueller_matrix(linear_polarizer(0)) == res + ################################################################# + res = Matrix([[1, 0, 0, 0], [0, 0, 0, -I], [0, 0, 1, 0], [0, -I, 0, 0]]) + assert polarizing_beam_splitter() == res diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_utils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..6c93883a081d3614a604aeadc8a4b617181de669 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_utils.py @@ -0,0 +1,202 @@ +from sympy.core.numbers import comp, Rational +from sympy.physics.optics.utils import (refraction_angle, fresnel_coefficients, + deviation, brewster_angle, critical_angle, lens_makers_formula, + mirror_formula, lens_formula, hyperfocal_distance, + transverse_magnification) +from sympy.physics.optics.medium import Medium +from sympy.physics.units import e0 + +from sympy.core.numbers import oo +from sympy.core.symbol import symbols +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices.dense import Matrix +from sympy.geometry.point import Point3D +from sympy.geometry.line import Ray3D +from sympy.geometry.plane import Plane + +from sympy.testing.pytest import raises + + +ae = lambda a, b, n: comp(a, b, 10**-n) + + +def test_refraction_angle(): + n1, n2 = symbols('n1, n2') + m1 = Medium('m1') + m2 = Medium('m2') + r1 = Ray3D(Point3D(-1, -1, 1), Point3D(0, 0, 0)) + i = Matrix([1, 1, 1]) + n = Matrix([0, 0, 1]) + normal_ray = Ray3D(Point3D(0, 0, 0), Point3D(0, 0, 1)) + P = Plane(Point3D(0, 0, 0), normal_vector=[0, 0, 1]) + assert refraction_angle(r1, 1, 1, n) == Matrix([ + [ 1], + [ 1], + [-1]]) + assert refraction_angle([1, 1, 1], 1, 1, n) == Matrix([ + [ 1], + [ 1], + [-1]]) + assert refraction_angle((1, 1, 1), 1, 1, n) == Matrix([ + [ 1], + [ 1], + [-1]]) + assert refraction_angle(i, 1, 1, [0, 0, 1]) == Matrix([ + [ 1], + [ 1], + [-1]]) + assert refraction_angle(i, 1, 1, (0, 0, 1)) == Matrix([ + [ 1], + [ 1], + [-1]]) + assert refraction_angle(i, 1, 1, normal_ray) == Matrix([ + [ 1], + [ 1], + [-1]]) + assert refraction_angle(i, 1, 1, plane=P) == Matrix([ + [ 1], + [ 1], + [-1]]) + assert refraction_angle(r1, 1, 1, plane=P) == \ + Ray3D(Point3D(0, 0, 0), Point3D(1, 1, -1)) + assert refraction_angle(r1, m1, 1.33, plane=P) == \ + Ray3D(Point3D(0, 0, 0), Point3D(Rational(100, 133), Rational(100, 133), -789378201649271*sqrt(3)/1000000000000000)) + assert refraction_angle(r1, 1, m2, plane=P) == \ + Ray3D(Point3D(0, 0, 0), Point3D(1, 1, -1)) + assert refraction_angle(r1, n1, n2, plane=P) == \ + Ray3D(Point3D(0, 0, 0), Point3D(n1/n2, n1/n2, -sqrt(3)*sqrt(-2*n1**2/(3*n2**2) + 1))) + assert refraction_angle(r1, 1.33, 1, plane=P) == 0 # TIR + assert refraction_angle(r1, 1, 1, normal_ray) == \ + Ray3D(Point3D(0, 0, 0), direction_ratio=[1, 1, -1]) + assert ae(refraction_angle(0.5, 1, 2), 0.24207, 5) + assert ae(refraction_angle(0.5, 2, 1), 1.28293, 5) + raises(ValueError, lambda: refraction_angle(r1, m1, m2, normal_ray, P)) + raises(TypeError, lambda: refraction_angle(m1, m1, m2)) # can add other values for arg[0] + raises(TypeError, lambda: refraction_angle(r1, m1, m2, None, i)) + raises(TypeError, lambda: refraction_angle(r1, m1, m2, m2)) + + +def test_fresnel_coefficients(): + assert all(ae(i, j, 5) for i, j in zip( + fresnel_coefficients(0.5, 1, 1.33), + [0.11163, -0.17138, 0.83581, 0.82862])) + assert all(ae(i, j, 5) for i, j in zip( + fresnel_coefficients(0.5, 1.33, 1), + [-0.07726, 0.20482, 1.22724, 1.20482])) + m1 = Medium('m1') + m2 = Medium('m2', n=2) + assert all(ae(i, j, 5) for i, j in zip( + fresnel_coefficients(0.3, m1, m2), + [0.31784, -0.34865, 0.65892, 0.65135])) + ans = [[-0.23563, -0.97184], [0.81648, -0.57738]] + got = fresnel_coefficients(0.6, m2, m1) + for i, j in zip(got, ans): + for a, b in zip(i.as_real_imag(), j): + assert ae(a, b, 5) + + +def test_deviation(): + n1, n2 = symbols('n1, n2') + r1 = Ray3D(Point3D(-1, -1, 1), Point3D(0, 0, 0)) + n = Matrix([0, 0, 1]) + i = Matrix([-1, -1, -1]) + normal_ray = Ray3D(Point3D(0, 0, 0), Point3D(0, 0, 1)) + P = Plane(Point3D(0, 0, 0), normal_vector=[0, 0, 1]) + assert deviation(r1, 1, 1, normal=n) == 0 + assert deviation(r1, 1, 1, plane=P) == 0 + assert deviation(r1, 1, 1.1, plane=P).evalf(3) + 0.119 < 1e-3 + assert deviation(i, 1, 1.1, normal=normal_ray).evalf(3) + 0.119 < 1e-3 + assert deviation(r1, 1.33, 1, plane=P) is None # TIR + assert deviation(r1, 1, 1, normal=[0, 0, 1]) == 0 + assert deviation([-1, -1, -1], 1, 1, normal=[0, 0, 1]) == 0 + assert ae(deviation(0.5, 1, 2), -0.25793, 5) + assert ae(deviation(0.5, 2, 1), 0.78293, 5) + + +def test_brewster_angle(): + m1 = Medium('m1', n=1) + m2 = Medium('m2', n=1.33) + assert ae(brewster_angle(m1, m2), 0.93, 2) + m1 = Medium('m1', permittivity=e0, n=1) + m2 = Medium('m2', permittivity=e0, n=1.33) + assert ae(brewster_angle(m1, m2), 0.93, 2) + assert ae(brewster_angle(1, 1.33), 0.93, 2) + + +def test_critical_angle(): + m1 = Medium('m1', n=1) + m2 = Medium('m2', n=1.33) + assert ae(critical_angle(m2, m1), 0.85, 2) + + +def test_lens_makers_formula(): + n1, n2 = symbols('n1, n2') + m1 = Medium('m1', permittivity=e0, n=1) + m2 = Medium('m2', permittivity=e0, n=1.33) + assert lens_makers_formula(n1, n2, 10, -10) == 5.0*n2/(n1 - n2) + assert ae(lens_makers_formula(m1, m2, 10, -10), -20.15, 2) + assert ae(lens_makers_formula(1.33, 1, 10, -10), 15.15, 2) + + +def test_mirror_formula(): + u, v, f = symbols('u, v, f') + assert mirror_formula(focal_length=f, u=u) == f*u/(-f + u) + assert mirror_formula(focal_length=f, v=v) == f*v/(-f + v) + assert mirror_formula(u=u, v=v) == u*v/(u + v) + assert mirror_formula(u=oo, v=v) == v + assert mirror_formula(u=oo, v=oo) is oo + assert mirror_formula(focal_length=oo, u=u) == -u + assert mirror_formula(u=u, v=oo) == u + assert mirror_formula(focal_length=oo, v=oo) is oo + assert mirror_formula(focal_length=f, v=oo) == f + assert mirror_formula(focal_length=oo, v=v) == -v + assert mirror_formula(focal_length=oo, u=oo) is oo + assert mirror_formula(focal_length=f, u=oo) == f + assert mirror_formula(focal_length=oo, u=u) == -u + raises(ValueError, lambda: mirror_formula(focal_length=f, u=u, v=v)) + + +def test_lens_formula(): + u, v, f = symbols('u, v, f') + assert lens_formula(focal_length=f, u=u) == f*u/(f + u) + assert lens_formula(focal_length=f, v=v) == f*v/(f - v) + assert lens_formula(u=u, v=v) == u*v/(u - v) + assert lens_formula(u=oo, v=v) == v + assert lens_formula(u=oo, v=oo) is oo + assert lens_formula(focal_length=oo, u=u) == u + assert lens_formula(u=u, v=oo) == -u + assert lens_formula(focal_length=oo, v=oo) is -oo + assert lens_formula(focal_length=oo, v=v) == v + assert lens_formula(focal_length=f, v=oo) == -f + assert lens_formula(focal_length=oo, u=oo) is oo + assert lens_formula(focal_length=oo, u=u) == u + assert lens_formula(focal_length=f, u=oo) == f + raises(ValueError, lambda: lens_formula(focal_length=f, u=u, v=v)) + + +def test_hyperfocal_distance(): + f, N, c = symbols('f, N, c') + assert hyperfocal_distance(f=f, N=N, c=c) == f**2/(N*c) + assert ae(hyperfocal_distance(f=0.5, N=8, c=0.0033), 9.47, 2) + + +def test_transverse_magnification(): + si, so = symbols('si, so') + assert transverse_magnification(si, so) == -si/so + assert transverse_magnification(30, 15) == -2 + + +def test_lens_makers_formula_thick_lens(): + n1, n2 = symbols('n1, n2') + m1 = Medium('m1', permittivity=e0, n=1) + m2 = Medium('m2', permittivity=e0, n=1.33) + assert ae(lens_makers_formula(m1, m2, 10, -10, d=1), -19.82, 2) + assert lens_makers_formula(n1, n2, 1, -1, d=0.1) == n2/((2.0 - (0.1*n1 - 0.1*n2)/n1)*(n1 - n2)) + + +def test_lens_makers_formula_plano_lens(): + n1, n2 = symbols('n1, n2') + m1 = Medium('m1', permittivity=e0, n=1) + m2 = Medium('m2', permittivity=e0, n=1.33) + assert ae(lens_makers_formula(m1, m2, 10, oo), -40.30, 2) + assert lens_makers_formula(n1, n2, 10, oo) == 10.0*n2/(n1 - n2) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_waves.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_waves.py new file mode 100644 index 0000000000000000000000000000000000000000..3cb8f804fb5be86d6174cb7c7b15fd8979c85ff8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/tests/test_waves.py @@ -0,0 +1,82 @@ +from sympy.core.function import (Derivative, Function) +from sympy.core.numbers import (I, pi) +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (atan2, cos, sin) +from sympy.simplify.simplify import simplify +from sympy.abc import epsilon, mu +from sympy.functions.elementary.exponential import exp +from sympy.physics.units import speed_of_light, m, s +from sympy.physics.optics import TWave + +from sympy.testing.pytest import raises + +c = speed_of_light.convert_to(m/s) + +def test_twave(): + A1, phi1, A2, phi2, f = symbols('A1, phi1, A2, phi2, f') + n = Symbol('n') # Refractive index + t = Symbol('t') # Time + x = Symbol('x') # Spatial variable + E = Function('E') + w1 = TWave(A1, f, phi1) + w2 = TWave(A2, f, phi2) + assert w1.amplitude == A1 + assert w1.frequency == f + assert w1.phase == phi1 + assert w1.wavelength == c/(f*n) + assert w1.time_period == 1/f + assert w1.angular_velocity == 2*pi*f + assert w1.wavenumber == 2*pi*f*n/c + assert w1.speed == c/n + + w3 = w1 + w2 + assert w3.amplitude == sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + A2**2) + assert w3.frequency == f + assert w3.phase == atan2(A1*sin(phi1) + A2*sin(phi2), A1*cos(phi1) + A2*cos(phi2)) + assert w3.wavelength == c/(f*n) + assert w3.time_period == 1/f + assert w3.angular_velocity == 2*pi*f + assert w3.wavenumber == 2*pi*f*n/c + assert w3.speed == c/n + assert simplify(w3.rewrite(sin) - w2.rewrite(sin) - w1.rewrite(sin)) == 0 + assert w3.rewrite('pde') == epsilon*mu*Derivative(E(x, t), t, t) + Derivative(E(x, t), x, x) + assert w3.rewrite(cos) == sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + + A2**2)*cos(pi*f*n*x*s/(149896229*m) - 2*pi*f*t + atan2(A1*sin(phi1) + + A2*sin(phi2), A1*cos(phi1) + A2*cos(phi2))) + assert w3.rewrite(exp) == sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + + A2**2)*exp(I*(-2*pi*f*t + atan2(A1*sin(phi1) + A2*sin(phi2), A1*cos(phi1) + + A2*cos(phi2)) + pi*s*f*n*x/(149896229*m))) + + w4 = TWave(A1, None, 0, 1/f) + assert w4.frequency == f + + w5 = w1 - w2 + assert w5.amplitude == sqrt(A1**2 - 2*A1*A2*cos(phi1 - phi2) + A2**2) + assert w5.frequency == f + assert w5.phase == atan2(A1*sin(phi1) - A2*sin(phi2), A1*cos(phi1) - A2*cos(phi2)) + assert w5.wavelength == c/(f*n) + assert w5.time_period == 1/f + assert w5.angular_velocity == 2*pi*f + assert w5.wavenumber == 2*pi*f*n/c + assert w5.speed == c/n + assert simplify(w5.rewrite(sin) - w1.rewrite(sin) + w2.rewrite(sin)) == 0 + assert w5.rewrite('pde') == epsilon*mu*Derivative(E(x, t), t, t) + Derivative(E(x, t), x, x) + assert w5.rewrite(cos) == sqrt(A1**2 - 2*A1*A2*cos(phi1 - phi2) + + A2**2)*cos(-2*pi*f*t + atan2(A1*sin(phi1) - A2*sin(phi2), A1*cos(phi1) + - A2*cos(phi2)) + pi*s*f*n*x/(149896229*m)) + assert w5.rewrite(exp) == sqrt(A1**2 - 2*A1*A2*cos(phi1 - phi2) + + A2**2)*exp(I*(-2*pi*f*t + atan2(A1*sin(phi1) - A2*sin(phi2), A1*cos(phi1) + - A2*cos(phi2)) + pi*s*f*n*x/(149896229*m))) + + w6 = 2*w1 + assert w6.amplitude == 2*A1 + assert w6.frequency == f + assert w6.phase == phi1 + w7 = -w6 + assert w7.amplitude == -2*A1 + assert w7.frequency == f + assert w7.phase == phi1 + + raises(ValueError, lambda:TWave(A1)) + raises(ValueError, lambda:TWave(A1, f, phi1, t)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/utils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..72c3b78bd4b09eb069757fb3f8d3632f09ec4b80 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/utils.py @@ -0,0 +1,698 @@ +""" +**Contains** + +* refraction_angle +* fresnel_coefficients +* deviation +* brewster_angle +* critical_angle +* lens_makers_formula +* mirror_formula +* lens_formula +* hyperfocal_distance +* transverse_magnification +""" + +__all__ = ['refraction_angle', + 'deviation', + 'fresnel_coefficients', + 'brewster_angle', + 'critical_angle', + 'lens_makers_formula', + 'mirror_formula', + 'lens_formula', + 'hyperfocal_distance', + 'transverse_magnification' + ] + +from sympy.core.numbers import (Float, I, oo, pi, zoo) +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (acos, asin, atan2, cos, sin, tan) +from sympy.matrices.dense import Matrix +from sympy.polys.polytools import cancel +from sympy.series.limits import Limit +from sympy.geometry.line import Ray3D +from sympy.geometry.util import intersection +from sympy.geometry.plane import Plane +from sympy.utilities.iterables import is_sequence +from .medium import Medium + + +def refractive_index_of_medium(medium): + """ + Helper function that returns refractive index, given a medium + """ + if isinstance(medium, Medium): + n = medium.refractive_index + else: + n = sympify(medium) + return n + + +def refraction_angle(incident, medium1, medium2, normal=None, plane=None): + """ + This function calculates transmitted vector after refraction at planar + surface. ``medium1`` and ``medium2`` can be ``Medium`` or any sympifiable object. + If ``incident`` is a number then treated as angle of incidence (in radians) + in which case refraction angle is returned. + + If ``incident`` is an object of `Ray3D`, `normal` also has to be an instance + of `Ray3D` in order to get the output as a `Ray3D`. Please note that if + plane of separation is not provided and normal is an instance of `Ray3D`, + ``normal`` will be assumed to be intersecting incident ray at the plane of + separation. This will not be the case when `normal` is a `Matrix` or + any other sequence. + If ``incident`` is an instance of `Ray3D` and `plane` has not been provided + and ``normal`` is not `Ray3D`, output will be a `Matrix`. + + Parameters + ========== + + incident : Matrix, Ray3D, sequence or a number + Incident vector or angle of incidence + medium1 : sympy.physics.optics.medium.Medium or sympifiable + Medium 1 or its refractive index + medium2 : sympy.physics.optics.medium.Medium or sympifiable + Medium 2 or its refractive index + normal : Matrix, Ray3D, or sequence + Normal vector + plane : Plane + Plane of separation of the two media. + + Returns + ======= + + Returns an angle of refraction or a refracted ray depending on inputs. + + Examples + ======== + + >>> from sympy.physics.optics import refraction_angle + >>> from sympy.geometry import Point3D, Ray3D, Plane + >>> from sympy.matrices import Matrix + >>> from sympy import symbols, pi + >>> n = Matrix([0, 0, 1]) + >>> P = Plane(Point3D(0, 0, 0), normal_vector=[0, 0, 1]) + >>> r1 = Ray3D(Point3D(-1, -1, 1), Point3D(0, 0, 0)) + >>> refraction_angle(r1, 1, 1, n) + Matrix([ + [ 1], + [ 1], + [-1]]) + >>> refraction_angle(r1, 1, 1, plane=P) + Ray3D(Point3D(0, 0, 0), Point3D(1, 1, -1)) + + With different index of refraction of the two media + + >>> n1, n2 = symbols('n1, n2') + >>> refraction_angle(r1, n1, n2, n) + Matrix([ + [ n1/n2], + [ n1/n2], + [-sqrt(3)*sqrt(-2*n1**2/(3*n2**2) + 1)]]) + >>> refraction_angle(r1, n1, n2, plane=P) + Ray3D(Point3D(0, 0, 0), Point3D(n1/n2, n1/n2, -sqrt(3)*sqrt(-2*n1**2/(3*n2**2) + 1))) + >>> round(refraction_angle(pi/6, 1.2, 1.5), 5) + 0.41152 + """ + + n1 = refractive_index_of_medium(medium1) + n2 = refractive_index_of_medium(medium2) + + # check if an incidence angle was supplied instead of a ray + try: + angle_of_incidence = float(incident) + except TypeError: + angle_of_incidence = None + + try: + critical_angle_ = critical_angle(medium1, medium2) + except (ValueError, TypeError): + critical_angle_ = None + + if angle_of_incidence is not None: + if normal is not None or plane is not None: + raise ValueError('Normal/plane not allowed if incident is an angle') + + if not 0.0 <= angle_of_incidence < pi*0.5: + raise ValueError('Angle of incidence not in range [0:pi/2)') + + if critical_angle_ and angle_of_incidence > critical_angle_: + raise ValueError('Ray undergoes total internal reflection') + return asin(n1*sin(angle_of_incidence)/n2) + + # Treat the incident as ray below + # A flag to check whether to return Ray3D or not + return_ray = False + + if plane is not None and normal is not None: + raise ValueError("Either plane or normal is acceptable.") + + if not isinstance(incident, Matrix): + if is_sequence(incident): + _incident = Matrix(incident) + elif isinstance(incident, Ray3D): + _incident = Matrix(incident.direction_ratio) + else: + raise TypeError( + "incident should be a Matrix, Ray3D, or sequence") + else: + _incident = incident + + # If plane is provided, get direction ratios of the normal + # to the plane from the plane else go with `normal` param. + if plane is not None: + if not isinstance(plane, Plane): + raise TypeError("plane should be an instance of geometry.plane.Plane") + # If we have the plane, we can get the intersection + # point of incident ray and the plane and thus return + # an instance of Ray3D. + if isinstance(incident, Ray3D): + return_ray = True + intersection_pt = plane.intersection(incident)[0] + _normal = Matrix(plane.normal_vector) + else: + if not isinstance(normal, Matrix): + if is_sequence(normal): + _normal = Matrix(normal) + elif isinstance(normal, Ray3D): + _normal = Matrix(normal.direction_ratio) + if isinstance(incident, Ray3D): + intersection_pt = intersection(incident, normal) + if len(intersection_pt) == 0: + raise ValueError( + "Normal isn't concurrent with the incident ray.") + else: + return_ray = True + intersection_pt = intersection_pt[0] + else: + raise TypeError( + "Normal should be a Matrix, Ray3D, or sequence") + else: + _normal = normal + + eta = n1/n2 # Relative index of refraction + # Calculating magnitude of the vectors + mag_incident = sqrt(sum(i**2 for i in _incident)) + mag_normal = sqrt(sum(i**2 for i in _normal)) + # Converting vectors to unit vectors by dividing + # them with their magnitudes + _incident /= mag_incident + _normal /= mag_normal + c1 = -_incident.dot(_normal) # cos(angle_of_incidence) + cs2 = 1 - eta**2*(1 - c1**2) # cos(angle_of_refraction)**2 + if cs2.is_negative: # This is the case of total internal reflection(TIR). + return S.Zero + drs = eta*_incident + (eta*c1 - sqrt(cs2))*_normal + # Multiplying unit vector by its magnitude + drs = drs*mag_incident + if not return_ray: + return drs + else: + return Ray3D(intersection_pt, direction_ratio=drs) + + +def fresnel_coefficients(angle_of_incidence, medium1, medium2): + """ + This function uses Fresnel equations to calculate reflection and + transmission coefficients. Those are obtained for both polarisations + when the electric field vector is in the plane of incidence (labelled 'p') + and when the electric field vector is perpendicular to the plane of + incidence (labelled 's'). There are four real coefficients unless the + incident ray reflects in total internal in which case there are two complex + ones. Angle of incidence is the angle between the incident ray and the + surface normal. ``medium1`` and ``medium2`` can be ``Medium`` or any + sympifiable object. + + Parameters + ========== + + angle_of_incidence : sympifiable + + medium1 : Medium or sympifiable + Medium 1 or its refractive index + + medium2 : Medium or sympifiable + Medium 2 or its refractive index + + Returns + ======= + + Returns a list with four real Fresnel coefficients: + [reflection p (TM), reflection s (TE), + transmission p (TM), transmission s (TE)] + If the ray is undergoes total internal reflection then returns a + list of two complex Fresnel coefficients: + [reflection p (TM), reflection s (TE)] + + Examples + ======== + + >>> from sympy.physics.optics import fresnel_coefficients + >>> fresnel_coefficients(0.3, 1, 2) + [0.317843553417859, -0.348645229818821, + 0.658921776708929, 0.651354770181179] + >>> fresnel_coefficients(0.6, 2, 1) + [-0.235625382192159 - 0.971843958291041*I, + 0.816477005968898 - 0.577377951366403*I] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Fresnel_equations + """ + if not 0 <= 2*angle_of_incidence < pi: + raise ValueError('Angle of incidence not in range [0:pi/2)') + + n1 = refractive_index_of_medium(medium1) + n2 = refractive_index_of_medium(medium2) + + angle_of_refraction = asin(n1*sin(angle_of_incidence)/n2) + try: + angle_of_total_internal_reflection_onset = critical_angle(n1, n2) + except ValueError: + angle_of_total_internal_reflection_onset = None + + if angle_of_total_internal_reflection_onset is None or\ + angle_of_total_internal_reflection_onset > angle_of_incidence: + R_s = -sin(angle_of_incidence - angle_of_refraction)\ + /sin(angle_of_incidence + angle_of_refraction) + R_p = tan(angle_of_incidence - angle_of_refraction)\ + /tan(angle_of_incidence + angle_of_refraction) + T_s = 2*sin(angle_of_refraction)*cos(angle_of_incidence)\ + /sin(angle_of_incidence + angle_of_refraction) + T_p = 2*sin(angle_of_refraction)*cos(angle_of_incidence)\ + /(sin(angle_of_incidence + angle_of_refraction)\ + *cos(angle_of_incidence - angle_of_refraction)) + return [R_p, R_s, T_p, T_s] + else: + n = n2/n1 + R_s = cancel((cos(angle_of_incidence)-\ + I*sqrt(sin(angle_of_incidence)**2 - n**2))\ + /(cos(angle_of_incidence)+\ + I*sqrt(sin(angle_of_incidence)**2 - n**2))) + R_p = cancel((n**2*cos(angle_of_incidence)-\ + I*sqrt(sin(angle_of_incidence)**2 - n**2))\ + /(n**2*cos(angle_of_incidence)+\ + I*sqrt(sin(angle_of_incidence)**2 - n**2))) + return [R_p, R_s] + + +def deviation(incident, medium1, medium2, normal=None, plane=None): + """ + This function calculates the angle of deviation of a ray + due to refraction at planar surface. + + Parameters + ========== + + incident : Matrix, Ray3D, sequence or float + Incident vector or angle of incidence + medium1 : sympy.physics.optics.medium.Medium or sympifiable + Medium 1 or its refractive index + medium2 : sympy.physics.optics.medium.Medium or sympifiable + Medium 2 or its refractive index + normal : Matrix, Ray3D, or sequence + Normal vector + plane : Plane + Plane of separation of the two media. + + Returns angular deviation between incident and refracted rays + + Examples + ======== + + >>> from sympy.physics.optics import deviation + >>> from sympy.geometry import Point3D, Ray3D, Plane + >>> from sympy.matrices import Matrix + >>> from sympy import symbols + >>> n1, n2 = symbols('n1, n2') + >>> n = Matrix([0, 0, 1]) + >>> P = Plane(Point3D(0, 0, 0), normal_vector=[0, 0, 1]) + >>> r1 = Ray3D(Point3D(-1, -1, 1), Point3D(0, 0, 0)) + >>> deviation(r1, 1, 1, n) + 0 + >>> deviation(r1, n1, n2, plane=P) + -acos(-sqrt(-2*n1**2/(3*n2**2) + 1)) + acos(-sqrt(3)/3) + >>> round(deviation(0.1, 1.2, 1.5), 5) + -0.02005 + """ + refracted = refraction_angle(incident, + medium1, + medium2, + normal=normal, + plane=plane) + try: + angle_of_incidence = Float(incident) + except TypeError: + angle_of_incidence = None + + if angle_of_incidence is not None: + return float(refracted) - angle_of_incidence + + if refracted != 0: + if isinstance(refracted, Ray3D): + refracted = Matrix(refracted.direction_ratio) + + if not isinstance(incident, Matrix): + if is_sequence(incident): + _incident = Matrix(incident) + elif isinstance(incident, Ray3D): + _incident = Matrix(incident.direction_ratio) + else: + raise TypeError( + "incident should be a Matrix, Ray3D, or sequence") + else: + _incident = incident + + if plane is None: + if not isinstance(normal, Matrix): + if is_sequence(normal): + _normal = Matrix(normal) + elif isinstance(normal, Ray3D): + _normal = Matrix(normal.direction_ratio) + else: + raise TypeError( + "normal should be a Matrix, Ray3D, or sequence") + else: + _normal = normal + else: + _normal = Matrix(plane.normal_vector) + + mag_incident = sqrt(sum(i**2 for i in _incident)) + mag_normal = sqrt(sum(i**2 for i in _normal)) + mag_refracted = sqrt(sum(i**2 for i in refracted)) + _incident /= mag_incident + _normal /= mag_normal + refracted /= mag_refracted + i = acos(_incident.dot(_normal)) + r = acos(refracted.dot(_normal)) + return i - r + + +def brewster_angle(medium1, medium2): + """ + This function calculates the Brewster's angle of incidence to Medium 2 from + Medium 1 in radians. + + Parameters + ========== + + medium 1 : Medium or sympifiable + Refractive index of Medium 1 + medium 2 : Medium or sympifiable + Refractive index of Medium 1 + + Examples + ======== + + >>> from sympy.physics.optics import brewster_angle + >>> brewster_angle(1, 1.33) + 0.926093295503462 + + """ + + n1 = refractive_index_of_medium(medium1) + n2 = refractive_index_of_medium(medium2) + + return atan2(n2, n1) + +def critical_angle(medium1, medium2): + """ + This function calculates the critical angle of incidence (marking the onset + of total internal) to Medium 2 from Medium 1 in radians. + + Parameters + ========== + + medium 1 : Medium or sympifiable + Refractive index of Medium 1. + medium 2 : Medium or sympifiable + Refractive index of Medium 1. + + Examples + ======== + + >>> from sympy.physics.optics import critical_angle + >>> critical_angle(1.33, 1) + 0.850908514477849 + + """ + + n1 = refractive_index_of_medium(medium1) + n2 = refractive_index_of_medium(medium2) + + if n2 > n1: + raise ValueError('Total internal reflection impossible for n1 < n2') + else: + return asin(n2/n1) + + + +def lens_makers_formula(n_lens, n_surr, r1, r2, d=0): + """ + This function calculates focal length of a lens. + It follows cartesian sign convention. + + Parameters + ========== + + n_lens : Medium or sympifiable + Index of refraction of lens. + n_surr : Medium or sympifiable + Index of reflection of surrounding. + r1 : sympifiable + Radius of curvature of first surface. + r2 : sympifiable + Radius of curvature of second surface. + d : sympifiable, optional + Thickness of lens, default value is 0. + + Examples + ======== + + >>> from sympy.physics.optics import lens_makers_formula + >>> from sympy import S + >>> lens_makers_formula(1.33, 1, 10, -10) + 15.1515151515151 + >>> lens_makers_formula(1.2, 1, 10, S.Infinity) + 50.0000000000000 + >>> lens_makers_formula(1.33, 1, 10, -10, d=1) + 15.3418463277618 + + """ + + if isinstance(n_lens, Medium): + n_lens = n_lens.refractive_index + else: + n_lens = sympify(n_lens) + if isinstance(n_surr, Medium): + n_surr = n_surr.refractive_index + else: + n_surr = sympify(n_surr) + d = sympify(d) + + focal_length = 1/((n_lens - n_surr) / n_surr*(1/r1 - 1/r2 + (((n_lens - n_surr) * d) / (n_lens * r1 * r2)))) + + if focal_length == zoo: + return S.Infinity + return focal_length + + +def mirror_formula(focal_length=None, u=None, v=None): + """ + This function provides one of the three parameters + when two of them are supplied. + This is valid only for paraxial rays. + + Parameters + ========== + + focal_length : sympifiable + Focal length of the mirror. + u : sympifiable + Distance of object from the pole on + the principal axis. + v : sympifiable + Distance of the image from the pole + on the principal axis. + + Examples + ======== + + >>> from sympy.physics.optics import mirror_formula + >>> from sympy.abc import f, u, v + >>> mirror_formula(focal_length=f, u=u) + f*u/(-f + u) + >>> mirror_formula(focal_length=f, v=v) + f*v/(-f + v) + >>> mirror_formula(u=u, v=v) + u*v/(u + v) + + """ + if focal_length and u and v: + raise ValueError("Please provide only two parameters") + + focal_length = sympify(focal_length) + u = sympify(u) + v = sympify(v) + if u is oo: + _u = Symbol('u') + if v is oo: + _v = Symbol('v') + if focal_length is oo: + _f = Symbol('f') + if focal_length is None: + if u is oo and v is oo: + return Limit(Limit(_v*_u/(_v + _u), _u, oo), _v, oo).doit() + if u is oo: + return Limit(v*_u/(v + _u), _u, oo).doit() + if v is oo: + return Limit(_v*u/(_v + u), _v, oo).doit() + return v*u/(v + u) + if u is None: + if v is oo and focal_length is oo: + return Limit(Limit(_v*_f/(_v - _f), _v, oo), _f, oo).doit() + if v is oo: + return Limit(_v*focal_length/(_v - focal_length), _v, oo).doit() + if focal_length is oo: + return Limit(v*_f/(v - _f), _f, oo).doit() + return v*focal_length/(v - focal_length) + if v is None: + if u is oo and focal_length is oo: + return Limit(Limit(_u*_f/(_u - _f), _u, oo), _f, oo).doit() + if u is oo: + return Limit(_u*focal_length/(_u - focal_length), _u, oo).doit() + if focal_length is oo: + return Limit(u*_f/(u - _f), _f, oo).doit() + return u*focal_length/(u - focal_length) + + +def lens_formula(focal_length=None, u=None, v=None): + """ + This function provides one of the three parameters + when two of them are supplied. + This is valid only for paraxial rays. + + Parameters + ========== + + focal_length : sympifiable + Focal length of the mirror. + u : sympifiable + Distance of object from the optical center on + the principal axis. + v : sympifiable + Distance of the image from the optical center + on the principal axis. + + Examples + ======== + + >>> from sympy.physics.optics import lens_formula + >>> from sympy.abc import f, u, v + >>> lens_formula(focal_length=f, u=u) + f*u/(f + u) + >>> lens_formula(focal_length=f, v=v) + f*v/(f - v) + >>> lens_formula(u=u, v=v) + u*v/(u - v) + + """ + if focal_length and u and v: + raise ValueError("Please provide only two parameters") + + focal_length = sympify(focal_length) + u = sympify(u) + v = sympify(v) + if u is oo: + _u = Symbol('u') + if v is oo: + _v = Symbol('v') + if focal_length is oo: + _f = Symbol('f') + if focal_length is None: + if u is oo and v is oo: + return Limit(Limit(_v*_u/(_u - _v), _u, oo), _v, oo).doit() + if u is oo: + return Limit(v*_u/(_u - v), _u, oo).doit() + if v is oo: + return Limit(_v*u/(u - _v), _v, oo).doit() + return v*u/(u - v) + if u is None: + if v is oo and focal_length is oo: + return Limit(Limit(_v*_f/(_f - _v), _v, oo), _f, oo).doit() + if v is oo: + return Limit(_v*focal_length/(focal_length - _v), _v, oo).doit() + if focal_length is oo: + return Limit(v*_f/(_f - v), _f, oo).doit() + return v*focal_length/(focal_length - v) + if v is None: + if u is oo and focal_length is oo: + return Limit(Limit(_u*_f/(_u + _f), _u, oo), _f, oo).doit() + if u is oo: + return Limit(_u*focal_length/(_u + focal_length), _u, oo).doit() + if focal_length is oo: + return Limit(u*_f/(u + _f), _f, oo).doit() + return u*focal_length/(u + focal_length) + +def hyperfocal_distance(f, N, c): + """ + + Parameters + ========== + + f: sympifiable + Focal length of a given lens. + + N: sympifiable + F-number of a given lens. + + c: sympifiable + Circle of Confusion (CoC) of a given image format. + + Example + ======= + + >>> from sympy.physics.optics import hyperfocal_distance + >>> round(hyperfocal_distance(f = 0.5, N = 8, c = 0.0033), 2) + 9.47 + """ + + f = sympify(f) + N = sympify(N) + c = sympify(c) + + return (1/(N * c))*(f**2) + +def transverse_magnification(si, so): + """ + + Calculates the transverse magnification upon reflection in a mirror, + which is the ratio of the image size to the object size. + + Parameters + ========== + + so: sympifiable + Lens-object distance. + + si: sympifiable + Lens-image distance. + + Example + ======= + + >>> from sympy.physics.optics import transverse_magnification + >>> transverse_magnification(30, 15) + -2 + + """ + + si = sympify(si) + so = sympify(so) + + return (-(si/so)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/waves.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/waves.py new file mode 100644 index 0000000000000000000000000000000000000000..61e2ff4db578543f9f2694f239f03439bfab2c41 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/optics/waves.py @@ -0,0 +1,340 @@ +""" +This module has all the classes and functions related to waves in optics. + +**Contains** + +* TWave +""" + +__all__ = ['TWave'] + +from sympy.core.basic import Basic +from sympy.core.expr import Expr +from sympy.core.function import Derivative, Function +from sympy.core.numbers import (Number, pi, I) +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.core.sympify import _sympify, sympify +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (atan2, cos, sin) +from sympy.physics.units import speed_of_light, meter, second + + +c = speed_of_light.convert_to(meter/second) + + +class TWave(Expr): + + r""" + This is a simple transverse sine wave travelling in a one-dimensional space. + Basic properties are required at the time of creation of the object, + but they can be changed later with respective methods provided. + + Explanation + =========== + + It is represented as :math:`A \times cos(k*x - \omega \times t + \phi )`, + where :math:`A` is the amplitude, :math:`\omega` is the angular frequency, + :math:`k` is the wavenumber (spatial frequency), :math:`x` is a spatial variable + to represent the position on the dimension on which the wave propagates, + and :math:`\phi` is the phase angle of the wave. + + + Arguments + ========= + + amplitude : Sympifyable + Amplitude of the wave. + frequency : Sympifyable + Frequency of the wave. + phase : Sympifyable + Phase angle of the wave. + time_period : Sympifyable + Time period of the wave. + n : Sympifyable + Refractive index of the medium. + + Raises + ======= + + ValueError : When neither frequency nor time period is provided + or they are not consistent. + TypeError : When anything other than TWave objects is added. + + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.optics import TWave + >>> A1, phi1, A2, phi2, f = symbols('A1, phi1, A2, phi2, f') + >>> w1 = TWave(A1, f, phi1) + >>> w2 = TWave(A2, f, phi2) + >>> w3 = w1 + w2 # Superposition of two waves + >>> w3 + TWave(sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + A2**2), f, + atan2(A1*sin(phi1) + A2*sin(phi2), A1*cos(phi1) + A2*cos(phi2)), 1/f, n) + >>> w3.amplitude + sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + A2**2) + >>> w3.phase + atan2(A1*sin(phi1) + A2*sin(phi2), A1*cos(phi1) + A2*cos(phi2)) + >>> w3.speed + 299792458*meter/(second*n) + >>> w3.angular_velocity + 2*pi*f + + """ + + def __new__( + cls, + amplitude, + frequency=None, + phase=S.Zero, + time_period=None, + n=Symbol('n')): + if time_period is not None: + time_period = _sympify(time_period) + _frequency = S.One/time_period + if frequency is not None: + frequency = _sympify(frequency) + _time_period = S.One/frequency + if time_period is not None: + if frequency != S.One/time_period: + raise ValueError("frequency and time_period should be consistent.") + if frequency is None and time_period is None: + raise ValueError("Either frequency or time period is needed.") + if frequency is None: + frequency = _frequency + if time_period is None: + time_period = _time_period + + amplitude = _sympify(amplitude) + phase = _sympify(phase) + n = sympify(n) + obj = Basic.__new__(cls, amplitude, frequency, phase, time_period, n) + return obj + + @property + def amplitude(self): + """ + Returns the amplitude of the wave. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.optics import TWave + >>> A, phi, f = symbols('A, phi, f') + >>> w = TWave(A, f, phi) + >>> w.amplitude + A + """ + return self.args[0] + + @property + def frequency(self): + """ + Returns the frequency of the wave, + in cycles per second. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.optics import TWave + >>> A, phi, f = symbols('A, phi, f') + >>> w = TWave(A, f, phi) + >>> w.frequency + f + """ + return self.args[1] + + @property + def phase(self): + """ + Returns the phase angle of the wave, + in radians. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.optics import TWave + >>> A, phi, f = symbols('A, phi, f') + >>> w = TWave(A, f, phi) + >>> w.phase + phi + """ + return self.args[2] + + @property + def time_period(self): + """ + Returns the temporal period of the wave, + in seconds per cycle. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.optics import TWave + >>> A, phi, f = symbols('A, phi, f') + >>> w = TWave(A, f, phi) + >>> w.time_period + 1/f + """ + return self.args[3] + + @property + def n(self): + """ + Returns the refractive index of the medium + """ + return self.args[4] + + @property + def wavelength(self): + """ + Returns the wavelength (spatial period) of the wave, + in meters per cycle. + It depends on the medium of the wave. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.optics import TWave + >>> A, phi, f = symbols('A, phi, f') + >>> w = TWave(A, f, phi) + >>> w.wavelength + 299792458*meter/(second*f*n) + """ + return c/(self.frequency*self.n) + + + @property + def speed(self): + """ + Returns the propagation speed of the wave, + in meters per second. + It is dependent on the propagation medium. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.optics import TWave + >>> A, phi, f = symbols('A, phi, f') + >>> w = TWave(A, f, phi) + >>> w.speed + 299792458*meter/(second*n) + """ + return self.wavelength*self.frequency + + @property + def angular_velocity(self): + """ + Returns the angular velocity of the wave, + in radians per second. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.optics import TWave + >>> A, phi, f = symbols('A, phi, f') + >>> w = TWave(A, f, phi) + >>> w.angular_velocity + 2*pi*f + """ + return 2*pi*self.frequency + + @property + def wavenumber(self): + """ + Returns the wavenumber of the wave, + in radians per meter. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.optics import TWave + >>> A, phi, f = symbols('A, phi, f') + >>> w = TWave(A, f, phi) + >>> w.wavenumber + pi*second*f*n/(149896229*meter) + """ + return 2*pi/self.wavelength + + def __str__(self): + """String representation of a TWave.""" + from sympy.printing import sstr + return type(self).__name__ + sstr(self.args) + + __repr__ = __str__ + + def __add__(self, other): + """ + Addition of two waves will result in their superposition. + The type of interference will depend on their phase angles. + """ + if isinstance(other, TWave): + if self.frequency == other.frequency and self.wavelength == other.wavelength: + return TWave(sqrt(self.amplitude**2 + other.amplitude**2 + 2 * + self.amplitude*other.amplitude*cos( + self.phase - other.phase)), + self.frequency, + atan2(self.amplitude*sin(self.phase) + + other.amplitude*sin(other.phase), + self.amplitude*cos(self.phase) + + other.amplitude*cos(other.phase)) + ) + else: + raise NotImplementedError("Interference of waves with different frequencies" + " has not been implemented.") + else: + raise TypeError(type(other).__name__ + " and TWave objects cannot be added.") + + def __mul__(self, other): + """ + Multiplying a wave by a scalar rescales the amplitude of the wave. + """ + other = sympify(other) + if isinstance(other, Number): + return TWave(self.amplitude*other, *self.args[1:]) + else: + raise TypeError(type(other).__name__ + " and TWave objects cannot be multiplied.") + + def __sub__(self, other): + return self.__add__(-1*other) + + def __neg__(self): + return self.__mul__(-1) + + def __radd__(self, other): + return self.__add__(other) + + def __rmul__(self, other): + return self.__mul__(other) + + def __rsub__(self, other): + return (-self).__radd__(other) + + def _eval_rewrite_as_sin(self, *args, **kwargs): + return self.amplitude*sin(self.wavenumber*Symbol('x') + - self.angular_velocity*Symbol('t') + self.phase + pi/2, evaluate=False) + + def _eval_rewrite_as_cos(self, *args, **kwargs): + return self.amplitude*cos(self.wavenumber*Symbol('x') + - self.angular_velocity*Symbol('t') + self.phase) + + def _eval_rewrite_as_pde(self, *args, **kwargs): + mu, epsilon, x, t = symbols('mu, epsilon, x, t') + E = Function('E') + return Derivative(E(x, t), x, 2) + mu*epsilon*Derivative(E(x, t), t, 2) + + def _eval_rewrite_as_exp(self, *args, **kwargs): + return self.amplitude*exp(I*(self.wavenumber*Symbol('x') + - self.angular_velocity*Symbol('t') + self.phase)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..36203f1a48c4c53832ce44942878ddc7b89f8091 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__init__.py @@ -0,0 +1,65 @@ +# Names exposed by 'from sympy.physics.quantum import *' + +__all__ = [ + 'AntiCommutator', + + 'qapply', + + 'Commutator', + + 'Dagger', + + 'HilbertSpaceError', 'HilbertSpace', 'TensorProductHilbertSpace', + 'TensorPowerHilbertSpace', 'DirectSumHilbertSpace', 'ComplexSpace', 'L2', + 'FockSpace', + + 'InnerProduct', + + 'Operator', 'HermitianOperator', 'UnitaryOperator', 'IdentityOperator', + 'OuterProduct', 'DifferentialOperator', + + 'represent', 'rep_innerproduct', 'rep_expectation', 'integrate_result', + 'get_basis', 'enumerate_states', + + 'KetBase', 'BraBase', 'StateBase', 'State', 'Ket', 'Bra', 'TimeDepState', + 'TimeDepBra', 'TimeDepKet', 'OrthogonalKet', 'OrthogonalBra', + 'OrthogonalState', 'Wavefunction', + + 'TensorProduct', 'tensor_product_simp', + + 'hbar', 'HBar', + + '_postprocess_state_mul', '_postprocess_state_pow' +] + +from .anticommutator import AntiCommutator + +from .qapply import qapply + +from .commutator import Commutator + +from .dagger import Dagger + +from .hilbert import (HilbertSpaceError, HilbertSpace, + TensorProductHilbertSpace, TensorPowerHilbertSpace, + DirectSumHilbertSpace, ComplexSpace, L2, FockSpace) + +from .innerproduct import InnerProduct + +from .operator import (Operator, HermitianOperator, UnitaryOperator, + IdentityOperator, OuterProduct, DifferentialOperator) + +from .represent import (represent, rep_innerproduct, rep_expectation, + integrate_result, get_basis, enumerate_states) + +from .state import (KetBase, BraBase, StateBase, State, Ket, Bra, + TimeDepState, TimeDepBra, TimeDepKet, OrthogonalKet, + OrthogonalBra, OrthogonalState, Wavefunction) + +from .tensorproduct import TensorProduct, tensor_product_simp + +from .constants import hbar, HBar + +# These are private, but need to be imported so they are registered +# as postprocessing transformers with Mul and Pow. +from .transforms import _postprocess_state_mul, _postprocess_state_pow diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6a3cc1333943e5e075423f18cea8825398fefd2c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/anticommutator.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/anticommutator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..704bdfb1742e3b9b3ebb284b76f95f4d0690c445 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/anticommutator.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/boson.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/boson.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e59dae0eb1e92791c602ab77fe54bcc1a0cf8609 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/boson.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/cartesian.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/cartesian.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ddaeb1e52e2686fd27463064a1a1b2f514712ea Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/cartesian.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/cg.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/cg.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..342ebbb7d21d9ffa0e3a6bb0984e3ae33b6a793d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/cg.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/circuitplot.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/circuitplot.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e7db250797a8bb466ac4a0141b7b79929714ebe8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/circuitplot.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/circuitutils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/circuitutils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d79d5f262c037feae3c86a2ce6db4c2edd5ce2aa Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/circuitutils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/commutator.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/commutator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..79a5add3f8a63731d0e008acda32c9ed1c5b38e7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/commutator.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/constants.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/constants.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2be1d219f6e723135fe4e03db3ef3d01d366ef30 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/constants.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/dagger.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/dagger.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b7a2625242c2267c54c21b742cd53b688f2d977 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/dagger.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/density.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/density.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..701654a21c711e615789cc7f5afc54e92634cd47 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/density.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/fermion.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/fermion.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69d0613f6a2e993cb0b6474d04dd356d00c56620 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/fermion.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/gate.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/gate.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..486fc9fb257a8e380b14e1235c899387cec515e8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/gate.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/grover.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/grover.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..980cd17123e8a0ee472dd020596fc71bd5146a20 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/grover.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/hilbert.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/hilbert.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c434aabf2bb6a22c4ff96a28cd5620120450046 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/hilbert.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/identitysearch.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/identitysearch.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8d4ab0afd74a0e37377eafdbd29b37b7fd274838 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/identitysearch.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/innerproduct.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/innerproduct.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af8adffd2c2ed6f311d8dc4bbf5e071f411dd84f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/innerproduct.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/kind.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/kind.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59ed0cf7de6617fc949e5f7e9b29212387b6ca60 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/kind.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/matrixcache.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/matrixcache.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..573909fe844d43c59d4dd863ad8f321fc118c4a5 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/matrixcache.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/matrixutils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/matrixutils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a4d46f1c43f88ce0665ae5a8378ef5b83da29b67 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/matrixutils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/operator.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/operator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e349d21bbbfa073dcba1b8bbf56864b116d936e4 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/operator.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/operatorordering.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/operatorordering.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..317c3aadd5576151e562323fc299fac4d2a237f5 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/operatorordering.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/operatorset.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/operatorset.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa601260315065c337f1b426062403469b427c0b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/operatorset.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/pauli.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/pauli.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc11337580a6453c395c074a060fe5965e8ab518 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/pauli.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/piab.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/piab.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4326a4835f2cccef9919bbdd6f43e0ac76432689 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/piab.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qapply.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qapply.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6ba9dc404df7a8dd0c1bb57e34966b687b48c27 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qapply.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qasm.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qasm.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..587e9f7a0906533c63a082acd6aac29d379ab800 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qasm.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qexpr.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qexpr.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..471f9a81d9e012a9c7e498909817cd1fbd177d24 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qexpr.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qft.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qft.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc427f776992d8a2cd81bf6cc0067877edd37e9b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qft.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qubit.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qubit.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07675a7bc2c4147a67cb5e887b108c917ffe3711 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/qubit.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/represent.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/represent.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05605c137341c4c50e5f7eb1db1c26c8ad830c9a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/represent.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/sho1d.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/sho1d.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d10091c382b441aa40eb8296a1dce8cc6597d154 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/sho1d.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/shor.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/shor.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f48543215ab5539b9ed560e08a0ff06e49ac890e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/shor.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/state.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/state.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63fccee825ada59c6629fc242d7ee6921f3129c6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/state.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/tensorproduct.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/tensorproduct.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5064f44882ca456c44754d77d6105a70b422e6bd Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/tensorproduct.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/trace.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/trace.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93944bf53de063fcd6527b64435383d4404a260e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/trace.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/transforms.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/transforms.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0cd01a5e9e1363b10764cc9e03aebef3fc40c5ae Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/__pycache__/transforms.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/anticommutator.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/anticommutator.py new file mode 100644 index 0000000000000000000000000000000000000000..cbd26eade640b60a48eaac8c8b0abaf236478ca9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/anticommutator.py @@ -0,0 +1,166 @@ +"""The anti-commutator: ``{A,B} = A*B + B*A``.""" + +from sympy.core.expr import Expr +from sympy.core.kind import KindDispatcher +from sympy.core.mul import Mul +from sympy.core.numbers import Integer +from sympy.core.singleton import S +from sympy.printing.pretty.stringpict import prettyForm + +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.kind import _OperatorKind, OperatorKind + +__all__ = [ + 'AntiCommutator' +] + +#----------------------------------------------------------------------------- +# Anti-commutator +#----------------------------------------------------------------------------- + + +class AntiCommutator(Expr): + """The standard anticommutator, in an unevaluated state. + + Explanation + =========== + + Evaluating an anticommutator is defined [1]_ as: ``{A, B} = A*B + B*A``. + This class returns the anticommutator in an unevaluated form. To evaluate + the anticommutator, use the ``.doit()`` method. + + Canonical ordering of an anticommutator is ``{A, B}`` for ``A < B``. The + arguments of the anticommutator are put into canonical order using + ``__cmp__``. If ``B < A``, then ``{A, B}`` is returned as ``{B, A}``. + + Parameters + ========== + + A : Expr + The first argument of the anticommutator {A,B}. + B : Expr + The second argument of the anticommutator {A,B}. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.quantum import AntiCommutator + >>> from sympy.physics.quantum import Operator, Dagger + >>> x, y = symbols('x,y') + >>> A = Operator('A') + >>> B = Operator('B') + + Create an anticommutator and use ``doit()`` to multiply them out. + + >>> ac = AntiCommutator(A,B); ac + {A,B} + >>> ac.doit() + A*B + B*A + + The commutator orders it arguments in canonical order: + + >>> ac = AntiCommutator(B,A); ac + {A,B} + + Commutative constants are factored out: + + >>> AntiCommutator(3*x*A,x*y*B) + 3*x**2*y*{A,B} + + Adjoint operations applied to the anticommutator are properly applied to + the arguments: + + >>> Dagger(AntiCommutator(A,B)) + {Dagger(A),Dagger(B)} + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Commutator + """ + is_commutative = False + + _kind_dispatcher = KindDispatcher("AntiCommutator_kind_dispatcher", commutative=True) + + @property + def kind(self): + arg_kinds = (a.kind for a in self.args) + return self._kind_dispatcher(*arg_kinds) + + def __new__(cls, A, B): + r = cls.eval(A, B) + if r is not None: + return r + obj = Expr.__new__(cls, A, B) + return obj + + @classmethod + def eval(cls, a, b): + 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 + + # [xA,yB] -> xy*[A,B] + ca, nca = a.args_cnc() + cb, ncb = b.args_cnc() + c_part = ca + cb + if c_part: + return Mul(Mul(*c_part), cls(Mul._from_args(nca), Mul._from_args(ncb))) + + # Canonical ordering of arguments + #The Commutator [A,B] is on canonical form if A < B. + if a.compare(b) == 1: + return cls(b, a) + + def doit(self, **hints): + """ Evaluate anticommutator """ + # Keep the import of Operator here to avoid problems with + # circular imports. + from sympy.physics.quantum.operator import Operator + A = self.args[0] + B = self.args[1] + if isinstance(A, Operator) and isinstance(B, Operator): + try: + comm = A._eval_anticommutator(B, **hints) + except NotImplementedError: + try: + comm = B._eval_anticommutator(A, **hints) + except NotImplementedError: + comm = None + if comm is not None: + return comm.doit(**hints) + return (A*B + B*A).doit(**hints) + + def _eval_adjoint(self): + return AntiCommutator(Dagger(self.args[0]), Dagger(self.args[1])) + + def _sympyrepr(self, printer, *args): + return "%s(%s,%s)" % ( + self.__class__.__name__, printer._print( + self.args[0]), printer._print(self.args[1]) + ) + + def _sympystr(self, printer, *args): + return "{%s,%s}" % ( + printer._print(self.args[0]), printer._print(self.args[1])) + + def _pretty(self, printer, *args): + pform = printer._print(self.args[0], *args) + pform = prettyForm(*pform.right(prettyForm(','))) + pform = prettyForm(*pform.right(printer._print(self.args[1], *args))) + pform = prettyForm(*pform.parens(left='{', right='}')) + return pform + + def _latex(self, printer, *args): + return "\\left\\{%s,%s\\right\\}" % tuple([ + printer._print(arg, *args) for arg in self.args]) + + +@AntiCommutator._kind_dispatcher.register(_OperatorKind, _OperatorKind) +def find_op_kind(e1, e2): + """Find the kind of an anticommutator of two OperatorKinds.""" + return OperatorKind diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/boson.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/boson.py new file mode 100644 index 0000000000000000000000000000000000000000..0f24cae2a7ad2f438234fcf00dadb2a4a9d76fe8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/boson.py @@ -0,0 +1,243 @@ +"""Bosonic quantum operators.""" + +from sympy.core.numbers import Integer +from sympy.core.singleton import S +from sympy.functions.elementary.complexes import conjugate +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.physics.quantum import Operator +from sympy.physics.quantum import HilbertSpace, FockSpace, Ket, Bra +from sympy.functions.special.tensor_functions import KroneckerDelta + + +__all__ = [ + 'BosonOp', + 'BosonFockKet', + 'BosonFockBra', + 'BosonCoherentKet', + 'BosonCoherentBra' +] + + +class BosonOp(Operator): + """A bosonic operator that satisfies [a, Dagger(a)] == 1. + + Parameters + ========== + + name : str + A string that labels the bosonic mode. + + annihilation : bool + A bool that indicates if the bosonic operator is an annihilation (True, + default value) or creation operator (False) + + Examples + ======== + + >>> from sympy.physics.quantum import Dagger, Commutator + >>> from sympy.physics.quantum.boson import BosonOp + >>> a = BosonOp("a") + >>> Commutator(a, Dagger(a)).doit() + 1 + """ + + @property + def name(self): + return self.args[0] + + @property + def is_annihilation(self): + return bool(self.args[1]) + + @classmethod + def default_args(self): + return ("a", True) + + def __new__(cls, *args, **hints): + if not len(args) in [1, 2]: + raise ValueError('1 or 2 parameters expected, got %s' % args) + + if len(args) == 1: + args = (args[0], S.One) + + if len(args) == 2: + args = (args[0], Integer(args[1])) + + return Operator.__new__(cls, *args) + + def _eval_commutator_BosonOp(self, other, **hints): + if self.name == other.name: + # [a^\dagger, a] = -1 + if not self.is_annihilation and other.is_annihilation: + return S.NegativeOne + + elif 'independent' in hints and hints['independent']: + # [a, b] = 0 + return S.Zero + + return None + + def _eval_commutator_FermionOp(self, other, **hints): + return S.Zero + + def _eval_anticommutator_BosonOp(self, other, **hints): + if 'independent' in hints and hints['independent']: + # {a, b} = 2 * a * b, because [a, b] = 0 + return 2 * self * other + + return None + + def _eval_adjoint(self): + return BosonOp(str(self.name), not self.is_annihilation) + + def _print_contents_latex(self, printer, *args): + if self.is_annihilation: + return r'{%s}' % str(self.name) + else: + return r'{{%s}^\dagger}' % str(self.name) + + def _print_contents(self, printer, *args): + if self.is_annihilation: + return r'%s' % str(self.name) + else: + return r'Dagger(%s)' % str(self.name) + + def _print_contents_pretty(self, printer, *args): + from sympy.printing.pretty.stringpict import prettyForm + pform = printer._print(self.args[0], *args) + if self.is_annihilation: + return pform + else: + return pform**prettyForm('\N{DAGGER}') + + +class BosonFockKet(Ket): + """Fock state ket for a bosonic mode. + + Parameters + ========== + + n : Number + The Fock state number. + + """ + + def __new__(cls, n): + return Ket.__new__(cls, n) + + @property + def n(self): + return self.label[0] + + @classmethod + def dual_class(self): + return BosonFockBra + + @classmethod + def _eval_hilbert_space(cls, label): + return FockSpace() + + def _eval_innerproduct_BosonFockBra(self, bra, **hints): + return KroneckerDelta(self.n, bra.n) + + def _apply_from_right_to_BosonOp(self, op, **options): + if op.is_annihilation: + return sqrt(self.n) * BosonFockKet(self.n - 1) + else: + return sqrt(self.n + 1) * BosonFockKet(self.n + 1) + + +class BosonFockBra(Bra): + """Fock state bra for a bosonic mode. + + Parameters + ========== + + n : Number + The Fock state number. + + """ + + def __new__(cls, n): + return Bra.__new__(cls, n) + + @property + def n(self): + return self.label[0] + + @classmethod + def dual_class(self): + return BosonFockKet + + @classmethod + def _eval_hilbert_space(cls, label): + return FockSpace() + + +class BosonCoherentKet(Ket): + """Coherent state ket for a bosonic mode. + + Parameters + ========== + + alpha : Number, Symbol + The complex amplitude of the coherent state. + + """ + + def __new__(cls, alpha): + return Ket.__new__(cls, alpha) + + @property + def alpha(self): + return self.label[0] + + @classmethod + def dual_class(self): + return BosonCoherentBra + + @classmethod + def _eval_hilbert_space(cls, label): + return HilbertSpace() + + def _eval_innerproduct_BosonCoherentBra(self, bra, **hints): + if self.alpha == bra.alpha: + return S.One + else: + return exp(-(abs(self.alpha)**2 + abs(bra.alpha)**2 - 2 * conjugate(bra.alpha) * self.alpha)/2) + + def _apply_from_right_to_BosonOp(self, op, **options): + if op.is_annihilation: + return self.alpha * self + else: + return None + + +class BosonCoherentBra(Bra): + """Coherent state bra for a bosonic mode. + + Parameters + ========== + + alpha : Number, Symbol + The complex amplitude of the coherent state. + + """ + + def __new__(cls, alpha): + return Bra.__new__(cls, alpha) + + @property + def alpha(self): + return self.label[0] + + @classmethod + def dual_class(self): + return BosonCoherentKet + + def _apply_operator_BosonOp(self, op, **options): + if not op.is_annihilation: + return self.alpha * self + else: + return None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/cartesian.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/cartesian.py new file mode 100644 index 0000000000000000000000000000000000000000..f3af1856f22c8fe4535b24be30bf99d0b3541a50 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/cartesian.py @@ -0,0 +1,341 @@ +"""Operators and states for 1D cartesian position and momentum. + +TODO: + +* Add 3D classes to mappings in operatorset.py + +""" + +from sympy.core.numbers import (I, pi) +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.special.delta_functions import DiracDelta +from sympy.sets.sets import Interval + +from sympy.physics.quantum.constants import hbar +from sympy.physics.quantum.hilbert import L2 +from sympy.physics.quantum.operator import DifferentialOperator, HermitianOperator +from sympy.physics.quantum.state import Ket, Bra, State + +__all__ = [ + 'XOp', + 'YOp', + 'ZOp', + 'PxOp', + 'X', + 'Y', + 'Z', + 'Px', + 'XKet', + 'XBra', + 'PxKet', + 'PxBra', + 'PositionState3D', + 'PositionKet3D', + 'PositionBra3D' +] + +#------------------------------------------------------------------------- +# Position operators +#------------------------------------------------------------------------- + + +class XOp(HermitianOperator): + """1D cartesian position operator.""" + + @classmethod + def default_args(self): + return ("X",) + + @classmethod + def _eval_hilbert_space(self, args): + return L2(Interval(S.NegativeInfinity, S.Infinity)) + + def _eval_commutator_PxOp(self, other): + return I*hbar + + def _apply_operator_XKet(self, ket, **options): + return ket.position*ket + + def _apply_operator_PositionKet3D(self, ket, **options): + return ket.position_x*ket + + def _represent_PxKet(self, basis, *, index=1, **options): + states = basis._enumerate_state(2, start_index=index) + coord1 = states[0].momentum + coord2 = states[1].momentum + d = DifferentialOperator(coord1) + delta = DiracDelta(coord1 - coord2) + + return I*hbar*(d*delta) + + +class YOp(HermitianOperator): + """ Y cartesian coordinate operator (for 2D or 3D systems) """ + + @classmethod + def default_args(self): + return ("Y",) + + @classmethod + def _eval_hilbert_space(self, args): + return L2(Interval(S.NegativeInfinity, S.Infinity)) + + def _apply_operator_PositionKet3D(self, ket, **options): + return ket.position_y*ket + + +class ZOp(HermitianOperator): + """ Z cartesian coordinate operator (for 3D systems) """ + + @classmethod + def default_args(self): + return ("Z",) + + @classmethod + def _eval_hilbert_space(self, args): + return L2(Interval(S.NegativeInfinity, S.Infinity)) + + def _apply_operator_PositionKet3D(self, ket, **options): + return ket.position_z*ket + +#------------------------------------------------------------------------- +# Momentum operators +#------------------------------------------------------------------------- + + +class PxOp(HermitianOperator): + """1D cartesian momentum operator.""" + + @classmethod + def default_args(self): + return ("Px",) + + @classmethod + def _eval_hilbert_space(self, args): + return L2(Interval(S.NegativeInfinity, S.Infinity)) + + def _apply_operator_PxKet(self, ket, **options): + return ket.momentum*ket + + def _represent_XKet(self, basis, *, index=1, **options): + states = basis._enumerate_state(2, start_index=index) + coord1 = states[0].position + coord2 = states[1].position + d = DifferentialOperator(coord1) + delta = DiracDelta(coord1 - coord2) + + return -I*hbar*(d*delta) + +X = XOp('X') +Y = YOp('Y') +Z = ZOp('Z') +Px = PxOp('Px') + +#------------------------------------------------------------------------- +# Position eigenstates +#------------------------------------------------------------------------- + + +class XKet(Ket): + """1D cartesian position eigenket.""" + + @classmethod + def _operators_to_state(self, op, **options): + return self.__new__(self, *_lowercase_labels(op), **options) + + def _state_to_operators(self, op_class, **options): + return op_class.__new__(op_class, + *_uppercase_labels(self), **options) + + @classmethod + def default_args(self): + return ("x",) + + @classmethod + def dual_class(self): + return XBra + + @property + def position(self): + """The position of the state.""" + return self.label[0] + + def _enumerate_state(self, num_states, **options): + return _enumerate_continuous_1D(self, num_states, **options) + + def _eval_innerproduct_XBra(self, bra, **hints): + 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.""" + + @classmethod + def default_args(self): + return ("x",) + + @classmethod + def dual_class(self): + return XKet + + @property + def position(self): + """The position of the state.""" + return self.label[0] + + +class PositionState3D(State): + """ Base class for 3D cartesian position eigenstates """ + + @classmethod + def _operators_to_state(self, op, **options): + return self.__new__(self, *_lowercase_labels(op), **options) + + def _state_to_operators(self, op_class, **options): + return op_class.__new__(op_class, + *_uppercase_labels(self), **options) + + @classmethod + def default_args(self): + return ("x", "y", "z") + + @property + def position_x(self): + """ The x coordinate of the state """ + return self.label[0] + + @property + def position_y(self): + """ The y coordinate of the state """ + return self.label[1] + + @property + def position_z(self): + """ The z coordinate of the state """ + return self.label[2] + + +class PositionKet3D(Ket, PositionState3D): + """ 3D cartesian position eigenket """ + + def _eval_innerproduct_PositionBra3D(self, bra, **options): + x_diff = self.position_x - bra.position_x + y_diff = self.position_y - bra.position_y + z_diff = self.position_z - bra.position_z + + return DiracDelta(x_diff)*DiracDelta(y_diff)*DiracDelta(z_diff) + + @classmethod + def dual_class(self): + return PositionBra3D + + +# XXX: The type:ignore here is because mypy gives Definition of +# "_state_to_operators" in base class "PositionState3D" is incompatible with +# definition in base class "BraBase" +class PositionBra3D(Bra, PositionState3D): # type: ignore + """ 3D cartesian position eigenbra """ + + @classmethod + def dual_class(self): + return PositionKet3D + +#------------------------------------------------------------------------- +# Momentum eigenstates +#------------------------------------------------------------------------- + + +class PxKet(Ket): + """1D cartesian momentum eigenket.""" + + @classmethod + def _operators_to_state(self, op, **options): + return self.__new__(self, *_lowercase_labels(op), **options) + + def _state_to_operators(self, op_class, **options): + return op_class.__new__(op_class, + *_uppercase_labels(self), **options) + + @classmethod + def default_args(self): + return ("px",) + + @classmethod + def dual_class(self): + return PxBra + + @property + def momentum(self): + """The momentum of the state.""" + return self.label[0] + + def _enumerate_state(self, *args, **options): + return _enumerate_continuous_1D(self, *args, **options) + + def _eval_innerproduct_XBra(self, bra, **hints): + 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) + + +class PxBra(Bra): + """1D cartesian momentum eigenbra.""" + + @classmethod + def default_args(self): + return ("px",) + + @classmethod + def dual_class(self): + return PxKet + + @property + def momentum(self): + """The momentum of the state.""" + return self.label[0] + +#------------------------------------------------------------------------- +# Global helper functions +#------------------------------------------------------------------------- + + +def _enumerate_continuous_1D(*args, **options): + state = args[0] + num_states = args[1] + state_class = state.__class__ + index_list = options.pop('index_list', []) + + if len(index_list) == 0: + start_index = options.pop('start_index', 1) + index_list = list(range(start_index, start_index + num_states)) + + enum_states = [0 for i in range(len(index_list))] + + for i, ind in enumerate(index_list): + label = state.args[0] + enum_states[i] = state_class(str(label) + "_" + str(ind), **options) + + 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() + + str(arg.label[0])[1:] for arg in ops] + + return new_args diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/cg.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/cg.py new file mode 100644 index 0000000000000000000000000000000000000000..0f285cd39413a953246777c42fb6763c22a5716b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/cg.py @@ -0,0 +1,754 @@ +#TODO: +# -Implement Clebsch-Gordan symmetries +# -Improve simplification method +# -Implement new simplifications +"""Clebsch-Gordon Coefficients.""" + +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.expr import Expr +from sympy.core.function import expand +from sympy.core.mul import Mul +from sympy.core.power import Pow +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Wild, symbols) +from sympy.core.sympify import sympify +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.printing.pretty.stringpict import prettyForm, stringPict + +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.physics.wigner import clebsch_gordan, wigner_3j, wigner_6j, wigner_9j +from sympy.printing.precedence import PRECEDENCE + +__all__ = [ + 'CG', + 'Wigner3j', + 'Wigner6j', + 'Wigner9j', + 'cg_simp' +] + +#----------------------------------------------------------------------------- +# CG Coefficients +#----------------------------------------------------------------------------- + + +class Wigner3j(Expr): + """Class for the Wigner-3j symbols. + + Explanation + =========== + + Wigner 3j-symbols are coefficients determined by the coupling of + two angular momenta. When created, they are expressed as symbolic + quantities that, for numerical parameters, can be evaluated using the + ``.doit()`` method [1]_. + + Parameters + ========== + + j1, m1, j2, m2, j3, m3 : Number, Symbol + Terms determining the angular momentum of coupled angular momentum + systems. + + Examples + ======== + + Declare a Wigner-3j coefficient and calculate its value + + >>> from sympy.physics.quantum.cg import Wigner3j + >>> w3j = Wigner3j(6,0,4,0,2,0) + >>> w3j + Wigner3j(6, 0, 4, 0, 2, 0) + >>> w3j.doit() + sqrt(715)/143 + + See Also + ======== + + CG: Clebsch-Gordan coefficients + + References + ========== + + .. [1] Varshalovich, D A, Quantum Theory of Angular Momentum. 1988. + """ + + is_commutative = True + + def __new__(cls, j1, m1, j2, m2, j3, m3): + args = map(sympify, (j1, m1, j2, m2, j3, m3)) + return Expr.__new__(cls, *args) + + @property + def j1(self): + return self.args[0] + + @property + def m1(self): + return self.args[1] + + @property + def j2(self): + return self.args[2] + + @property + def m2(self): + return self.args[3] + + @property + def j3(self): + return self.args[4] + + @property + def m3(self): + return self.args[5] + + @property + def is_symbolic(self): + return not all(arg.is_number for arg in self.args) + + # 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)), + (printer._print(self.j3), printer._print(self.m3))) + hsep = 2 + vsep = 1 + maxw = [-1]*3 + for j in range(3): + maxw[j] = max(m[j][i].width() for i in range(2)) + D = None + for i in range(2): + D_row = None + for j in range(3): + s = m[j][i] + wdelta = maxw[j] - s.width() + wleft = wdelta //2 + wright = wdelta - wleft + + s = prettyForm(*s.right(' '*wright)) + s = prettyForm(*s.left(' '*wleft)) + + if D_row is None: + D_row = s + continue + D_row = prettyForm(*D_row.right(' '*hsep)) + D_row = prettyForm(*D_row.right(s)) + if D is None: + D = D_row + continue + for _ in range(vsep): + D = prettyForm(*D.below(' ')) + D = prettyForm(*D.below(D_row)) + D = prettyForm(*D.parens()) + return D + + def _latex(self, printer, *args): + label = 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) + + def doit(self, **hints): + if self.is_symbolic: + raise ValueError("Coefficients must be numerical") + return wigner_3j(self.j1, self.j2, self.j3, self.m1, self.m2, self.m3) + + +class CG(Wigner3j): + r"""Class for Clebsch-Gordan coefficient. + + Explanation + =========== + + Clebsch-Gordan coefficients describe the angular momentum coupling between + two systems. The coefficients give the expansion of a coupled total angular + momentum state and an uncoupled tensor product state. The Clebsch-Gordan + coefficients are defined as [1]_: + + .. math :: + C^{j_3,m_3}_{j_1,m_1,j_2,m_2} = \left\langle j_1,m_1;j_2,m_2 | j_3,m_3\right\rangle + + Parameters + ========== + + j1, m1, j2, m2 : Number, Symbol + Angular momenta of states 1 and 2. + + j3, m3: Number, Symbol + Total angular momentum of the coupled system. + + Examples + ======== + + Define a Clebsch-Gordan coefficient and evaluate its value + + >>> from sympy.physics.quantum.cg import CG + >>> from sympy import S + >>> cg = CG(S(3)/2, S(3)/2, S(1)/2, -S(1)/2, 1, 1) + >>> cg + CG(3/2, 3/2, 1/2, -1/2, 1, 1) + >>> cg.doit() + sqrt(3)/2 + >>> CG(j1=S(1)/2, m1=-S(1)/2, j2=S(1)/2, m2=+S(1)/2, j3=1, m3=0).doit() + sqrt(2)/2 + + + Compare [2]_. + + See Also + ======== + + Wigner3j: Wigner-3j symbols + + References + ========== + + .. [1] Varshalovich, D A, Quantum Theory of Angular Momentum. 1988. + .. [2] `Clebsch-Gordan Coefficients, Spherical Harmonics, and d Functions + `_ + in P.A. Zyla *et al.* (Particle Data Group), Prog. Theor. Exp. Phys. + 2020, 083C01 (2020). + """ + precedence = PRECEDENCE["Pow"] - 1 + + 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) + + def _pretty(self, printer, *args): + 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()) + bot = prettyForm(*bot.left(' ')) + top = prettyForm(*top.left(' ')) + + if not pad == bot.width(): + bot = prettyForm(*bot.right(' '*(pad - bot.width()))) + if not 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 = 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) + + +class Wigner6j(Expr): + """Class for the Wigner-6j symbols + + See Also + ======== + + Wigner3j: Wigner-3j symbols + + """ + def __new__(cls, j1, j2, j12, j3, j, j23): + args = map(sympify, (j1, j2, j12, j3, j, j23)) + return Expr.__new__(cls, *args) + + @property + def j1(self): + return self.args[0] + + @property + def j2(self): + return self.args[1] + + @property + def j12(self): + return self.args[2] + + @property + def j3(self): + return self.args[3] + + @property + def j(self): + return self.args[4] + + @property + def j23(self): + return self.args[5] + + @property + def is_symbolic(self): + return not all(arg.is_number for arg in self.args) + + # 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)), + (printer._print(self.j12), printer._print(self.j23))) + hsep = 2 + vsep = 1 + maxw = [-1]*3 + for j in range(3): + maxw[j] = max(m[j][i].width() for i in range(2)) + D = None + for i in range(2): + D_row = None + for j in range(3): + s = m[j][i] + wdelta = maxw[j] - s.width() + wleft = wdelta //2 + wright = wdelta - wleft + + s = prettyForm(*s.right(' '*wright)) + s = prettyForm(*s.left(' '*wleft)) + + if D_row is None: + D_row = s + continue + D_row = prettyForm(*D_row.right(' '*hsep)) + D_row = prettyForm(*D_row.right(s)) + if D is None: + D = D_row + continue + for _ in range(vsep): + D = prettyForm(*D.below(' ')) + D = prettyForm(*D.below(D_row)) + D = prettyForm(*D.parens(left='{', right='}')) + return D + + def _latex(self, printer, *args): + label = 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) + + def doit(self, **hints): + if self.is_symbolic: + raise ValueError("Coefficients must be numerical") + return wigner_6j(self.j1, self.j2, self.j12, self.j3, self.j, self.j23) + + +class Wigner9j(Expr): + """Class for the Wigner-9j symbols + + See Also + ======== + + Wigner3j: Wigner-3j symbols + + """ + def __new__(cls, j1, j2, j12, j3, j4, j34, j13, j24, j): + args = map(sympify, (j1, j2, j12, j3, j4, j34, j13, j24, j)) + return Expr.__new__(cls, *args) + + @property + def j1(self): + return self.args[0] + + @property + def j2(self): + return self.args[1] + + @property + def j12(self): + return self.args[2] + + @property + def j3(self): + return self.args[3] + + @property + def j4(self): + return self.args[4] + + @property + def j34(self): + return self.args[5] + + @property + def j13(self): + return self.args[6] + + @property + def j24(self): + return self.args[7] + + @property + def j(self): + return self.args[8] + + @property + def is_symbolic(self): + return not all(arg.is_number for arg in self.args) + + # 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)), + (printer._print(self.j12), printer._print(self.j34), printer._print(self.j))) + hsep = 2 + vsep = 1 + maxw = [-1]*3 + for j in range(3): + maxw[j] = max(m[j][i].width() for i in range(3)) + D = None + for i in range(3): + D_row = None + for j in range(3): + s = m[j][i] + wdelta = maxw[j] - s.width() + wleft = wdelta //2 + wright = wdelta - wleft + + s = prettyForm(*s.right(' '*wright)) + s = prettyForm(*s.left(' '*wleft)) + + if D_row is None: + D_row = s + continue + D_row = prettyForm(*D_row.right(' '*hsep)) + D_row = prettyForm(*D_row.right(s)) + if D is None: + D = D_row + continue + for _ in range(vsep): + D = prettyForm(*D.below(' ')) + D = prettyForm(*D.below(D_row)) + D = prettyForm(*D.parens(left='{', right='}')) + return D + + def _latex(self, printer, *args): + label = 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) + + def doit(self, **hints): + if self.is_symbolic: + raise ValueError("Coefficients must be numerical") + return wigner_9j(self.j1, self.j2, self.j12, self.j3, self.j4, self.j34, self.j13, self.j24, self.j) + + +def cg_simp(e): + """Simplify and combine CG coefficients. + + Explanation + =========== + + This function uses various symmetry and properties of sums and + products of Clebsch-Gordan coefficients to simplify statements + involving these terms [1]_. + + Examples + ======== + + Simplify the sum over CG(a,alpha,0,0,a,alpha) for all alpha to + 2*a+1 + + >>> from sympy.physics.quantum.cg import CG, cg_simp + >>> a = CG(1,1,0,0,1,1) + >>> b = CG(1,0,0,0,1,0) + >>> c = CG(1,-1,0,0,1,-1) + >>> cg_simp(a+b+c) + 3 + + See Also + ======== + + CG: Clebsh-Gordan coefficients + + References + ========== + + .. [1] Varshalovich, D A, Quantum Theory of Angular Momentum. 1988. + """ + if isinstance(e, Add): + return _cg_simp_add(e) + elif isinstance(e, Sum): + return _cg_simp_sum(e) + elif isinstance(e, Mul): + return Mul(*[cg_simp(arg) for arg in e.args]) + elif isinstance(e, Pow): + return Pow(cg_simp(e.base), e.exp) + else: + return e + + +def _cg_simp_add(e): + #TODO: Improve simplification method + """Takes a sum of terms involving Clebsch-Gordan coefficients and + simplifies the terms. + + Explanation + =========== + + First, we create two lists, cg_part, which is all the terms involving CG + coefficients, and other_part, which is all other terms. The cg_part list + is then passed to the simplification methods, which return the new cg_part + and any additional terms that are added to other_part + """ + cg_part = [] + other_part = [] + + e = expand(e) + for arg in e.args: + if arg.has(CG): + if isinstance(arg, Sum): + other_part.append(_cg_simp_sum(arg)) + elif isinstance(arg, Mul): + terms = 1 + for term in arg.args: + if isinstance(term, Sum): + terms *= _cg_simp_sum(term) + else: + terms *= term + if terms.has(CG): + cg_part.append(terms) + else: + other_part.append(terms) + else: + cg_part.append(arg) + else: + other_part.append(arg) + + cg_part, other = _check_varsh_871_1(cg_part) + other_part.append(other) + cg_part, other = _check_varsh_871_2(cg_part) + other_part.append(other) + cg_part, other = _check_varsh_872_9(cg_part) + other_part.append(other) + 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 = 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) + + +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 = 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 = 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 + simp = S.One + 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) + + # 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) + + # 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) + sign = S.One + 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, S.One, 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, S.One, 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 + + +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 + simplified list of terms and any terms generated by simplification. + + Parameters + ========== + + expr: expression + The expression with Wild terms that will be matched to the terms in + the sum + + simp: expression + The expression with Wild terms that is substituted in place of the CG + terms in the case of simplification + + sign: expression + The expression with Wild terms denoting the sign that is on expr that + must match + + lt: expression + The expression with Wild terms that gives the leading term of the + matched expr + + term_list: list + A list of all of the terms is the sum to be simplified + + variables: list + A list of all the variables that appears in expr + + dep_variables: list + A list of the variables that must match for all the terms in the sum, + i.e. the dependent variables + + build_index_expr: expression + Expression with Wild terms giving the number of elements in cg_index + + index_expr: expression + Expression with Wild terms giving the index terms have when storing + them to cg_index + + """ + other_part = 0 + i = 0 + while i < len(term_list): + sub_1 = _check_cg(term_list[i], expr, len(variables)) + if sub_1 is None: + i += 1 + continue + if not build_index_expr.subs(sub_1).is_number: + i += 1 + continue + 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))) + if sub_2 is None: + continue + if not 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) + if not any(i is None for i in cg_index): + min_lt = min(*[ abs(term[2]) for term in cg_index ]) + indices = [ term[0] for term in cg_index] + indices.sort() + indices.reverse() + [ term_list.pop(j) for j in indices ] + for term in cg_index: + if abs(term[2]) > min_lt: + 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 + matches = cg_term.match(expr) + if matches is None: + return + if sign is not None: + if not isinstance(sign, tuple): + raise TypeError('sign must be a tuple') + if not sign[0] == (sign[1]).subs(matches): + return + 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))) + if match is not None and len(match) == 2: + 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))) + if match is not None and len(match) == 2: + return (sqrt(2*a + 1)*KroneckerDelta(c, 0)).subs(match) + return e + + +def _check_varsh_sum_872_4(e): + alpha = symbols('alpha') + beta = symbols('beta') + a = Wild('a') + b = Wild('b') + c = Wild('c') + cp = Wild('cp') + gamma = Wild('gamma') + gammap = Wild('gammap') + cg1 = CG(a, alpha, b, beta, c, gamma) + cg2 = CG(a, alpha, b, beta, cp, gammap) + match1 = e.match(Sum(cg1*cg2, (alpha, -a, a), (beta, -b, b))) + if match1 is not None and len(match1) == 6: + return (KroneckerDelta(c, cp)*KroneckerDelta(gamma, gammap)).subs(match1) + match2 = e.match(Sum(cg1**2, (alpha, -a, a), (beta, -b, b))) + if match2 is not None and len(match2) == 4: + return S.One + return e + + +def _cg_list(term): + if isinstance(term, CG): + return (term,), 1, 1 + cg = [] + coeff = 1 + if not isinstance(term, (Mul, Pow)): + raise NotImplementedError('term must be CG, Add, Mul or Pow') + if isinstance(term, Pow) and term.exp.is_number: + if term.exp.is_number: + [ cg.append(term.base) for _ in range(term.exp) ] + else: + return (term,), 1, 1 + if isinstance(term, Mul): + for arg in term.args: + if isinstance(arg, CG): + cg.append(arg) + else: + coeff *= arg + return cg, coeff, coeff/abs(coeff) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/circuitplot.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/circuitplot.py new file mode 100644 index 0000000000000000000000000000000000000000..316a4be613b2e275565999130c06ea678acd8b96 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/circuitplot.py @@ -0,0 +1,370 @@ +"""Matplotlib based plotting of quantum circuits. + +Todo: + +* Optimize printing of large circuits. +* Get this to work with single gates. +* Do a better job checking the form of circuits to make sure it is a Mul of + Gates. +* Get multi-target gates plotting. +* Get initial and final states to plot. +* Get measurements to plot. Might need to rethink measurement as a gate + issue. +* Get scale and figsize to be handled in a better way. +* Write some tests/examples! +""" + +from __future__ import annotations + +from sympy.core.mul import Mul +from sympy.external import import_module +from sympy.physics.quantum.gate import Gate, OneQubitGate, CGate, CGateS + + +__all__ = [ + 'CircuitPlot', + 'circuit_plot', + 'labeller', + 'Mz', + 'Mx', + 'CreateOneQubitGate', + 'CreateCGate', +] + +np = import_module('numpy') +matplotlib = import_module( + 'matplotlib', import_kwargs={'fromlist': ['pyplot']}, + catch=(RuntimeError,)) # This is raised in environments that have no display. + +if np and matplotlib: + pyplot = matplotlib.pyplot + Line2D = matplotlib.lines.Line2D + Circle = matplotlib.patches.Circle + +#from matplotlib import rc +#rc('text',usetex=True) + +class CircuitPlot: + """A class for managing a circuit plot.""" + + scale = 1.0 + fontsize = 20.0 + linewidth = 1.0 + control_radius = 0.05 + not_radius = 0.15 + swap_delta = 0.05 + labels: list[str] = [] + inits: dict[str, str] = {} + label_buffer = 0.5 + + def __init__(self, c, nqubits, **kwargs): + if not np or not matplotlib: + raise ImportError('numpy or matplotlib not available.') + self.circuit = c + self.ngates = len(self.circuit.args) + self.nqubits = nqubits + self.update(kwargs) + self._create_grid() + self._create_figure() + self._plot_wires() + self._plot_gates() + self._finish() + + def update(self, kwargs): + """Load the kwargs into the instance dict.""" + self.__dict__.update(kwargs) + + 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) + 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), + facecolor='w', + edgecolor='w' + ) + ax = self._figure.add_subplot( + 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_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) + for i in range(self.nqubits): + ydata = (self._wire_grid[i], self._wire_grid[i]) + line = Line2D( + xdata, ydata, + color='k', + lw=self.linewidth + ) + self._axes.add_line(line) + if self.labels: + init_label_buffer = 0 + if self.inits.get(self.labels[i]): init_label_buffer = 0.25 + self._axes.text( + xdata[0]-self.label_buffer-init_label_buffer,ydata[0], + render_label(self.labels[i],self.inits), + size=self.fontsize, + color='k',ha='center',va='center') + self._plot_measured_wires() + + def _plot_measured_wires(self): + ismeasured = self._measurements() + xstop = self._gate_grid[-1] + dy = 0.04 # amount to shift wires when doubled + # Plot doubled wires after they are measured + for im in ismeasured: + xdata = (self._gate_grid[ismeasured[im]],xstop+self.scale) + ydata = (self._wire_grid[im]+dy,self._wire_grid[im]+dy) + line = Line2D( + xdata, ydata, + color='k', + lw=self.linewidth + ) + self._axes.add_line(line) + # Also double any controlled lines off these wires + for i,g in enumerate(self._gates()): + if isinstance(g, (CGate, CGateS)): + wires = g.controls + g.targets + for wire in wires: + if wire in ismeasured and \ + self._gate_grid[i] > self._gate_grid[ismeasured[wire]]: + ydata = min(wires), max(wires) + xdata = self._gate_grid[i]-dy, self._gate_grid[i]-dy + line = Line2D( + xdata, ydata, + color='k', + lw=self.linewidth + ) + self._axes.add_line(line) + def _gates(self): + """Create a list of all gates in the circuit plot.""" + gates = [] + if isinstance(self.circuit, Mul): + for g in reversed(self.circuit.args): + if isinstance(g, Gate): + gates.append(g) + elif isinstance(self.circuit, Gate): + gates.append(self.circuit) + return gates + + def _plot_gates(self): + """Iterate through the gates and plot each of them.""" + for i, gate in enumerate(self._gates()): + gate.plot_gate(self, i) + + def _measurements(self): + """Return a dict ``{i:j}`` where i is the index of the wire that has + been measured, and j is the gate where the wire is measured. + """ + ismeasured = {} + for i,g in enumerate(self._gates()): + if getattr(g,'measurement',False): + for target in g.targets: + if target in ismeasured: + if ismeasured[target] > i: + ismeasured[target] = i + else: + ismeasured[target] = i + return ismeasured + + def _finish(self): + # Disable clipping to make panning work well for large circuits. + for o in self._figure.findobj(): + o.set_clip_on(False) + + def one_qubit_box(self, t, gate_idx, wire_idx): + """Draw a box for a single qubit gate.""" + x = self._gate_grid[gate_idx] + y = self._wire_grid[wire_idx] + self._axes.text( + x, y, t, + color='k', + ha='center', + va='center', + bbox={"ec": 'k', "fc": 'w', "fill": True, "lw": self.linewidth}, + size=self.fontsize + ) + + def two_qubit_box(self, t, gate_idx, wire_idx): + """Draw a box for a two qubit gate. Does not work yet. + """ + # x = self._gate_grid[gate_idx] + # y = self._wire_grid[wire_idx]+0.5 + print(self._gate_grid) + print(self._wire_grid) + # unused: + # obj = self._axes.text( + # x, y, t, + # color='k', + # ha='center', + # va='center', + # bbox=dict(ec='k', fc='w', fill=True, lw=self.linewidth), + # size=self.fontsize + # ) + + def control_line(self, gate_idx, min_wire, max_wire): + """Draw a vertical control line.""" + 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, + color='k', + lw=self.linewidth + ) + self._axes.add_line(line) + + def control_point(self, gate_idx, wire_idx): + """Draw a control point.""" + x = self._gate_grid[gate_idx] + y = self._wire_grid[wire_idx] + radius = self.control_radius + c = Circle( + (x, y), + radius*self.scale, + ec='k', + fc='k', + fill=True, + lw=self.linewidth + ) + self._axes.add_patch(c) + + def not_point(self, gate_idx, wire_idx): + """Draw a NOT gates as the circle with plus in the middle.""" + x = self._gate_grid[gate_idx] + y = self._wire_grid[wire_idx] + radius = self.not_radius + c = Circle( + (x, y), + radius, + ec='k', + fc='w', + fill=False, + lw=self.linewidth + ) + self._axes.add_patch(c) + l = Line2D( + (x, x), (y - radius, y + radius), + color='k', + lw=self.linewidth + ) + self._axes.add_line(l) + + def swap_point(self, gate_idx, wire_idx): + """Draw a swap point as a cross.""" + x = self._gate_grid[gate_idx] + y = self._wire_grid[wire_idx] + d = self.swap_delta + l1 = Line2D( + (x - d, x + d), + (y - d, y + d), + color='k', + lw=self.linewidth + ) + l2 = Line2D( + (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. + + Parameters + ========== + + c : circuit + The circuit to plot. Should be a product of Gate instances. + nqubits : int + The number of qubits to include in the circuit. Must be at least + as big as the largest ``min_qubits`` of the gates. + """ + return CircuitPlot(c, nqubits, **kwargs) + +def render_label(label, inits={}): + """Slightly more flexible way to render labels. + + >>> from sympy.physics.quantum.circuitplot import render_label + >>> render_label('q0') + '$\\\\left|q0\\\\right\\\\rangle$' + >>> render_label('q0', {'q0':'0'}) + '$\\\\left|q0\\\\right\\\\rangle=\\\\left|0\\\\right\\\\rangle$' + """ + init = inits.get(label) + if init: + return r'$\left|%s\right\rangle=\left|%s\right\rangle$' % (label, init) + return r'$\left|%s\right\rangle$' % label + +def labeller(n, symbol='q'): + """Autogenerate labels for wires of quantum circuits. + + Parameters + ========== + + n : int + number of qubits in the circuit. + symbol : string + A character string to precede all gate labels. E.g. 'q_0', 'q_1', etc. + + >>> from sympy.physics.quantum.circuitplot import labeller + >>> labeller(2) + ['q_1', 'q_0'] + >>> labeller(3,'j') + ['j_2', 'j_1', 'j_0'] + """ + return ['%s_%d' % (symbol,n-i-1) for i in range(n)] + +class Mz(OneQubitGate): + """Mock-up of a z measurement gate. + + This is in circuitplot rather than gate.py because it's not a real + gate, it just draws one. + """ + measurement = True + gate_name='Mz' + gate_name_latex='M_z' + +class Mx(OneQubitGate): + """Mock-up of an x measurement gate. + + This is in circuitplot rather than gate.py because it's not a real + gate, it just draws one. + """ + measurement = True + gate_name='Mx' + gate_name_latex='M_x' + +class CreateOneQubitGate(type): + def __new__(mcl, name, latexname=None): + if not latexname: + latexname = name + return type(name + "Gate", (OneQubitGate,), + {'gate_name': name, 'gate_name_latex': latexname}) + +def CreateCGate(name, latexname=None): + """Use a lexical closure to make a controlled gate. + """ + if not latexname: + latexname = name + onequbitgate = CreateOneQubitGate(name, latexname) + def ControlledGate(ctrls,target): + return CGate(tuple(ctrls),onequbitgate(target)) + return ControlledGate diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/circuitutils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/circuitutils.py new file mode 100644 index 0000000000000000000000000000000000000000..84955d3d724a2658f2dc3b26738133bd46f1aa57 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/circuitutils.py @@ -0,0 +1,488 @@ +"""Primitive circuit operations on quantum circuits.""" + +from functools import reduce + +from sympy.core.sorting import default_sort_key +from sympy.core.containers import Tuple +from sympy.core.mul import Mul +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.utilities import numbered_symbols +from sympy.physics.quantum.gate import Gate + +__all__ = [ + 'kmp_table', + 'find_subcircuit', + 'replace_subcircuit', + 'convert_to_symbolic_indices', + 'convert_to_real_indices', + 'random_reduce', + 'random_insert' +] + + +def kmp_table(word): + """Build the 'partial match' table of the Knuth-Morris-Pratt algorithm. + + Note: This is applicable to strings or + quantum circuits represented as tuples. + """ + + # Current position in subcircuit + pos = 2 + # Beginning position of candidate substring that + # may reappear later in word + cnd = 0 + # The 'partial match' table that helps one determine + # the next location to start substring search + table = [] + table.append(-1) + table.append(0) + + while pos < len(word): + if word[pos - 1] == word[cnd]: + cnd = cnd + 1 + table.append(cnd) + pos = pos + 1 + elif cnd > 0: + cnd = table[cnd] + else: + table.append(0) + pos = pos + 1 + + return table + + +def find_subcircuit(circuit, subcircuit, start=0, end=0): + """Finds the subcircuit in circuit, if it exists. + + Explanation + =========== + + If the subcircuit exists, the index of the start of + the subcircuit in circuit is returned; otherwise, + -1 is returned. The algorithm that is implemented + is the Knuth-Morris-Pratt algorithm. + + Parameters + ========== + + circuit : tuple, Gate or Mul + A tuple of Gates or Mul representing a quantum circuit + subcircuit : tuple, Gate or Mul + A tuple of Gates or Mul to find in circuit + start : int + The location to start looking for subcircuit. + If start is the same or past end, -1 is returned. + end : int + The last place to look for a subcircuit. If end + is less than 1 (one), then the length of circuit + is taken to be end. + + Examples + ======== + + Find the first instance of a subcircuit: + + >>> from sympy.physics.quantum.circuitutils import find_subcircuit + >>> from sympy.physics.quantum.gate import X, Y, Z, H + >>> circuit = X(0)*Z(0)*Y(0)*H(0) + >>> subcircuit = Z(0)*Y(0) + >>> find_subcircuit(circuit, subcircuit) + 1 + + Find the first instance starting at a specific position: + + >>> find_subcircuit(circuit, subcircuit, start=1) + 1 + + >>> find_subcircuit(circuit, subcircuit, start=2) + -1 + + >>> circuit = circuit*subcircuit + >>> find_subcircuit(circuit, subcircuit, start=2) + 4 + + Find the subcircuit within some interval: + + >>> find_subcircuit(circuit, subcircuit, start=2, end=2) + -1 + """ + + if isinstance(circuit, Mul): + circuit = circuit.args + + if isinstance(subcircuit, Mul): + subcircuit = subcircuit.args + + if len(subcircuit) == 0 or len(subcircuit) > len(circuit): + return -1 + + if end < 1: + end = len(circuit) + + # Location in circuit + pos = start + # Location in the subcircuit + index = 0 + # 'Partial match' table + table = kmp_table(subcircuit) + + while (pos + index) < end: + if subcircuit[index] == circuit[pos + index]: + index = index + 1 + else: + pos = pos + index - table[index] + index = table[index] if table[index] > -1 else 0 + + if index == len(subcircuit): + return pos + + return -1 + + +def replace_subcircuit(circuit, subcircuit, replace=None, pos=0): + """Replaces a subcircuit with another subcircuit in circuit, + if it exists. + + Explanation + =========== + + If multiple instances of subcircuit exists, the first instance is + replaced. The position to being searching from (if different from + 0) may be optionally given. If subcircuit cannot be found, circuit + is returned. + + Parameters + ========== + + circuit : tuple, Gate or Mul + A quantum circuit. + subcircuit : tuple, Gate or Mul + The circuit to be replaced. + replace : tuple, Gate or Mul + The replacement circuit. + pos : int + The location to start search and replace + subcircuit, if it exists. This may be used + if it is known beforehand that multiple + instances exist, and it is desirable to + replace a specific instance. If a negative number + is given, pos will be defaulted to 0. + + Examples + ======== + + Find and remove the subcircuit: + + >>> from sympy.physics.quantum.circuitutils import replace_subcircuit + >>> from sympy.physics.quantum.gate import X, Y, Z, H + >>> circuit = X(0)*Z(0)*Y(0)*H(0)*X(0)*H(0)*Y(0) + >>> subcircuit = Z(0)*Y(0) + >>> replace_subcircuit(circuit, subcircuit) + (X(0), H(0), X(0), H(0), Y(0)) + + Remove the subcircuit given a starting search point: + + >>> replace_subcircuit(circuit, subcircuit, pos=1) + (X(0), H(0), X(0), H(0), Y(0)) + + >>> replace_subcircuit(circuit, subcircuit, pos=2) + (X(0), Z(0), Y(0), H(0), X(0), H(0), Y(0)) + + Replace the subcircuit: + + >>> replacement = H(0)*Z(0) + >>> replace_subcircuit(circuit, subcircuit, replace=replacement) + (X(0), H(0), Z(0), H(0), X(0), H(0), Y(0)) + """ + + if pos < 0: + pos = 0 + + if isinstance(circuit, Mul): + circuit = circuit.args + + if isinstance(subcircuit, Mul): + subcircuit = subcircuit.args + + if isinstance(replace, Mul): + replace = replace.args + elif replace is None: + replace = () + + # Look for the subcircuit starting at pos + loc = find_subcircuit(circuit, subcircuit, start=pos) + + # If subcircuit was found + if loc > -1: + # Get the gates to the left of subcircuit + left = circuit[0:loc] + # Get the gates to the right of subcircuit + right = circuit[loc + len(subcircuit):len(circuit)] + # Recombine the left and right side gates into a circuit + circuit = left + replace + right + + 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. + + The mapping is 1 to 1 and onto (bijective). + + Parameters + ========== + + seq : tuple, Gate/Integer/tuple or Mul + A tuple of Gate, Integer, or tuple objects, or a Mul + start : Symbol + An optional starting symbolic index + gen : object + An optional numbered symbol generator + qubit_map : dict + An existing mapping of symbolic indices to real indices + + All symbolic indices have the format 'i#', where # is + some number >= 0. + """ + + if isinstance(seq, Mul): + seq = seq.args + + # A numbered symbol generator + index_gen = numbered_symbols(prefix='i', start=-1) + cur_ndx = next(index_gen) + + # keys are symbolic indices; values are real indices + ndx_map = {} + + def create_inverse_map(symb_to_real_map): + rev_items = lambda item: (item[1], item[0]) + return dict(map(rev_items, symb_to_real_map.items())) + + if start is not None: + if not isinstance(start, Symbol): + msg = 'Expected Symbol for starting index, got %r.' % start + raise TypeError(msg) + cur_ndx = start + + if gen is not None: + if not isinstance(gen, numbered_symbols().__class__): + msg = 'Expected a generator, got %r.' % gen + raise TypeError(msg) + index_gen = gen + + if qubit_map is not None: + if not isinstance(qubit_map, dict): + msg = ('Expected dict for existing map, got ' + + '%r.' % qubit_map) + raise TypeError(msg) + ndx_map = qubit_map + + ndx_map = _sympify_qubit_map(ndx_map) + # keys are real indices; keys are symbolic indices + inv_map = create_inverse_map(ndx_map) + + sym_seq = () + for item in seq: + # Nested items, so recurse + if isinstance(item, Gate): + result = convert_to_symbolic_indices(item.args, + qubit_map=ndx_map, + start=cur_ndx, + gen=index_gen) + sym_item, new_map, cur_ndx, index_gen = result + ndx_map.update(new_map) + inv_map = create_inverse_map(ndx_map) + + elif isinstance(item, (tuple, Tuple)): + result = convert_to_symbolic_indices(item, + qubit_map=ndx_map, + start=cur_ndx, + gen=index_gen) + sym_item, new_map, cur_ndx, index_gen = result + ndx_map.update(new_map) + inv_map = create_inverse_map(ndx_map) + + elif item in inv_map: + sym_item = inv_map[item] + + else: + cur_ndx = next(gen) + ndx_map[cur_ndx] = item + inv_map[item] = cur_ndx + sym_item = cur_ndx + + if isinstance(item, Gate): + sym_item = item.__class__(*sym_item) + + sym_seq = sym_seq + (sym_item,) + + return sym_seq, ndx_map, cur_ndx, index_gen + + +def convert_to_real_indices(seq, qubit_map): + """Returns the circuit with real indices. + + Parameters + ========== + + seq : tuple, Gate/Integer/tuple or Mul + A tuple of Gate, Integer, or tuple objects or a Mul + qubit_map : dict + A dictionary mapping symbolic indices to real indices. + + Examples + ======== + + Change the symbolic indices to real integers: + + >>> from sympy import symbols + >>> from sympy.physics.quantum.circuitutils import convert_to_real_indices + >>> from sympy.physics.quantum.gate import X, Y, H + >>> i0, i1 = symbols('i:2') + >>> index_map = {i0 : 0, i1 : 1} + >>> convert_to_real_indices(X(i0)*Y(i1)*H(i0)*X(i1), index_map) + (X(0), Y(1), H(0), X(1)) + """ + + if isinstance(seq, Mul): + seq = seq.args + + if not isinstance(qubit_map, dict): + msg = 'Expected dict for qubit_map, got %r.' % qubit_map + raise TypeError(msg) + + qubit_map = _sympify_qubit_map(qubit_map) + real_seq = () + for item in seq: + # Nested items, so recurse + if isinstance(item, Gate): + real_item = convert_to_real_indices(item.args, qubit_map) + + elif isinstance(item, (tuple, Tuple)): + real_item = convert_to_real_indices(item, qubit_map) + + else: + real_item = qubit_map[item] + + if isinstance(item, Gate): + real_item = item.__class__(*real_item) + + real_seq = real_seq + (real_item,) + + return real_seq + + +def random_reduce(circuit, gate_ids, seed=None): + """Shorten the length of a quantum circuit. + + Explanation + =========== + + random_reduce looks for circuit identities in circuit, randomly chooses + one to remove, and returns a shorter yet equivalent circuit. If no + identities are found, the same circuit is returned. + + Parameters + ========== + + circuit : Gate tuple of Mul + A tuple of Gates representing a quantum circuit + gate_ids : list, GateIdentity + List of gate identities to find in circuit + seed : int or list + seed used for _randrange; to override the random selection, provide a + list of integers: the elements of gate_ids will be tested in the order + given by the list + + """ + from sympy.core.random import _randrange + + if not gate_ids: + return circuit + + if isinstance(circuit, Mul): + circuit = circuit.args + + ids = flatten_ids(gate_ids) + + # Create the random integer generator with the seed + randrange = _randrange(seed) + + # Look for an identity in the circuit + while ids: + i = randrange(len(ids)) + id = ids.pop(i) + if find_subcircuit(circuit, id) != -1: + break + else: + # no identity was found + return circuit + + # 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. + + Explanation + =========== + + random_insert randomly chooses a location in the circuit to insert + a randomly selected circuit from amongst the given choices. + + Parameters + ========== + + circuit : Gate tuple or Mul + A tuple or Mul of Gates representing a quantum circuit + choices : list + Set of circuit choices + seed : int or list + seed used for _randrange; to override the random selections, give + a list two integers, [i, j] where i is the circuit location where + choice[j] will be inserted. + + Notes + ===== + + Indices for insertion should be [0, n] if n is the length of the + circuit. + """ + from sympy.core.random import _randrange + + if not choices: + return circuit + + if isinstance(circuit, Mul): + circuit = circuit.args + + # get the location in the circuit and the element to insert from choices + randrange = _randrange(seed) + loc = randrange(len(circuit) + 1) + choice = choices[randrange(len(choices))] + + circuit = list(circuit) + circuit[loc: loc] = choice + 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) + ids = reduce(collapse, ids, []) + ids.sort(key=default_sort_key) + return ids diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/commutator.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/commutator.py new file mode 100644 index 0000000000000000000000000000000000000000..a2d97a679e27387077429a9973de21ad868e84ac --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/commutator.py @@ -0,0 +1,256 @@ +"""The commutator: [A,B] = A*B - B*A.""" + +from sympy.core.add import Add +from sympy.core.expr import Expr +from sympy.core.kind import KindDispatcher +from sympy.core.mul import Mul +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.printing.pretty.stringpict import prettyForm + +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.kind import _OperatorKind, OperatorKind + + +__all__ = [ + 'Commutator' +] + +#----------------------------------------------------------------------------- +# Commutator +#----------------------------------------------------------------------------- + + +class Commutator(Expr): + """The standard commutator, in an unevaluated state. + + Explanation + =========== + + Evaluating a commutator is defined [1]_ as: ``[A, B] = A*B - B*A``. This + class returns the commutator in an unevaluated form. To evaluate the + commutator, use the ``.doit()`` method. + + Canonical ordering of a commutator is ``[A, B]`` for ``A < B``. The + arguments of the commutator are put into canonical order using ``__cmp__``. + If ``B < A``, then ``[B, A]`` is returned as ``-[A, B]``. + + Parameters + ========== + + A : Expr + The first argument of the commutator [A,B]. + B : Expr + The second argument of the commutator [A,B]. + + Examples + ======== + + >>> from sympy.physics.quantum import Commutator, Dagger, Operator + >>> from sympy.abc import x, y + >>> A = Operator('A') + >>> B = Operator('B') + >>> C = Operator('C') + + Create a commutator and use ``.doit()`` to evaluate it: + + >>> comm = Commutator(A, B) + >>> comm + [A,B] + >>> comm.doit() + A*B - B*A + + The commutator orders it arguments in canonical order: + + >>> comm = Commutator(B, A); comm + -[A,B] + + Commutative constants are factored out: + + >>> Commutator(3*x*A, x*y*B) + 3*x**2*y*[A,B] + + Using ``.expand(commutator=True)``, the standard commutator expansion rules + can be applied: + + >>> Commutator(A+B, C).expand(commutator=True) + [A,C] + [B,C] + >>> Commutator(A, B+C).expand(commutator=True) + [A,B] + [A,C] + >>> Commutator(A*B, C).expand(commutator=True) + [A,C]*B + A*[B,C] + >>> Commutator(A, B*C).expand(commutator=True) + [A,B]*C + B*[A,C] + + Adjoint operations applied to the commutator are properly applied to the + arguments: + + >>> Dagger(Commutator(A, B)) + -[Dagger(A),Dagger(B)] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Commutator + """ + is_commutative = False + + _kind_dispatcher = KindDispatcher("Commutator_kind_dispatcher", commutative=True) + + @property + def kind(self): + arg_kinds = (a.kind for a in self.args) + return self._kind_dispatcher(*arg_kinds) + + def __new__(cls, A, B): + r = cls.eval(A, B) + if r is not None: + return r + obj = Expr.__new__(cls, A, B) + return obj + + @classmethod + def eval(cls, a, b): + 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 + + # [xA,yB] -> xy*[A,B] + ca, nca = a.args_cnc() + cb, ncb = b.args_cnc() + c_part = ca + cb + if c_part: + return Mul(Mul(*c_part), cls(Mul._from_args(nca), Mul._from_args(ncb))) + + # Canonical ordering of arguments + # The Commutator [A, B] is in canonical form if A < B. + if a.compare(b) == 1: + return S.NegativeOne*cls(b, a) + + def _expand_pow(self, A, B, sign): + exp = A.exp + if not exp.is_integer or not exp.is_constant() or abs(exp) <= 1: + # nothing to do + return self + base = A.base + if exp.is_negative: + base = A.base**-1 + exp = -exp + comm = Commutator(base, B).expand(commutator=True) + + result = base**(exp - 1) * comm + for i in range(1, exp): + result += base**(exp - 1 - i) * comm * base**i + return sign*result.expand() + + def _eval_expand_commutator(self, **hints): + A = self.args[0] + B = self.args[1] + + if isinstance(A, Add): + # [A + B, C] -> [A, C] + [B, C] + sargs = [] + for term in A.args: + comm = Commutator(term, B) + if isinstance(comm, Commutator): + comm = comm._eval_expand_commutator() + sargs.append(comm) + return Add(*sargs) + elif isinstance(B, Add): + # [A, B + C] -> [A, B] + [A, C] + sargs = [] + for term in B.args: + comm = Commutator(A, term) + if isinstance(comm, Commutator): + comm = comm._eval_expand_commutator() + sargs.append(comm) + return Add(*sargs) + elif isinstance(A, Mul): + # [A*B, C] -> A*[B, C] + [A, C]*B + a = A.args[0] + b = Mul(*A.args[1:]) + c = B + comm1 = Commutator(b, c) + comm2 = Commutator(a, c) + if isinstance(comm1, Commutator): + comm1 = comm1._eval_expand_commutator() + if isinstance(comm2, Commutator): + comm2 = comm2._eval_expand_commutator() + first = Mul(a, comm1) + second = Mul(comm2, b) + return Add(first, second) + elif isinstance(B, Mul): + # [A, B*C] -> [A, B]*C + B*[A, C] + a = A + b = B.args[0] + c = Mul(*B.args[1:]) + comm1 = Commutator(a, b) + comm2 = Commutator(a, c) + if isinstance(comm1, Commutator): + comm1 = comm1._eval_expand_commutator() + if isinstance(comm2, Commutator): + comm2 = comm2._eval_expand_commutator() + first = Mul(comm1, c) + second = Mul(b, comm2) + return Add(first, second) + elif isinstance(A, Pow): + # [A**n, C] -> A**(n - 1)*[A, C] + A**(n - 2)*[A, C]*A + ... + [A, C]*A**(n-1) + return self._expand_pow(A, B, 1) + elif isinstance(B, Pow): + # [A, C**n] -> C**(n - 1)*[C, A] + C**(n - 2)*[C, A]*C + ... + [C, A]*C**(n-1) + return self._expand_pow(B, A, -1) + + # No changes, so return self + return self + + def doit(self, **hints): + """ Evaluate commutator """ + # Keep the import of Operator here to avoid problems with + # circular imports. + from sympy.physics.quantum.operator import Operator + A = self.args[0] + B = self.args[1] + if isinstance(A, Operator) and isinstance(B, Operator): + try: + comm = A._eval_commutator(B, **hints) + except NotImplementedError: + try: + comm = -1*B._eval_commutator(A, **hints) + except NotImplementedError: + comm = None + if comm is not None: + return comm.doit(**hints) + return (A*B - B*A).doit(**hints) + + def _eval_adjoint(self): + return Commutator(Dagger(self.args[1]), Dagger(self.args[0])) + + def _sympyrepr(self, printer, *args): + return "%s(%s,%s)" % ( + self.__class__.__name__, printer._print( + self.args[0]), printer._print(self.args[1]) + ) + + def _sympystr(self, printer, *args): + return "[%s,%s]" % ( + printer._print(self.args[0]), printer._print(self.args[1])) + + def _pretty(self, printer, *args): + pform = printer._print(self.args[0], *args) + pform = prettyForm(*pform.right(prettyForm(','))) + pform = prettyForm(*pform.right(printer._print(self.args[1], *args))) + pform = prettyForm(*pform.parens(left='[', right=']')) + return pform + + def _latex(self, printer, *args): + return "\\left[%s,%s\\right]" % tuple([ + printer._print(arg, *args) for arg in self.args]) + + +@Commutator._kind_dispatcher.register(_OperatorKind, _OperatorKind) +def find_op_kind(e1, e2): + """Find the kind of an anticommutator of two OperatorKinds.""" + return OperatorKind diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/constants.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..3e848bf24e95e3bd612169128a1845202066c6e9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/constants.py @@ -0,0 +1,59 @@ +"""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 mpmath.libmp as mlib + +#----------------------------------------------------------------------------- +# Constants +#----------------------------------------------------------------------------- + +__all__ = [ + 'hbar', + 'HBar', +] + + +class HBar(NumberSymbol, metaclass=Singleton): + """Reduced Plank's constant in numerical and symbolic form [1]_. + + Examples + ======== + + >>> from sympy.physics.quantum.constants import hbar + >>> hbar.evalf() + 1.05457162000000e-34 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Planck_constant + """ + + is_real = True + is_positive = True + is_negative = False + is_irrational = True + + __slots__ = () + + def _as_mpf_val(self, prec): + return mlib.from_float(1.05457162e-34, prec) + + def _sympyrepr(self, printer, *args): + return 'HBar()' + + def _sympystr(self, printer, *args): + return 'hbar' + + def _pretty(self, printer, *args): + if printer._use_unicode: + return prettyForm('\N{PLANCK CONSTANT OVER TWO PI}') + return prettyForm('hbar') + + def _latex(self, printer, *args): + return r'\hbar' + +# Create an instance for everyone to use. +hbar = HBar() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/dagger.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/dagger.py new file mode 100644 index 0000000000000000000000000000000000000000..f96f01e3b9ac86ae30b03e3b97293bbafceaed8a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/dagger.py @@ -0,0 +1,95 @@ +"""Hermitian conjugation.""" + +from sympy.core import Expr, sympify +from sympy.functions.elementary.complexes import adjoint + +__all__ = [ + 'Dagger' +] + + +class Dagger(adjoint): + """General Hermitian conjugate operation. + + Explanation + =========== + + Take the Hermetian conjugate of an argument [1]_. For matrices this + operation is equivalent to transpose and complex conjugate [2]_. + + Parameters + ========== + + arg : Expr + The SymPy expression that we want to take the dagger of. + evaluate : bool + Whether the resulting expression should be directly evaluated. + + Examples + ======== + + Daggering various quantum objects: + + >>> from sympy.physics.quantum.dagger import Dagger + >>> from sympy.physics.quantum.state import Ket, Bra + >>> from sympy.physics.quantum.operator import Operator + >>> Dagger(Ket('psi')) + >> Dagger(Bra('phi')) + |phi> + >>> Dagger(Operator('A')) + Dagger(A) + + Inner and outer products:: + + >>> from sympy.physics.quantum import InnerProduct, OuterProduct + >>> Dagger(InnerProduct(Bra('a'), Ket('b'))) + + >>> Dagger(OuterProduct(Ket('a'), Bra('b'))) + |b>>> A = Operator('A') + >>> B = Operator('B') + >>> Dagger(A*B) + Dagger(B)*Dagger(A) + >>> Dagger(A+B) + Dagger(A) + Dagger(B) + >>> Dagger(A**2) + Dagger(A)**2 + + Dagger also seamlessly handles complex numbers and matrices:: + + >>> from sympy import Matrix, I + >>> m = Matrix([[1,I],[2,I]]) + >>> m + Matrix([ + [1, I], + [2, I]]) + >>> Dagger(m) + Matrix([ + [ 1, 2], + [-I, -I]]) + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hermitian_adjoint + .. [2] https://en.wikipedia.org/wiki/Hermitian_transpose + """ + + @property + def kind(self): + """Find the kind of a dagger of something (just the kind of the something).""" + return self.args[0].kind + + def __new__(cls, arg, evaluate=True): + if hasattr(arg, 'adjoint') and evaluate: + return arg.adjoint() + elif hasattr(arg, 'conjugate') and hasattr(arg, 'transpose') and evaluate: + return arg.conjugate().transpose() + return Expr.__new__(cls, sympify(arg)) + +adjoint.__name__ = "Dagger" +adjoint._sympyrepr = lambda a, b: "Dagger(%s)" % b._print(a.args[0]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/density.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/density.py new file mode 100644 index 0000000000000000000000000000000000000000..941373e8105dd0c725626396dfd9cd794b19d3f5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/density.py @@ -0,0 +1,315 @@ +from itertools import product + +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.function import expand +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import log +from sympy.matrices.dense import MutableDenseMatrix as Matrix +from sympy.printing.pretty.stringpict import prettyForm +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.operator import HermitianOperator +from sympy.physics.quantum.represent import represent +from sympy.physics.quantum.matrixutils import numpy_ndarray, scipy_sparse_matrix, to_numpy +from sympy.physics.quantum.trace import Tr + + +class Density(HermitianOperator): + """Density operator for representing mixed states. + + TODO: Density operator support for Qubits + + Parameters + ========== + + values : tuples/lists + Each tuple/list should be of form (state, prob) or [state,prob] + + Examples + ======== + + Create a density operator with 2 states represented by Kets. + + >>> from sympy.physics.quantum.state import Ket + >>> from sympy.physics.quantum.density import Density + >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) + >>> d + Density((|0>, 0.5),(|1>, 0.5)) + + """ + @classmethod + def _eval_args(cls, args): + # call this to qsympify the args + args = super()._eval_args(args) + + for arg in args: + # Check if arg is a tuple + if not (isinstance(arg, Tuple) and len(arg) == 2): + raise ValueError("Each argument should be of form [state,prob]" + " or ( state, prob )") + + return args + + def states(self): + """Return list of all states. + + Examples + ======== + + >>> from sympy.physics.quantum.state import Ket + >>> from sympy.physics.quantum.density import Density + >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) + >>> d.states() + (|0>, |1>) + + """ + return Tuple(*[arg[0] for arg in self.args]) + + def probs(self): + """Return list of all probabilities. + + Examples + ======== + + >>> from sympy.physics.quantum.state import Ket + >>> from sympy.physics.quantum.density import Density + >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) + >>> d.probs() + (0.5, 0.5) + + """ + return Tuple(*[arg[1] for arg in self.args]) + + def get_state(self, index): + """Return specific state by index. + + Parameters + ========== + + index : index of state to be returned + + Examples + ======== + + >>> from sympy.physics.quantum.state import Ket + >>> from sympy.physics.quantum.density import Density + >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) + >>> d.states()[1] + |1> + + """ + state = self.args[index][0] + return state + + def get_prob(self, index): + """Return probability of specific state by index. + + Parameters + =========== + + index : index of states whose probability is returned. + + Examples + ======== + + >>> from sympy.physics.quantum.state import Ket + >>> from sympy.physics.quantum.density import Density + >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) + >>> d.probs()[1] + 0.500000000000000 + + """ + prob = self.args[index][1] + return prob + + def apply_op(self, op): + """op will operate on each individual state. + + Parameters + ========== + + op : Operator + + Examples + ======== + + >>> from sympy.physics.quantum.state import Ket + >>> from sympy.physics.quantum.density import Density + >>> from sympy.physics.quantum.operator import Operator + >>> A = Operator('A') + >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) + >>> d.apply_op(A) + Density((A*|0>, 0.5),(A*|1>, 0.5)) + + """ + new_args = [(op*state, prob) for (state, prob) in self.args] + return Density(*new_args) + + def doit(self, **hints): + """Expand the density operator into an outer product format. + + Examples + ======== + + >>> from sympy.physics.quantum.state import Ket + >>> from sympy.physics.quantum.density import Density + >>> from sympy.physics.quantum.operator import Operator + >>> A = Operator('A') + >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) + >>> d.doit() + 0.5*|0><0| + 0.5*|1><1| + + """ + + terms = [] + for (state, prob) in self.args: + 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)) + + return Add(*terms) + + 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 len(nc_part2) == 0): + raise ValueError('Atleast one-pair of' + ' Non-commutative instance required' + ' for outer product.') + + # We were able to remove some tensor product simplifications that + # used to be here as those transformations are not automatically + # applied by transforms.py. + op = Mul(*nc_part1)*Dagger(Mul(*nc_part2)) + + return Mul(*c_part1)*Mul(*c_part2) * op + + def _represent(self, **options): + return represent(self.doit(), **options) + + def _print_operator_name_latex(self, printer, *args): + return r'\rho' + + def _print_operator_name_pretty(self, printer, *args): + return prettyForm('\N{GREEK SMALL LETTER RHO}') + + def _eval_trace(self, **kwargs): + indices = kwargs.get('indices', []) + return Tr(self.doit(), indices).doit() + + def entropy(self): + """ Compute the entropy of a density matrix. + + Refer to density.entropy() method for examples. + """ + return entropy(self) + + +def entropy(density): + """Compute the entropy of a matrix/density object. + + This computes -Tr(density*ln(density)) using the eigenvalue decomposition + of density, which is given as either a Density instance or a matrix + (numpy.ndarray, sympy.Matrix or scipy.sparse). + + Parameters + ========== + + density : density matrix of type Density, SymPy matrix, + scipy.sparse or numpy.ndarray + + Examples + ======== + + >>> from sympy.physics.quantum.density import Density, entropy + >>> from sympy.physics.quantum.spin import JzKet + >>> from sympy import S + >>> up = JzKet(S(1)/2,S(1)/2) + >>> down = JzKet(S(1)/2,-S(1)/2) + >>> d = Density((up,S(1)/2),(down,S(1)/2)) + >>> entropy(d) + log(2)/2 + + """ + if isinstance(density, Density): + density = represent(density) # represent in Matrix + + if isinstance(density, scipy_sparse_matrix): + density = to_numpy(density) + + if isinstance(density, Matrix): + eigvals = density.eigenvals().keys() + return expand(-sum(e*log(e) for e in eigvals)) + elif isinstance(density, numpy_ndarray): + import numpy as np + eigvals = np.linalg.eigvals(density) + return -np.sum(eigvals*np.log(eigvals)) + else: + raise ValueError( + "numpy.ndarray, scipy.sparse or SymPy matrix expected") + + +def fidelity(state1, state2): + """ Computes the fidelity [1]_ between two quantum states + + The arguments provided to this function should be a square matrix or a + Density object. If it is a square matrix, it is assumed to be diagonalizable. + + Parameters + ========== + + state1, state2 : a density matrix or Matrix + + + Examples + ======== + + >>> from sympy import S, sqrt + >>> from sympy.physics.quantum.dagger import Dagger + >>> from sympy.physics.quantum.spin import JzKet + >>> from sympy.physics.quantum.density import fidelity + >>> from sympy.physics.quantum.represent import represent + >>> + >>> up = JzKet(S(1)/2,S(1)/2) + >>> down = JzKet(S(1)/2,-S(1)/2) + >>> amp = 1/sqrt(2) + >>> updown = (amp*up) + (amp*down) + >>> + >>> # represent turns Kets into matrices + >>> up_dm = represent(up*Dagger(up)) + >>> down_dm = represent(down*Dagger(down)) + >>> updown_dm = represent(updown*Dagger(updown)) + >>> + >>> fidelity(up_dm, up_dm) + 1 + >>> fidelity(up_dm, down_dm) #orthogonal states + 0 + >>> fidelity(up_dm, updown_dm).evalf().round(3) + 0.707 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Fidelity_of_quantum_states + + """ + state1 = represent(state1) if isinstance(state1, Density) else state1 + state2 = represent(state2) if isinstance(state2, Density) else state2 + + if not isinstance(state1, Matrix) or 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 " + "matrix obtained should be a square matrix") + + sqrt_state1 = state1**S.Half + return Tr((sqrt_state1*state2*sqrt_state1)**S.Half).doit() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/fermion.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/fermion.py new file mode 100644 index 0000000000000000000000000000000000000000..8080bd3b0904b837652fdae7be0bd526da2d508f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/fermion.py @@ -0,0 +1,191 @@ +"""Fermionic quantum operators.""" + +from sympy.core.numbers import Integer +from sympy.core.singleton import S +from sympy.physics.quantum import Operator +from sympy.physics.quantum import HilbertSpace, Ket, Bra +from sympy.functions.special.tensor_functions import KroneckerDelta + + +__all__ = [ + 'FermionOp', + 'FermionFockKet', + 'FermionFockBra' +] + + +class FermionOp(Operator): + """A fermionic operator that satisfies {c, Dagger(c)} == 1. + + Parameters + ========== + + name : str + A string that labels the fermionic mode. + + annihilation : bool + A bool that indicates if the fermionic operator is an annihilation + (True, default value) or creation operator (False) + + Examples + ======== + + >>> from sympy.physics.quantum import Dagger, AntiCommutator + >>> from sympy.physics.quantum.fermion import FermionOp + >>> c = FermionOp("c") + >>> AntiCommutator(c, Dagger(c)).doit() + 1 + """ + @property + def name(self): + return self.args[0] + + @property + def is_annihilation(self): + return bool(self.args[1]) + + @classmethod + def default_args(self): + return ("c", True) + + def __new__(cls, *args, **hints): + if not len(args) in [1, 2]: + raise ValueError('1 or 2 parameters expected, got %s' % args) + + if len(args) == 1: + args = (args[0], S.One) + + if len(args) == 2: + args = (args[0], Integer(args[1])) + + return Operator.__new__(cls, *args) + + def _eval_commutator_FermionOp(self, other, **hints): + if 'independent' in hints and hints['independent']: + # [c, d] = 0 + return S.Zero + + return None + + def _eval_anticommutator_FermionOp(self, other, **hints): + if self.name == other.name: + # {a^\dagger, a} = 1 + if not self.is_annihilation and other.is_annihilation: + return S.One + + elif 'independent' in hints and hints['independent']: + # {c, d} = 2 * c * d, because [c, d] = 0 for independent operators + return 2 * self * other + + return None + + def _eval_anticommutator_BosonOp(self, other, **hints): + # because fermions and bosons commute + return 2 * self * other + + def _eval_commutator_BosonOp(self, other, **hints): + return S.Zero + + def _eval_adjoint(self): + return FermionOp(str(self.name), not self.is_annihilation) + + def _print_contents_latex(self, printer, *args): + if self.is_annihilation: + return r'{%s}' % str(self.name) + else: + return r'{{%s}^\dagger}' % str(self.name) + + def _print_contents(self, printer, *args): + if self.is_annihilation: + return r'%s' % str(self.name) + else: + return r'Dagger(%s)' % str(self.name) + + def _print_contents_pretty(self, printer, *args): + from sympy.printing.pretty.stringpict import prettyForm + pform = printer._print(self.args[0], *args) + if self.is_annihilation: + return pform + else: + return pform**prettyForm('\N{DAGGER}') + + def _eval_power(self, exp): + from sympy.core.singleton import S + if exp == 0: + return S.One + elif exp == 1: + return self + elif (exp > 1) == True and exp.is_integer == True: + return S.Zero + elif (exp < 0) == True or exp.is_integer == False: + raise ValueError("Fermionic operators can only be raised to a" + " positive integer power") + return Operator._eval_power(self, exp) + +class FermionFockKet(Ket): + """Fock state ket for a fermionic mode. + + Parameters + ========== + + n : Number + The Fock state number. + + """ + + def __new__(cls, n): + if n not in (0, 1): + raise ValueError("n must be 0 or 1") + return Ket.__new__(cls, n) + + @property + def n(self): + return self.label[0] + + @classmethod + def dual_class(self): + return FermionFockBra + + @classmethod + def _eval_hilbert_space(cls, label): + return HilbertSpace() + + def _eval_innerproduct_FermionFockBra(self, bra, **hints): + return KroneckerDelta(self.n, bra.n) + + def _apply_from_right_to_FermionOp(self, op, **options): + if op.is_annihilation: + if self.n == 1: + return FermionFockKet(0) + else: + return S.Zero + else: + if self.n == 0: + return FermionFockKet(1) + else: + return S.Zero + + +class FermionFockBra(Bra): + """Fock state bra for a fermionic mode. + + Parameters + ========== + + n : Number + The Fock state number. + + """ + + def __new__(cls, n): + if n not in (0, 1): + raise ValueError("n must be 0 or 1") + return Bra.__new__(cls, n) + + @property + def n(self): + return self.label[0] + + @classmethod + def dual_class(self): + return FermionFockKet diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/gate.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/gate.py new file mode 100644 index 0000000000000000000000000000000000000000..f8bcf5cd3611173cd9ebd6308dbbc896f5257f20 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/gate.py @@ -0,0 +1,1309 @@ +"""An implementation of gates that act on qubits. + +Gates are unitary operators that act on the space of qubits. + +Medium Term Todo: + +* Optimize Gate._apply_operators_Qubit to remove the creation of many + intermediate Qubit objects. +* Add commutation relationships to all operators and use this in gate_sort. +* Fix gate_sort and gate_simp. +* Get multi-target UGates plotting properly. +* Get UGate to work with either sympy/numpy matrices and output either + format. This should also use the matrix slots. +""" + +from itertools import chain +import random + +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.mul import Mul +from sympy.core.numbers import (I, Integer) +from sympy.core.power import Pow +from sympy.core.numbers import Number +from sympy.core.singleton import S as _S +from sympy.core.sorting import default_sort_key +from sympy.core.sympify import _sympify +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.printing.pretty.stringpict import prettyForm, stringPict + +from sympy.physics.quantum.anticommutator import AntiCommutator +from sympy.physics.quantum.commutator import Commutator +from sympy.physics.quantum.qexpr import QuantumError +from sympy.physics.quantum.hilbert import ComplexSpace +from sympy.physics.quantum.operator import (UnitaryOperator, Operator, + HermitianOperator) +from sympy.physics.quantum.matrixutils import matrix_tensor_product, matrix_eye +from sympy.physics.quantum.matrixcache import matrix_cache + +from sympy.matrices.matrixbase import MatrixBase + +from sympy.utilities.iterables import is_sequence + +__all__ = [ + 'Gate', + 'CGate', + 'UGate', + 'OneQubitGate', + 'TwoQubitGate', + 'IdentityGate', + 'HadamardGate', + 'XGate', + 'YGate', + 'ZGate', + 'TGate', + 'PhaseGate', + 'SwapGate', + 'CNotGate', + # Aliased gate names + 'CNOT', + 'SWAP', + 'H', + 'X', + 'Y', + 'Z', + 'T', + 'S', + 'Phase', + 'normalized', + 'gate_sort', + 'gate_simp', + 'random_circuit', + 'CPHASE', + 'CGateS', +] + +#----------------------------------------------------------------------------- +# Gate Super-Classes +#----------------------------------------------------------------------------- + +_normalized = True + + +def _max(*args, **kwargs): + if "key" not in kwargs: + kwargs["key"] = default_sort_key + return max(*args, **kwargs) + + +def _min(*args, **kwargs): + if "key" not in kwargs: + kwargs["key"] = default_sort_key + return min(*args, **kwargs) + + +def normalized(normalize): + r"""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 off the leading `1/\sqrt{2}` of the Hadamard gate. + + Parameters + ---------- + normalize : bool + Should the Hadamard gate include the `1/\sqrt{2}` normalization factor? + When True, the Hadamard gate will have the `1/\sqrt{2}`. When False, the + Hadamard gate will not have this factor. + """ + global _normalized + _normalized = normalize + + +def _validate_targets_controls(tandc): + tandc = list(tandc) + # Check for integers + for bit in tandc: + if not bit.is_Integer and not bit.is_Symbol: + raise TypeError('Integer expected, got: %r' % tandc[bit]) + # Detect duplicates + if len(set(tandc)) != len(tandc): + raise QuantumError( + 'Target/control qubits in a gate cannot be duplicated' + ) + + +class Gate(UnitaryOperator): + """Non-controlled unitary gate operator that acts on qubits. + + This is a general abstract gate that needs to be subclassed to do anything + useful. + + Parameters + ---------- + label : tuple, int + A list of the target qubits (as ints) that the gate will apply to. + + Examples + ======== + + + """ + + _label_separator = ',' + + gate_name = 'G' + gate_name_latex = 'G' + + #------------------------------------------------------------------------- + # Initialization/creation + #------------------------------------------------------------------------- + + @classmethod + def _eval_args(cls, args): + args = Tuple(*UnitaryOperator._eval_args(args)) + _validate_targets_controls(args) + return args + + @classmethod + def _eval_hilbert_space(cls, args): + """This returns the smallest possible Hilbert space.""" + return ComplexSpace(2)**(_max(args) + 1) + + #------------------------------------------------------------------------- + # Properties + #------------------------------------------------------------------------- + + @property + def nqubits(self): + """The total number of qubits this gate acts on. + + 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) + + @property + def min_qubits(self): + """The minimum number of qubits this gate needs to act on.""" + return _max(self.targets) + 1 + + @property + def targets(self): + """A tuple of target qubits.""" + return self.label + + @property + def gate_name_plot(self): + return r'$%s$' % self.gate_name_latex + + #------------------------------------------------------------------------- + # Gate methods + #------------------------------------------------------------------------- + + def get_target_matrix(self, format='sympy'): + """The matrix representation of the target part of the gate. + + Parameters + ---------- + format : str + The format string ('sympy','numpy', etc.) + """ + raise NotImplementedError( + 'get_target_matrix is not implemented in Gate.') + + #------------------------------------------------------------------------- + # Apply + #------------------------------------------------------------------------- + + def _apply_operator_IntQubit(self, qubits, **options): + """Redirect an apply from IntQubit to Qubit""" + return self._apply_operator_Qubit(qubits, **options) + + def _apply_operator_Qubit(self, qubits, **options): + """Apply this gate to a Qubit.""" + + # 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) + ) + + # If the controls are not met, just return + if isinstance(self, CGate): + if not self.eval_controls(qubits): + return qubits + + targets = self.targets + target_matrix = self.get_target_matrix(format='sympy') + + # Find which column of the target matrix this applies to. + column_index = 0 + n = 1 + for target in targets: + column_index += n*qubits[target] + n = n << 1 + column = target_matrix[:, int(column_index)] + + # Now apply each column element to the qubit. + result = 0 + for index in range(column.rows): + # TODO: This can be optimized to reduce the number of Qubit + # creations. We should simply manipulate the raw list of qubit + # values and then build the new Qubit object once. + # Make a copy of the incoming qubits. + new_qubit = qubits.__class__(*qubits.args) + # Flip the bits that need to be flipped. + for bit, target in enumerate(targets): + if new_qubit[target] != (index >> bit) & 1: + new_qubit = new_qubit.flip(target) + # The value in that row and column times the flipped-bit qubit + # is the result for that part. + result += column[index]*new_qubit + return result + + #------------------------------------------------------------------------- + # Represent + #------------------------------------------------------------------------- + + def _represent_default_basis(self, **options): + return self._represent_ZGate(None, **options) + + def _represent_ZGate(self, basis, **options): + format = options.get('format', 'sympy') + nqubits = options.get('nqubits', 0) + if nqubits == 0: + 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: + raise QuantumError( + 'The number of qubits %r is too small for the gate.' % nqubits + ) + + target_matrix = self.get_target_matrix(format) + targets = self.targets + if isinstance(self, CGate): + controls = self.controls + else: + controls = [] + m = represent_zbasis( + controls, targets, target_matrix, nqubits, format + ) + return m + + #------------------------------------------------------------------------- + # Print methods + #------------------------------------------------------------------------- + + def _sympystr(self, printer, *args): + label = self._print_label(printer, *args) + return '%s(%s)' % (self.gate_name, label) + + def _pretty(self, printer, *args): + a = stringPict(self.gate_name) + b = self._print_label_pretty(printer, *args) + return self._print_subscript_pretty(a, b) + + def _latex(self, printer, *args): + label = self._print_label(printer, *args) + return '%s_{%s}' % (self.gate_name_latex, label) + + def plot_gate(self, axes, gate_idx, gate_grid, wire_grid): + raise NotImplementedError('plot_gate is not implemented.') + + +class CGate(Gate): + """A general unitary gate with control qubits. + + A general control gate applies a target gate to a set of targets if all + of the control qubits have a particular values (set by + ``CGate.control_value``). + + Parameters + ---------- + label : tuple + The label in this case has the form (controls, gate), where controls + is a tuple/list of control qubits (as ints) and gate is a ``Gate`` + instance that is the target operator. + + Examples + ======== + + """ + + gate_name = 'C' + gate_name_latex = 'C' + + # The values this class controls for. + control_value = _S.One + + simplify_cgate = False + + #------------------------------------------------------------------------- + # Initialization + #------------------------------------------------------------------------- + + @classmethod + def _eval_args(cls, args): + # _eval_args has the right logic for the controls argument. + controls = args[0] + gate = args[1] + if not is_sequence(controls): + controls = (controls,) + controls = UnitaryOperator._eval_args(controls) + _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) + + #------------------------------------------------------------------------- + # Properties + #------------------------------------------------------------------------- + + @property + def nqubits(self): + """The total number of qubits this gate acts on. + + 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) + + @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 + + @property + def targets(self): + """A tuple of target qubits.""" + return self.gate.targets + + @property + def controls(self): + """A tuple of control qubits.""" + return tuple(self.label[0]) + + @property + def gate(self): + """The non-controlled gate that will be applied to the targets.""" + return self.label[1] + + #------------------------------------------------------------------------- + # Gate methods + #------------------------------------------------------------------------- + + def get_target_matrix(self, format='sympy'): + return self.gate.get_target_matrix(format) + + 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) + + def decompose(self, **options): + """Decompose the controlled gate into CNOT and single qubits gates.""" + if len(self.controls) == 1: + c = self.controls[0] + t = self.gate.targets[0] + if isinstance(self.gate, YGate): + g1 = PhaseGate(t) + g2 = CNotGate(c, t) + g3 = PhaseGate(t) + g4 = ZGate(t) + return g1*g2*g3*g4 + if isinstance(self.gate, ZGate): + g1 = HadamardGate(t) + g2 = CNotGate(c, t) + g3 = HadamardGate(t) + return g1*g2*g3 + else: + return self + + #------------------------------------------------------------------------- + # Print methods + #------------------------------------------------------------------------- + + 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) + + def _pretty(self, printer, *args): + controls = self._print_sequence_pretty( + self.controls, ',', printer, *args) + gate = printer._print(self.gate) + gate_name = stringPict(self.gate_name) + first = self._print_subscript_pretty(gate_name, controls) + gate = self._print_parens_pretty(gate) + final = prettyForm(*first.right(gate)) + return final + + 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)}' % \ + (self.gate_name_latex, controls, gate) + + def plot_gate(self, circ_plot, gate_idx): + """ + Plot the controlled gate. If *simplify_cgate* is true, simplify + C-X and C-Z gates into their more familiar forms. + """ + min_wire = int(_min(chain(self.controls, self.targets))) + max_wire = int(_max(chain(self.controls, self.targets))) + circ_plot.control_line(gate_idx, min_wire, max_wire) + for c in self.controls: + circ_plot.control_point(gate_idx, int(c)) + if self.simplify_cgate: + if self.gate.gate_name == 'X': + self.gate.plot_gate_plus(circ_plot, gate_idx) + elif self.gate.gate_name == 'Z': + circ_plot.control_point(gate_idx, self.targets[0]) + else: + self.gate.plot_gate(circ_plot, gate_idx) + else: + self.gate.plot_gate(circ_plot, gate_idx) + + #------------------------------------------------------------------------- + # Miscellaneous + #------------------------------------------------------------------------- + + def _eval_dagger(self): + if isinstance(self.gate, HermitianOperator): + return self + else: + return Gate._eval_dagger(self) + + def _eval_inverse(self): + if isinstance(self.gate, HermitianOperator): + return self + else: + return Gate._eval_inverse(self) + + def _eval_power(self, exp): + if isinstance(self.gate, HermitianOperator): + if exp == -1: + return Gate._eval_power(self, exp) + elif abs(exp) % 2 == 0: + return self*(Gate._eval_inverse(self)) + else: + return self + else: + return Gate._eval_power(self, exp) + +class CGateS(CGate): + """Version of CGate that allows gate simplifications. + I.e. cnot looks like an oplus, cphase has dots, etc. + """ + simplify_cgate=True + + +class UGate(Gate): + """General gate specified by a set of targets and a target matrix. + + Parameters + ---------- + label : tuple + A tuple of the form (targets, U), where targets is a tuple of the + target qubits and U is a unitary matrix with dimension of + len(targets). + """ + gate_name = 'U' + gate_name_latex = 'U' + + #------------------------------------------------------------------------- + # Initialization + #------------------------------------------------------------------------- + + @classmethod + def _eval_args(cls, args): + targets = args[0] + if not is_sequence(targets): + targets = (targets,) + targets = Gate._eval_args(targets) + _validate_targets_controls(targets) + mat = args[1] + if not isinstance(mat, MatrixBase): + raise TypeError('Matrix expected, got: %r' % mat) + #make sure this matrix is of a Basic type + mat = _sympify(mat) + 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' % + (targets, mat) + ) + return (targets, mat) + + @classmethod + def _eval_hilbert_space(cls, args): + """This returns the smallest possible Hilbert space.""" + return ComplexSpace(2)**(_max(args[0]) + 1) + + #------------------------------------------------------------------------- + # Properties + #------------------------------------------------------------------------- + + @property + def targets(self): + """A tuple of target qubits.""" + return tuple(self.label[0]) + + #------------------------------------------------------------------------- + # Gate methods + #------------------------------------------------------------------------- + + def get_target_matrix(self, format='sympy'): + """The matrix rep. of the target part of the gate. + + Parameters + ---------- + format : str + The format string ('sympy','numpy', etc.) + """ + return self.label[1] + + #------------------------------------------------------------------------- + # Print methods + #------------------------------------------------------------------------- + def _pretty(self, printer, *args): + targets = self._print_sequence_pretty( + self.targets, ',', printer, *args) + gate_name = stringPict(self.gate_name) + return self._print_subscript_pretty(gate_name, targets) + + def _latex(self, printer, *args): + targets = self._print_sequence(self.targets, ',', printer, *args) + return r'%s_{%s}' % (self.gate_name_latex, targets) + + def plot_gate(self, circ_plot, gate_idx): + circ_plot.one_qubit_box( + self.gate_name_plot, + gate_idx, int(self.targets[0]) + ) + + +class OneQubitGate(Gate): + """A single qubit unitary gate base class.""" + + nqubits = _S.One + + def plot_gate(self, circ_plot, gate_idx): + circ_plot.one_qubit_box( + self.gate_name_plot, + gate_idx, int(self.targets[0]) + ) + + def _eval_commutator(self, other, **hints): + if isinstance(other, OneQubitGate): + if self.targets != other.targets or self.__class__ == other.__class__: + return _S.Zero + return Operator._eval_commutator(self, other, **hints) + + def _eval_anticommutator(self, other, **hints): + if isinstance(other, OneQubitGate): + if self.targets != other.targets or self.__class__ == other.__class__: + return Integer(2)*self*other + return Operator._eval_anticommutator(self, other, **hints) + + +class TwoQubitGate(Gate): + """A two qubit unitary gate base class.""" + + nqubits = Integer(2) + +#----------------------------------------------------------------------------- +# Single Qubit Gates +#----------------------------------------------------------------------------- + + +class IdentityGate(OneQubitGate): + """The single qubit identity gate. + + Parameters + ---------- + target : int + The target qubit this gate will apply to. + + Examples + ======== + + """ + is_hermitian = True + gate_name = '1' + gate_name_latex = '1' + + # Short cut version of gate._apply_operator_Qubit + def _apply_operator_Qubit(self, qubits, **options): + # Check number of qubits this gate acts on (see gate._apply_operator_Qubit) + 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) + ) + return qubits # no computation required for IdentityGate + + def get_target_matrix(self, format='sympy'): + return matrix_cache.get_matrix('eye2', format) + + def _eval_commutator(self, other, **hints): + return _S.Zero + + def _eval_anticommutator(self, other, **hints): + return Integer(2)*other + + +class HadamardGate(HermitianOperator, OneQubitGate): + """The single qubit Hadamard gate. + + Parameters + ---------- + target : int + The target qubit this gate will apply to. + + 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' + + def get_target_matrix(self, format='sympy'): + if _normalized: + return matrix_cache.get_matrix('H', format) + else: + return matrix_cache.get_matrix('Hsqrt2', format) + + def _eval_commutator_XGate(self, other, **hints): + 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])) + + def _eval_commutator_ZGate(self, other, **hints): + return -I*sqrt(2)*YGate(self.targets[0]) + + def _eval_anticommutator_XGate(self, other, **hints): + return sqrt(2)*IdentityGate(self.targets[0]) + + def _eval_anticommutator_YGate(self, other, **hints): + return _S.Zero + + def _eval_anticommutator_ZGate(self, other, **hints): + return sqrt(2)*IdentityGate(self.targets[0]) + + +class XGate(HermitianOperator, OneQubitGate): + """The single qubit X, or NOT, gate. + + Parameters + ---------- + target : int + The target qubit this gate will apply to. + + Examples + ======== + + """ + gate_name = 'X' + gate_name_latex = 'X' + + def get_target_matrix(self, format='sympy'): + return matrix_cache.get_matrix('X', format) + + def plot_gate(self, circ_plot, gate_idx): + OneQubitGate.plot_gate(self,circ_plot,gate_idx) + + def plot_gate_plus(self, circ_plot, gate_idx): + circ_plot.not_point( + gate_idx, int(self.label[0]) + ) + + def _eval_commutator_YGate(self, other, **hints): + return Integer(2)*I*ZGate(self.targets[0]) + + def _eval_anticommutator_XGate(self, other, **hints): + return Integer(2)*IdentityGate(self.targets[0]) + + def _eval_anticommutator_YGate(self, other, **hints): + return _S.Zero + + def _eval_anticommutator_ZGate(self, other, **hints): + return _S.Zero + + +class YGate(HermitianOperator, OneQubitGate): + """The single qubit Y gate. + + Parameters + ---------- + target : int + The target qubit this gate will apply to. + + Examples + ======== + + """ + gate_name = 'Y' + gate_name_latex = 'Y' + + def get_target_matrix(self, format='sympy'): + return matrix_cache.get_matrix('Y', format) + + def _eval_commutator_ZGate(self, other, **hints): + return Integer(2)*I*XGate(self.targets[0]) + + def _eval_anticommutator_YGate(self, other, **hints): + return Integer(2)*IdentityGate(self.targets[0]) + + def _eval_anticommutator_ZGate(self, other, **hints): + return _S.Zero + + +class ZGate(HermitianOperator, OneQubitGate): + """The single qubit Z gate. + + Parameters + ---------- + target : int + The target qubit this gate will apply to. + + Examples + ======== + + """ + gate_name = 'Z' + gate_name_latex = 'Z' + + def get_target_matrix(self, format='sympy'): + return matrix_cache.get_matrix('Z', format) + + def _eval_commutator_XGate(self, other, **hints): + return Integer(2)*I*YGate(self.targets[0]) + + def _eval_anticommutator_YGate(self, other, **hints): + return _S.Zero + + +class PhaseGate(OneQubitGate): + """The single qubit phase, or S, gate. + + This gate rotates the phase of the state by pi/2 if the state is ``|1>`` and + does nothing if the state is ``|0>``. + + Parameters + ---------- + target : int + The target qubit this gate will apply to. + + Examples + ======== + + """ + is_hermitian = False + gate_name = 'S' + gate_name_latex = 'S' + + def get_target_matrix(self, format='sympy'): + return matrix_cache.get_matrix('S', format) + + def _eval_commutator_ZGate(self, other, **hints): + return _S.Zero + + def _eval_commutator_TGate(self, other, **hints): + return _S.Zero + + +class TGate(OneQubitGate): + """The single qubit pi/8 gate. + + This gate rotates the phase of the state by pi/4 if the state is ``|1>`` and + does nothing if the state is ``|0>``. + + Parameters + ---------- + target : int + The target qubit this gate will apply to. + + Examples + ======== + + """ + is_hermitian = False + gate_name = 'T' + gate_name_latex = 'T' + + def get_target_matrix(self, format='sympy'): + return matrix_cache.get_matrix('T', format) + + def _eval_commutator_ZGate(self, other, **hints): + return _S.Zero + + def _eval_commutator_PhaseGate(self, other, **hints): + return _S.Zero + + +# Aliases for gate names. +H = HadamardGate +X = XGate +Y = YGate +Z = ZGate +T = TGate +Phase = S = PhaseGate + + +#----------------------------------------------------------------------------- +# 2 Qubit Gates +#----------------------------------------------------------------------------- + + +class CNotGate(HermitianOperator, CGate, TwoQubitGate): + """Two qubit controlled-NOT. + + This gate performs the NOT or X gate on the target qubit if the control + qubits all have the value 1. + + Parameters + ---------- + label : tuple + A tuple of the form (control, target). + + 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 = r'\text{CNOT}' + simplify_cgate = True + + #------------------------------------------------------------------------- + # Initialization + #------------------------------------------------------------------------- + + @classmethod + def _eval_args(cls, args): + args = Gate._eval_args(args) + return args + + @classmethod + def _eval_hilbert_space(cls, args): + """This returns the smallest possible Hilbert space.""" + return ComplexSpace(2)**(_max(args) + 1) + + #------------------------------------------------------------------------- + # Properties + #------------------------------------------------------------------------- + + @property + def min_qubits(self): + """The minimum number of qubits this gate needs to act on.""" + return _max(self.label) + 1 + + @property + def targets(self): + """A tuple of target qubits.""" + return (self.label[1],) + + @property + def controls(self): + """A tuple of control qubits.""" + return (self.label[0],) + + @property + def gate(self): + """The non-controlled gate that will be applied to the targets.""" + return XGate(self.label[1]) + + #------------------------------------------------------------------------- + # Properties + #------------------------------------------------------------------------- + + # The default printing of Gate works better than those of CGate, so we + # go around the overridden methods in CGate. + + def _print_label(self, printer, *args): + return Gate._print_label(self, printer, *args) + + def _pretty(self, printer, *args): + return Gate._pretty(self, printer, *args) + + def _latex(self, printer, *args): + return Gate._latex(self, printer, *args) + + #------------------------------------------------------------------------- + # Commutator/AntiCommutator + #------------------------------------------------------------------------- + + def _eval_commutator_ZGate(self, other, **hints): + """[CNOT(i, j), Z(i)] == 0.""" + if self.controls[0] == other.targets[0]: + return _S.Zero + else: + raise NotImplementedError('Commutator not implemented: %r' % other) + + def _eval_commutator_TGate(self, other, **hints): + """[CNOT(i, j), T(i)] == 0.""" + return self._eval_commutator_ZGate(other, **hints) + + def _eval_commutator_PhaseGate(self, other, **hints): + """[CNOT(i, j), S(i)] == 0.""" + return self._eval_commutator_ZGate(other, **hints) + + def _eval_commutator_XGate(self, other, **hints): + """[CNOT(i, j), X(j)] == 0.""" + if self.targets[0] == other.targets[0]: + return _S.Zero + else: + raise NotImplementedError('Commutator not implemented: %r' % other) + + def _eval_commutator_CNotGate(self, other, **hints): + """[CNOT(i, j), CNOT(i,k)] == 0.""" + if self.controls[0] == other.controls[0]: + return _S.Zero + else: + raise NotImplementedError('Commutator not implemented: %r' % other) + + +class SwapGate(TwoQubitGate): + """Two qubit SWAP gate. + + This gate swap the values of the two qubits. + + Parameters + ---------- + label : tuple + A tuple of the form (target1, target2). + + Examples + ======== + + """ + is_hermitian = True + gate_name = 'SWAP' + gate_name_latex = r'\text{SWAP}' + + def get_target_matrix(self, format='sympy'): + return matrix_cache.get_matrix('SWAP', format) + + def decompose(self, **options): + """Decompose the SWAP gate into CNOT gates.""" + i, j = self.targets[0], self.targets[1] + g1 = CNotGate(i, j) + g2 = CNotGate(j, i) + return g1*g2*g1 + + def plot_gate(self, circ_plot, gate_idx): + min_wire = int(_min(self.targets)) + max_wire = int(_max(self.targets)) + circ_plot.control_line(gate_idx, min_wire, max_wire) + circ_plot.swap_point(gate_idx, min_wire) + circ_plot.swap_point(gate_idx, max_wire) + + def _represent_ZGate(self, basis, **options): + """Represent the SWAP gate in the computational basis. + + The following representation is used to compute this: + + SWAP = |1><1|x|1><1| + |0><0|x|0><0| + |1><0|x|0><1| + |0><1|x|1><0| + """ + format = options.get('format', 'sympy') + targets = [int(t) for t in self.targets] + min_target = _min(targets) + max_target = _max(targets) + nqubits = options.get('nqubits', self.min_qubits) + + op01 = matrix_cache.get_matrix('op01', format) + op10 = matrix_cache.get_matrix('op10', format) + op11 = matrix_cache.get_matrix('op11', format) + op00 = matrix_cache.get_matrix('op00', format) + eye2 = matrix_cache.get_matrix('eye2', format) + + result = None + 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 + new_result = matrix_tensor_product(*product) + if result is None: + result = new_result + else: + result = result + new_result + + return result + + +# Aliases for gate names. +CNOT = CNotGate +SWAP = SwapGate +def CPHASE(a,b): return CGateS((a,),Z(b)) + + +#----------------------------------------------------------------------------- +# Represent +#----------------------------------------------------------------------------- + + +def represent_zbasis(controls, targets, target_matrix, nqubits, format='sympy'): + """Represent a gate with controls, targets and target_matrix. + + This function does the low-level work of representing gates as matrices + in the standard computational basis (ZGate). Currently, we support two + main cases: + + 1. One target qubit and no control qubits. + 2. One target qubits and multiple control qubits. + + For the base of multiple controls, we use the following expression [1]: + + 1_{2**n} + (|1><1|)^{(n-1)} x (target-matrix - 1_{2}) + + Parameters + ---------- + controls : list, tuple + A sequence of control qubits. + targets : list, tuple + A sequence of target qubits. + target_matrix : sympy.Matrix, numpy.matrix, scipy.sparse + The matrix form of the transformation to be performed on the target + qubits. The format of this matrix must match that passed into + the `format` argument. + nqubits : int + The total number of qubits used for the representation. + format : str + The format of the final matrix ('sympy', 'numpy', 'scipy.sparse'). + + Examples + ======== + + References + ---------- + [1] http://www.johnlapeyre.com/qinf/qinf_html/node6.html. + """ + controls = [int(x) for x in controls] + targets = [int(x) for x in targets] + nqubits = int(nqubits) + + # This checks for the format as well. + op11 = matrix_cache.get_matrix('op11', format) + eye2 = matrix_cache.get_matrix('eye2', format) + + # Plain single qubit case + if len(controls) == 0 and len(targets) == 1: + product = [] + 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)) + product.append(target_matrix) + if bit != 0: + product.append(matrix_eye(2**bit, format=format)) + return matrix_tensor_product(*product) + + # Single target, multiple controls. + elif len(targets) == 1 and len(controls) >= 1: + 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 + + return matrix_eye(2**nqubits, format=format) + \ + matrix_tensor_product(*product2) + + # Multi-target, multi-control is not yet implemented. + else: + raise NotImplementedError( + 'The representation of multi-target, multi-control gates ' + 'is not implemented.' + ) + + +#----------------------------------------------------------------------------- +# Gate manipulation functions. +#----------------------------------------------------------------------------- + + +def gate_simp(circuit): + """Simplifies gates symbolically + + It first sorts gates using gate_sort. It then applies basic + simplification rules to the circuit, e.g., XGate**2 = Identity + """ + + # Bubble sort out gates that commute. + circuit = gate_sort(circuit) + + # Do simplifications by subing a simplification into the first element + # which can be simplified. We recursively call gate_simp with new circuit + # as input more simplifications exist. + if isinstance(circuit, Add): + return sum(gate_simp(t) for t in circuit.args) + elif isinstance(circuit, Mul): + circuit_args = circuit.args + elif isinstance(circuit, Pow): + b, e = circuit.as_base_exp() + circuit_args = (gate_simp(b)**e,) + else: + return circuit + + # Iterate through each element in circuit, simplify if possible. + for i in range(len(circuit_args)): + # H,X,Y or Z squared is 1. + # 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): + # 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:]) + # Recursively simplify the new circuit. + circuit = gate_simp(Mul(*newargs)) + break + elif isinstance(circuit_args[i].base, PhaseGate): + # Build a new circuit taking old circuit but splicing + # 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** + (circuit_args[i].exp % 2)) + # Append the last elements. + newargs = newargs + circuit_args[i + 1:] + # Recursively simplify the new circuit. + 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)) + + # Append the last elements. + newargs = newargs + circuit_args[i + 1:] + # Recursively simplify the new circuit. + circuit = gate_simp(Mul(*newargs)) + break + return circuit + + +def gate_sort(circuit): + """Sorts the gates while keeping track of commutation relations + + This function uses a bubble sort to rearrange the order of gate + application. Keeps track of Quantum computations special commutation + relations (e.g. things that apply to the same Qubit do not commute with + each other) + + circuit is the Mul of gates that are to be sorted. + """ + # Make sure we have an Add or Mul. + if isinstance(circuit, Add): + return sum(gate_sort(t) for t in circuit.args) + if isinstance(circuit, Pow): + return gate_sort(circuit.base)**circuit.exp + elif isinstance(circuit, Gate): + return circuit + if not isinstance(circuit, Mul): + return circuit + + changes = True + while changes: + changes = False + circ_array = circuit.args + 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 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() + + # 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:]) + circuit = Mul(*new_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:]) + sign = _S.NegativeOne**(first_exp*second_exp) + circuit = sign*Mul(*new_args) + changes = True + break + return circuit + + +#----------------------------------------------------------------------------- +# Utility functions +#----------------------------------------------------------------------------- + + +def random_circuit(ngates, nqubits, gate_space=(X, Y, Z, S, T, H, CNOT, SWAP)): + """Return a random circuit of ngates and nqubits. + + This uses an equally weighted sample of (X, Y, Z, S, T, H, CNOT, SWAP) + gates. + + Parameters + ---------- + ngates : int + The number of gates in the circuit. + nqubits : int + The number of qubits in the circuit. + gate_space : tuple + A tuple of the gate classes that will be used in the circuit. + Repeating gate classes multiple times in this tuple will increase + the frequency they appear in the random circuit. + """ + qubit_space = range(nqubits) + result = [] + for i in range(ngates): + g = random.choice(gate_space) + if g == CNotGate or g == SwapGate: + qubits = random.sample(qubit_space, 2) + g = g(*qubits) + else: + qubit = random.choice(qubit_space) + g = g(qubit) + result.append(g) + return Mul(*result) + + +def zx_basis_transform(self, format='sympy'): + """Transformation matrix from Z to X basis.""" + return matrix_cache.get_matrix('ZX', format) + + +def zy_basis_transform(self, format='sympy'): + """Transformation matrix from Z to Y basis.""" + return matrix_cache.get_matrix('ZY', format) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/grover.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/grover.py new file mode 100644 index 0000000000000000000000000000000000000000..a03bd3a61a6e0960ab66d55bcc0fc7f25936199e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/grover.py @@ -0,0 +1,345 @@ +"""Grover's algorithm and helper functions. + +Todo: + +* W gate construction (or perhaps -W gate based on Mermin's book) +* Generalize the algorithm for an unknown function that returns 1 on multiple + qubit states, not just one. +* Implement _represent_ZGate in OracleGate +""" + +from sympy.core.numbers import pi +from sympy.core.sympify import sympify +from sympy.core.basic import Atom +from sympy.functions.elementary.integers import floor +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices.dense import eye +from sympy.core.numbers import NegativeOne +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.qexpr import QuantumError +from sympy.physics.quantum.hilbert import ComplexSpace +from sympy.physics.quantum.operator import UnitaryOperator +from sympy.physics.quantum.gate import Gate +from sympy.physics.quantum.qubit import IntQubit + +__all__ = [ + 'OracleGate', + 'WGate', + 'superposition_basis', + 'grover_iteration', + 'apply_grover' +] + + +def superposition_basis(nqubits): + """Creates an equal superposition of the computational basis. + + Parameters + ========== + + nqubits : int + The number of qubits. + + Returns + ======= + + state : Qubit + An equal superposition of the computational basis with nqubits. + + Examples + ======== + + Create an equal superposition of 2 qubits:: + + >>> from sympy.physics.quantum.grover import superposition_basis + >>> superposition_basis(2) + |0>/2 + |1>/2 + |2>/2 + |3>/2 + """ + + amp = 1/sqrt(2**nqubits) + return sum(amp*IntQubit(n, nqubits=nqubits) for n in range(2**nqubits)) + +class OracleGateFunction(Atom): + """Wrapper for python functions used in `OracleGate`s""" + + def __new__(cls, function): + if not callable(function): + raise TypeError('Callable expected, got: %r' % function) + obj = Atom.__new__(cls) + obj.function = function + return obj + + def _hashable_content(self): + return type(self), self.function + + def __call__(self, *args): + return self.function(*args) + + +class OracleGate(Gate): + """A black box gate. + + The gate marks the desired qubits of an unknown function by flipping + the sign of the qubits. The unknown function returns true when it + finds its desired qubits and false otherwise. + + Parameters + ========== + + qubits : int + Number of qubits. + + oracle : callable + A callable function that returns a boolean on a computational basis. + + Examples + ======== + + Apply an Oracle gate that flips the sign of ``|2>`` on different qubits:: + + >>> from sympy.physics.quantum.qubit import IntQubit + >>> from sympy.physics.quantum.qapply import qapply + >>> from sympy.physics.quantum.grover import OracleGate + >>> f = lambda qubits: qubits == IntQubit(2) + >>> v = OracleGate(2, f) + >>> qapply(v*IntQubit(2)) + -|2> + >>> qapply(v*IntQubit(3)) + |3> + """ + + gate_name = 'V' + gate_name_latex = 'V' + + #------------------------------------------------------------------------- + # Initialization/creation + #------------------------------------------------------------------------- + + @classmethod + def _eval_args(cls, args): + if len(args) != 2: + raise QuantumError( + 'Insufficient/excessive arguments to Oracle. Please ' + + 'supply the number of qubits and an unknown function.' + ) + sub_args = (args[0],) + sub_args = UnitaryOperator._eval_args(sub_args) + if not sub_args[0].is_Integer: + raise TypeError('Integer expected, got: %r' % sub_args[0]) + + function = args[1] + if not isinstance(function, OracleGateFunction): + function = OracleGateFunction(function) + + return (sub_args[0], function) + + @classmethod + def _eval_hilbert_space(cls, args): + """This returns the smallest possible Hilbert space.""" + return ComplexSpace(2)**args[0] + + #------------------------------------------------------------------------- + # Properties + #------------------------------------------------------------------------- + + @property + def search_function(self): + """The unknown function that helps find the sought after qubits.""" + return self.label[1] + + @property + def targets(self): + """A tuple of target qubits.""" + return sympify(tuple(range(self.args[0]))) + + #------------------------------------------------------------------------- + # Apply + #------------------------------------------------------------------------- + + def _apply_operator_Qubit(self, qubits, **options): + """Apply this operator to a Qubit subclass. + + Parameters + ========== + + qubits : Qubit + The qubit subclass to apply this operator to. + + Returns + ======= + + state : Expr + The resulting quantum state. + """ + if qubits.nqubits != self.nqubits: + raise QuantumError( + 'OracleGate operates on %r qubits, got: %r' + % (self.nqubits, qubits.nqubits) + ) + # If function returns 1 on qubits + # return the negative of the qubits (flip the sign) + if self.search_function(qubits): + return -qubits + else: + return qubits + + #------------------------------------------------------------------------- + # Represent + #------------------------------------------------------------------------- + + def _represent_ZGate(self, basis, **options): + """ + Represent the OracleGate in the computational basis. + """ + nbasis = 2**self.nqubits # compute it only once + matrixOracle = eye(nbasis) + # Flip the sign given the output of the oracle function + for i in range(nbasis): + if self.search_function(IntQubit(i, nqubits=self.nqubits)): + matrixOracle[i, i] = NegativeOne() + return matrixOracle + + +class WGate(Gate): + """General n qubit W Gate in Grover's algorithm. + + The gate performs the operation ``2|phi> = (tensor product of n Hadamards)*(|0> with n qubits)`` + + Parameters + ========== + + nqubits : int + The number of qubits to operate on + + """ + + gate_name = 'W' + gate_name_latex = 'W' + + @classmethod + def _eval_args(cls, args): + if len(args) != 1: + raise QuantumError( + 'Insufficient/excessive arguments to W gate. Please ' + + 'supply the number of qubits to operate on.' + ) + args = UnitaryOperator._eval_args(args) + if not args[0].is_Integer: + raise TypeError('Integer expected, got: %r' % args[0]) + return args + + #------------------------------------------------------------------------- + # Properties + #------------------------------------------------------------------------- + + @property + def targets(self): + return sympify(tuple(reversed(range(self.args[0])))) + + #------------------------------------------------------------------------- + # Apply + #------------------------------------------------------------------------- + + def _apply_operator_Qubit(self, qubits, **options): + """ + qubits: a set of qubits (Qubit) + Returns: quantum object (quantum expression - QExpr) + """ + if qubits.nqubits != self.nqubits: + raise QuantumError( + 'WGate operates on %r qubits, got: %r' + % (self.nqubits, qubits.nqubits) + ) + + # See 'Quantum Computer Science' by David Mermin p.92 -> W|a> result + # Return (2/(sqrt(2^n)))|phi> - |a> where |a> is the current basis + # state and phi is the superposition of basis states (see function + # create_computational_basis above) + basis_states = superposition_basis(self.nqubits) + 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. + + Parameters + ========== + + qstate : Qubit + A superposition of qubits. + oracle : OracleGate + The black box operator that flips the sign of the desired basis qubits. + + Returns + ======= + + Qubit : The qubits after applying the Oracle and W gate. + + Examples + ======== + + Perform one iteration of grover's algorithm to see a phase change:: + + >>> from sympy.physics.quantum.qapply import qapply + >>> from sympy.physics.quantum.qubit import IntQubit + >>> from sympy.physics.quantum.grover import OracleGate + >>> from sympy.physics.quantum.grover import superposition_basis + >>> from sympy.physics.quantum.grover import grover_iteration + >>> numqubits = 2 + >>> basis_states = superposition_basis(numqubits) + >>> f = lambda qubits: qubits == IntQubit(2) + >>> v = OracleGate(numqubits, f) + >>> qapply(grover_iteration(basis_states, v)) + |2> + + """ + wgate = WGate(oracle.nqubits) + return wgate*oracle*qstate + + +def apply_grover(oracle, nqubits, iterations=None): + """Applies grover's algorithm. + + Parameters + ========== + + oracle : callable + The unknown callable function that returns true when applied to the + desired qubits and false otherwise. + + Returns + ======= + + state : Expr + The resulting state after Grover's algorithm has been iterated. + + Examples + ======== + + Apply grover's algorithm to an even superposition of 2 qubits:: + + >>> from sympy.physics.quantum.qapply import qapply + >>> from sympy.physics.quantum.qubit import IntQubit + >>> from sympy.physics.quantum.grover import apply_grover + >>> f = lambda qubits: qubits == IntQubit(2) + >>> qapply(apply_grover(f, 2)) + |2> + + """ + if nqubits <= 0: + raise QuantumError( + 'Grover\'s algorithm needs nqubits > 0, received %r qubits' + % nqubits + ) + if iterations is None: + iterations = floor(sqrt(2**nqubits)*(pi/4)) + + v = OracleGate(nqubits, oracle) + iterated = superposition_basis(nqubits) + for iter in range(iterations): + iterated = grover_iteration(iterated, v) + iterated = qapply(iterated) + + return iterated diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/hilbert.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/hilbert.py new file mode 100644 index 0000000000000000000000000000000000000000..f475a9e83a6ccc93e9e2dbb9873ad111c1d05f93 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/hilbert.py @@ -0,0 +1,653 @@ +"""Hilbert spaces for quantum mechanics. + +Authors: +* Brian Granger +* Matt Curry +""" + +from functools import reduce + +from sympy.core.basic import Basic +from sympy.core.singleton import S +from sympy.core.sympify import sympify +from sympy.sets.sets import Interval +from sympy.printing.pretty.stringpict import prettyForm +from sympy.physics.quantum.qexpr import QuantumError + + +__all__ = [ + 'HilbertSpaceError', + 'HilbertSpace', + 'TensorProductHilbertSpace', + 'TensorPowerHilbertSpace', + 'DirectSumHilbertSpace', + 'ComplexSpace', + 'L2', + 'FockSpace' +] + +#----------------------------------------------------------------------------- +# Main objects +#----------------------------------------------------------------------------- + + +class HilbertSpaceError(QuantumError): + pass + +#----------------------------------------------------------------------------- +# Main objects +#----------------------------------------------------------------------------- + + +class HilbertSpace(Basic): + """An abstract Hilbert space for quantum mechanics. + + In short, a Hilbert space is an abstract vector space that is complete + with inner products defined [1]_. + + Examples + ======== + + >>> from sympy.physics.quantum.hilbert import HilbertSpace + >>> hs = HilbertSpace() + >>> hs + H + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hilbert_space + """ + + def __new__(cls): + obj = Basic.__new__(cls) + return obj + + @property + def dimension(self): + """Return the Hilbert dimension of the space.""" + raise NotImplementedError('This Hilbert space has no dimension.') + + def __add__(self, other): + return DirectSumHilbertSpace(self, other) + + def __radd__(self, other): + return DirectSumHilbertSpace(other, self) + + def __mul__(self, other): + return TensorProductHilbertSpace(self, other) + + def __rmul__(self, other): + return TensorProductHilbertSpace(other, self) + + def __pow__(self, other, mod=None): + if mod is not None: + raise ValueError('The third argument to __pow__ is not supported \ + for Hilbert spaces.') + return TensorPowerHilbertSpace(self, other) + + def __contains__(self, other): + """Is the operator or state in this Hilbert space. + + This is checked by comparing the classes of the Hilbert spaces, not + the instances. This is to allow Hilbert Spaces with symbolic + dimensions. + """ + if other.hilbert_space.__class__ == self.__class__: + return True + else: + return False + + def _sympystr(self, printer, *args): + return 'H' + + def _pretty(self, printer, *args): + ustr = '\N{LATIN CAPITAL LETTER H}' + return prettyForm(ustr) + + def _latex(self, printer, *args): + return r'\mathcal{H}' + + +class ComplexSpace(HilbertSpace): + """Finite dimensional Hilbert space of complex vectors. + + The elements of this Hilbert space are n-dimensional complex valued + vectors with the usual inner product that takes the complex conjugate + of the vector on the right. + + A classic example of this type of Hilbert space is spin-1/2, which is + ``ComplexSpace(2)``. Generalizing to spin-s, the space is + ``ComplexSpace(2*s+1)``. Quantum computing with N qubits is done with the + direct product space ``ComplexSpace(2)**N``. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.physics.quantum.hilbert import ComplexSpace + >>> c1 = ComplexSpace(2) + >>> c1 + C(2) + >>> c1.dimension + 2 + + >>> n = symbols('n') + >>> c2 = ComplexSpace(n) + >>> c2 + C(n) + >>> c2.dimension + n + + """ + + def __new__(cls, dimension): + dimension = sympify(dimension) + r = cls.eval(dimension) + if isinstance(r, Basic): + return r + obj = Basic.__new__(cls, dimension) + return obj + + @classmethod + def eval(cls, dimension): + if len(dimension.atoms()) == 1: + if not (dimension.is_Integer and dimension > 0 or dimension is S.Infinity + or dimension.is_Symbol): + raise TypeError('The dimension of a ComplexSpace can only' + 'be a positive integer, oo, or a Symbol: %r' + % dimension) + else: + for dim in dimension.atoms(): + if not (dim.is_Integer or dim is S.Infinity or dim.is_Symbol): + raise TypeError('The dimension of a ComplexSpace can only' + ' contain integers, oo, or a Symbol: %r' + % dim) + + @property + def dimension(self): + return self.args[0] + + def _sympyrepr(self, printer, *args): + return "%s(%s)" % (self.__class__.__name__, + printer._print(self.dimension, *args)) + + def _sympystr(self, printer, *args): + return "C(%s)" % printer._print(self.dimension, *args) + + def _pretty(self, printer, *args): + ustr = '\N{LATIN CAPITAL LETTER C}' + pform_exp = printer._print(self.dimension, *args) + pform_base = prettyForm(ustr) + return pform_base**pform_exp + + def _latex(self, printer, *args): + return r'\mathcal{C}^{%s}' % printer._print(self.dimension, *args) + + +class L2(HilbertSpace): + """The Hilbert space of square integrable functions on an interval. + + An L2 object takes in a single SymPy Interval argument which represents + the interval its functions (vectors) are defined on. + + Examples + ======== + + >>> from sympy import Interval, oo + >>> from sympy.physics.quantum.hilbert import L2 + >>> hs = L2(Interval(0,oo)) + >>> hs + L2(Interval(0, oo)) + >>> hs.dimension + oo + >>> hs.interval + Interval(0, oo) + + """ + + def __new__(cls, interval): + if not isinstance(interval, Interval): + raise TypeError('L2 interval must be an Interval instance: %r' + % interval) + obj = Basic.__new__(cls, interval) + return obj + + @property + def dimension(self): + return S.Infinity + + @property + def interval(self): + return self.args[0] + + def _sympyrepr(self, printer, *args): + return "L2(%s)" % printer._print(self.interval, *args) + + def _sympystr(self, printer, *args): + return "L2(%s)" % printer._print(self.interval, *args) + + def _pretty(self, printer, *args): + pform_exp = prettyForm('2') + pform_base = prettyForm('L') + return pform_base**pform_exp + + def _latex(self, printer, *args): + interval = printer._print(self.interval, *args) + return r'{\mathcal{L}^2}\left( %s \right)' % interval + + +class FockSpace(HilbertSpace): + """The Hilbert space for second quantization. + + Technically, this Hilbert space is a infinite direct sum of direct + products of single particle Hilbert spaces [1]_. This is a mess, so we have + a class to represent it directly. + + Examples + ======== + + >>> from sympy.physics.quantum.hilbert import FockSpace + >>> hs = FockSpace() + >>> hs + F + >>> hs.dimension + oo + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Fock_space + """ + + def __new__(cls): + obj = Basic.__new__(cls) + return obj + + @property + def dimension(self): + return S.Infinity + + def _sympyrepr(self, printer, *args): + return "FockSpace()" + + def _sympystr(self, printer, *args): + return "F" + + def _pretty(self, printer, *args): + ustr = '\N{LATIN CAPITAL LETTER F}' + return prettyForm(ustr) + + def _latex(self, printer, *args): + return r'\mathcal{F}' + + +class TensorProductHilbertSpace(HilbertSpace): + """A tensor product of Hilbert spaces [1]_. + + The tensor product between Hilbert spaces is represented by the + operator ``*`` Products of the same Hilbert space will be combined into + tensor powers. + + A ``TensorProductHilbertSpace`` object takes in an arbitrary number of + ``HilbertSpace`` objects as its arguments. In addition, multiplication of + ``HilbertSpace`` objects will automatically return this tensor product + object. + + Examples + ======== + + >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace + >>> from sympy import symbols + + >>> c = ComplexSpace(2) + >>> f = FockSpace() + >>> hs = c*f + >>> hs + C(2)*F + >>> hs.dimension + oo + >>> hs.spaces + (C(2), F) + + >>> c1 = ComplexSpace(2) + >>> n = symbols('n') + >>> c2 = ComplexSpace(n) + >>> hs = c1*c2 + >>> hs + C(2)*C(n) + >>> hs.dimension + 2*n + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Tensor_products + """ + + def __new__(cls, *args): + r = cls.eval(args) + if isinstance(r, Basic): + return r + obj = Basic.__new__(cls, *args) + return obj + + @classmethod + def eval(cls, args): + """Evaluates the direct product.""" + new_args = [] + recall = False + #flatten arguments + for arg in args: + if isinstance(arg, TensorProductHilbertSpace): + new_args.extend(arg.args) + recall = True + elif isinstance(arg, (HilbertSpace, TensorPowerHilbertSpace)): + new_args.append(arg) + else: + 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 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 is None: + prev_arg = new_arg + comb_args.append(prev_arg) + if recall: + return TensorProductHilbertSpace(*comb_args) + elif len(comb_args) == 1: + return TensorPowerHilbertSpace(comb_args[0].base, comb_args[0].exp) + else: + return None + + @property + def dimension(self): + arg_list = [arg.dimension for arg in self.args] + if S.Infinity in arg_list: + return S.Infinity + else: + return reduce(lambda x, y: x*y, arg_list) + + @property + def spaces(self): + """A tuple of the Hilbert spaces in this tensor product.""" + return self.args + + def _spaces_printer(self, printer, *args): + spaces_strs = [] + for arg in self.args: + s = printer._print(arg, *args) + if isinstance(arg, DirectSumHilbertSpace): + s = '(%s)' % s + spaces_strs.append(s) + return spaces_strs + + def _sympyrepr(self, printer, *args): + spaces_reprs = self._spaces_printer(printer, *args) + return "TensorProductHilbertSpace(%s)" % ','.join(spaces_reprs) + + def _sympystr(self, printer, *args): + spaces_strs = self._spaces_printer(printer, *args) + return '*'.join(spaces_strs) + + def _pretty(self, printer, *args): + length = len(self.args) + pform = printer._print('', *args) + for i in range(length): + next_pform = printer._print(self.args[i], *args) + if isinstance(self.args[i], (DirectSumHilbertSpace, + TensorProductHilbertSpace)): + next_pform = prettyForm( + *next_pform.parens(left='(', right=')') + ) + pform = prettyForm(*pform.right(next_pform)) + if i != length - 1: + if printer._use_unicode: + pform = prettyForm(*pform.right(' ' + '\N{N-ARY CIRCLED TIMES OPERATOR}' + ' ')) + else: + pform = prettyForm(*pform.right(' x ')) + return pform + + def _latex(self, printer, *args): + length = len(self.args) + s = '' + for i in range(length): + arg_s = printer._print(self.args[i], *args) + if isinstance(self.args[i], (DirectSumHilbertSpace, + TensorProductHilbertSpace)): + arg_s = r'\left(%s\right)' % arg_s + s = s + arg_s + if i != length - 1: + s = s + r'\otimes ' + return s + + +class DirectSumHilbertSpace(HilbertSpace): + """A direct sum of Hilbert spaces [1]_. + + This class uses the ``+`` operator to represent direct sums between + different Hilbert spaces. + + A ``DirectSumHilbertSpace`` object takes in an arbitrary number of + ``HilbertSpace`` objects as its arguments. Also, addition of + ``HilbertSpace`` objects will automatically return a direct sum object. + + Examples + ======== + + >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace + + >>> c = ComplexSpace(2) + >>> f = FockSpace() + >>> hs = c+f + >>> hs + C(2)+F + >>> hs.dimension + oo + >>> list(hs.spaces) + [C(2), F] + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Direct_sums + """ + def __new__(cls, *args): + r = cls.eval(args) + if isinstance(r, Basic): + return r + obj = Basic.__new__(cls, *args) + return obj + + @classmethod + def eval(cls, args): + """Evaluates the direct product.""" + new_args = [] + recall = False + #flatten arguments + for arg in args: + if isinstance(arg, DirectSumHilbertSpace): + new_args.extend(arg.args) + recall = True + elif isinstance(arg, HilbertSpace): + new_args.append(arg) + else: + raise TypeError('Hilbert spaces can only be summed with other \ + Hilbert spaces: %r' % arg) + if recall: + return DirectSumHilbertSpace(*new_args) + else: + return None + + @property + def dimension(self): + arg_list = [arg.dimension for arg in self.args] + if S.Infinity in arg_list: + return S.Infinity + else: + return reduce(lambda x, y: x + y, arg_list) + + @property + def spaces(self): + """A tuple of the Hilbert spaces in this direct sum.""" + return self.args + + def _sympyrepr(self, printer, *args): + spaces_reprs = [printer._print(arg, *args) for arg in self.args] + return "DirectSumHilbertSpace(%s)" % ','.join(spaces_reprs) + + def _sympystr(self, printer, *args): + spaces_strs = [printer._print(arg, *args) for arg in self.args] + return '+'.join(spaces_strs) + + def _pretty(self, printer, *args): + length = len(self.args) + pform = printer._print('', *args) + for i in range(length): + next_pform = printer._print(self.args[i], *args) + if isinstance(self.args[i], (DirectSumHilbertSpace, + TensorProductHilbertSpace)): + next_pform = prettyForm( + *next_pform.parens(left='(', right=')') + ) + pform = prettyForm(*pform.right(next_pform)) + if i != length - 1: + if printer._use_unicode: + pform = prettyForm(*pform.right(' \N{CIRCLED PLUS} ')) + else: + pform = prettyForm(*pform.right(' + ')) + return pform + + def _latex(self, printer, *args): + length = len(self.args) + s = '' + for i in range(length): + arg_s = printer._print(self.args[i], *args) + if isinstance(self.args[i], (DirectSumHilbertSpace, + TensorProductHilbertSpace)): + arg_s = r'\left(%s\right)' % arg_s + s = s + arg_s + if i != length - 1: + s = s + r'\oplus ' + return s + + +class TensorPowerHilbertSpace(HilbertSpace): + """An exponentiated Hilbert space [1]_. + + Tensor powers (repeated tensor products) are represented by the + operator ``**`` Identical Hilbert spaces that are multiplied together + will be automatically combined into a single tensor power object. + + Any Hilbert space, product, or sum may be raised to a tensor power. The + ``TensorPowerHilbertSpace`` takes two arguments: the Hilbert space; and the + tensor power (number). + + Examples + ======== + + >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace + >>> from sympy import symbols + + >>> n = symbols('n') + >>> c = ComplexSpace(2) + >>> hs = c**n + >>> hs + C(2)**n + >>> hs.dimension + 2**n + + >>> c = ComplexSpace(2) + >>> c*c + C(2)**2 + >>> f = FockSpace() + >>> c*f*f + C(2)*F**2 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Tensor_products + """ + + def __new__(cls, *args): + r = cls.eval(args) + if isinstance(r, Basic): + return r + return Basic.__new__(cls, *r) + + @classmethod + def eval(cls, args): + new_args = args[0], sympify(args[1]) + exp = new_args[1] + #simplify hs**1 -> hs + if exp is S.One: + return args[0] + #simplify hs**0 -> 1 + if exp is S.Zero: + return S.One + #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 \ + 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 \ + or Symbols: %r' % power) + return new_args + + @property + def base(self): + return self.args[0] + + @property + def exp(self): + return self.args[1] + + @property + def dimension(self): + if self.base.dimension is S.Infinity: + return S.Infinity + else: + return self.base.dimension**self.exp + + def _sympyrepr(self, printer, *args): + 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), + printer._print(self.exp, *args)) + + def _pretty(self, printer, *args): + pform_exp = printer._print(self.exp, *args) + if printer._use_unicode: + pform_exp = prettyForm(*pform_exp.left(prettyForm('\N{N-ARY CIRCLED TIMES OPERATOR}'))) + else: + pform_exp = prettyForm(*pform_exp.left(prettyForm('x'))) + pform_base = printer._print(self.base, *args) + return pform_base**pform_exp + + def _latex(self, printer, *args): + base = printer._print(self.base, *args) + exp = printer._print(self.exp, *args) + return r'{%s}^{\otimes %s}' % (base, exp) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/identitysearch.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/identitysearch.py new file mode 100644 index 0000000000000000000000000000000000000000..9a178e9b808450b7ce91175600d6b393fc9797d6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/identitysearch.py @@ -0,0 +1,853 @@ +from collections import deque +from sympy.core.random import randint + +from sympy.external import import_module +from sympy.core.basic import Basic +from sympy.core.mul import Mul +from sympy.core.numbers import Number, equal_valued +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.physics.quantum.represent import represent +from sympy.physics.quantum.dagger import Dagger + +__all__ = [ + # Public interfaces + 'generate_gate_rules', + 'generate_equivalent_ids', + 'GateIdentity', + 'bfs_identity_search', + 'random_identity_search', + + # "Private" functions + 'is_scalar_sparse_matrix', + 'is_scalar_nonsparse_matrix', + 'is_degenerate', + 'is_reducible', +] + +np = import_module('numpy') +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. + + A scalar matrix is such that B = bI, where B is the scalar + matrix, b is some scalar multiple, and I is the identity + matrix. A scalar matrix would have only the element b along + it's main diagonal and zeroes elsewhere. + + Parameters + ========== + + circuit : Gate tuple + Sequence of quantum gates representing a quantum circuit + nqubits : int + Number of qubits in the circuit + identity_only : bool + Check for only identity matrices + eps : number + The tolerance value for zeroing out elements in the matrix. + Values in the range [-eps, +eps] will be changed to a zero. + """ + + if not np or not scipy: + pass + + matrix = represent(Mul(*circuit), nqubits=nqubits, + format='scipy.sparse') + + # In some cases, represent returns a 1D scalar value in place + # of a multi-dimensional scalar matrix + if (isinstance(matrix, int)): + return matrix == 1 if identity_only else True + + # If represent returns a matrix, check if the matrix is diagonal + # and if every item along the diagonal is the same + else: + # Due to floating pointing operations, must zero out + # elements that are "very" small in the dense matrix + # See parameter for default value. + + # Get the ndarray version of the dense matrix + dense_matrix = matrix.todense().getA() + # Since complex values can't be compared, must split + # 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) + # Find the imaginary values between -eps and eps + bool_imag = np.logical_and(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) + # Convert the matrix with real values into imaginary values + corrected_imag = corrected_imag * complex(1j) + # Recombine the real and imaginary components + corrected_dense = corrected_real + corrected_imag + + # Check if it's diagonal + row_indices = corrected_dense.nonzero()[0] + col_indices = corrected_dense.nonzero()[1] + # Check if the rows indices and columns indices are the same + # If they match, then matrix only contains elements along diagonal + bool_indices = row_indices == col_indices + is_diagonal = bool_indices.all() + + 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): + return False + + # The dimensions of the dense matrix should still + # be 2^nqubits if there are elements all along the + # the main diagonal + trace_of_corrected = (corrected_dense/first_element).trace() + expected_trace = pow(2, nqubits) + has_correct_trace = trace_of_corrected == expected_trace + + # If only looking for identity matrices + # first element must be a 1 + real_is_one = abs(first_element.real - 1.0) < eps + 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 bool(is_diagonal and has_correct_trace and is_identity) + + +def is_scalar_nonsparse_matrix(circuit, nqubits, identity_only, eps=None): + """Checks if a given circuit, in matrix form, is equivalent to + a scalar value. + + Parameters + ========== + + circuit : Gate tuple + Sequence of quantum gates representing a quantum circuit + nqubits : int + Number of qubits in the circuit + identity_only : bool + Check for only identity matrices + eps : number + This argument is ignored. It is just for signature compatibility with + is_scalar_sparse_matrix. + + Note: Used in situations when is_scalar_sparse_matrix has bugs + """ + + matrix = represent(Mul(*circuit), nqubits=nqubits) + + # In some cases, represent returns a 1D scalar value in place + # of a multi-dimensional scalar matrix + if (isinstance(matrix, Number)): + return matrix == 1 if identity_only else True + + # If represent returns a matrix, check if the matrix is diagonal + # and if every item along the diagonal is the same + else: + # Added up the diagonal elements + matrix_trace = matrix.trace() + # Divide the trace by the first element in the matrix + # if matrix is not required to be the identity matrix + adjusted_matrix_trace = (matrix_trace/matrix[0] + if not identity_only + else matrix_trace) + + is_identity = equal_valued(matrix[0], 1) if identity_only else True + + has_correct_trace = adjusted_matrix_trace == pow(2, nqubits) + + # The matrix is scalar if it's diagonal and the adjusted trace + # value is equal to 2^nqubits + 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. + + A LL operation multiplies both left and right circuits + with the dagger of the left circuit's leftmost gate, and + the dagger is multiplied on the left side of both circuits. + + If a LL is possible, it returns the new gate rule as a + 2-tuple (LHS, RHS), where LHS is the left circuit and + and RHS is the right circuit of the new rule. + If a LL is not possible, None is returned. + + Parameters + ========== + + left : Gate tuple + The left circuit of a gate rule expression. + right : Gate tuple + The right circuit of a gate rule expression. + + Examples + ======== + + Generate a new gate rule using a LL operation: + + >>> from sympy.physics.quantum.identitysearch import ll_op + >>> from sympy.physics.quantum.gate import X, Y, Z + >>> x = X(0); y = Y(0); z = Z(0) + >>> ll_op((x, y, z), ()) + ((Y(0), Z(0)), (X(0),)) + + >>> ll_op((y, z), (x,)) + ((Z(0),), (Y(0), X(0))) + """ + + 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) + + if (len(left) > 0 and ll_gate_is_unitary): + # Get the new left side w/o the leftmost gate + new_left = left[1:len(left)] + # Add the leftmost gate to the left position on the right side + new_right = (Dagger(ll_gate),) + right + # Return the new gate rule + return (new_left, new_right) + + return None + + +def lr_op(left, right): + """Perform a LR operation. + + A LR operation multiplies both left and right circuits + with the dagger of the left circuit's rightmost gate, and + the dagger is multiplied on the right side of both circuits. + + If a LR is possible, it returns the new gate rule as a + 2-tuple (LHS, RHS), where LHS is the left circuit and + and RHS is the right circuit of the new rule. + If a LR is not possible, None is returned. + + Parameters + ========== + + left : Gate tuple + The left circuit of a gate rule expression. + right : Gate tuple + The right circuit of a gate rule expression. + + Examples + ======== + + Generate a new gate rule using a LR operation: + + >>> from sympy.physics.quantum.identitysearch import lr_op + >>> from sympy.physics.quantum.gate import X, Y, Z + >>> x = X(0); y = Y(0); z = Z(0) + >>> lr_op((x, y, z), ()) + ((X(0), Y(0)), (Z(0),)) + + >>> lr_op((x, y), (z,)) + ((X(0),), (Z(0), Y(0))) + """ + + if (len(left) > 0): + lr_gate = left[len(left) - 1] + lr_gate_is_unitary = is_scalar_matrix( + (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] + # Add the rightmost gate to the right position on the right side + new_right = right + (Dagger(lr_gate),) + # Return the new gate rule + return (new_left, new_right) + + return None + + +def rl_op(left, right): + """Perform a RL operation. + + A RL operation multiplies both left and right circuits + with the dagger of the right circuit's leftmost gate, and + the dagger is multiplied on the left side of both circuits. + + If a RL is possible, it returns the new gate rule as a + 2-tuple (LHS, RHS), where LHS is the left circuit and + and RHS is the right circuit of the new rule. + If a RL is not possible, None is returned. + + Parameters + ========== + + left : Gate tuple + The left circuit of a gate rule expression. + right : Gate tuple + The right circuit of a gate rule expression. + + Examples + ======== + + Generate a new gate rule using a RL operation: + + >>> from sympy.physics.quantum.identitysearch import rl_op + >>> from sympy.physics.quantum.gate import X, Y, Z + >>> x = X(0); y = Y(0); z = Z(0) + >>> rl_op((x,), (y, z)) + ((Y(0), X(0)), (Z(0),)) + + >>> rl_op((x, y), (z,)) + ((Z(0), X(0), Y(0)), ()) + """ + + 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) + + if (len(right) > 0 and rl_gate_is_unitary): + # Get the new right side w/o the leftmost gate + new_right = right[1:len(right)] + # Add the leftmost gate to the left position on the left side + new_left = (Dagger(rl_gate),) + left + # Return the new gate rule + return (new_left, new_right) + + return None + + +def rr_op(left, right): + """Perform a RR operation. + + A RR operation multiplies both left and right circuits + with the dagger of the right circuit's rightmost gate, and + the dagger is multiplied on the right side of both circuits. + + If a RR is possible, it returns the new gate rule as a + 2-tuple (LHS, RHS), where LHS is the left circuit and + and RHS is the right circuit of the new rule. + If a RR is not possible, None is returned. + + Parameters + ========== + + left : Gate tuple + The left circuit of a gate rule expression. + right : Gate tuple + The right circuit of a gate rule expression. + + Examples + ======== + + Generate a new gate rule using a RR operation: + + >>> from sympy.physics.quantum.identitysearch import rr_op + >>> from sympy.physics.quantum.gate import X, Y, Z + >>> x = X(0); y = Y(0); z = Z(0) + >>> rr_op((x, y), (z,)) + ((X(0), Y(0), Z(0)), ()) + + >>> rr_op((x,), (y, z)) + ((X(0), Z(0)), (Y(0),)) + """ + + if (len(right) > 0): + rr_gate = right[len(right) - 1] + rr_gate_is_unitary = is_scalar_matrix( + (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] + # Add the rightmost gate to the right position on the right side + new_left = left + (Dagger(rr_gate),) + # Return the new gate rule + return (new_left, new_right) + + 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 + scalar value. + + This function uses the four operations (LL, LR, RL, RR) + to generate the gate rules. + + A gate rule is an expression such as ABC = D or AB = CD, where + A, B, C, and D are gates. Each value on either side of the + equal sign represents a circuit. The four operations allow + one to find a set of equivalent circuits from a gate identity. + The letters denoting the operation tell the user what + activities to perform on each expression. The first letter + indicates which side of the equal sign to focus on. The + second letter indicates which gate to focus on given the + side. Once this information is determined, the inverse + of the gate is multiplied on both circuits to create a new + gate rule. + + For example, given the identity, ABCD = 1, a LL operation + means look at the left value and multiply both left sides by the + inverse of the leftmost gate A. If A is Hermitian, the inverse + of A is still A. The resulting new rule is BCD = A. + + The following is a summary of the four operations. Assume + that in the examples, all gates are Hermitian. + + LL : left circuit, left multiply + ABCD = E -> AABCD = AE -> BCD = AE + LR : left circuit, right multiply + ABCD = E -> ABCDD = ED -> ABC = ED + RL : right circuit, left multiply + ABC = ED -> EABC = EED -> EABC = D + RR : right circuit, right multiply + AB = CD -> ABD = CDD -> ABD = C + + The number of gate rules generated is n*(n+1), where n + is the number of gates in the sequence (unproven). + + Parameters + ========== + + gate_seq : Gate tuple, Mul, or Number + A variable length tuple or Mul of Gates whose product is equal to + a scalar matrix + return_as_muls : bool + True to return a set of Muls; False to return a set of tuples + + Examples + ======== + + Find the gate rules of the current circuit using tuples: + + >>> from sympy.physics.quantum.identitysearch import generate_gate_rules + >>> from sympy.physics.quantum.gate import X, Y, Z + >>> x = X(0); y = Y(0); z = Z(0) + >>> generate_gate_rules((x, x)) + {((X(0),), (X(0),)), ((X(0), X(0)), ())} + + >>> generate_gate_rules((x, y, z)) + {((), (X(0), Z(0), Y(0))), ((), (Y(0), X(0), Z(0))), + ((), (Z(0), Y(0), X(0))), ((X(0),), (Z(0), Y(0))), + ((Y(0),), (X(0), Z(0))), ((Z(0),), (Y(0), X(0))), + ((X(0), Y(0)), (Z(0),)), ((Y(0), Z(0)), (X(0),)), + ((Z(0), X(0)), (Y(0),)), ((X(0), Y(0), Z(0)), ()), + ((Y(0), Z(0), X(0)), ()), ((Z(0), X(0), Y(0)), ())} + + Find the gate rules of the current circuit using Muls: + + >>> generate_gate_rules(x*x, return_as_muls=True) + {(1, 1)} + + >>> generate_gate_rules(x*y*z, return_as_muls=True) + {(1, X(0)*Z(0)*Y(0)), (1, Y(0)*X(0)*Z(0)), + (1, Z(0)*Y(0)*X(0)), (X(0)*Y(0), Z(0)), + (Y(0)*Z(0), X(0)), (Z(0)*X(0), Y(0)), + (X(0)*Y(0)*Z(0), 1), (Y(0)*Z(0)*X(0), 1), + (Z(0)*X(0)*Y(0), 1), (X(0), Z(0)*Y(0)), + (Y(0), X(0)*Z(0)), (Z(0), Y(0)*X(0))} + """ + + if isinstance(gate_seq, Number): + if return_as_muls: + return {(S.One, S.One)} + else: + return {((), ())} + + elif isinstance(gate_seq, Mul): + gate_seq = gate_seq.args + + # Each item in queue is a 3-tuple: + # i) first item is the left side of an equality + # ii) second item is the right side of an equality + # iii) third item is the number of operations performed + # The argument, gate_seq, will start on the left side, and + # the right side will be empty, implying the presence of an + # identity. + queue = deque() + # A set of gate rules + rules = set() + # Maximum number of operations to perform + max_ops = len(gate_seq) + + def process_new_rule(new_rule, ops): + if new_rule is not None: + new_left, new_right = new_rule + + if new_rule not in rules and (new_right, new_left) not in rules: + rules.add(new_rule) + # If haven't reached the max limit on operations + if ops + 1 < max_ops: + queue.append(new_rule + (ops + 1,)) + + queue.append((gate_seq, (), 0)) + rules.add((gate_seq, ())) + + while len(queue) > 0: + left, right, ops = queue.popleft() + + # Do a LL + new_rule = ll_op(left, right) + process_new_rule(new_rule, ops) + # Do a LR + new_rule = lr_op(left, right) + process_new_rule(new_rule, ops) + # Do a RL + new_rule = rl_op(left, right) + process_new_rule(new_rule, ops) + # Do a RR + new_rule = rr_op(left, right) + process_new_rule(new_rule, ops) + + if return_as_muls: + # Convert each rule as tuples into a rule as muls + mul_rules = set() + for rule in rules: + left, right = rule + mul_rules.add((Mul(*left), Mul(*right))) + + rules = mul_rules + + return rules + + +def generate_equivalent_ids(gate_seq, return_as_muls=False): + """Returns a set of equivalent gate identities. + + A gate identity is a quantum circuit such that the product + of the gates in the circuit is equal to a scalar value. + For example, XYZ = i, where X, Y, Z are the Pauli gates and + i is the imaginary value, is considered a gate identity. + + This function uses the four operations (LL, LR, RL, RR) + to generate the gate rules and, subsequently, to locate equivalent + gate identities. + + Note that all equivalent identities are reachable in n operations + from the starting gate identity, where n is the number of gates + in the sequence. + + The max number of gate identities is 2n, where n is the number + of gates in the sequence (unproven). + + Parameters + ========== + + gate_seq : Gate tuple, Mul, or Number + A variable length tuple or Mul of Gates whose product is equal to + a scalar matrix. + return_as_muls: bool + True to return as Muls; False to return as tuples + + Examples + ======== + + Find equivalent gate identities from the current circuit with tuples: + + >>> from sympy.physics.quantum.identitysearch import generate_equivalent_ids + >>> from sympy.physics.quantum.gate import X, Y, Z + >>> x = X(0); y = Y(0); z = Z(0) + >>> generate_equivalent_ids((x, x)) + {(X(0), X(0))} + + >>> generate_equivalent_ids((x, y, z)) + {(X(0), Y(0), Z(0)), (X(0), Z(0), Y(0)), (Y(0), X(0), Z(0)), + (Y(0), Z(0), X(0)), (Z(0), X(0), Y(0)), (Z(0), Y(0), X(0))} + + Find equivalent gate identities from the current circuit with Muls: + + >>> generate_equivalent_ids(x*x, return_as_muls=True) + {1} + + >>> generate_equivalent_ids(x*y*z, return_as_muls=True) + {X(0)*Y(0)*Z(0), X(0)*Z(0)*Y(0), Y(0)*X(0)*Z(0), + Y(0)*Z(0)*X(0), Z(0)*X(0)*Y(0), Z(0)*Y(0)*X(0)} + """ + + if isinstance(gate_seq, Number): + return {S.One} + elif isinstance(gate_seq, Mul): + gate_seq = gate_seq.args + + # Filter through the gate rules and keep the rules + # with an empty tuple either on the left or right side + + # A set of equivalent gate identities + eq_ids = set() + + gate_rules = generate_gate_rules(gate_seq) + for rule in gate_rules: + l, r = rule + if l == (): + eq_ids.add(r) + elif r == (): + eq_ids.add(l) + + if return_as_muls: + convert_to_mul = lambda id_seq: Mul(*id_seq) + eq_ids = set(map(convert_to_mul, eq_ids)) + + return eq_ids + + +class GateIdentity(Basic): + """Wrapper class for circuits that reduce to a scalar value. + + A gate identity is a quantum circuit such that the product + of the gates in the circuit is equal to a scalar value. + For example, XYZ = i, where X, Y, Z are the Pauli gates and + i is the imaginary value, is considered a gate identity. + + Parameters + ========== + + args : Gate tuple + A variable length tuple of Gates that form an identity. + + Examples + ======== + + Create a GateIdentity and look at its attributes: + + >>> from sympy.physics.quantum.identitysearch import GateIdentity + >>> from sympy.physics.quantum.gate import X, Y, Z + >>> x = X(0); y = Y(0); z = Z(0) + >>> an_identity = GateIdentity(x, y, z) + >>> an_identity.circuit + X(0)*Y(0)*Z(0) + + >>> an_identity.equivalent_ids + {(X(0), Y(0), Z(0)), (X(0), Z(0), Y(0)), (Y(0), X(0), Z(0)), + (Y(0), Z(0), X(0)), (Z(0), X(0), Y(0)), (Z(0), Y(0), X(0))} + """ + + def __new__(cls, *args): + # args should be a tuple - a variable length argument list + obj = Basic.__new__(cls, *args) + obj._circuit = Mul(*args) + obj._rules = generate_gate_rules(args) + obj._eq_ids = generate_equivalent_ids(args) + + return obj + + @property + def circuit(self): + return self._circuit + + @property + def gate_rules(self): + return self._rules + + @property + def equivalent_ids(self): + return self._eq_ids + + @property + def sequence(self): + return self.args + + def __str__(self): + """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. + + Parameters + ========== + + identity_set : set + A Python set with GateIdentity objects. + gate_identity : GateIdentity + The GateIdentity to check for existence in the set. + + Examples + ======== + + Check if the identity is a permutation of another identity: + + >>> from sympy.physics.quantum.identitysearch import ( + ... GateIdentity, is_degenerate) + >>> from sympy.physics.quantum.gate import X, Y, Z + >>> x = X(0); y = Y(0); z = Z(0) + >>> an_identity = GateIdentity(x, y, z) + >>> id_set = {an_identity} + >>> another_id = (y, z, x) + >>> is_degenerate(id_set, another_id) + True + + >>> another_id = (x, x) + >>> is_degenerate(id_set, another_id) + False + """ + + # For now, just iteratively go through the set and check if the current + # gate_identity is a permutation of an identity in the set + for an_id in identity_set: + if (gate_identity in an_id.equivalent_ids): + 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. + + Parameters + ========== + + circuit : Gate tuple + A tuple of Gates representing a circuit. The circuit to check + if a gate identity is contained in a subcircuit. + nqubits : int + The number of qubits the circuit operates on. + begin : int + The leftmost gate in the circuit to include in a subcircuit. + end : int + The rightmost gate in the circuit to include in a subcircuit. + + Examples + ======== + + Check if the circuit can be reduced: + + >>> from sympy.physics.quantum.identitysearch import is_reducible + >>> from sympy.physics.quantum.gate import X, Y, Z + >>> x = X(0); y = Y(0); z = Z(0) + >>> is_reducible((x, y, z), 1, 0, 3) + True + + Check if an interval in the circuit can be reduced: + + >>> is_reducible((x, y, z), 1, 1, 3) + False + + >>> is_reducible((x, y, y), 1, 1, 3) + True + """ + + current_circuit = () + # Start from the gate at "end" and go down to almost the gate at "begin" + for ndx in reversed(range(begin, end)): + next_gate = circuit[ndx] + current_circuit = (next_gate,) + current_circuit + + # If a circuit as a matrix is equivalent to a scalar value + if (is_scalar_matrix(current_circuit, nqubits, False)): + return True + + 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. + + Performs a breadth first search over the space of gate identities. + This allows the finding of the shortest gate identities first. + + Parameters + ========== + + gate_list : list, Gate + A list of Gates from which to search for gate identities. + nqubits : int + The number of qubits the quantum circuit operates on. + max_depth : int + The longest quantum circuit to construct from gate_list. + identity_only : bool + True to search for gate identities that reduce to identity; + False to search for gate identities that reduce to a scalar. + + Examples + ======== + + Find a list of gate identities: + + >>> from sympy.physics.quantum.identitysearch import bfs_identity_search + >>> from sympy.physics.quantum.gate import X, Y, Z + >>> x = X(0); y = Y(0); z = Z(0) + >>> bfs_identity_search([x], 1, max_depth=2) + {GateIdentity(X(0), X(0))} + + >>> bfs_identity_search([x, y, z], 1) + {GateIdentity(X(0), X(0)), GateIdentity(Y(0), Y(0)), + GateIdentity(Z(0), Z(0)), GateIdentity(X(0), Y(0), Z(0))} + + Find a list of identities that only equal to 1: + + >>> bfs_identity_search([x, y, z], 1, identity_only=True) + {GateIdentity(X(0), X(0)), GateIdentity(Y(0), Y(0)), + GateIdentity(Z(0), Z(0))} + """ + + if max_depth is None or max_depth <= 0: + max_depth = len(gate_list) + + id_only = identity_only + + # Start with an empty sequence (implicitly contains an IdentityGate) + queue = deque([()]) + + # Create an empty set of gate identities + ids = set() + + # Begin searching for gate identities in given space. + while (len(queue) > 0): + current_circuit = queue.popleft() + + for next_gate in gate_list: + new_circuit = current_circuit + (next_gate,) + + # Determines if a (strict) subcircuit is a scalar matrix + circuit_reducible = is_reducible(new_circuit, nqubits, + 1, len(new_circuit)) + + # In many cases when the matrix is a scalar value, + # 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): + ids.add(GateIdentity(*new_circuit)) + + elif (len(new_circuit) < max_depth and + 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. + + If the circuit is a gate identity, the circuit is returned; + Otherwise, None is returned. + """ + + gate_size = len(gate_list) + circuit = () + + for i in range(numgates): + next_gate = gate_list[randint(0, gate_size - 1)] + circuit = circuit + (next_gate,) + + is_scalar = is_scalar_matrix(circuit, nqubits, False) + + return circuit if is_scalar else None diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/innerproduct.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/innerproduct.py new file mode 100644 index 0000000000000000000000000000000000000000..11fed882b6068a4df5a787ff90eee5392f97447a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/innerproduct.py @@ -0,0 +1,138 @@ +"""Symbolic inner product.""" + +from sympy.core.expr import Expr +from sympy.core.kind import NumberKind +from sympy.functions.elementary.complexes import conjugate +from sympy.printing.pretty.stringpict import prettyForm +from sympy.physics.quantum.dagger import Dagger + + +__all__ = [ + 'InnerProduct' +] + + +# InnerProduct is not an QExpr because it is really just a regular commutative +# number. We have gone back and forth about this, but we gain a lot by having +# it subclass Expr. The main challenges were getting Dagger to work +# (we use _eval_conjugate) and represent (we can use atoms and subs). Having +# it be an Expr, mean that there are no commutative QExpr subclasses, +# which simplifies the design of everything. + +class InnerProduct(Expr): + """An unevaluated inner product between a Bra and a Ket [1]. + + Parameters + ========== + + bra : BraBase or subclass + The bra on the left side of the inner product. + ket : KetBase or subclass + The ket on the right side of the inner product. + + Examples + ======== + + Create an InnerProduct and check its properties: + + >>> from sympy.physics.quantum import Bra, Ket + >>> b = Bra('b') + >>> k = Ket('k') + >>> ip = b*k + >>> ip + + >>> ip.bra + >> ip.ket + |k> + + In quantum expressions, inner products will be automatically + identified and created:: + + >>> b*k + + + In more complex expressions, where there is ambiguity in whether inner or + outer products should be created, inner products have high priority:: + + >>> k*b*k*b + *|k> moved to the left of the expression + because inner products are commutative complex numbers. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Inner_product + """ + + kind = NumberKind + + is_complex = True + + def __new__(cls, bra, ket): + # Keep the import of BraBase and KetBase here to avoid problems + # with circular imports. + from sympy.physics.quantum.state import KetBase, BraBase + if not isinstance(ket, KetBase): + raise TypeError('KetBase subclass expected, got: %r' % ket) + if not isinstance(bra, BraBase): + raise TypeError('BraBase subclass expected, got: %r' % ket) + obj = Expr.__new__(cls, bra, ket) + return obj + + @property + def bra(self): + return self.args[0] + + @property + def ket(self): + return self.args[1] + + def _eval_conjugate(self): + return InnerProduct(Dagger(self.ket), Dagger(self.bra)) + + def _sympyrepr(self, printer, *args): + return '%s(%s,%s)' % (self.__class__.__name__, + printer._print(self.bra, *args), printer._print(self.ket, *args)) + + def _sympystr(self, printer, *args): + sbra = printer._print(self.bra) + sket = printer._print(self.ket) + return '%s|%s' % (sbra[:-1], sket[1:]) + + def _pretty(self, printer, *args): + # Print state contents + bra = self.bra._print_contents_pretty(printer, *args) + ket = self.ket._print_contents_pretty(printer, *args) + # Print brackets + height = max(bra.height(), ket.height()) + use_unicode = printer._use_unicode + lbracket, _ = self.bra._pretty_brackets(height, use_unicode) + cbracket, rbracket = self.ket._pretty_brackets(height, use_unicode) + # Build innerproduct + pform = prettyForm(*bra.left(lbracket)) + pform = prettyForm(*pform.right(cbracket)) + pform = prettyForm(*pform.right(ket)) + pform = prettyForm(*pform.right(rbracket)) + return pform + + def _latex(self, printer, *args): + bra_label = self.bra._print_contents_latex(printer, *args) + ket = printer._print(self.ket, *args) + return r'\left\langle %s \right. %s' % (bra_label, ket) + + def doit(self, **hints): + try: + r = self.ket._eval_innerproduct(self.bra, **hints) + except NotImplementedError: + try: + r = conjugate( + self.bra.dual._eval_innerproduct(self.ket.dual, **hints) + ) + except NotImplementedError: + r = None + if r is not None: + return r + return self diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/kind.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/kind.py new file mode 100644 index 0000000000000000000000000000000000000000..14b5bd2c7b0c87f49dc7e6dc9c1b492fbfad6d56 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/kind.py @@ -0,0 +1,103 @@ +"""Kinds for Operators, Bras, and Kets. + +This module defines kinds for operators, bras, and kets. These are useful +in various places in ``sympy.physics.quantum`` as you often want to know +what the kind is of a compound expression. For example, if you multiply +an operator, bra, or ket by a number, you get back another operator, bra, +or ket - even though if you did an ``isinstance`` check you would find that +you have a ``Mul`` instead. The kind system is meant to give you a quick +way of determining how a compound expression behaves in terms of lower +level kinds. + +The resolution calculation of kinds for compound expressions can be found +either in container classes or in functions that are registered with +kind dispatchers. +""" + +from sympy.core.mul import Mul +from sympy.core.kind import Kind, _NumberKind + + +__all__ = [ + '_KetKind', + 'KetKind', + '_BraKind', + 'BraKind', + '_OperatorKind', + 'OperatorKind', +] + + +class _KetKind(Kind): + """A kind for quantum kets.""" + + def __new__(cls): + obj = super().__new__(cls) + return obj + + def __repr__(self): + return "KetKind" + +# Create an instance as many situations need this. +KetKind = _KetKind() + + +class _BraKind(Kind): + """A kind for quantum bras.""" + + def __new__(cls): + obj = super().__new__(cls) + return obj + + def __repr__(self): + return "BraKind" + +# Create an instance as many situations need this. +BraKind = _BraKind() + + +from sympy.core.kind import Kind + +class _OperatorKind(Kind): + """A kind for quantum operators.""" + + def __new__(cls): + obj = super().__new__(cls) + return obj + + def __repr__(self): + return "OperatorKind" + +# Create an instance as many situations need this. +OperatorKind = _OperatorKind() + + +#----------------------------------------------------------------------------- +# Kind resolution. +#----------------------------------------------------------------------------- + +# Note: We can't currently add kind dispatchers for the following combinations +# as the Mul._kind_dispatcher is set to commutative and will also +# register the opposite order, which isn't correct for these pairs: +# +# 1. (_OperatorKind, _KetKind) +# 2. (_BraKind, _OperatorKind) +# 3. (_BraKind, _KetKind) + + +@Mul._kind_dispatcher.register(_NumberKind, _KetKind) +def _mul_number_ket_kind(lhs, rhs): + """Perform the kind calculation of NumberKind*KetKind -> KetKind.""" + return KetKind + + +@Mul._kind_dispatcher.register(_NumberKind, _BraKind) +def _mul_number_bra_kind(lhs, rhs): + """Perform the kind calculation of NumberKind*BraKind -> BraKind.""" + return BraKind + + +@Mul._kind_dispatcher.register(_NumberKind, _OperatorKind) +def _mul_operator_kind(lhs, rhs): + """Perform the kind calculation of NumberKind*OperatorKind -> OperatorKind.""" + return OperatorKind diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/matrixcache.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/matrixcache.py new file mode 100644 index 0000000000000000000000000000000000000000..3cfab3c3490c909966d8a56af395ffa578724ea7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/matrixcache.py @@ -0,0 +1,103 @@ +"""A cache for storing small matrices in multiple formats.""" + +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.power import Pow +from sympy.functions.elementary.exponential import exp +from sympy.matrices.dense import Matrix + +from sympy.physics.quantum.matrixutils import ( + to_sympy, to_numpy, to_scipy_sparse +) + + +class MatrixCache: + """A cache for small matrices in different formats. + + This class takes small matrices in the standard ``sympy.Matrix`` format, + and then converts these to both ``numpy.matrix`` and + ``scipy.sparse.csr_matrix`` matrices. These matrices are then stored for + future recovery. + """ + + def __init__(self, dtype='complex'): + self._cache = {} + self.dtype = dtype + + def cache_matrix(self, name, m): + """Cache a matrix by its name. + + Parameters + ---------- + name : str + A descriptive name for the matrix, like "identity2". + m : list of lists + The raw matrix data as a SymPy Matrix. + """ + try: + self._sympy_matrix(name, m) + except ImportError: + pass + try: + self._numpy_matrix(name, m) + except ImportError: + pass + try: + self._scipy_sparse_matrix(name, m) + except ImportError: + pass + + def get_matrix(self, name, format): + """Get a cached matrix by name and format. + + Parameters + ---------- + name : str + A descriptive name for the matrix, like "identity2". + format : str + The format desired ('sympy', 'numpy', 'scipy.sparse') + """ + m = self._cache.get((name, format)) + if m is not None: + return m + raise NotImplementedError( + 'Matrix with name %s and format %s is not available.' % + (name, format) + ) + + def _store_matrix(self, name, format, m): + self._cache[(name, format)] = m + + def _sympy_matrix(self, name, m): + self._store_matrix(name, 'sympy', to_sympy(m)) + + def _numpy_matrix(self, name, m): + m = to_numpy(m, dtype=self.dtype) + self._store_matrix(name, 'numpy', m) + + def _scipy_sparse_matrix(self, name, m): + # TODO: explore different sparse formats. But sparse.kron will use + # coo in most cases, so we use that here. + m = to_scipy_sparse(m, dtype=self.dtype) + self._store_matrix(name, 'scipy.sparse', m) + + +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('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]])) +matrix_cache.cache_matrix('S', Matrix([[1, 0], [0, I]])) +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]])) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/matrixutils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/matrixutils.py new file mode 100644 index 0000000000000000000000000000000000000000..1082ea326b68256dac96030e36d72efa664495d2 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/matrixutils.py @@ -0,0 +1,272 @@ +"""Utilities to deal with sympy.Matrix, numpy and scipy.sparse.""" + +from sympy.core.expr import Expr +from sympy.core.numbers import I +from sympy.core.singleton import S +from sympy.matrices.matrixbase import MatrixBase +from sympy.matrices import eye, zeros +from sympy.external import import_module + +__all__ = [ + 'numpy_ndarray', + 'scipy_sparse_matrix', + 'sympy_to_numpy', + 'sympy_to_scipy_sparse', + 'numpy_to_sympy', + 'scipy_sparse_to_sympy', + 'flatten_scalar', + 'matrix_dagger', + 'to_sympy', + 'to_numpy', + 'to_scipy_sparse', + 'matrix_tensor_product', + 'matrix_zeros' +] + +# Conditionally define the base classes for numpy and scipy.sparse arrays +# for use in isinstance tests. + +np = import_module('numpy') +if not np: + class numpy_ndarray: + pass +else: + numpy_ndarray = np.ndarray # type: ignore + +scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) +if not scipy: + class scipy_sparse_matrix: + pass + sparse = None +else: + sparse = scipy.sparse + scipy_sparse_matrix = sparse.spmatrix # type: ignore + + +def sympy_to_numpy(m, **options): + """Convert a SymPy Matrix/complex number to a numpy matrix or scalar.""" + if not np: + raise ImportError + dtype = options.get('dtype', 'complex') + if isinstance(m, MatrixBase): + return np.array(m.tolist(), dtype=dtype) + elif isinstance(m, Expr): + if m.is_Number or m.is_NumberSymbol or m == I: + return complex(m) + raise TypeError('Expected MatrixBase or complex scalar, got: %r' % m) + + +def sympy_to_scipy_sparse(m, **options): + """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') + if isinstance(m, MatrixBase): + return sparse.csr_matrix(np.array(m.tolist(), dtype=dtype)) + elif isinstance(m, Expr): + if m.is_Number or m.is_NumberSymbol or m == I: + return complex(m) + raise TypeError('Expected MatrixBase or complex scalar, got: %r' % m) + + +def scipy_sparse_to_sympy(m, **options): + """Convert a scipy.sparse matrix to a SymPy matrix.""" + return MatrixBase(m.todense()) + + +def numpy_to_sympy(m, **options): + """Convert a numpy matrix to a SymPy matrix.""" + return MatrixBase(m) + + +def to_sympy(m, **options): + """Convert a numpy/scipy.sparse matrix to a SymPy matrix.""" + if isinstance(m, MatrixBase): + return m + elif isinstance(m, numpy_ndarray): + return numpy_to_sympy(m) + elif isinstance(m, scipy_sparse_matrix): + return scipy_sparse_to_sympy(m) + elif isinstance(m, Expr): + 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') + if isinstance(m, (MatrixBase, Expr)): + return sympy_to_numpy(m, dtype=dtype) + elif isinstance(m, numpy_ndarray): + return m + elif isinstance(m, scipy_sparse_matrix): + return m.todense() + raise TypeError('Expected sympy/numpy/scipy.sparse matrix, got: %r' % m) + + +def to_scipy_sparse(m, **options): + """Convert a sympy/numpy matrix to a scipy.sparse matrix.""" + dtype = options.get('dtype', 'complex') + if isinstance(m, (MatrixBase, Expr)): + return sympy_to_scipy_sparse(m, dtype=dtype) + elif isinstance(m, numpy_ndarray): + if not sparse: + raise ImportError + return sparse.csr_matrix(m) + elif isinstance(m, scipy_sparse_matrix): + return m + raise TypeError('Expected sympy/numpy/scipy.sparse matrix, got: %r' % m) + + +def flatten_scalar(e): + """Flatten a 1x1 matrix to a scalar, return larger matrices unchanged.""" + if isinstance(e, MatrixBase): + 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]) + return e + + +def matrix_dagger(e): + """Return the dagger of a sympy/numpy/scipy.sparse matrix.""" + if isinstance(e, MatrixBase): + return e.H + elif isinstance(e, (numpy_ndarray, scipy_sparse_matrix)): + return e.conjugate().transpose() + raise TypeError('Expected sympy/numpy/scipy.sparse matrix, got: %r' % e) + + +# TODO: Move this into sympy.matrices. +def _sympy_tensor_product(*matrices): + """Compute the kronecker product of a sequence of SymPy Matrices. + """ + from sympy.matrices.expressions.kronecker import matrix_kronecker_product + + return matrix_kronecker_product(*matrices) + + +def _numpy_tensor_product(*product): + """numpy version of tensor product of multiple arguments.""" + if not np: + raise ImportError + answer = product[0] + for item in product[1:]: + answer = np.kron(answer, item) + return answer + + +def _scipy_sparse_tensor_product(*product): + """scipy.sparse version of tensor product of multiple arguments.""" + if not sparse: + raise ImportError + answer = product[0] + for item in product[1:]: + answer = sparse.kron(answer, item) + # The final matrices will just be multiplied, so csr is a good final + # sparse format. + return sparse.csr_matrix(answer) + + +def matrix_tensor_product(*product): + """Compute the matrix tensor product of sympy/numpy/scipy.sparse matrices.""" + if isinstance(product[0], MatrixBase): + return _sympy_tensor_product(*product) + elif isinstance(product[0], numpy_ndarray): + return _numpy_tensor_product(*product) + elif isinstance(product[0], scipy_sparse_matrix): + return _scipy_sparse_tensor_product(*product) + + +def _numpy_eye(n): + """numpy version of complex eye.""" + if not np: + raise ImportError + return np.array(np.eye(n, dtype='complex')) + + +def _scipy_sparse_eye(n): + """scipy.sparse version of complex eye.""" + if not sparse: + raise ImportError + return sparse.eye(n, n, dtype='complex') + + +def matrix_eye(n, **options): + """Get the version of eye and tensor_product for a given format.""" + format = options.get('format', 'sympy') + if format == 'sympy': + return eye(n) + elif format == 'numpy': + return _numpy_eye(n) + elif format == 'scipy.sparse': + return _scipy_sparse_eye(n) + raise NotImplementedError('Invalid format: %r' % format) + + +def _numpy_zeros(m, n, **options): + """numpy version 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 version 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') + 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: + raise ImportError + test = np.zeros_like(e) + if np.allclose(e, test): + return 0.0 + else: + return e + + +def _scipy_sparse_matrix_to_zero(e): + """Convert a scipy.sparse zero matrix to the zero scalar.""" + if not np: + raise ImportError + edense = e.todense() + test = np.zeros_like(edense) + if np.allclose(edense, test): + return 0.0 + else: + return e + + +def matrix_to_zero(e): + """Convert a zero matrix to the scalar zero.""" + if isinstance(e, MatrixBase): + if zeros(*e.shape) == e: + e = S.Zero + elif isinstance(e, numpy_ndarray): + e = _numpy_matrix_to_zero(e) + elif isinstance(e, scipy_sparse_matrix): + e = _scipy_sparse_matrix_to_zero(e) + return e diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/operator.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/operator.py new file mode 100644 index 0000000000000000000000000000000000000000..b44617e15c19e8b30b76f011630430787233e724 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/operator.py @@ -0,0 +1,653 @@ +"""Quantum mechanical operators. + +TODO: + +* Fix early 0 in apply_operators. +* Debug and test apply_operators. +* Get cse working with classes in this file. +* Doctests and documentation of special methods for InnerProduct, Commutator, + AntiCommutator, represent, apply_operators. +""" +from typing import Optional + +from sympy.core.add import Add +from sympy.core.expr import Expr +from sympy.core.function import (Derivative, expand) +from sympy.core.mul import Mul +from sympy.core.numbers import oo +from sympy.core.singleton import S +from sympy.printing.pretty.stringpict import prettyForm +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.kind import OperatorKind +from sympy.physics.quantum.qexpr import QExpr, dispatch_method +from sympy.matrices import eye +from sympy.utilities.exceptions import sympy_deprecation_warning + + + +__all__ = [ + 'Operator', + 'HermitianOperator', + 'UnitaryOperator', + 'IdentityOperator', + 'OuterProduct', + 'DifferentialOperator' +] + +#----------------------------------------------------------------------------- +# Operators and outer products +#----------------------------------------------------------------------------- + + +class Operator(QExpr): + """Base class for non-commuting quantum operators. + + An operator maps between quantum states [1]_. In quantum mechanics, + observables (including, but not limited to, measured physical values) are + represented as Hermitian operators [2]_. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the + operator. For time-dependent operators, this will include the time. + + Examples + ======== + + Create an operator and examine its attributes:: + + >>> from sympy.physics.quantum import Operator + >>> from sympy import I + >>> A = Operator('A') + >>> A + A + >>> A.hilbert_space + H + >>> A.label + (A,) + >>> A.is_commutative + False + + Create another operator and do some arithmetic operations:: + + >>> B = Operator('B') + >>> C = 2*A*A + I*B + >>> C + 2*A**2 + I*B + + Operators do not commute:: + + >>> A.is_commutative + False + >>> B.is_commutative + False + >>> A*B == B*A + False + + Polymonials of operators respect the commutation properties:: + + >>> e = (A+B)**3 + >>> e.expand() + A*B*A + A*B**2 + A**2*B + A**3 + B*A*B + B*A**2 + B**2*A + B**3 + + Operator inverses are handle symbolically:: + + >>> A.inv() + A**(-1) + >>> A*A.inv() + 1 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Operator_%28physics%29 + .. [2] https://en.wikipedia.org/wiki/Observable + """ + is_hermitian: Optional[bool] = None + is_unitary: Optional[bool] = None + @classmethod + def default_args(self): + return ("O",) + + kind = OperatorKind + + #------------------------------------------------------------------------- + # Printing + #------------------------------------------------------------------------- + + _label_separator = ',' + + def _print_operator_name(self, printer, *args): + return self.__class__.__name__ + + _print_operator_name_latex = _print_operator_name + + def _print_operator_name_pretty(self, printer, *args): + return prettyForm(self.__class__.__name__) + + def _print_contents(self, printer, *args): + if len(self.label) == 1: + return self._print_label(printer, *args) + else: + return '%s(%s)' % ( + self._print_operator_name(printer, *args), + self._print_label(printer, *args) + ) + + def _print_contents_pretty(self, printer, *args): + if len(self.label) == 1: + return self._print_label_pretty(printer, *args) + else: + pform = self._print_operator_name_pretty(printer, *args) + label_pform = self._print_label_pretty(printer, *args) + label_pform = prettyForm( + *label_pform.parens(left='(', right=')') + ) + pform = prettyForm(*pform.right(label_pform)) + return pform + + def _print_contents_latex(self, printer, *args): + if len(self.label) == 1: + return self._print_label_latex(printer, *args) + else: + return r'%s\left(%s\right)' % ( + self._print_operator_name_latex(printer, *args), + self._print_label_latex(printer, *args) + ) + + #------------------------------------------------------------------------- + # _eval_* methods + #------------------------------------------------------------------------- + + def _eval_commutator(self, other, **options): + """Evaluate [self, other] if known, return None if not known.""" + return dispatch_method(self, '_eval_commutator', other, **options) + + def _eval_anticommutator(self, other, **options): + """Evaluate [self, other] if known.""" + return dispatch_method(self, '_eval_anticommutator', other, **options) + + #------------------------------------------------------------------------- + # Operator application + #------------------------------------------------------------------------- + + def _apply_operator(self, ket, **options): + return dispatch_method(self, '_apply_operator', ket, **options) + + def _apply_from_right_to(self, bra, **options): + return None + + def matrix_element(self, *args): + raise NotImplementedError('matrix_elements is not defined') + + def inverse(self): + return self._eval_inverse() + + inv = inverse + + def _eval_inverse(self): + return self**(-1) + + +class HermitianOperator(Operator): + """A Hermitian operator that satisfies H == Dagger(H). + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the + operator. For time-dependent operators, this will include the time. + + Examples + ======== + + >>> from sympy.physics.quantum import Dagger, HermitianOperator + >>> H = HermitianOperator('H') + >>> Dagger(H) + H + """ + + is_hermitian = True + + def _eval_inverse(self): + if isinstance(self, UnitaryOperator): + return self + else: + return Operator._eval_inverse(self) + + def _eval_power(self, exp): + if isinstance(self, UnitaryOperator): + # so all eigenvalues of self are 1 or -1 + if exp.is_even: + from sympy.core.singleton import S + return S.One # is identity, see Issue 24153. + elif exp.is_odd: + return self + # No simplification in all other cases + return Operator._eval_power(self, exp) + + +class UnitaryOperator(Operator): + """A unitary operator that satisfies U*Dagger(U) == 1. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the + operator. For time-dependent operators, this will include the time. + + Examples + ======== + + >>> from sympy.physics.quantum import Dagger, UnitaryOperator + >>> U = UnitaryOperator('U') + >>> U*Dagger(U) + 1 + """ + is_unitary = True + def _eval_adjoint(self): + return self._eval_inverse() + + +class IdentityOperator(Operator): + """An identity operator I that satisfies op * I == I * op == op for any + operator op. + + .. deprecated:: 1.14. + Use the scalar S.One instead as the multiplicative identity for + operators and states. + + Parameters + ========== + + N : Integer + Optional parameter that specifies the dimension of the Hilbert space + of operator. This is used when generating a matrix representation. + + Examples + ======== + + >>> from sympy.physics.quantum import IdentityOperator + >>> IdentityOperator() # doctest: +SKIP + I + """ + is_hermitian = True + is_unitary = True + @property + def dimension(self): + return self.N + + @classmethod + def default_args(self): + return (oo,) + + def __init__(self, *args, **hints): + sympy_deprecation_warning( + """ + IdentityOperator has been deprecated. In the future, please use + S.One as the identity for quantum operators and states. + """, + deprecated_since_version="1.14", + active_deprecations_target='deprecated-operator-identity', + ) + if not len(args) in (0, 1): + raise ValueError('0 or 1 parameters expected, got %s' % args) + + self.N = args[0] if (len(args) == 1 and args[0]) else oo + + def _eval_commutator(self, other, **hints): + return S.Zero + + def _eval_anticommutator(self, other, **hints): + return 2 * other + + def _eval_inverse(self): + return self + + def _eval_adjoint(self): + return self + + def _apply_operator(self, ket, **options): + return ket + + def _apply_from_right_to(self, bra, **options): + return bra + + def _eval_power(self, exp): + return self + + def _print_contents(self, printer, *args): + return 'I' + + def _print_contents_pretty(self, printer, *args): + return prettyForm('I') + + def _print_contents_latex(self, printer, *args): + return r'{\mathcal{I}}' + + def _represent_default_basis(self, **options): + if not self.N or self.N == oo: + raise NotImplementedError('Cannot represent infinite dimensional' + + ' identity operator as a matrix') + + format = options.get('format', 'sympy') + if format != 'sympy': + raise NotImplementedError('Representation in format ' + + '%s not implemented.' % format) + + return eye(self.N) + + +class OuterProduct(Operator): + """An unevaluated outer product between a ket and bra. + + This constructs an outer product between any subclass of ``KetBase`` and + ``BraBase`` as ``|a>>> from sympy.physics.quantum import Ket, Bra, OuterProduct, Dagger + + >>> k = Ket('k') + >>> b = Bra('b') + >>> op = OuterProduct(k, b) + >>> op + |k>>> op.hilbert_space + H + >>> op.ket + |k> + >>> op.bra + >> Dagger(op) + |b>>> k*b + |k>>> b*k*b + *>> from sympy import Derivative, Function, Symbol + >>> from sympy.physics.quantum.operator import DifferentialOperator + >>> from sympy.physics.quantum.state import Wavefunction + >>> from sympy.physics.quantum.qapply import qapply + >>> f = Function('f') + >>> x = Symbol('x') + >>> d = DifferentialOperator(1/x*Derivative(f(x), x), f(x)) + >>> w = Wavefunction(x**2, x) + >>> d.function + f(x) + >>> d.variables + (x,) + >>> qapply(d*w) + Wavefunction(2, x) + + """ + + @property + def variables(self): + """ + Returns the variables with which the function in the specified + arbitrary expression is evaluated + + Examples + ======== + + >>> from sympy.physics.quantum.operator import DifferentialOperator + >>> from sympy import Symbol, Function, Derivative + >>> x = Symbol('x') + >>> f = Function('f') + >>> d = DifferentialOperator(1/x*Derivative(f(x), x), f(x)) + >>> d.variables + (x,) + >>> y = Symbol('y') + >>> d = DifferentialOperator(Derivative(f(x, y), x) + + ... Derivative(f(x, y), y), f(x, y)) + >>> d.variables + (x, y) + """ + + return self.args[-1].args + + @property + def function(self): + """ + Returns the function which is to be replaced with the Wavefunction + + Examples + ======== + + >>> from sympy.physics.quantum.operator import DifferentialOperator + >>> from sympy import Function, Symbol, Derivative + >>> x = Symbol('x') + >>> f = Function('f') + >>> d = DifferentialOperator(Derivative(f(x), x), f(x)) + >>> d.function + f(x) + >>> y = Symbol('y') + >>> d = DifferentialOperator(Derivative(f(x, y), x) + + ... Derivative(f(x, y), y), f(x, y)) + >>> d.function + f(x, y) + """ + + return self.args[-1] + + @property + def expr(self): + """ + Returns the arbitrary expression which is to have the Wavefunction + substituted into it + + Examples + ======== + + >>> from sympy.physics.quantum.operator import DifferentialOperator + >>> from sympy import Function, Symbol, Derivative + >>> x = Symbol('x') + >>> f = Function('f') + >>> d = DifferentialOperator(Derivative(f(x), x), f(x)) + >>> d.expr + Derivative(f(x), x) + >>> y = Symbol('y') + >>> d = DifferentialOperator(Derivative(f(x, y), x) + + ... Derivative(f(x, y), y), f(x, y)) + >>> d.expr + Derivative(f(x, y), x) + Derivative(f(x, y), y) + """ + + return self.args[0] + + @property + def free_symbols(self): + """ + Return the free symbols of the expression. + """ + + return self.expr.free_symbols + + def _apply_operator_Wavefunction(self, func, **options): + from sympy.physics.quantum.state import Wavefunction + var = self.variables + wf_vars = func.args[1:] + + f = self.function + new_expr = self.expr.subs(f, func(*var)) + new_expr = new_expr.doit() + + return Wavefunction(new_expr, *wf_vars) + + def _eval_derivative(self, symbol): + new_expr = Derivative(self.expr, symbol) + return DifferentialOperator(new_expr, self.args[-1]) + + #------------------------------------------------------------------------- + # Printing + #------------------------------------------------------------------------- + + def _print(self, printer, *args): + 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) + label_pform = self._print_label_pretty(printer, *args) + label_pform = prettyForm( + *label_pform.parens(left='(', right=')') + ) + pform = prettyForm(*pform.right(label_pform)) + return pform diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/operatorordering.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/operatorordering.py new file mode 100644 index 0000000000000000000000000000000000000000..d6ba3dd83b4b79b773793b0094e636cc8a901f44 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/operatorordering.py @@ -0,0 +1,290 @@ +"""Functions for reordering operator expressions.""" + +import warnings + +from sympy.core.add import Add +from sympy.core.mul import Mul +from sympy.core.numbers import Integer +from sympy.core.power import Pow +from sympy.physics.quantum import Commutator, AntiCommutator +from sympy.physics.quantum.boson import BosonOp +from sympy.physics.quantum.fermion import FermionOp + +__all__ = [ + 'normal_order', + 'normal_ordered_form' +] + + +def _expand_powers(factors): + """ + Helper function for normal_ordered_form and normal_order: Expand a + power expression to a multiplication expression so that that the + expression can be handled by the normal ordering functions. + """ + + new_factors = [] + for factor in factors.args: + if (isinstance(factor, Pow) + and isinstance(factor.args[1], Integer) + and factor.args[1] > 0): + for n in range(factor.args[1]): + new_factors.append(factor.args[0]) + else: + new_factors.append(factor) + + return new_factors + +def _normal_ordered_form_factor(product, independent=False, recursive_limit=10, + _recursive_depth=0): + """ + Helper function for normal_ordered_form_factor: Write multiplication + expression with bosonic or fermionic operators on normally ordered form, + using the bosonic and fermionic commutation relations. The resulting + operator expression is equivalent to the argument, but will in general be + a sum of operator products instead of a simple product. + """ + + factors = _expand_powers(product) + + new_factors = [] + n = 0 + while n < len(factors) - 1: + current, next = factors[n], factors[n + 1] + if any(not isinstance(f, (FermionOp, BosonOp)) for f in (current, next)): + new_factors.append(current) + n += 1 + continue + + key_1 = (current.is_annihilation, str(current.name)) + key_2 = (next.is_annihilation, str(next.name)) + + if key_1 <= key_2: + new_factors.append(current) + n += 1 + continue + + n += 2 + if current.is_annihilation and not next.is_annihilation: + if isinstance(current, BosonOp) and isinstance(next, BosonOp): + if current.args[0] != next.args[0]: + if independent: + c = 0 + else: + c = Commutator(current, next) + new_factors.append(next * current + c) + else: + new_factors.append(next * current + 1) + elif isinstance(current, FermionOp) and isinstance(next, FermionOp): + if current.args[0] != next.args[0]: + if independent: + c = 0 + else: + c = AntiCommutator(current, next) + new_factors.append(-next * current + c) + else: + new_factors.append(-next * current + 1) + elif (current.is_annihilation == next.is_annihilation and + isinstance(current, FermionOp) and isinstance(next, FermionOp)): + new_factors.append(-next * current) + else: + new_factors.append(next * current) + + if n == len(factors) - 1: + new_factors.append(factors[-1]) + + if new_factors == factors: + return product + else: + expr = Mul(*new_factors).expand() + return normal_ordered_form(expr, + recursive_limit=recursive_limit, + _recursive_depth=_recursive_depth + 1, + independent=independent) + + +def _normal_ordered_form_terms(expr, independent=False, recursive_limit=10, + _recursive_depth=0): + """ + Helper function for normal_ordered_form: loop through each term in an + addition expression and call _normal_ordered_form_factor to perform the + factor to an normally ordered expression. + """ + + new_terms = [] + for term in expr.args: + if isinstance(term, Mul): + new_term = _normal_ordered_form_factor( + term, recursive_limit=recursive_limit, + _recursive_depth=_recursive_depth, independent=independent) + new_terms.append(new_term) + else: + new_terms.append(term) + + return Add(*new_terms) + + +def normal_ordered_form(expr, independent=False, recursive_limit=10, + _recursive_depth=0): + """Write an expression with bosonic or fermionic operators on normal + ordered form, where each term is normally ordered. Note that this + normal ordered form is equivalent to the original expression. + + Parameters + ========== + + expr : expression + The expression write on normal ordered form. + independent : bool (default False) + Whether to consider operator with different names as operating in + different Hilbert spaces. If False, the (anti-)commutation is left + explicit. + recursive_limit : int (default 10) + The number of allowed recursive applications of the function. + + Examples + ======== + + >>> from sympy.physics.quantum import Dagger + >>> from sympy.physics.quantum.boson import BosonOp + >>> from sympy.physics.quantum.operatorordering import normal_ordered_form + >>> a = BosonOp("a") + >>> normal_ordered_form(a * Dagger(a)) + 1 + Dagger(a)*a + """ + + if _recursive_depth > recursive_limit: + warnings.warn("Too many recursions, aborting") + return expr + + if isinstance(expr, Add): + return _normal_ordered_form_terms(expr, + recursive_limit=recursive_limit, + _recursive_depth=_recursive_depth, + independent=independent) + elif isinstance(expr, Mul): + return _normal_ordered_form_factor(expr, + recursive_limit=recursive_limit, + _recursive_depth=_recursive_depth, + independent=independent) + else: + return expr + + +def _normal_order_factor(product, recursive_limit=10, _recursive_depth=0): + """ + Helper function for normal_order: Normal order a multiplication expression + with bosonic or fermionic operators. In general the resulting operator + expression will not be equivalent to original product. + """ + + factors = _expand_powers(product) + + n = 0 + new_factors = [] + while n < len(factors) - 1: + + if (isinstance(factors[n], BosonOp) and + factors[n].is_annihilation): + # boson + if not isinstance(factors[n + 1], BosonOp): + new_factors.append(factors[n]) + else: + if factors[n + 1].is_annihilation: + new_factors.append(factors[n]) + else: + if factors[n].args[0] != factors[n + 1].args[0]: + new_factors.append(factors[n + 1] * factors[n]) + else: + new_factors.append(factors[n + 1] * factors[n]) + n += 1 + + elif (isinstance(factors[n], FermionOp) and + factors[n].is_annihilation): + # fermion + if not isinstance(factors[n + 1], FermionOp): + new_factors.append(factors[n]) + else: + if factors[n + 1].is_annihilation: + new_factors.append(factors[n]) + else: + if factors[n].args[0] != factors[n + 1].args[0]: + new_factors.append(-factors[n + 1] * factors[n]) + else: + new_factors.append(-factors[n + 1] * factors[n]) + n += 1 + + else: + new_factors.append(factors[n]) + + n += 1 + + if n == len(factors) - 1: + new_factors.append(factors[-1]) + + if new_factors == factors: + return product + else: + expr = Mul(*new_factors).expand() + return normal_order(expr, + recursive_limit=recursive_limit, + _recursive_depth=_recursive_depth + 1) + + +def _normal_order_terms(expr, recursive_limit=10, _recursive_depth=0): + """ + Helper function for normal_order: look through each term in an addition + expression and call _normal_order_factor to perform the normal ordering + on the factors. + """ + + new_terms = [] + for term in expr.args: + if isinstance(term, Mul): + new_term = _normal_order_factor(term, + recursive_limit=recursive_limit, + _recursive_depth=_recursive_depth) + new_terms.append(new_term) + else: + new_terms.append(term) + + return Add(*new_terms) + + +def normal_order(expr, recursive_limit=10, _recursive_depth=0): + """Normal order an expression with bosonic or fermionic operators. Note + that this normal order is not equivalent to the original expression, but + the creation and annihilation operators in each term in expr is reordered + so that the expression becomes normal ordered. + + Parameters + ========== + + expr : expression + The expression to normal order. + + recursive_limit : int (default 10) + The number of allowed recursive applications of the function. + + Examples + ======== + + >>> from sympy.physics.quantum import Dagger + >>> from sympy.physics.quantum.boson import BosonOp + >>> from sympy.physics.quantum.operatorordering import normal_order + >>> a = BosonOp("a") + >>> normal_order(a * Dagger(a)) + Dagger(a)*a + """ + if _recursive_depth > recursive_limit: + warnings.warn("Too many recursions, aborting") + return expr + + if isinstance(expr, Add): + return _normal_order_terms(expr, recursive_limit=recursive_limit, + _recursive_depth=_recursive_depth) + elif isinstance(expr, Mul): + return _normal_order_factor(expr, recursive_limit=recursive_limit, + _recursive_depth=_recursive_depth) + else: + return expr diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/operatorset.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/operatorset.py new file mode 100644 index 0000000000000000000000000000000000000000..bf32bcabbe5d33381dff0b94a9b130375032adef --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/operatorset.py @@ -0,0 +1,279 @@ +""" A module for mapping operators to their corresponding eigenstates +and vice versa + +It contains a global dictionary with eigenstate-operator pairings. +If a new state-operator pair is created, this dictionary should be +updated as well. + +It also contains functions operators_to_state and state_to_operators +for mapping between the two. These can handle both classes and +instances of operators and states. See the individual function +descriptions for details. + +TODO List: +- Update the dictionary with a complete list of state-operator pairs +""" + +from sympy.physics.quantum.cartesian import (XOp, YOp, ZOp, XKet, PxOp, PxKet, + PositionKet3D) +from sympy.physics.quantum.operator import Operator +from sympy.physics.quantum.state import StateBase, BraBase, Ket +from sympy.physics.quantum.spin import (JxOp, JyOp, JzOp, J2Op, JxKet, JyKet, + JzKet) + +__all__ = [ + 'operators_to_state', + 'state_to_operators' +] + +#state_mapping stores the mappings between states and their associated +#operators or tuples of operators. This should be updated when new +#classes are written! Entries are of the form PxKet : PxOp or +#something like 3DKet : (ROp, ThetaOp, PhiOp) + +#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 } + +op_mapping = {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 + + A global function for mapping operator classes to their associated + states. It takes either an Operator or a set of operators and + returns the state associated with these. + + This function can handle both instances of a given operator or + just the class itself (i.e. both XOp() and XOp) + + There are multiple use cases to consider: + + 1) A class or set of classes is passed: First, we try to + instantiate default instances for these operators. If this fails, + then the class is simply returned. If we succeed in instantiating + default instances, then we try to call state._operators_to_state + on the operator instances. If this fails, the class is returned. + Otherwise, the instance returned by _operators_to_state is returned. + + 2) An instance or set of instances is passed: In this case, + state._operators_to_state is called on the instances passed. If + this fails, a state class is returned. If the method returns an + instance, that instance is returned. + + In both cases, if the operator class or set does not exist in the + state_mapping dictionary, None is returned. + + Parameters + ========== + + arg: Operator or set + The class or instance of the operator or set of operators + to be mapped to a state + + Examples + ======== + + >>> from sympy.physics.quantum.cartesian import XOp, PxOp + >>> from sympy.physics.quantum.operatorset import operators_to_state + >>> from sympy.physics.quantum.operator import Operator + >>> operators_to_state(XOp) + |x> + >>> operators_to_state(XOp()) + |x> + >>> operators_to_state(PxOp) + |px> + >>> operators_to_state(PxOp()) + |px> + >>> operators_to_state(Operator) + |psi> + >>> operators_to_state(Operator()) + |psi> + """ + + if not (isinstance(operators, (Operator, 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) + or issubclass(s, Operator)): + raise NotImplementedError("Set is not all Operators!") + + ops = frozenset(operators) + + 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: + op_instances = [op() for op in ops] + ret = _get_state(op_mapping[ops], set(op_instances), **options) + except NotImplementedError: + ret = op_mapping[ops] + + return ret + else: + tmp = [type(o) for o in ops] + classes = frozenset(tmp) + + if classes in op_mapping: + ret = _get_state(op_mapping[classes], ops, **options) + else: + ret = None + + return ret + else: + if operators in op_mapping: + try: + op_instance = operators() + ret = _get_state(op_mapping[operators], op_instance, **options) + except NotImplementedError: + ret = op_mapping[operators] + + return ret + elif type(operators) in op_mapping: + return _get_state(op_mapping[type(operators)], operators, **options) + else: + return None + + +def state_to_operators(state, **options): + """ Returns the operator or set of operators corresponding to the + given eigenstate + + A global function for mapping state classes to their associated + operators or sets of operators. It takes either a state class + or instance. + + This function can handle both instances of a given state or just + the class itself (i.e. both XKet() and XKet) + + There are multiple use cases to consider: + + 1) A state class is passed: In this case, we first try + instantiating a default instance of the class. If this succeeds, + then we try to call state._state_to_operators on that instance. + If the creation of the default instance or if the calling of + _state_to_operators fails, then either an operator class or set of + operator classes is returned. Otherwise, the appropriate + operator instances are returned. + + 2) A state instance is returned: Here, state._state_to_operators + is called for the instance. If this fails, then a class or set of + operator classes is returned. Otherwise, the instances are returned. + + In either case, if the state's class does not exist in + state_mapping, None is returned. + + Parameters + ========== + + arg: StateBase class or instance (or subclasses) + The class or instance of the state to be mapped to an + operator or set of operators + + Examples + ======== + + >>> from sympy.physics.quantum.cartesian import XKet, PxKet, XBra, PxBra + >>> from sympy.physics.quantum.operatorset import state_to_operators + >>> from sympy.physics.quantum.state import Ket, Bra + >>> state_to_operators(XKet) + X + >>> state_to_operators(XKet()) + X + >>> state_to_operators(PxKet) + Px + >>> state_to_operators(PxKet()) + Px + >>> state_to_operators(PxBra) + Px + >>> state_to_operators(XBra) + X + >>> state_to_operators(Ket) + O + >>> state_to_operators(Bra) + O + """ + + 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 + state_inst = _make_default(state) + try: + 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, + _make_set(state_mapping[type(state)]), **options) + elif isinstance(state, BraBase) and state.dual_class() in state_mapping: + 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, + _make_set(state_mapping[state.dual_class()])) + except (NotImplementedError, TypeError): + ret = state_mapping[state.dual_class()] + else: + ret = None + + return _make_set(ret) + + +def _make_default(expr): + # XXX: Catching TypeError like this is a bad way of distinguishing between + # classes and instances. The logic using this function should be rewritten + # somehow. + try: + ret = expr() + except TypeError: + ret = expr + + 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 + try: + ret = state_class._operators_to_state(ops, **options) + except NotImplementedError: + ret = _make_default(state_class) + + 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 + try: + ret = state_inst._state_to_operators(op_classes, **options) + except NotImplementedError: + if isinstance(op_classes, (set, tuple, frozenset)): + ret = tuple(_make_default(x) for x in op_classes) + else: + ret = _make_default(op_classes) + + if isinstance(ret, set) and len(ret) == 1: + return ret[0] + + return ret + + +def _make_set(ops): + if isinstance(ops, (tuple, list, frozenset)): + return set(ops) + else: + return ops diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/pauli.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/pauli.py new file mode 100644 index 0000000000000000000000000000000000000000..89762ed2b38e1c5df3775714ee08d3700df0fa65 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/pauli.py @@ -0,0 +1,675 @@ +"""Pauli operators and states""" + +from sympy.core.add import Add +from sympy.core.mul import Mul +from sympy.core.numbers import I +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import exp +from sympy.physics.quantum import Operator, Ket, Bra +from sympy.physics.quantum import ComplexSpace +from sympy.matrices import Matrix +from sympy.functions.special.tensor_functions import KroneckerDelta + +__all__ = [ + 'SigmaX', 'SigmaY', 'SigmaZ', 'SigmaMinus', 'SigmaPlus', 'SigmaZKet', + 'SigmaZBra', 'qsimplify_pauli' +] + + +class SigmaOpBase(Operator): + """Pauli sigma operator, base class""" + + @property + def name(self): + return self.args[0] + + @property + def use_name(self): + return bool(self.args[0]) is not False + + @classmethod + def default_args(self): + return (False,) + + def __new__(cls, *args, **hints): + return Operator.__new__(cls, *args, **hints) + + def _eval_commutator_BosonOp(self, other, **hints): + return S.Zero + + +class SigmaX(SigmaOpBase): + """Pauli sigma x operator + + Parameters + ========== + + name : str + An optional string that labels the operator. Pauli operators with + different names commute. + + Examples + ======== + + >>> from sympy.physics.quantum import represent + >>> from sympy.physics.quantum.pauli import SigmaX + >>> sx = SigmaX() + >>> sx + SigmaX() + >>> represent(sx) + Matrix([ + [0, 1], + [1, 0]]) + """ + + def __new__(cls, *args, **hints): + return SigmaOpBase.__new__(cls, *args, **hints) + + def _eval_commutator_SigmaY(self, other, **hints): + if self.name != other.name: + return S.Zero + else: + return 2 * I * SigmaZ(self.name) + + def _eval_commutator_SigmaZ(self, other, **hints): + if self.name != other.name: + return S.Zero + else: + return - 2 * I * SigmaY(self.name) + + def _eval_commutator_BosonOp(self, other, **hints): + return S.Zero + + def _eval_anticommutator_SigmaY(self, other, **hints): + return S.Zero + + def _eval_anticommutator_SigmaZ(self, other, **hints): + return S.Zero + + def _eval_adjoint(self): + return self + + def _print_contents_latex(self, printer, *args): + if self.use_name: + return r'{\sigma_x^{(%s)}}' % str(self.name) + else: + return r'{\sigma_x}' + + def _print_contents(self, printer, *args): + return 'SigmaX()' + + def _eval_power(self, e): + if e.is_Integer and e.is_positive: + return SigmaX(self.name).__pow__(int(e) % 2) + + def _represent_default_basis(self, **options): + format = options.get('format', 'sympy') + if format == 'sympy': + return Matrix([[0, 1], [1, 0]]) + else: + raise NotImplementedError('Representation in format ' + + format + ' not implemented.') + + +class SigmaY(SigmaOpBase): + """Pauli sigma y operator + + Parameters + ========== + + name : str + An optional string that labels the operator. Pauli operators with + different names commute. + + Examples + ======== + + >>> from sympy.physics.quantum import represent + >>> from sympy.physics.quantum.pauli import SigmaY + >>> sy = SigmaY() + >>> sy + SigmaY() + >>> represent(sy) + Matrix([ + [0, -I], + [I, 0]]) + """ + + def __new__(cls, *args, **hints): + return SigmaOpBase.__new__(cls, *args) + + def _eval_commutator_SigmaZ(self, other, **hints): + if self.name != other.name: + return S.Zero + else: + return 2 * I * SigmaX(self.name) + + def _eval_commutator_SigmaX(self, other, **hints): + if self.name != other.name: + return S.Zero + else: + return - 2 * I * SigmaZ(self.name) + + def _eval_anticommutator_SigmaX(self, other, **hints): + return S.Zero + + def _eval_anticommutator_SigmaZ(self, other, **hints): + return S.Zero + + def _eval_adjoint(self): + return self + + def _print_contents_latex(self, printer, *args): + if self.use_name: + return r'{\sigma_y^{(%s)}}' % str(self.name) + else: + return r'{\sigma_y}' + + def _print_contents(self, printer, *args): + return 'SigmaY()' + + def _eval_power(self, e): + if e.is_Integer and e.is_positive: + return SigmaY(self.name).__pow__(int(e) % 2) + + def _represent_default_basis(self, **options): + format = options.get('format', 'sympy') + if format == 'sympy': + return Matrix([[0, -I], [I, 0]]) + else: + raise NotImplementedError('Representation in format ' + + format + ' not implemented.') + + +class SigmaZ(SigmaOpBase): + """Pauli sigma z operator + + Parameters + ========== + + name : str + An optional string that labels the operator. Pauli operators with + different names commute. + + Examples + ======== + + >>> from sympy.physics.quantum import represent + >>> from sympy.physics.quantum.pauli import SigmaZ + >>> sz = SigmaZ() + >>> sz ** 3 + SigmaZ() + >>> represent(sz) + Matrix([ + [1, 0], + [0, -1]]) + """ + + def __new__(cls, *args, **hints): + return SigmaOpBase.__new__(cls, *args) + + def _eval_commutator_SigmaX(self, other, **hints): + if self.name != other.name: + return S.Zero + else: + return 2 * I * SigmaY(self.name) + + def _eval_commutator_SigmaY(self, other, **hints): + if self.name != other.name: + return S.Zero + else: + return - 2 * I * SigmaX(self.name) + + def _eval_anticommutator_SigmaX(self, other, **hints): + return S.Zero + + def _eval_anticommutator_SigmaY(self, other, **hints): + return S.Zero + + def _eval_adjoint(self): + return self + + def _print_contents_latex(self, printer, *args): + if self.use_name: + return r'{\sigma_z^{(%s)}}' % str(self.name) + else: + return r'{\sigma_z}' + + def _print_contents(self, printer, *args): + return 'SigmaZ()' + + def _eval_power(self, e): + if e.is_Integer and e.is_positive: + return SigmaZ(self.name).__pow__(int(e) % 2) + + def _represent_default_basis(self, **options): + format = options.get('format', 'sympy') + if format == 'sympy': + return Matrix([[1, 0], [0, -1]]) + else: + raise NotImplementedError('Representation in format ' + + format + ' not implemented.') + + +class SigmaMinus(SigmaOpBase): + """Pauli sigma minus operator + + Parameters + ========== + + name : str + An optional string that labels the operator. Pauli operators with + different names commute. + + Examples + ======== + + >>> from sympy.physics.quantum import represent, Dagger + >>> from sympy.physics.quantum.pauli import SigmaMinus + >>> sm = SigmaMinus() + >>> sm + SigmaMinus() + >>> Dagger(sm) + SigmaPlus() + >>> represent(sm) + Matrix([ + [0, 0], + [1, 0]]) + """ + + def __new__(cls, *args, **hints): + return SigmaOpBase.__new__(cls, *args) + + def _eval_commutator_SigmaX(self, other, **hints): + if self.name != other.name: + return S.Zero + else: + return -SigmaZ(self.name) + + def _eval_commutator_SigmaY(self, other, **hints): + if self.name != other.name: + return S.Zero + else: + return I * SigmaZ(self.name) + + def _eval_commutator_SigmaZ(self, other, **hints): + return 2 * self + + def _eval_commutator_SigmaMinus(self, other, **hints): + return SigmaZ(self.name) + + def _eval_anticommutator_SigmaZ(self, other, **hints): + return S.Zero + + def _eval_anticommutator_SigmaX(self, other, **hints): + return S.One + + def _eval_anticommutator_SigmaY(self, other, **hints): + return I * S.NegativeOne + + def _eval_anticommutator_SigmaPlus(self, other, **hints): + return S.One + + def _eval_adjoint(self): + return SigmaPlus(self.name) + + def _eval_power(self, e): + if e.is_Integer and e.is_positive: + return S.Zero + + def _print_contents_latex(self, printer, *args): + if self.use_name: + return r'{\sigma_-^{(%s)}}' % str(self.name) + else: + return r'{\sigma_-}' + + def _print_contents(self, printer, *args): + return 'SigmaMinus()' + + def _represent_default_basis(self, **options): + format = options.get('format', 'sympy') + if format == 'sympy': + return Matrix([[0, 0], [1, 0]]) + else: + raise NotImplementedError('Representation in format ' + + format + ' not implemented.') + + +class SigmaPlus(SigmaOpBase): + """Pauli sigma plus operator + + Parameters + ========== + + name : str + An optional string that labels the operator. Pauli operators with + different names commute. + + Examples + ======== + + >>> from sympy.physics.quantum import represent, Dagger + >>> from sympy.physics.quantum.pauli import SigmaPlus + >>> sp = SigmaPlus() + >>> sp + SigmaPlus() + >>> Dagger(sp) + SigmaMinus() + >>> represent(sp) + Matrix([ + [0, 1], + [0, 0]]) + """ + + def __new__(cls, *args, **hints): + return SigmaOpBase.__new__(cls, *args) + + def _eval_commutator_SigmaX(self, other, **hints): + if self.name != other.name: + return S.Zero + else: + return SigmaZ(self.name) + + def _eval_commutator_SigmaY(self, other, **hints): + if self.name != other.name: + return S.Zero + else: + return I * SigmaZ(self.name) + + def _eval_commutator_SigmaZ(self, other, **hints): + if self.name != other.name: + return S.Zero + else: + return -2 * self + + def _eval_commutator_SigmaMinus(self, other, **hints): + return SigmaZ(self.name) + + def _eval_anticommutator_SigmaZ(self, other, **hints): + return S.Zero + + def _eval_anticommutator_SigmaX(self, other, **hints): + return S.One + + def _eval_anticommutator_SigmaY(self, other, **hints): + return I + + def _eval_anticommutator_SigmaMinus(self, other, **hints): + return S.One + + def _eval_adjoint(self): + return SigmaMinus(self.name) + + def _eval_mul(self, other): + return self * other + + def _eval_power(self, e): + if e.is_Integer and e.is_positive: + return S.Zero + + def _print_contents_latex(self, printer, *args): + if self.use_name: + return r'{\sigma_+^{(%s)}}' % str(self.name) + else: + return r'{\sigma_+}' + + def _print_contents(self, printer, *args): + return 'SigmaPlus()' + + def _represent_default_basis(self, **options): + format = options.get('format', 'sympy') + if format == 'sympy': + return Matrix([[0, 1], [0, 0]]) + else: + raise NotImplementedError('Representation in format ' + + format + ' not implemented.') + + +class SigmaZKet(Ket): + """Ket for a two-level system quantum system. + + Parameters + ========== + + n : Number + The state number (0 or 1). + + """ + + def __new__(cls, n): + if n not in (0, 1): + raise ValueError("n must be 0 or 1") + return Ket.__new__(cls, n) + + @property + def n(self): + return self.label[0] + + @classmethod + def dual_class(self): + return SigmaZBra + + @classmethod + def _eval_hilbert_space(cls, label): + return ComplexSpace(2) + + def _eval_innerproduct_SigmaZBra(self, bra, **hints): + return KroneckerDelta(self.n, bra.n) + + def _apply_from_right_to_SigmaZ(self, op, **options): + if self.n == 0: + return self + else: + return S.NegativeOne * self + + def _apply_from_right_to_SigmaX(self, op, **options): + return SigmaZKet(1) if self.n == 0 else SigmaZKet(0) + + def _apply_from_right_to_SigmaY(self, op, **options): + return I * SigmaZKet(1) if self.n == 0 else (-I) * SigmaZKet(0) + + def _apply_from_right_to_SigmaMinus(self, op, **options): + if self.n == 0: + return SigmaZKet(1) + else: + return S.Zero + + def _apply_from_right_to_SigmaPlus(self, op, **options): + if self.n == 0: + return S.Zero + else: + return SigmaZKet(0) + + def _represent_default_basis(self, **options): + format = options.get('format', 'sympy') + if format == 'sympy': + return Matrix([[1], [0]]) if self.n == 0 else Matrix([[0], [1]]) + else: + raise NotImplementedError('Representation in format ' + + format + ' not implemented.') + + +class SigmaZBra(Bra): + """Bra for a two-level quantum system. + + Parameters + ========== + + n : Number + The state number (0 or 1). + + """ + + def __new__(cls, n): + if n not in (0, 1): + raise ValueError("n must be 0 or 1") + return Bra.__new__(cls, n) + + @property + def n(self): + return self.label[0] + + @classmethod + def dual_class(self): + return SigmaZKet + + +def _qsimplify_pauli_product(a, b): + """ + Internal helper function for simplifying products of Pauli operators. + """ + if not (isinstance(a, SigmaOpBase) and isinstance(b, SigmaOpBase)): + return Mul(a, b) + + if a.name != b.name: + # Pauli matrices with different labels commute; sort by name + if a.name < b.name: + return Mul(a, b) + else: + return Mul(b, a) + + elif isinstance(a, SigmaX): + + if isinstance(b, SigmaX): + return S.One + + if isinstance(b, SigmaY): + return I * SigmaZ(a.name) + + if isinstance(b, SigmaZ): + return - I * SigmaY(a.name) + + if isinstance(b, SigmaMinus): + return (S.Half + SigmaZ(a.name)/2) + + if isinstance(b, SigmaPlus): + return (S.Half - SigmaZ(a.name)/2) + + elif isinstance(a, SigmaY): + + if isinstance(b, SigmaX): + return - I * SigmaZ(a.name) + + if isinstance(b, SigmaY): + return S.One + + if isinstance(b, SigmaZ): + return I * SigmaX(a.name) + + if isinstance(b, SigmaMinus): + return -I * (S.One + SigmaZ(a.name))/2 + + if isinstance(b, SigmaPlus): + return I * (S.One - SigmaZ(a.name))/2 + + elif isinstance(a, SigmaZ): + + if isinstance(b, SigmaX): + return I * SigmaY(a.name) + + if isinstance(b, SigmaY): + return - I * SigmaX(a.name) + + if isinstance(b, SigmaZ): + return S.One + + if isinstance(b, SigmaMinus): + return - SigmaMinus(a.name) + + if isinstance(b, SigmaPlus): + return SigmaPlus(a.name) + + elif isinstance(a, SigmaMinus): + + if isinstance(b, SigmaX): + return (S.One - SigmaZ(a.name))/2 + + if isinstance(b, SigmaY): + return - I * (S.One - SigmaZ(a.name))/2 + + if isinstance(b, SigmaZ): + # (SigmaX(a.name) - I * SigmaY(a.name))/2 + return SigmaMinus(b.name) + + if isinstance(b, SigmaMinus): + return S.Zero + + if isinstance(b, SigmaPlus): + return S.Half - SigmaZ(a.name)/2 + + elif isinstance(a, SigmaPlus): + + if isinstance(b, SigmaX): + return (S.One + SigmaZ(a.name))/2 + + if isinstance(b, SigmaY): + return I * (S.One + SigmaZ(a.name))/2 + + if isinstance(b, SigmaZ): + #-(SigmaX(a.name) + I * SigmaY(a.name))/2 + return -SigmaPlus(a.name) + + if isinstance(b, SigmaMinus): + return (S.One + SigmaZ(a.name))/2 + + if isinstance(b, SigmaPlus): + return S.Zero + + else: + return a * b + + +def qsimplify_pauli(e): + """ + Simplify an expression that includes products of pauli operators. + + Parameters + ========== + + e : expression + An expression that contains products of Pauli operators that is + to be simplified. + + Examples + ======== + + >>> from sympy.physics.quantum.pauli import SigmaX, SigmaY + >>> from sympy.physics.quantum.pauli import qsimplify_pauli + >>> sx, sy = SigmaX(), SigmaY() + >>> sx * sy + SigmaX()*SigmaY() + >>> qsimplify_pauli(sx * sy) + I*SigmaZ() + """ + if isinstance(e, Operator): + return e + + if isinstance(e, (Add, Pow, exp)): + t = type(e) + return t(*(qsimplify_pauli(arg) for arg in e.args)) + + if isinstance(e, Mul): + + c, nc = e.args_cnc() + + nc_s = [] + while nc: + curr = nc.pop(0) + + while (len(nc) and + isinstance(curr, SigmaOpBase) and + isinstance(nc[0], SigmaOpBase) and + curr.name == nc[0].name): + + x = nc.pop(0) + y = _qsimplify_pauli_product(curr, x) + c1, nc1 = y.args_cnc() + curr = Mul(*nc1) + c = c + c1 + + nc_s.append(curr) + + return Mul(*c) * Mul(*nc_s) + + return e diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/piab.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/piab.py new file mode 100644 index 0000000000000000000000000000000000000000..f8ac8135ee03e640f745070602c7dd8ca20f2767 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/piab.py @@ -0,0 +1,72 @@ +"""1D quantum particle in a box.""" + +from sympy.core.numbers import pi +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin +from sympy.sets.sets import Interval + +from sympy.physics.quantum.operator import HermitianOperator +from sympy.physics.quantum.state import Ket, Bra +from sympy.physics.quantum.constants import hbar +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.physics.quantum.hilbert import L2 + +m = Symbol('m') +L = Symbol('L') + + +__all__ = [ + 'PIABHamiltonian', + 'PIABKet', + 'PIABBra' +] + + +class PIABHamiltonian(HermitianOperator): + """Particle in a box Hamiltonian operator.""" + + @classmethod + def _eval_hilbert_space(cls, label): + return L2(Interval(S.NegativeInfinity, S.Infinity)) + + def _apply_operator_PIABKet(self, ket, **options): + n = ket.label[0] + return (n**2*pi**2*hbar**2)/(2*m*L**2)*ket + + +class PIABKet(Ket): + """Particle in a box eigenket.""" + + @classmethod + def _eval_hilbert_space(cls, args): + return L2(Interval(S.NegativeInfinity, S.Infinity)) + + @classmethod + def dual_class(self): + return PIABBra + + def _represent_default_basis(self, **options): + return self._represent_XOp(None, **options) + + def _represent_XOp(self, basis, **options): + x = Symbol('x') + n = Symbol('n') + subs_info = options.get('subs', {}) + return sqrt(2/L)*sin(n*pi*x/L).subs(subs_info) + + def _eval_innerproduct_PIABBra(self, bra): + return KroneckerDelta(bra.label[0], self.label[0]) + + +class PIABBra(Bra): + """Particle in a box eigenbra.""" + + @classmethod + def _eval_hilbert_space(cls, label): + return L2(Interval(S.NegativeInfinity, S.Infinity)) + + @classmethod + def dual_class(self): + return PIABKet diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qapply.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qapply.py new file mode 100644 index 0000000000000000000000000000000000000000..a2d8c92e51552c8114d65a1304fcd1925ae752f4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qapply.py @@ -0,0 +1,263 @@ +"""Logic for applying operators to states. + +Todo: +* Sometimes the final result needs to be expanded, we should do this by hand. +""" + +from sympy.concrete import Sum +from sympy.core.add import Add +from sympy.core.kind import NumberKind +from sympy.core.mul import Mul +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.sympify import sympify, _sympify + +from sympy.physics.quantum.anticommutator import AntiCommutator +from sympy.physics.quantum.commutator import Commutator +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.innerproduct import InnerProduct +from sympy.physics.quantum.operator import OuterProduct, Operator +from sympy.physics.quantum.state import State, KetBase, BraBase, Wavefunction +from sympy.physics.quantum.tensorproduct import TensorProduct + +__all__ = [ + 'qapply' +] + + +#----------------------------------------------------------------------------- +# Main code +#----------------------------------------------------------------------------- + + +def ip_doit_func(e): + """Transform the inner products in an expression by calling ``.doit()``.""" + return e.replace(InnerProduct, lambda *args: InnerProduct(*args).doit()) + + +def sum_doit_func(e): + """Transform the sums in an expression by calling ``.doit()``.""" + return e.replace(Sum, lambda *args: Sum(*args).doit()) + + +def qapply(e, **options): + """Apply operators to states in a quantum expression. + + Parameters + ========== + + e : Expr + The expression containing operators and states. This expression tree + will be walked to find operators acting on states symbolically. + options : dict + A dict of key/value pairs that determine how the operator actions + are carried out. + + The following options are valid: + + * ``dagger``: try to apply Dagger operators to the left + (default: False). + * ``ip_doit``: call ``.doit()`` in inner products when they are + encountered (default: True). + * ``sum_doit``: call ``.doit()`` on sums when they are encountered + (default: False). This is helpful for collapsing sums over Kronecker + delta's that are created when calling ``qapply``. + + Returns + ======= + + e : Expr + The original expression, but with the operators applied to states. + + Examples + ======== + + >>> from sympy.physics.quantum import qapply, Ket, Bra + >>> b = Bra('b') + >>> k = Ket('k') + >>> A = k * b + >>> A + |k>>> qapply(A * b.dual / (b * b.dual)) + |k> + >>> qapply(k.dual * A / (k.dual * k)) + and A*(|a>+|b>) and all Commutators and + # TensorProducts. The only problem with this is that if we can't apply + # all the Operators, we have just expanded everything. + # TODO: don't expand the scalars in front of each Mul. + e = e.expand(commutator=True, tensorproduct=True) + + # If we just have a raw ket, return it. + if isinstance(e, KetBase): + return e + + # We have an Add(a, b, c, ...) and compute + # Add(qapply(a), qapply(b), ...) + elif isinstance(e, Add): + result = 0 + for arg in e.args: + result += qapply(arg, **options) + return result.expand() + + # 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] + return Density(*new_args) + + # For a raw TensorProduct, call qapply on its args. + elif isinstance(e, TensorProduct): + return TensorProduct(*[qapply(t, **options) for t in e.args]) + + # For a Sum, call qapply on its function. + elif isinstance(e, Sum): + result = Sum(qapply(e.function, **options), *e.limits) + result = sum_doit_func(result) if sum_doit else result + return result + + # For a Pow, call qapply on its base. + elif isinstance(e, Pow): + return qapply(e.base, **options)**e.exp + + # We have a Mul where there might be actual operators to apply to kets. + elif isinstance(e, Mul): + c_part, nc_part = e.args_cnc() + c_mul = Mul(*c_part) + nc_mul = Mul(*nc_part) + if not nc_part: # If we only have a commuting part, just return it. + result = c_mul + elif isinstance(nc_mul, Mul): + result = c_mul*qapply_Mul(nc_mul, **options) + else: + result = c_mul*qapply(nc_mul, **options) + if result == e and dagger: + result = Dagger(qapply_Mul(Dagger(e), **options)) + result = ip_doit_func(result) if ip_doit else result + result = sum_doit_func(result) if sum_doit else result + return result + + # In all other cases (State, Operator, Pow, Commutator, InnerProduct, + # OuterProduct) we won't ever have operators to apply to kets. + else: + return e + + +def qapply_Mul(e, **options): + + args = list(e.args) + extra = S.One + result = None + + # If we only have 0 or 1 args, we have nothing to do and return. + if len(args) <= 1 or not isinstance(e, Mul): + return e + rhs = args.pop() + lhs = args.pop() + + # Make sure we have two non-commutative objects before proceeding. + if (not isinstance(rhs, Wavefunction) and sympify(rhs).is_commutative) or \ + (not isinstance(lhs, Wavefunction) and sympify(lhs).is_commutative): + 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)) + lhs = lhs.base + + # Pull OuterProduct apart + if isinstance(lhs, OuterProduct): + args.append(lhs.ket) + lhs = lhs.bra + + if isinstance(rhs, OuterProduct): + extra = rhs.bra # Append to the right of the result + rhs = rhs.ket + + # Call .doit() on Commutator/AntiCommutator. + if isinstance(lhs, (Commutator, AntiCommutator)): + comm = lhs.doit() + if isinstance(comm, Add): + return qapply( + e.func(*(args + [comm.args[0], rhs])) + + e.func(*(args + [comm.args[1], rhs])), + **options + )*extra + else: + return qapply(e.func(*args)*comm*rhs, **options)*extra + + # Apply tensor products of operators to states + if isinstance(lhs, TensorProduct) and all(isinstance(arg, (Operator, State, Mul, Pow)) or arg == 1 for arg in lhs.args) and \ + isinstance(rhs, TensorProduct) and all(isinstance(arg, (Operator, State, Mul, Pow)) 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*extra + + # For Sums, move the Sum to the right. + if isinstance(rhs, Sum): + if isinstance(lhs, Sum): + if set(lhs.variables).intersection(set(rhs.variables)): + raise ValueError('Duplicated dummy indices in separate sums in qapply.') + limits = lhs.limits + rhs.limits + result = Sum(qapply(lhs.function*rhs.function, **options), *limits) + return qapply_Mul(e.func(*args)*result, **options) + else: + result = Sum(qapply(lhs*rhs.function, **options), *rhs.limits) + return qapply_Mul(e.func(*args)*result, **options) + + if isinstance(lhs, Sum): + result = Sum(qapply(lhs.function*rhs, **options), *lhs.limits) + return qapply_Mul(e.func(*args)*result, **options) + + # Now try to actually apply the operator and build an inner product. + _apply = getattr(lhs, '_apply_operator', None) + if _apply is not None: + try: + result = _apply(rhs, **options) + except NotImplementedError: + result = None + else: + result = None + + if result is None: + _apply_right = getattr(rhs, '_apply_from_right_to', None) + if _apply_right is not None: + try: + result = _apply_right(lhs, **options) + except NotImplementedError: + result = None + + if result is None: + if isinstance(lhs, BraBase) and isinstance(rhs, KetBase): + result = InnerProduct(lhs, rhs) + + # TODO: I may need to expand before returning the final result. + if isinstance(result, (int, complex, float)): + return _sympify(result) + elif result is None: + if len(args) == 0: + # We had two args to begin with so args=[]. + return e + else: + return qapply_Mul(e.func(*(args + [lhs])), **options)*rhs*extra + elif isinstance(result, InnerProduct): + return result*qapply_Mul(e.func(*args), **options)*extra + else: # result is a scalar times a Mul, Add or TensorProduct + return qapply(e.func(*args)*result, **options)*extra diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qasm.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qasm.py new file mode 100644 index 0000000000000000000000000000000000000000..39b49d9a67399114e7d03f12148854b2e41b0b26 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qasm.py @@ -0,0 +1,224 @@ +""" + +qasm.py - Functions to parse a set of qasm commands into a SymPy Circuit. + +Examples taken from Chuang's page: https://web.archive.org/web/20220120121541/https://www.media.mit.edu/quanta/qasm2circ/ + +The code returns a circuit and an associated list of labels. + +>>> from sympy.physics.quantum.qasm import Qasm +>>> q = Qasm('qubit q0', 'qubit q1', 'h q0', 'cnot q0,q1') +>>> q.get_circuit() +CNOT(1,0)*H(1) + +>>> q = Qasm('qubit q0', 'qubit q1', 'cnot q0,q1', 'cnot q1,q0', 'cnot q0,q1') +>>> q.get_circuit() +CNOT(1,0)*CNOT(0,1)*CNOT(1,0) +""" + +__all__ = [ + 'Qasm', + ] + +from math import prod + +from sympy.physics.quantum.gate import H, CNOT, X, Z, CGate, CGateS, SWAP, S, T,CPHASE +from sympy.physics.quantum.circuitplot import Mz + +def read_qasm(lines): + return Qasm(*lines.splitlines()) + +def read_qasm_file(filename): + return Qasm(*open(filename).readlines()) + +def flip_index(i, n): + """Reorder qubit indices from largest to smallest. + + >>> from sympy.physics.quantum.qasm import flip_index + >>> flip_index(0, 2) + 1 + >>> flip_index(1, 2) + 0 + """ + return n-i-1 + +def trim(line): + """Remove everything following comment # characters in line. + + >>> from sympy.physics.quantum.qasm import trim + >>> trim('nothing happens here') + 'nothing happens here' + >>> trim('something #happens here') + 'something ' + """ + if '#' not in line: + return line + return line.split('#')[0] + +def get_index(target, labels): + """Get qubit labels from the rest of the line,and return indices + + >>> from sympy.physics.quantum.qasm import get_index + >>> get_index('q0', ['q0', 'q1']) + 1 + >>> get_index('q1', ['q0', 'q1']) + 0 + """ + nq = len(labels) + return flip_index(labels.index(target), nq) + +def get_indices(targets, labels): + return [get_index(t, labels) for t in targets] + +def nonblank(args): + for line in args: + line = trim(line) + if line.isspace(): + continue + yield line + return + +def fullsplit(line): + words = line.split() + rest = ' '.join(words[1:]) + return fixcommand(words[0]), [s.strip() for s in rest.split(',')] + +def fixcommand(c): + """Fix Qasm command names. + + Remove all of forbidden characters from command c, and + replace 'def' with 'qdef'. + """ + forbidden_characters = ['-'] + c = c.lower() + for char in forbidden_characters: + c = c.replace(char, '') + if c == 'def': + return 'qdef' + return c + +def stripquotes(s): + """Replace explicit quotes in a string. + + >>> from sympy.physics.quantum.qasm import stripquotes + >>> stripquotes("'S'") == 'S' + True + >>> stripquotes('"S"') == 'S' + True + >>> stripquotes('S') == 'S' + True + """ + s = s.replace('"', '') # Remove second set of quotes? + s = s.replace("'", '') + return s + +class Qasm: + """Class to form objects from Qasm lines + + >>> from sympy.physics.quantum.qasm import Qasm + >>> q = Qasm('qubit q0', 'qubit q1', 'h q0', 'cnot q0,q1') + >>> q.get_circuit() + CNOT(1,0)*H(1) + >>> q = Qasm('qubit q0', 'qubit q1', 'cnot q0,q1', 'cnot q1,q0', 'cnot q0,q1') + >>> q.get_circuit() + CNOT(1,0)*CNOT(0,1)*CNOT(1,0) + """ + def __init__(self, *args, **kwargs): + self.defs = {} + self.circuit = [] + self.labels = [] + self.inits = {} + self.add(*args) + self.kwargs = kwargs + + def add(self, *lines): + for line in nonblank(lines): + command, rest = fullsplit(line) + if self.defs.get(command): #defs come first, since you can override built-in + function = self.defs.get(command) + indices = self.indices(rest) + if len(indices) == 1: + self.circuit.append(function(indices[0])) + else: + self.circuit.append(function(indices[:-1], indices[-1])) + elif hasattr(self, command): + function = getattr(self, command) + function(*rest) + else: + print("Function %s not defined. Skipping" % command) + + def get_circuit(self): + return prod(reversed(self.circuit)) + + def get_labels(self): + return list(reversed(self.labels)) + + def plot(self): + from sympy.physics.quantum.circuitplot import CircuitPlot + circuit, labels = self.get_circuit(), self.get_labels() + CircuitPlot(circuit, len(labels), labels=labels, inits=self.inits) + + def qubit(self, arg, init=None): + self.labels.append(arg) + if init: self.inits[arg] = init + + def indices(self, args): + return get_indices(args, self.labels) + + def index(self, arg): + return get_index(arg, self.labels) + + def nop(self, *args): + pass + + def x(self, arg): + self.circuit.append(X(self.index(arg))) + + def z(self, arg): + self.circuit.append(Z(self.index(arg))) + + def h(self, arg): + self.circuit.append(H(self.index(arg))) + + def s(self, arg): + self.circuit.append(S(self.index(arg))) + + def t(self, arg): + self.circuit.append(T(self.index(arg))) + + def measure(self, arg): + self.circuit.append(Mz(self.index(arg))) + + def cnot(self, a1, a2): + self.circuit.append(CNOT(*self.indices([a1, a2]))) + + def swap(self, a1, a2): + self.circuit.append(SWAP(*self.indices([a1, a2]))) + + def cphase(self, a1, a2): + self.circuit.append(CPHASE(*self.indices([a1, a2]))) + + def toffoli(self, a1, a2, a3): + i1, i2, i3 = self.indices([a1, a2, a3]) + self.circuit.append(CGateS((i1, i2), X(i3))) + + def cx(self, a1, a2): + fi, fj = self.indices([a1, a2]) + self.circuit.append(CGate(fi, X(fj))) + + def cz(self, a1, a2): + fi, fj = self.indices([a1, a2]) + self.circuit.append(CGate(fi, Z(fj))) + + def defbox(self, *args): + print("defbox not supported yet. Skipping: ", args) + + def qdef(self, name, ncontrols, symbol): + from sympy.physics.quantum.circuitplot import CreateOneQubitGate, CreateCGate + ncontrols = int(ncontrols) + command = fixcommand(name) + symbol = stripquotes(symbol) + if ncontrols > 0: + self.defs[command] = CreateCGate(symbol) + else: + self.defs[command] = CreateOneQubitGate(symbol) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qexpr.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qexpr.py new file mode 100644 index 0000000000000000000000000000000000000000..64f7e2a200fa7d89b35db1da551bcbd25492f2d9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qexpr.py @@ -0,0 +1,409 @@ +from sympy.core.expr import Expr +from sympy.core.symbol import Symbol +from sympy.core.sympify import sympify +from sympy.matrices.dense import Matrix +from sympy.printing.pretty.stringpict import prettyForm +from sympy.core.containers import Tuple +from sympy.utilities.iterables import is_sequence + +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.matrixutils import ( + numpy_ndarray, scipy_sparse_matrix, + to_sympy, to_numpy, to_scipy_sparse +) + +__all__ = [ + 'QuantumError', + 'QExpr' +] + + +#----------------------------------------------------------------------------- +# Error handling +#----------------------------------------------------------------------------- + +class QuantumError(Exception): + pass + + +def _qsympify_sequence(seq): + """Convert elements of a sequence to standard form. + + This is like sympify, but it performs special logic for arguments passed + to QExpr. The following conversions are done: + + * (list, tuple, Tuple) => _qsympify_sequence each element and convert + sequence to a Tuple. + * basestring => Symbol + * Matrix => Matrix + * other => sympify + + Strings are passed to Symbol, not sympify to make sure that variables like + 'pi' are kept as Symbols, not the SymPy built-in number subclasses. + + Examples + ======== + + >>> from sympy.physics.quantum.qexpr import _qsympify_sequence + >>> _qsympify_sequence((1,2,[3,4,[1,]])) + (1, 2, (3, 4, (1,))) + + """ + + return tuple(__qsympify_sequence_helper(seq)) + + +def __qsympify_sequence_helper(seq): + """ + Helper function for _qsympify_sequence + This function does the actual work. + """ + #base case. If not a list, do Sympification + if not is_sequence(seq): + if isinstance(seq, Matrix): + return seq + elif isinstance(seq, str): + return Symbol(seq) + else: + return sympify(seq) + + # base condition, when seq is QExpr and also + # is iterable. + if isinstance(seq, QExpr): + return seq + + #if list, recurse on each item in the list + result = [__qsympify_sequence_helper(item) for item in seq] + + return Tuple(*result) + + +#----------------------------------------------------------------------------- +# Basic Quantum Expression from which all objects descend +#----------------------------------------------------------------------------- + +class QExpr(Expr): + """A base class for all quantum object like operators and states.""" + + # In sympy, slots are for instance attributes that are computed + # dynamically by the __new__ method. They are not part of args, but they + # derive from args. + + # The Hilbert space a quantum Object belongs to. + __slots__ = ('hilbert_space', ) + + is_commutative = False + + # The separator used in printing the label. + _label_separator = '' + + def __new__(cls, *args, **kwargs): + """Construct a new quantum object. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the + quantum object. For a state, this will be its symbol or its + set of quantum numbers. + + Examples + ======== + + >>> from sympy.physics.quantum.qexpr import QExpr + >>> q = QExpr(0) + >>> q + 0 + >>> q.label + (0,) + >>> q.hilbert_space + H + >>> q.args + (0,) + >>> q.is_commutative + False + """ + + # First compute args and call Expr.__new__ to create the instance + args = cls._eval_args(args, **kwargs) + if len(args) == 0: + args = cls._eval_args(tuple(cls.default_args()), **kwargs) + inst = Expr.__new__(cls, *args) + # Now set the slots on the instance + inst.hilbert_space = cls._eval_hilbert_space(args) + return inst + + @classmethod + def _new_rawargs(cls, hilbert_space, *args, **old_assumptions): + """Create new instance of this class with hilbert_space and args. + + This is used to bypass the more complex logic in the ``__new__`` + method in cases where you already have the exact ``hilbert_space`` + and ``args``. This should be used when you are positive these + arguments are valid, in their final, proper form and want to optimize + the creation of the object. + """ + + obj = Expr.__new__(cls, *args, **old_assumptions) + obj.hilbert_space = hilbert_space + return obj + + #------------------------------------------------------------------------- + # Properties + #------------------------------------------------------------------------- + + @property + def label(self): + """The label is the unique set of identifiers for the object. + + Usually, this will include all of the information about the state + *except* the time (in the case of time-dependent objects). + + This must be a tuple, rather than a Tuple. + """ + 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 + + @property + def is_symbolic(self): + return True + + @classmethod + def default_args(self): + """If no arguments are specified, then this will return a default set + of arguments to be run through the constructor. + + NOTE: Any classes that override this MUST return a tuple of arguments. + Should be overridden by subclasses to specify the default arguments for kets and operators + """ + raise NotImplementedError("No default arguments for this class!") + + #------------------------------------------------------------------------- + # _eval_* methods + #------------------------------------------------------------------------- + + def _eval_adjoint(self): + obj = Expr._eval_adjoint(self) + if obj is None: + obj = Expr.__new__(Dagger, self) + if isinstance(obj, QExpr): + obj.hilbert_space = self.hilbert_space + return obj + + @classmethod + def _eval_args(cls, args): + """Process the args passed to the __new__ method. + + This simply runs args through _qsympify_sequence. + """ + return _qsympify_sequence(args) + + @classmethod + def _eval_hilbert_space(cls, args): + """Compute the Hilbert space instance from the args. + """ + from sympy.physics.quantum.hilbert import HilbertSpace + return HilbertSpace() + + #------------------------------------------------------------------------- + # Printing + #------------------------------------------------------------------------- + + # Utilities for printing: these operate on raw SymPy objects + + def _print_sequence(self, seq, sep, printer, *args): + result = [] + for item in seq: + result.append(printer._print(item, *args)) + return sep.join(result) + + def _print_sequence_pretty(self, seq, sep, printer, *args): + pform = printer._print(seq[0], *args) + for item in seq[1:]: + pform = prettyForm(*pform.right(sep)) + pform = prettyForm(*pform.right(printer._print(item, *args))) + return pform + + # Utilities for printing: these operate prettyForm objects + + def _print_subscript_pretty(self, a, b): + top = prettyForm(*b.left(' '*a.width())) + bot = prettyForm(*a.right(' '*b.width())) + return prettyForm(binding=prettyForm.POW, *bot.below(top)) + + def _print_superscript_pretty(self, a, b): + return a**b + + def _print_parens_pretty(self, pform, left='(', right=')'): + return prettyForm(*pform.parens(left=left, right=right)) + + # Printing of labels (i.e. args) + + def _print_label(self, printer, *args): + """Prints the label of the QExpr + + This method prints self.label, using self._label_separator to separate + the elements. This method should not be overridden, instead, override + _print_contents to change printing behavior. + """ + return self._print_sequence( + self.label, self._label_separator, printer, *args + ) + + def _print_label_repr(self, printer, *args): + return self._print_sequence( + self.label, ',', printer, *args + ) + + def _print_label_pretty(self, printer, *args): + return self._print_sequence_pretty( + self.label, self._label_separator, printer, *args + ) + + def _print_label_latex(self, printer, *args): + return self._print_sequence( + self.label, self._label_separator, printer, *args + ) + + # Printing of contents (default to label) + + def _print_contents(self, printer, *args): + """Printer for contents of QExpr + + Handles the printing of any unique identifying contents of a QExpr to + print as its contents, such as any variables or quantum numbers. The + default is to print the label, which is almost always the args. This + should not include printing of any brackets or parentheses. + """ + return self._print_label(printer, *args) + + def _print_contents_pretty(self, printer, *args): + return self._print_label_pretty(printer, *args) + + def _print_contents_latex(self, printer, *args): + return self._print_label_latex(printer, *args) + + # Main printing methods + + def _sympystr(self, printer, *args): + """Default printing behavior of QExpr objects + + Handles the default printing of a QExpr. To add other things to the + printing of the object, such as an operator name to operators or + brackets to states, the class should override the _print/_pretty/_latex + functions directly and make calls to _print_contents where appropriate. + This allows things like InnerProduct to easily control its printing the + printing of contents. + """ + return self._print_contents(printer, *args) + + def _sympyrepr(self, printer, *args): + classname = self.__class__.__name__ + label = self._print_label_repr(printer, *args) + return '%s(%s)' % (classname, label) + + def _pretty(self, printer, *args): + pform = self._print_contents_pretty(printer, *args) + return pform + + def _latex(self, printer, *args): + return self._print_contents_latex(printer, *args) + + #------------------------------------------------------------------------- + # Represent + #------------------------------------------------------------------------- + + def _represent_default_basis(self, **options): + raise NotImplementedError('This object does not have a default basis') + + def _represent(self, *, basis=None, **options): + """Represent this object in a given basis. + + This method dispatches to the actual methods that perform the + representation. Subclases of QExpr should define various methods to + determine how the object will be represented in various bases. The + format of these methods is:: + + def _represent_BasisName(self, basis, **options): + + Thus to define how a quantum object is represented in the basis of + the operator Position, you would define:: + + def _represent_Position(self, basis, **options): + + Usually, basis object will be instances of Operator subclasses, but + there is a chance we will relax this in the future to accommodate other + types of basis sets that are not associated with an operator. + + If the ``format`` option is given it can be ("sympy", "numpy", + "scipy.sparse"). This will ensure that any matrices that result from + representing the object are returned in the appropriate matrix format. + + Parameters + ========== + + basis : Operator + The Operator whose basis functions will be used as the basis for + representation. + options : dict + A dictionary of key/value pairs that give options and hints for + the representation, such as the number of basis functions to + be used. + """ + if basis is None: + result = self._represent_default_basis(**options) + else: + result = dispatch_method(self, '_represent', basis, **options) + + # If we get a matrix representation, convert it to the right format. + format = options.get('format', 'sympy') + result = self._format_represent(result, format) + return result + + def _format_represent(self, result, format): + if format == 'sympy' and not isinstance(result, Matrix): + 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): + 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 = [] + qexpr_part = [] + for arg in e.args: + if not isinstance(arg, QExpr): + expr_part.append(arg) + else: + qexpr_part.append(arg) + return expr_part, qexpr_part + + +def dispatch_method(self, basename, arg, **options): + """Dispatch a method to the proper handlers.""" + method_name = '%s_%s' % (basename, arg.__class__.__name__) + if hasattr(self, method_name): + f = getattr(self, method_name) + # This can raise and we will allow it to propagate. + result = f(arg, **options) + if result is not None: + return result + raise NotImplementedError( + "%s.%s cannot handle: %r" % + (self.__class__.__name__, basename, arg) + ) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qft.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qft.py new file mode 100644 index 0000000000000000000000000000000000000000..c6a3fa4539267f7bb6cf015521007e292b3d4cfd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qft.py @@ -0,0 +1,215 @@ +"""An implementation of qubits and gates acting on them. + +Todo: + +* Update docstrings. +* Update tests. +* Implement apply using decompose. +* Implement represent using decompose or something smarter. For this to + work we first have to implement represent for SWAP. +* Decide if we want upper index to be inclusive in the constructor. +* Fix the printing of Rk gates in plotting. +""" + +from sympy.core.expr import Expr +from sympy.core.numbers import (I, Integer, pi) +from sympy.core.symbol import Symbol +from sympy.functions.elementary.exponential import exp +from sympy.matrices.dense import Matrix +from sympy.functions import sqrt + +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.qexpr import QuantumError, QExpr +from sympy.matrices import eye +from sympy.physics.quantum.tensorproduct import matrix_tensor_product + +from sympy.physics.quantum.gate import ( + Gate, HadamardGate, SwapGate, OneQubitGate, CGate, PhaseGate, TGate, ZGate +) + +from sympy.functions.elementary.complexes import sign + +__all__ = [ + 'QFT', + 'IQFT', + 'RkGate', + 'Rk' +] + +#----------------------------------------------------------------------------- +# Fourier stuff +#----------------------------------------------------------------------------- + + +class RkGate(OneQubitGate): + """This is the R_k gate of the QTF.""" + gate_name = 'Rk' + gate_name_latex = 'R' + + def __new__(cls, *args): + if len(args) != 2: + raise QuantumError( + 'Rk gates only take two arguments, got: %r' % args + ) + # For small k, Rk gates simplify to other gates, using these + # substitutions give us familiar results for the QFT for small numbers + # of qubits. + target = args[0] + k = args[1] + if k == 1: + return ZGate(target) + elif k == 2: + return PhaseGate(target) + elif k == 3: + return TGate(target) + args = cls._eval_args(args) + inst = Expr.__new__(cls, *args) + inst.hilbert_space = cls._eval_hilbert_space(args) + return inst + + @classmethod + def _eval_args(cls, args): + # Fall back to this, because Gate._eval_args assumes that args is + # all targets and can't contain duplicates. + return QExpr._eval_args(args) + + @property + def k(self): + return self.label[1] + + @property + def targets(self): + return self.label[:1] + + @property + def gate_name_plot(self): + return r'$%s_%s$' % (self.gate_name_latex, str(self.k)) + + def get_target_matrix(self, format='sympy'): + if format == 'sympy': + return Matrix([[1, 0], [0, exp(sign(self.k)*Integer(2)*pi*I/(Integer(2)**abs(self.k)))]]) + raise NotImplementedError( + 'Invalid format for the R_k gate: %r' % format) + + +Rk = RkGate + + +class Fourier(Gate): + """Superclass of Quantum Fourier and Inverse Quantum Fourier Gates.""" + + @classmethod + def _eval_args(self, args): + if len(args) != 2: + raise QuantumError( + 'QFT/IQFT only takes two arguments, got: %r' % args + ) + if args[0] >= args[1]: + raise QuantumError("Start must be smaller than finish") + return Gate._eval_args(args) + + def _represent_default_basis(self, **options): + return self._represent_ZGate(None, **options) + + def _represent_ZGate(self, basis, **options): + """ + Represents the (I)QFT In the Z Basis + """ + nqubits = options.get('nqubits', 0) + if nqubits == 0: + 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 + ) + size = self.size + 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)] + 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))) + + return matrixFT + + @property + def targets(self): + return range(self.label[0], self.label[1]) + + @property + def min_qubits(self): + return self.label[1] + + @property + def size(self): + """Size is the size of the QFT matrix""" + return 2**(self.label[1] - self.label[0]) + + @property + def omega(self): + return Symbol('omega') + + +class QFT(Fourier): + """The forward quantum Fourier transform.""" + + gate_name = 'QFT' + gate_name_latex = 'QFT' + + def decompose(self): + """Decomposes QFT into elementary gates.""" + start = self.label[0] + finish = self.label[1] + circuit = 1 + for level in reversed(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 + return circuit + + def _apply_operator_Qubit(self, qubits, **options): + return qapply(self.decompose()*qubits) + + def _eval_inverse(self): + return IQFT(*self.args) + + @property + def omega(self): + return exp(2*pi*I/self.size) + + +class IQFT(Fourier): + """The inverse quantum Fourier transform.""" + + gate_name = 'IQFT' + gate_name_latex = '{QFT^{-1}}' + + def decompose(self): + """Decomposes IQFT into elementary gates.""" + 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 level in range(start, finish): + for i in reversed(range(level - start)): + circuit = CGate(level - i - 1, RkGate(level, -i - 2))*circuit + circuit = HadamardGate(level)*circuit + return circuit + + def _eval_inverse(self): + return QFT(*self.args) + + @property + def omega(self): + return exp(-2*pi*I/self.size) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qubit.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qubit.py new file mode 100644 index 0000000000000000000000000000000000000000..71d1dbc01e3a16e2a4b64eec3c3800b7218b2636 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/qubit.py @@ -0,0 +1,811 @@ +"""Qubits for quantum computing. + +Todo: +* Finish implementing measurement logic. This should include POVM. +* Update docstrings. +* Update tests. +""" + + +import math + +from sympy.core.add import Add +from sympy.core.mul import Mul +from sympy.core.numbers import Integer +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.functions.elementary.complexes import conjugate +from sympy.functions.elementary.exponential import log +from sympy.core.basic import _sympify +from sympy.external.gmpy import SYMPY_INTS +from sympy.matrices import Matrix, zeros +from sympy.printing.pretty.stringpict import prettyForm + +from sympy.physics.quantum.hilbert import ComplexSpace +from sympy.physics.quantum.state import Ket, Bra, State + +from sympy.physics.quantum.qexpr import QuantumError +from sympy.physics.quantum.represent import represent +from sympy.physics.quantum.matrixutils import ( + numpy_ndarray, scipy_sparse_matrix +) +from mpmath.libmp.libintmath import bitcount + +__all__ = [ + 'Qubit', + 'QubitBra', + 'IntQubit', + 'IntQubitBra', + 'qubit_to_matrix', + 'matrix_to_qubit', + 'matrix_to_density', + 'measure_all', + 'measure_partial', + 'measure_partial_oneshot', + 'measure_all_oneshot' +] + +#----------------------------------------------------------------------------- +# Qubit Classes +#----------------------------------------------------------------------------- + + +class QubitState(State): + """Base class for Qubit and QubitBra.""" + + #------------------------------------------------------------------------- + # Initialization/creation + #------------------------------------------------------------------------- + + @classmethod + def _eval_args(cls, args): + # If we are passed a QubitState or subclass, we just take its qubit + # values directly. + if len(args) == 1 and isinstance(args[0], QubitState): + return args[0].qubit_values + + # Turn strings into tuple of strings + if len(args) == 1 and isinstance(args[0], str): + args = tuple( S.Zero if qb == "0" else S.One for qb in args[0]) + else: + args = tuple( S.Zero if qb == "0" else S.One if qb == "1" else qb for qb in args) + args = tuple(_sympify(arg) for arg in args) + + # Validate input (must have 0 or 1 input) + for element in args: + if element not in (S.Zero, S.One): + raise ValueError( + "Qubit values must be 0 or 1, got: %r" % element) + return args + + @classmethod + def _eval_hilbert_space(cls, args): + return ComplexSpace(2)**len(args) + + #------------------------------------------------------------------------- + # Properties + #------------------------------------------------------------------------- + + @property + def dimension(self): + """The number of Qubits in the state.""" + return len(self.qubit_values) + + @property + def nqubits(self): + return self.dimension + + @property + def qubit_values(self): + """Returns the values of the qubits as a tuple.""" + return self.label + + #------------------------------------------------------------------------- + # Special methods + #------------------------------------------------------------------------- + + def __len__(self): + return self.dimension + + def __getitem__(self, bit): + return self.qubit_values[int(self.dimension - bit - 1)] + + #------------------------------------------------------------------------- + # Utility methods + #------------------------------------------------------------------------- + + def flip(self, *bits): + """Flip the bit(s) given.""" + newargs = list(self.qubit_values) + for i in bits: + bit = int(self.dimension - i - 1) + if newargs[bit] == 1: + newargs[bit] = 0 + else: + newargs[bit] = 1 + return self.__class__(*tuple(newargs)) + + +class Qubit(QubitState, Ket): + """A multi-qubit ket in the computational (z) basis. + + We use the normal convention that the least significant qubit is on the + right, so ``|00001>`` has a 1 in the least significant qubit. + + Parameters + ========== + + values : list, str + The qubit values as a list of ints ([0,0,0,1,1,]) or a string ('011'). + + Examples + ======== + + Create a qubit in a couple of different ways and look at their attributes: + + >>> from sympy.physics.quantum.qubit import Qubit + >>> Qubit(0,0,0) + |000> + >>> q = Qubit('0101') + >>> q + |0101> + + >>> q.nqubits + 4 + >>> len(q) + 4 + >>> q.dimension + 4 + >>> q.qubit_values + (0, 1, 0, 1) + + We can flip the value of an individual qubit: + + >>> q.flip(1) + |0111> + + We can take the dagger of a Qubit to get a bra: + + >>> from sympy.physics.quantum.dagger import Dagger + >>> Dagger(q) + <0101| + >>> type(Dagger(q)) + + + Inner products work as expected: + + >>> ip = Dagger(q)*q + >>> ip + <0101|0101> + >>> ip.doit() + 1 + """ + + @classmethod + def dual_class(self): + return QubitBra + + def _eval_innerproduct_QubitBra(self, bra, **hints): + if self.label == bra.label: + return S.One + else: + return S.Zero + + def _represent_default_basis(self, **options): + return self._represent_ZGate(None, **options) + + def _represent_ZGate(self, basis, **options): + """Represent this qubits in the computational basis (ZGate). + """ + _format = options.get('format', 'sympy') + n = 1 + definite_state = 0 + for it in reversed(self.qubit_values): + definite_state += n*it + n = n*2 + result = [0]*(2**self.dimension) + result[int(definite_state)] = 1 + if _format == 'sympy': + return Matrix(result) + elif _format == 'numpy': + import numpy as np + return np.array(result, dtype='complex').transpose() + elif _format == 'scipy.sparse': + from scipy import sparse + return sparse.csr_matrix(result, dtype='complex').transpose() + + def _eval_trace(self, bra, **kwargs): + indices = kwargs.get('indices', []) + + #sort index list to begin trace from most-significant + #qubit + sorted_idx = list(indices) + if len(sorted_idx) == 0: + sorted_idx = list(range(0, self.nqubits)) + sorted_idx.sort() + + #trace out for each of index + new_mat = self*bra + 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])) + + if (len(sorted_idx) == self.nqubits): + #in case full trace was requested + return new_mat[0] + else: + return matrix_to_density(new_mat) + + def _reduced_density(self, matrix, qubit, **options): + """Compute the reduced density matrix by tracing out one qubit. + The qubit argument should be of type Python int, since it is used + in bit operations + """ + def find_index_that_is_projected(j, k, qubit): + bit_mask = 2**qubit - 1 + return ((j >> qubit) << (1 + qubit)) + (j & bit_mask) + (k << qubit) + + old_matrix = represent(matrix, **options) + old_size = old_matrix.cols + #we expect the old_size to be even + new_size = old_size//2 + new_matrix = Matrix().zeros(new_size) + + for i in range(new_size): + for j in range(new_size): + 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] + + return new_matrix + + +class QubitBra(QubitState, Bra): + """A multi-qubit bra in the computational (z) basis. + + We use the normal convention that the least significant qubit is on the + right, so ``|00001>`` has a 1 in the least significant qubit. + + Parameters + ========== + + values : list, str + The qubit values as a list of ints ([0,0,0,1,1,]) or a string ('011'). + + See also + ======== + + Qubit: Examples using qubits + + """ + @classmethod + def dual_class(self): + return Qubit + + +class IntQubitState(QubitState): + """A base class for qubits that work with binary representations.""" + + @classmethod + def _eval_args(cls, args, nqubits=None): + # The case of a QubitState instance + if len(args) == 1 and isinstance(args[0], QubitState): + return QubitState._eval_args(args) + # otherwise, args should be integer + elif not all(isinstance(a, (int, Integer)) for a in args): + raise ValueError('values must be integers, got (%s)' % (tuple(type(a) for a in args),)) + # use nqubits if specified + if nqubits is not None: + if not isinstance(nqubits, (int, Integer)): + raise ValueError('nqubits must be an integer, got (%s)' % type(nqubits)) + if len(args) != 1: + raise ValueError( + 'too many positional arguments (%s). should be (number, nqubits=n)' % (args,)) + return cls._eval_args_with_nqubits(args[0], nqubits) + # For a single argument, we construct the binary representation of + # that integer with the minimal number of bits. + 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] + 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: + return cls._eval_args_with_nqubits(args[0], args[1]) + else: + return QubitState._eval_args(args) + + @classmethod + def _eval_args_with_nqubits(cls, number, nqubits): + need = bitcount(abs(number)) + if nqubits < need: + raise ValueError( + 'cannot represent %s with %s bits' % (number, nqubits)) + qubit_values = [(number >> i) & 1 for i in reversed(range(nqubits))] + return QubitState._eval_args(qubit_values) + + def as_int(self): + """Return the numerical value of the qubit.""" + number = 0 + n = 1 + for i in reversed(self.qubit_values): + number += n*i + n = n << 1 + return number + + def _print_label(self, printer, *args): + return str(self.as_int()) + + def _print_label_pretty(self, printer, *args): + label = self._print_label(printer, *args) + return prettyForm(label) + + _print_label_repr = _print_label + _print_label_latex = _print_label + + +class IntQubit(IntQubitState, Qubit): + """A qubit ket that store integers as binary numbers in qubit values. + + The differences between this class and ``Qubit`` are: + + * The form of the constructor. + * The qubit values are printed as their corresponding integer, rather + than the raw qubit values. The internal storage format of the qubit + values in the same as ``Qubit``. + + Parameters + ========== + + values : int, tuple + If a single argument, the integer we want to represent in the qubit + values. This integer will be represented using the fewest possible + number of qubits. + If a pair of integers and the second value is more than one, the first + integer gives the integer to represent in binary form and the second + integer gives the number of qubits to use. + List of zeros and ones is also accepted to generate qubit by bit pattern. + + nqubits : int + The integer that represents the number of qubits. + This number should be passed with keyword ``nqubits=N``. + You can use this in order to avoid ambiguity of Qubit-style tuple of bits. + Please see the example below for more details. + + Examples + ======== + + Create a qubit for the integer 5: + + >>> from sympy.physics.quantum.qubit import IntQubit + >>> from sympy.physics.quantum.qubit import Qubit + >>> q = IntQubit(5) + >>> q + |5> + + We can also create an ``IntQubit`` by passing a ``Qubit`` instance. + + >>> q = IntQubit(Qubit('101')) + >>> q + |5> + >>> q.as_int() + 5 + >>> q.nqubits + 3 + >>> q.qubit_values + (1, 0, 1) + + We can go back to the regular qubit form. + + >>> Qubit(q) + |101> + + Please note that ``IntQubit`` also accepts a ``Qubit``-style list of bits. + So, the code below yields qubits 3, not a single bit ``1``. + + >>> IntQubit(1, 1) + |3> + + To avoid ambiguity, use ``nqubits`` parameter. + Use of this keyword is recommended especially when you provide the values by variables. + + >>> IntQubit(1, nqubits=1) + |1> + >>> a = 1 + >>> IntQubit(a, nqubits=1) + |1> + """ + @classmethod + 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.""" + + @classmethod + def dual_class(self): + return IntQubit + + +#----------------------------------------------------------------------------- +# Qubit <---> Matrix conversion functions +#----------------------------------------------------------------------------- + + +def matrix_to_qubit(matrix): + """Convert from the matrix repr. to a sum of Qubit objects. + + Parameters + ---------- + matrix : Matrix, numpy.matrix, scipy.sparse + The matrix to build the Qubit representation of. This works with + SymPy matrices, numpy matrices and scipy.sparse sparse matrices. + + Examples + ======== + + Represent a state and then go back to its qubit form: + + >>> from sympy.physics.quantum.qubit import matrix_to_qubit, Qubit + >>> from sympy.physics.quantum.represent import represent + >>> q = Qubit('01') + >>> matrix_to_qubit(represent(q)) + |01> + """ + # Determine the format based on the type of the input matrix + format = 'sympy' + if isinstance(matrix, numpy_ndarray): + format = 'numpy' + if isinstance(matrix, scipy_sparse_matrix): + format = 'scipy.sparse' + + # Make sure it is of correct dimensions for a Qubit-matrix representation. + # This logic should work with sympy, numpy or scipy.sparse matrices. + if matrix.shape[0] == 1: + mlistlen = matrix.shape[1] + nqubits = log(mlistlen, 2) + ket = False + cls = QubitBra + elif matrix.shape[1] == 1: + mlistlen = matrix.shape[0] + nqubits = log(mlistlen, 2) + ket = True + cls = Qubit + else: + raise QuantumError( + 'Matrix must be a row/column vector, got %r' % matrix + ) + if not isinstance(nqubits, Integer): + raise QuantumError('Matrix must be a row/column vector of size ' + '2**nqubits, got: %r' % matrix) + # Go through each item in matrix, if element is non-zero, make it into a + # Qubit item times the element. + result = 0 + for i in range(mlistlen): + if ket: + element = matrix[i, 0] + else: + element = matrix[0, i] + if format in ('numpy', 'scipy.sparse'): + element = complex(element) + if element: + # Form Qubit array; 0 in bit-locations where i is 0, 1 in + # bit-locations where i is 1 + qubit_array = [int(i & (1 << x) != 0) for x in range(nqubits)] + qubit_array.reverse() + result = result + element*cls(*qubit_array) + + # If SymPy simplified by pulling out a constant coefficient, undo that. + if isinstance(result, (Mul, Add, Pow)): + result = result.expand() + + return result + + +def matrix_to_density(mat): + """ + Works by finding the eigenvectors and eigenvalues of the matrix. + We know we can decompose rho by doing: + sum(EigenVal*|Eigenvect>>> from sympy.physics.quantum.qubit import Qubit, measure_all + >>> from sympy.physics.quantum.gate import H + >>> from sympy.physics.quantum.qapply import qapply + + >>> c = H(0)*H(1)*Qubit('00') + >>> c + H(0)*H(1)*|00> + >>> q = qapply(c) + >>> measure_all(q) + [(|00>, 1/4), (|01>, 1/4), (|10>, 1/4), (|11>, 1/4)] + """ + m = qubit_to_matrix(qubit, format) + + if format == 'sympy': + results = [] + + if normalize: + m = m.normalized() + + size = max(m.shape) # Max of shape to account for bra or ket + nqubits = int(math.log(size)/math.log(2)) + for i in range(size): + if m[i]: + results.append( + (Qubit(IntQubit(i, nqubits=nqubits)), m[i]*conjugate(m[i])) + ) + return results + else: + raise NotImplementedError( + "This function cannot handle non-SymPy matrix formats yet" + ) + + +def measure_partial(qubit, bits, format='sympy', normalize=True): + """Perform a partial ensemble measure on the specified qubits. + + Parameters + ========== + + qubits : Qubit + The qubit to measure. This can be any Qubit or a linear combination + of them. + bits : tuple + The qubits to measure. + format : str + The format of the intermediate matrices to use. Possible values are + ('sympy','numpy','scipy.sparse'). Currently only 'sympy' is + implemented. + + Returns + ======= + + result : list + A list that consists of primitive states and their probabilities. + + Examples + ======== + + >>> from sympy.physics.quantum.qubit import Qubit, measure_partial + >>> from sympy.physics.quantum.gate import H + >>> from sympy.physics.quantum.qapply import qapply + + >>> c = H(0)*H(1)*Qubit('00') + >>> c + H(0)*H(1)*|00> + >>> q = qapply(c) + >>> measure_partial(q, (0,)) + [(sqrt(2)*|00>/2 + sqrt(2)*|10>/2, 1/2), (sqrt(2)*|01>/2 + sqrt(2)*|11>/2, 1/2)] + """ + m = qubit_to_matrix(qubit, format) + + if isinstance(bits, (SYMPY_INTS, Integer)): + bits = (int(bits),) + + if format == 'sympy': + if normalize: + m = m.normalized() + + possible_outcomes = _get_possible_outcomes(m, bits) + + # Form output from function. + output = [] + for outcome in possible_outcomes: + # Calculate probability of finding the specified bits with + # given values. + prob_of_outcome = 0 + prob_of_outcome += (outcome.H*outcome)[0] + + # If the output has a chance, append it to output with found + # probability. + if prob_of_outcome != 0: + if normalize: + next_matrix = matrix_to_qubit(outcome.normalized()) + else: + next_matrix = matrix_to_qubit(outcome) + + output.append(( + next_matrix, + prob_of_outcome + )) + + return output + else: + raise NotImplementedError( + "This function cannot handle non-SymPy matrix formats yet" + ) + + +def measure_partial_oneshot(qubit, bits, format='sympy'): + """Perform a partial oneshot measurement on the specified qubits. + + A oneshot measurement is equivalent to performing a measurement on a + quantum system. This type of measurement does not return the probabilities + like an ensemble measurement does, but rather returns *one* of the + possible resulting states. The exact state that is returned is determined + by picking a state randomly according to the ensemble probabilities. + + Parameters + ---------- + qubits : Qubit + The qubit to measure. This can be any Qubit or a linear combination + of them. + bits : tuple + The qubits to measure. + format : str + The format of the intermediate matrices to use. Possible values are + ('sympy','numpy','scipy.sparse'). Currently only 'sympy' is + implemented. + + Returns + ------- + result : Qubit + The qubit that the system collapsed to upon measurement. + """ + import random + m = qubit_to_matrix(qubit, format) + + if format == 'sympy': + m = m.normalized() + possible_outcomes = _get_possible_outcomes(m, bits) + + # Form output from function + random_number = random.random() + total_prob = 0 + for outcome in possible_outcomes: + # Calculate probability of finding the specified bits + # with given values + total_prob += (outcome.H*outcome)[0] + if total_prob >= random_number: + return matrix_to_qubit(outcome.normalized()) + else: + raise NotImplementedError( + "This function cannot handle non-SymPy matrix formats yet" + ) + + +def _get_possible_outcomes(m, bits): + """Get the possible states that can be produced in a measurement. + + Parameters + ---------- + m : Matrix + The matrix representing the state of the system. + bits : tuple, list + Which bits will be measured. + + Returns + ------- + result : list + The list of possible states which can occur given this measurement. + These are un-normalized so we can derive the probability of finding + this state by taking the inner product with itself + """ + + # This is filled with loads of dirty binary tricks...You have been warned + + size = max(m.shape) # Max of shape to account for bra or ket + nqubits = int(math.log2(size) + .1) # Number of qubits possible + + # Make the output states and put in output_matrices, nothing in them now. + # Each state will represent a possible outcome of the measurement + # Thus, output_matrices[0] is the matrix which we get when all measured + # bits return 0. and output_matrices[1] is the matrix for only the 0th + # bit being true + output_matrices = [] + for i in range(1 << len(bits)): + output_matrices.append(zeros(2**nqubits, 1)) + + # Bitmasks will help sort how to determine possible outcomes. + # When the bit mask is and-ed with a matrix-index, + # it will determine which state that index belongs to + bit_masks = [] + for bit in bits: + bit_masks.append(1 << bit) + + # Make possible outcome states + for i in range(2**nqubits): + trueness = 0 # This tells us to which output_matrix this value belongs + # Find trueness + for j in range(len(bit_masks)): + if i & bit_masks[j]: + trueness += j + 1 + # Put the value in the correct output matrix + output_matrices[trueness][i] = m[i] + return output_matrices + + +def measure_all_oneshot(qubit, format='sympy'): + """Perform a oneshot ensemble measurement on all qubits. + + A oneshot measurement is equivalent to performing a measurement on a + quantum system. This type of measurement does not return the probabilities + like an ensemble measurement does, but rather returns *one* of the + possible resulting states. The exact state that is returned is determined + by picking a state randomly according to the ensemble probabilities. + + Parameters + ---------- + qubits : Qubit + The qubit to measure. This can be any Qubit or a linear combination + of them. + format : str + The format of the intermediate matrices to use. Possible values are + ('sympy','numpy','scipy.sparse'). Currently only 'sympy' is + implemented. + + Returns + ------- + result : Qubit + The qubit that the system collapsed to upon measurement. + """ + import random + m = qubit_to_matrix(qubit) + + if format == 'sympy': + m = m.normalized() + random_number = random.random() + total = 0 + result = 0 + for i in m: + total += i*i.conjugate() + if total > random_number: + break + result += 1 + return Qubit(IntQubit(result, nqubits=int(math.log2(max(m.shape)) + .1))) + else: + raise NotImplementedError( + "This function cannot handle non-SymPy matrix formats yet" + ) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/represent.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/represent.py new file mode 100644 index 0000000000000000000000000000000000000000..3a1ada80aa6a3dd2caad43ec132fb9a148947106 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/represent.py @@ -0,0 +1,574 @@ +"""Logic for representing operators in state in various bases. + +TODO: + +* Get represent working with continuous hilbert spaces. +* Document default basis functionality. +""" + +from sympy.core.add import Add +from sympy.core.expr import Expr +from sympy.core.mul import Mul +from sympy.core.numbers import I +from sympy.core.power import Pow +from sympy.integrals.integrals import integrate +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.commutator import Commutator +from sympy.physics.quantum.anticommutator import AntiCommutator +from sympy.physics.quantum.innerproduct import InnerProduct +from sympy.physics.quantum.qexpr import QExpr +from sympy.physics.quantum.tensorproduct import TensorProduct +from sympy.physics.quantum.matrixutils import flatten_scalar +from sympy.physics.quantum.state import KetBase, BraBase, StateBase +from sympy.physics.quantum.operator import Operator, OuterProduct +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.operatorset import operators_to_state, state_to_operators + + +__all__ = [ + 'represent', + 'rep_innerproduct', + 'rep_expectation', + 'integrate_result', + 'get_basis', + 'enumerate_states' +] + +#----------------------------------------------------------------------------- +# Represent +#----------------------------------------------------------------------------- + + +def _sympy_to_scalar(e): + """Convert from a SymPy scalar to a Python scalar.""" + if isinstance(e, Expr): + if e.is_Integer: + return int(e) + elif e.is_Float: + return float(e) + elif e.is_Rational: + return float(e) + elif e.is_Number or e.is_NumberSymbol or e == I: + return complex(e) + raise TypeError('Expected number, got: %r' % e) + + +def represent(expr, **options): + """Represent the quantum expression in the given basis. + + In quantum mechanics abstract states and operators can be represented in + various basis sets. Under this operation the follow transforms happen: + + * Ket -> column vector or function + * Bra -> row vector of function + * Operator -> matrix or differential operator + + This function is the top-level interface for this action. + + This function walks the SymPy expression tree looking for ``QExpr`` + instances that have a ``_represent`` method. This method is then called + and the object is replaced by the representation returned by this method. + By default, the ``_represent`` method will dispatch to other methods + that handle the representation logic for a particular basis set. The + naming convention for these methods is the following:: + + def _represent_FooBasis(self, e, basis, **options) + + This function will have the logic for representing instances of its class + in the basis set having a class named ``FooBasis``. + + Parameters + ========== + + expr : Expr + The expression to represent. + basis : Operator, basis set + An object that contains the information about the basis set. If an + operator is used, the basis is assumed to be the orthonormal + eigenvectors of that operator. In general though, the basis argument + 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 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. + + Returns + ======= + + e : Expr + The SymPy expression of the represented quantum expression. + + Examples + ======== + + Here we subclass ``Operator`` and ``Ket`` to create the z-spin operator + and its spin 1/2 up eigenstate. By defining the ``_represent_SzOp`` + method, the ket can be represented in the z-spin basis. + + >>> from sympy.physics.quantum import Operator, represent, Ket + >>> from sympy import Matrix + + >>> class SzUpKet(Ket): + ... def _represent_SzOp(self, basis, **options): + ... return Matrix([1,0]) + ... + >>> class SzOp(Operator): + ... pass + ... + >>> sz = SzOp('Sz') + >>> up = SzUpKet('up') + >>> represent(up, basis=sz) + Matrix([ + [1], + [0]]) + + Here we see an example of representations in a continuous + basis. We see that the result of representing various combinations + of cartesian position operators and kets give us continuous + expressions involving DiracDelta functions. + + >>> from sympy.physics.quantum.cartesian import XOp, XKet, XBra + >>> X = XOp() + >>> x = XKet() + >>> y = XBra('y') + >>> represent(X*x) + x*DiracDelta(x - x_2) + """ + + format = options.get('format', 'sympy') + if format == 'numpy': + import numpy as np + if isinstance(expr, QExpr) and not isinstance(expr, OuterProduct): + options['replace_none'] = False + temp_basis = get_basis(expr, **options) + if temp_basis is not None: + options['basis'] = temp_basis + try: + return expr._represent(**options) + except NotImplementedError as strerr: + #If no _represent_FOO method exists, map to the + #appropriate basis state and try + #the other methods of representation + options['replace_none'] = True + + if isinstance(expr, (KetBase, BraBase)): + try: + return rep_innerproduct(expr, **options) + except NotImplementedError: + raise NotImplementedError(strerr) + elif isinstance(expr, Operator): + try: + return rep_expectation(expr, **options) + except NotImplementedError: + raise NotImplementedError(strerr) + else: + raise NotImplementedError(strerr) + elif isinstance(expr, Add): + result = represent(expr.args[0], **options) + for args in expr.args[1:]: + # scipy.sparse doesn't support += so we use plain = here. + result = result + represent(args, **options) + return result + elif isinstance(expr, Pow): + base, exp = expr.as_base_exp() + if format in ('numpy', 'scipy.sparse'): + exp = _sympy_to_scalar(exp) + base = represent(base, **options) + # scipy.sparse doesn't support negative exponents + # and warns when inverting a matrix in csr format. + if format == 'scipy.sparse' and exp < 0: + from scipy.sparse.linalg import inv + exp = - exp + base = inv(base.tocsc()).tocsr() + if format == 'numpy': + return np.linalg.matrix_power(base, exp) + return base ** exp + elif isinstance(expr, TensorProduct): + new_args = [represent(arg, **options) for arg in expr.args] + return TensorProduct(*new_args) + elif isinstance(expr, Dagger): + return Dagger(represent(expr.args[0], **options)) + elif isinstance(expr, Commutator): + A = expr.args[0] + B = expr.args[1] + return represent(Mul(A, B) - Mul(B, A), **options) + elif isinstance(expr, AntiCommutator): + A = expr.args[0] + B = expr.args[1] + return represent(Mul(A, B) + Mul(B, A), **options) + elif not isinstance(expr, (Mul, OuterProduct, InnerProduct)): + # We have removed special handling of inner products that used to be + # required (before automatic transforms). + # For numpy and scipy.sparse, we can only handle numerical prefactors. + if format in ('numpy', 'scipy.sparse'): + return _sympy_to_scalar(expr) + return expr + + if not isinstance(expr, (Mul, OuterProduct, InnerProduct)): + raise TypeError('Mul expected, got: %r' % expr) + + if "index" in options: + options["index"] += 1 + else: + options["index"] = 1 + + if "unities" not in options: + options["unities"] = [] + + result = represent(expr.args[-1], **options) + last_arg = expr.args[-1] + + for arg in reversed(expr.args[:-1]): + if isinstance(last_arg, Operator): + options["index"] += 1 + options["unities"].append(options["index"]) + elif isinstance(last_arg, BraBase) and isinstance(arg, KetBase): + options["index"] += 1 + elif isinstance(last_arg, KetBase) and isinstance(arg, Operator): + options["unities"].append(options["index"]) + elif isinstance(last_arg, KetBase) and isinstance(arg, BraBase): + options["unities"].append(options["index"]) + + next_arg = represent(arg, **options) + if format == 'numpy' and isinstance(next_arg, np.ndarray): + # Must use np.matmult to "matrix multiply" two np.ndarray + result = np.matmul(next_arg, result) + else: + result = next_arg*result + last_arg = arg + + # All three matrix formats create 1 by 1 matrices when inner products of + # vectors are taken. In these cases, we simply return a scalar. + result = flatten_scalar(result) + + result = integrate_result(expr, result, **options) + + return result + + +def rep_innerproduct(expr, **options): + """ + Returns an innerproduct like representation (e.g. ````) for the + given state. + + Attempts to calculate inner product with a bra from the specified + basis. Should only be passed an instance of KetBase or BraBase + + Parameters + ========== + + expr : KetBase or BraBase + The expression to be represented + + Examples + ======== + + >>> from sympy.physics.quantum.represent import rep_innerproduct + >>> from sympy.physics.quantum.cartesian import XOp, XKet, PxOp, PxKet + >>> rep_innerproduct(XKet()) + DiracDelta(x - x_1) + >>> rep_innerproduct(XKet(), basis=PxOp()) + sqrt(2)*exp(-I*px_1*x/hbar)/(2*sqrt(hbar)*sqrt(pi)) + >>> rep_innerproduct(PxKet(), basis=XOp()) + sqrt(2)*exp(I*px*x_1/hbar)/(2*sqrt(hbar)*sqrt(pi)) + + """ + + if not isinstance(expr, (KetBase, BraBase)): + raise TypeError("expr passed is not a Bra or Ket") + + basis = get_basis(expr, **options) + + if not isinstance(basis, StateBase): + raise NotImplementedError("Can't form this representation!") + + if "index" not in options: + options["index"] = 1 + + basis_kets = enumerate_states(basis, options["index"], 2) + + if isinstance(expr, BraBase): + bra = expr + 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) + ket = expr + + prod = InnerProduct(bra, ket) + result = prod.doit() + + format = options.get('format', 'sympy') + result = expr._format_represent(result, format) + return result + + +def rep_expectation(expr, **options): + """ + Returns an ```` type representation for the given operator. + + Parameters + ========== + + expr : Operator + Operator to be represented in the specified basis + + Examples + ======== + + >>> from sympy.physics.quantum.cartesian import XOp, PxOp, PxKet + >>> from sympy.physics.quantum.represent import rep_expectation + >>> rep_expectation(XOp()) + x_1*DiracDelta(x_1 - x_2) + >>> rep_expectation(XOp(), basis=PxOp()) + + >>> rep_expectation(XOp(), basis=PxKet()) + + + """ + + if "index" not in options: + options["index"] = 1 + + if not isinstance(expr, Operator): + raise TypeError("The passed expression is not an operator") + + basis_state = get_basis(expr, **options) + + if basis_state is None or not isinstance(basis_state, StateBase): + raise NotImplementedError("Could not get basis kets for this operator") + + basis_kets = enumerate_states(basis_state, options["index"], 2) + + bra = basis_kets[1].dual + ket = basis_kets[0] + + result = qapply(bra*expr*ket) + return result + + +def integrate_result(orig_expr, result, **options): + """ + Returns the result of integrating over any unities ``(|x>>> from sympy import symbols, DiracDelta + >>> from sympy.physics.quantum.represent import integrate_result + >>> from sympy.physics.quantum.cartesian import XOp, XKet + >>> x_ket = XKet() + >>> X_op = XOp() + >>> 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]) + x*DiracDelta(x - x_2) + + """ + if not isinstance(result, Expr): + return result + + options['replace_none'] = True + if "basis" not in options: + arg = orig_expr.args[-1] + options["basis"] = get_basis(arg, **options) + elif not isinstance(options["basis"], StateBase): + options["basis"] = get_basis(orig_expr, **options) + + basis = options.pop("basis", None) + + if basis is None: + return result + + unities = options.pop("unities", []) + + if len(unities) == 0: + return result + + kets = enumerate_states(basis, unities) + coords = [k.label[0] for k in kets] + + for coord in coords: + if coord in result.free_symbols: + #TODO: Add support for sets of operators + basis_op = state_to_operators(basis) + start = basis_op.hilbert_space.interval.start + end = basis_op.hilbert_space.interval.end + result = integrate(result, (coord, start, end)) + + return result + + +def get_basis(expr, *, basis=None, replace_none=True, **options): + """ + Returns a basis state instance corresponding to the basis specified in + options=s. If no basis is specified, the function tries to form a default + basis state of the given expression. + + There are three behaviors: + + 1. The basis specified in options is already an instance of StateBase. If + this is the case, it is simply returned. If the class is specified but + not an instance, a default instance is returned. + + 2. The basis specified is an operator or set of operators. If this + is the case, the operator_to_state mapping method is used. + + 3. No basis is specified. If expr is a state, then a default instance of + its class is returned. If expr is an operator, then it is mapped to the + corresponding state. If it is neither, then we cannot obtain the basis + state. + + If the basis cannot be mapped, then it is not changed. + + This will be called from within represent, and represent will + only pass QExpr's. + + TODO (?): Support for Muls and other types of expressions? + + Parameters + ========== + + expr : Operator or StateBase + Expression whose basis is sought + + Examples + ======== + + >>> from sympy.physics.quantum.represent import get_basis + >>> from sympy.physics.quantum.cartesian import XOp, XKet, PxOp, PxKet + >>> x = XKet() + >>> X = XOp() + >>> get_basis(x) + |x> + >>> get_basis(X) + |x> + >>> get_basis(x, basis=PxOp()) + |px> + >>> get_basis(x, basis=PxKet) + |px> + + """ + + if basis is None and not replace_none: + return None + + if basis is None: + if isinstance(expr, KetBase): + return _make_default(expr.__class__) + elif isinstance(expr, BraBase): + return _make_default(expr.dual_class()) + elif isinstance(expr, Operator): + state_inst = operators_to_state(expr) + return (state_inst if state_inst is not None else None) + else: + return None + elif (isinstance(basis, Operator) or + (not isinstance(basis, StateBase) and issubclass(basis, Operator))): + state = operators_to_state(basis) + if state is None: + return None + elif isinstance(state, StateBase): + return state + else: + return _make_default(state) + elif isinstance(basis, StateBase): + return basis + elif issubclass(basis, StateBase): + return _make_default(basis) + else: + return None + + +def _make_default(expr): + # XXX: Catching TypeError like this is a bad way of distinguishing + # instances from classes. The logic using this function should be + # rewritten somehow. + try: + expr = expr() + except TypeError: + return expr + + return expr + + +def enumerate_states(*args, **options): + """ + Returns instances of the given state with dummy indices appended + + Operates in two different modes: + + 1. Two arguments are passed to it. The first is the base state which is to + be indexed, and the second argument is a list of indices to append. + + 2. Three arguments are passed. The first is again the base state to be + indexed. The second is the start index for counting. The final argument + is the number of kets you wish to receive. + + Tries to call state._enumerate_state. If this fails, returns an empty list + + Parameters + ========== + + args : list + See list of operation modes above for explanation + + Examples + ======== + + >>> from sympy.physics.quantum.cartesian import XBra, XKet + >>> from sympy.physics.quantum.represent import enumerate_states + >>> test = XKet('foo') + >>> enumerate_states(test, 1, 3) + [|foo_1>, |foo_2>, |foo_3>] + >>> test2 = XBra('bar') + >>> enumerate_states(test2, [4, 5, 10]) + [>> 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, **kwargs): + return (S.One/sqrt(Integer(2)*hbar*m*omega))*( + S.NegativeOne*I*Px + m*omega*X) + + def _eval_adjoint(self): + return LoweringOp(*self.args) + + def _eval_commutator_LoweringOp(self, other): + return S.NegativeOne + + def _eval_commutator_NumberOp(self, other): + return S.NegativeOne*self + + def _apply_operator_SHOKet(self, ket, **options): + temp = ket.n + S.One + 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') + 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('\N{DAGGER}') + return pform + + def _print_contents_latex(self, printer, *args): + arg = printer._print(self.args[0]) + return '%s^{\\dagger}' % 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, **kwargs): + return (S.One/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 S.One + + def _eval_commutator_NumberOp(self, other): + return self + + def _apply_operator_SHOKet(self, ket, **options): + temp = ket.n - Integer(1) + if ket.n is S.Zero: + return S.Zero + 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') + 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, **kwargs): + return ad*a + + def _eval_rewrite_as_xp(self, *args, **kwargs): + return (S.One/(Integer(2)*m*hbar*omega))*(Px**2 + ( + m*omega*X)**2) - S.Half + + def _eval_rewrite_as_H(self, *args, **kwargs): + return H/(hbar*omega) - S.Half + + def _apply_operator_SHOKet(self, ket, **options): + return ket.n*ket + + def _eval_commutator_Hamiltonian(self, other): + return S.Zero + + def _eval_commutator_RaisingOp(self, other): + return other + + def _eval_commutator_LoweringOp(self, other): + return S.NegativeOne*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') + 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, **kwargs): + return hbar*omega*(ad*a + S.Half) + + def _eval_rewrite_as_xp(self, *args, **kwargs): + return (S.One/(Integer(2)*m))*(Px**2 + (m*omega*X)**2) + + def _eval_rewrite_as_N(self, *args, **kwargs): + return hbar*omega*(N + S.Half) + + def _apply_operator_SHOKet(self, ket, **options): + return (hbar*omega*(ket.n + S.Half))*ket + + def _eval_commutator_NumberOp(self, other): + return S.Zero + + 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') + matrix = matrix_zeros(ndim_info, ndim_info, **options) + for i in range(ndim_info): + value = i + S.Half + 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") + 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] = S.One + 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] = S.One + 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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/shor.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/shor.py new file mode 100644 index 0000000000000000000000000000000000000000..fc9e55229d74634bdb82efc03c2d1649e088efb3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/shor.py @@ -0,0 +1,173 @@ +"""Shor's algorithm and helper functions. + +Todo: + +* Get the CMod gate working again using the new Gate API. +* Fix everything. +* Update docstrings and reformat. +""" + +import math +import random + +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.core.intfunc import igcd +from sympy.ntheory import continued_fraction_periodic as continued_fraction +from sympy.utilities.iterables import variations + +from sympy.physics.quantum.gate import Gate +from sympy.physics.quantum.qubit import Qubit, measure_partial_oneshot +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.qft import QFT +from sympy.physics.quantum.qexpr import QuantumError + + +class OrderFindingException(QuantumError): + pass + + +class CMod(Gate): + """A controlled mod gate. + + This is black box controlled Mod function for use by shor's algorithm. + TODO: implement a decompose property that returns how to do this in terms + of elementary gates + """ + + @classmethod + def _eval_args(cls, args): + # t = args[0] + # a = args[1] + # N = args[2] + raise NotImplementedError('The CMod gate has not been completed.') + + @property + def t(self): + """Size of 1/2 input register. First 1/2 holds output.""" + return self.label[0] + + @property + def a(self): + """Base of the controlled mod function.""" + return self.label[1] + + @property + def N(self): + """N is the type of modular arithmetic we are doing.""" + return self.label[2] + + def _apply_operator_Qubit(self, qubits, **options): + """ + This directly calculates the controlled mod of the second half of + the register and puts it in the second + This will look pretty when we get Tensor Symbolically working + """ + n = 1 + k = 0 + # Determine the value stored in high memory. + for i in range(self.t): + k += n*qubits[self.t + i] + n *= 2 + + # The value to go in low memory will be out. + 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(range(self.t)): + outarray.append((out >> i) & 1) + + return Qubit(*outarray) + + +def shor(N): + """This function implements Shor's factoring algorithm on the Integer N + + The algorithm starts by picking a random number (a) and seeing if it is + coprime with N. If it is not, then the gcd of the two numbers is a factor + and we are done. Otherwise, it begins the period_finding subroutine which + finds the period of a in modulo N arithmetic. This period, if even, can + 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: + return igcd(N, a) + r = period_find(a, N) + if r % 2 == 1: + shor(N) + answer = (igcd(a**(r/2) - 1, N), igcd(a**(r/2) + 1, N)) + return answer + + +def getr(x, y, N): + fraction = continued_fraction(x, y) + # Now convert into r + total = ratioize(fraction, N) + return total + + +def ratioize(list, N): + if list[0] > N: + return S.Zero + if len(list) == 1: + return list[0] + return list[0] + ratioize(list[1:], N) + + +def period_find(a, N): + """Finds the period of a in modulo N arithmetic + + This is quantum part of Shor's algorithm. It takes two registers, + puts first in superposition of states with Hadamards so: ``|k>|0>`` + with k being all possible choices. It then does a controlled mod and + a QFT to determine the order of a. + """ + epsilon = .5 + # picks out t's such that maintains accuracy within epsilon + 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 arr in variations(range(2), t, repetition=True): + qbitArray = list(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 + # will measure first half of register giving one of the a**k%N's + + circuit = qapply(circuit) + for i in range(t): + circuit = measure_partial_oneshot(circuit, i) + # Now apply Inverse Quantum Fourier Transform on the second half of the register + + circuit = qapply(QFT(t, t*2).decompose()*circuit, floatingPoint=True) + for i in range(t): + circuit = measure_partial_oneshot(circuit, i + t) + if isinstance(circuit, Qubit): + register = circuit + elif isinstance(circuit, Mul): + register = circuit.args[-1] + else: + register = circuit.args[-1].args[-1] + + n = 1 + answer = 0 + for i in range(len(register)/2): + answer += n*register[i + t] + n = n << 1 + if answer == 0: + raise OrderFindingException( + "Order finder returned 0. Happens with chance %f" % epsilon) + #turn answer into r using continued fractions + g = getr(answer, 2**t, N) + return g diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/spin.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/spin.py new file mode 100644 index 0000000000000000000000000000000000000000..6be53d01711adbed8c078fffca1d618c1aa3c6e6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/spin.py @@ -0,0 +1,2150 @@ +"""Quantum mechanical angular momentum.""" + +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.numbers import int_valued +from sympy.core.mul import Mul +from sympy.core.numbers import (I, Integer, Rational, pi) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, symbols) +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import (binomial, factorial) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.simplify.simplify import simplify +from sympy.matrices import zeros +from sympy.printing.pretty.stringpict import prettyForm, stringPict +from sympy.printing.pretty.pretty_symbology import pretty_symbol + +from sympy.physics.quantum.qexpr import QExpr +from sympy.physics.quantum.operator import (HermitianOperator, Operator, + UnitaryOperator) +from sympy.physics.quantum.state import Bra, Ket, State +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.physics.quantum.constants import hbar +from sympy.physics.quantum.hilbert import ComplexSpace, DirectSumHilbertSpace +from sympy.physics.quantum.tensorproduct import TensorProduct +from sympy.physics.quantum.cg import CG +from sympy.physics.quantum.qapply import qapply + + +__all__ = [ + 'm_values', + 'Jplus', + 'Jminus', + 'Jx', + 'Jy', + 'Jz', + 'J2', + 'Rotation', + 'WignerD', + 'JxKet', + 'JxBra', + 'JyKet', + 'JyBra', + 'JzKet', + 'JzBra', + 'JzOp', + 'J2Op', + 'JxKetCoupled', + 'JxBraCoupled', + 'JyKetCoupled', + 'JyBraCoupled', + 'JzKetCoupled', + 'JzBraCoupled', + 'couple', + 'uncouple' +] + + +def m_values(j): + j = sympify(j) + size = 2*j + 1 + if not size.is_Integer or not size > 0: + 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))] + + +#----------------------------------------------------------------------------- +# Spin Operators +#----------------------------------------------------------------------------- + + +class SpinOpBase: + """Base class for spin operators.""" + + @classmethod + def _eval_hilbert_space(cls, label): + # We consider all j values so our space is infinite. + return ComplexSpace(S.Infinity) + + @property + def name(self): + return self.args[0] + + def _print_contents(self, printer, *args): + return '%s%s' % (self.name, self._coord) + + def _print_contents_pretty(self, printer, *args): + a = stringPict(str(self.name)) + b = stringPict(self._coord) + return self._print_subscript_pretty(a, b) + + def _print_contents_latex(self, printer, *args): + return r'%s_%s' % ((self.name, self._coord)) + + def _represent_base(self, basis, **options): + j = options.get('j', S.Half) + size, mvals = m_values(j) + result = zeros(size, size) + for p in range(size): + for q in range(size): + me = self.matrix_element(j, mvals[p], j, mvals[q]) + result[p, q] = me + return result + + def _apply_op(self, ket, orig_basis, **options): + state = ket.rewrite(self.basis) + # If the state has only one term + if isinstance(state, State): + ret = (hbar*state.m)*state + # state is a linear combination of states + elif isinstance(state, Sum): + ret = self._apply_operator_Sum(state, **options) + else: + ret = qapply(self*state) + if ret == self*state: + raise NotImplementedError + return ret.rewrite(orig_basis) + + def _apply_operator_JxKet(self, ket, **options): + return self._apply_op(ket, 'Jx', **options) + + def _apply_operator_JxKetCoupled(self, ket, **options): + return self._apply_op(ket, 'Jx', **options) + + def _apply_operator_JyKet(self, ket, **options): + return self._apply_op(ket, 'Jy', **options) + + def _apply_operator_JyKetCoupled(self, ket, **options): + return self._apply_op(ket, 'Jy', **options) + + def _apply_operator_JzKet(self, ket, **options): + return self._apply_op(ket, 'Jz', **options) + + def _apply_operator_JzKetCoupled(self, ket, **options): + return self._apply_op(ket, 'Jz', **options) + + def _apply_operator_TensorProduct(self, tp, **options): + # Uncoupling operator is only easily found for coordinate basis spin operators + # TODO: add methods for uncoupling operators + if not isinstance(self, (JxOp, JyOp, JzOp)): + raise NotImplementedError + result = [] + for n in range(len(tp.args)): + arg = [] + arg.extend(tp.args[:n]) + arg.append(self._apply_operator(tp.args[n])) + arg.extend(tp.args[n + 1:]) + result.append(tp.__class__(*arg)) + return Add(*result).expand() + + # TODO: move this to qapply_Mul + def _apply_operator_Sum(self, s, **options): + new_func = qapply(self*s.function) + if new_func == self*s.function: + raise NotImplementedError + return Sum(new_func, *s.limits) + + def _eval_trace(self, **options): + #TODO: use options to use different j values + #For now eval at default basis + + # is it efficient to represent each time + # to do a trace? + return self._represent_default_basis().trace() + + +class JplusOp(SpinOpBase, Operator): + """The J+ operator.""" + + _coord = '+' + + basis = 'Jz' + + def _eval_commutator_JminusOp(self, other): + return 2*hbar*JzOp(self.name) + + def _apply_operator_JzKet(self, ket, **options): + j = ket.j + m = ket.m + 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) + + def _apply_operator_JzKetCoupled(self, ket, **options): + j = ket.j + m = ket.m + jn = ket.jn + coupling = ket.coupling + 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) + + 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 *= KroneckerDelta(j, jp) + return result + + def _represent_default_basis(self, **options): + return self._represent_JzOp(None, **options) + + def _represent_JzOp(self, basis, **options): + return self._represent_base(basis, **options) + + def _eval_rewrite_as_xyz(self, *args, **kwargs): + return JxOp(args[0]) + I*JyOp(args[0]) + + +class JminusOp(SpinOpBase, Operator): + """The J- operator.""" + + _coord = '-' + + basis = 'Jz' + + def _apply_operator_JzKet(self, ket, **options): + j = ket.j + m = ket.m + 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) + + def _apply_operator_JzKetCoupled(self, ket, **options): + j = ket.j + m = ket.m + jn = ket.jn + coupling = ket.coupling + 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) + + 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 *= KroneckerDelta(j, jp) + return result + + def _represent_default_basis(self, **options): + return self._represent_JzOp(None, **options) + + def _represent_JzOp(self, basis, **options): + return self._represent_base(basis, **options) + + def _eval_rewrite_as_xyz(self, *args, **kwargs): + return JxOp(args[0]) - I*JyOp(args[0]) + + +class JxOp(SpinOpBase, HermitianOperator): + """The Jx operator.""" + + _coord = 'x' + + basis = 'Jx' + + def _eval_commutator_JyOp(self, other): + return I*hbar*JzOp(self.name) + + def _eval_commutator_JzOp(self, other): + return -I*hbar*JyOp(self.name) + + def _apply_operator_JzKet(self, ket, **options): + jp = JplusOp(self.name)._apply_operator_JzKet(ket, **options) + jm = JminusOp(self.name)._apply_operator_JzKet(ket, **options) + return (jp + jm)/Integer(2) + + def _apply_operator_JzKetCoupled(self, ket, **options): + jp = JplusOp(self.name)._apply_operator_JzKetCoupled(ket, **options) + jm = JminusOp(self.name)._apply_operator_JzKetCoupled(ket, **options) + return (jp + jm)/Integer(2) + + def _represent_default_basis(self, **options): + return self._represent_JzOp(None, **options) + + def _represent_JzOp(self, basis, **options): + jp = JplusOp(self.name)._represent_JzOp(basis, **options) + jm = JminusOp(self.name)._represent_JzOp(basis, **options) + return (jp + jm)/Integer(2) + + def _eval_rewrite_as_plusminus(self, *args, **kwargs): + return (JplusOp(args[0]) + JminusOp(args[0]))/2 + + +class JyOp(SpinOpBase, HermitianOperator): + """The Jy operator.""" + + _coord = 'y' + + basis = 'Jy' + + def _eval_commutator_JzOp(self, other): + return I*hbar*JxOp(self.name) + + def _eval_commutator_JxOp(self, other): + return -I*hbar*J2Op(self.name) + + def _apply_operator_JzKet(self, ket, **options): + jp = JplusOp(self.name)._apply_operator_JzKet(ket, **options) + jm = JminusOp(self.name)._apply_operator_JzKet(ket, **options) + return (jp - jm)/(Integer(2)*I) + + def _apply_operator_JzKetCoupled(self, ket, **options): + jp = JplusOp(self.name)._apply_operator_JzKetCoupled(ket, **options) + jm = JminusOp(self.name)._apply_operator_JzKetCoupled(ket, **options) + return (jp - jm)/(Integer(2)*I) + + def _represent_default_basis(self, **options): + return self._represent_JzOp(None, **options) + + def _represent_JzOp(self, basis, **options): + jp = JplusOp(self.name)._represent_JzOp(basis, **options) + jm = JminusOp(self.name)._represent_JzOp(basis, **options) + return (jp - jm)/(Integer(2)*I) + + def _eval_rewrite_as_plusminus(self, *args, **kwargs): + return (JplusOp(args[0]) - JminusOp(args[0]))/(2*I) + + +class JzOp(SpinOpBase, HermitianOperator): + """The Jz operator.""" + + _coord = 'z' + + basis = 'Jz' + + def _eval_commutator_JxOp(self, other): + return I*hbar*JyOp(self.name) + + def _eval_commutator_JyOp(self, other): + return -I*hbar*JxOp(self.name) + + def _eval_commutator_JplusOp(self, other): + return hbar*JplusOp(self.name) + + def _eval_commutator_JminusOp(self, other): + return -hbar*JminusOp(self.name) + + def matrix_element(self, j, m, jp, mp): + result = hbar*mp + result *= KroneckerDelta(m, mp) + result *= KroneckerDelta(j, jp) + return result + + def _represent_default_basis(self, **options): + return self._represent_JzOp(None, **options) + + def _represent_JzOp(self, basis, **options): + return self._represent_base(basis, **options) + + +class J2Op(SpinOpBase, HermitianOperator): + """The J^2 operator.""" + + _coord = '2' + + def _eval_commutator_JxOp(self, other): + return S.Zero + + def _eval_commutator_JyOp(self, other): + return S.Zero + + def _eval_commutator_JzOp(self, other): + return S.Zero + + def _eval_commutator_JplusOp(self, other): + return S.Zero + + def _eval_commutator_JminusOp(self, other): + return S.Zero + + def _apply_operator_JxKet(self, ket, **options): + j = ket.j + return hbar**2*j*(j + 1)*ket + + def _apply_operator_JxKetCoupled(self, ket, **options): + j = ket.j + return hbar**2*j*(j + 1)*ket + + def _apply_operator_JyKet(self, ket, **options): + j = ket.j + return hbar**2*j*(j + 1)*ket + + def _apply_operator_JyKetCoupled(self, ket, **options): + j = ket.j + return hbar**2*j*(j + 1)*ket + + def _apply_operator_JzKet(self, ket, **options): + j = ket.j + return hbar**2*j*(j + 1)*ket + + def _apply_operator_JzKetCoupled(self, ket, **options): + j = ket.j + return hbar**2*j*(j + 1)*ket + + def matrix_element(self, j, m, jp, mp): + result = (hbar**2)*j*(j + 1) + result *= KroneckerDelta(m, mp) + result *= KroneckerDelta(j, jp) + return result + + def _represent_default_basis(self, **options): + return self._represent_JzOp(None, **options) + + def _represent_JzOp(self, basis, **options): + return self._represent_base(basis, **options) + + def _print_contents_pretty(self, printer, *args): + a = prettyForm(str(self.name)) + b = prettyForm('2') + return a**b + + def _print_contents_latex(self, printer, *args): + return r'%s^2' % str(self.name) + + def _eval_rewrite_as_xyz(self, *args, **kwargs): + return JxOp(args[0])**2 + JyOp(args[0])**2 + JzOp(args[0])**2 + + def _eval_rewrite_as_plusminus(self, *args, **kwargs): + a = args[0] + return JzOp(a)**2 + \ + S.Half*(JplusOp(a)*JminusOp(a) + JminusOp(a)*JplusOp(a)) + + +class Rotation(UnitaryOperator): + """Wigner D operator in terms of Euler angles. + + Defines the rotation operator in terms of the Euler angles defined by + the z-y-z convention for a passive transformation. That is the coordinate + axes are rotated first about the z-axis, giving the new x'-y'-z' axes. Then + this new coordinate system is rotated about the new y'-axis, giving new + x''-y''-z'' axes. Then this new coordinate system is rotated about the + z''-axis. Conventions follow those laid out in [1]_. + + Parameters + ========== + + alpha : Number, Symbol + First Euler Angle + beta : Number, Symbol + Second Euler angle + gamma : Number, Symbol + Third Euler angle + + Examples + ======== + + A simple example rotation operator: + + >>> from sympy import pi + >>> from sympy.physics.quantum.spin import Rotation + >>> Rotation(pi, 0, pi/2) + R(pi,0,pi/2) + + With symbolic Euler angles and calculating the inverse rotation operator: + + >>> from sympy import symbols + >>> a, b, c = symbols('a b c') + >>> Rotation(a, b, c) + R(a,b,c) + >>> Rotation(a, b, c).inverse() + R(-c,-b,-a) + + See Also + ======== + + WignerD: Symbolic Wigner-D function + D: Wigner-D function + d: Wigner small-d function + + References + ========== + + .. [1] Varshalovich, D A, Quantum Theory of Angular Momentum. 1988. + """ + + @classmethod + def _eval_args(cls, args): + args = QExpr._eval_args(args) + if len(args) != 3: + raise ValueError('3 Euler angles required, got: %r' % args) + return args + + @classmethod + def _eval_hilbert_space(cls, label): + # We consider all j values so our space is infinite. + return ComplexSpace(S.Infinity) + + @property + def alpha(self): + return self.label[0] + + @property + def beta(self): + return self.label[1] + + @property + def gamma(self): + return self.label[2] + + def _print_operator_name(self, printer, *args): + return 'R' + + def _print_operator_name_pretty(self, printer, *args): + if printer._use_unicode: + return prettyForm('\N{SCRIPT CAPITAL R}' + ' ') + else: + return prettyForm("R ") + + def _print_operator_name_latex(self, printer, *args): + return r'\mathcal{R}' + + def _eval_inverse(self): + return Rotation(-self.gamma, -self.beta, -self.alpha) + + @classmethod + def D(cls, j, m, mp, alpha, beta, gamma): + """Wigner D-function. + + Returns an instance of the WignerD class corresponding to the Wigner-D + function specified by the parameters. + + Parameters + =========== + + j : Number + Total angular momentum + m : Number + Eigenvalue of angular momentum along axis after rotation + mp : Number + Eigenvalue of angular momentum along rotated axis + alpha : Number, Symbol + First Euler angle of rotation + beta : Number, Symbol + Second Euler angle of rotation + gamma : Number, Symbol + Third Euler angle of rotation + + Examples + ======== + + Return the Wigner-D matrix element for a defined rotation, both + numerical and symbolic: + + >>> from sympy.physics.quantum.spin import Rotation + >>> from sympy import pi, symbols + >>> alpha, beta, gamma = symbols('alpha beta gamma') + >>> Rotation.D(1, 1, 0,pi, pi/2,-pi) + WignerD(1, 1, 0, pi, pi/2, -pi) + + See Also + ======== + + WignerD: Symbolic Wigner-D function + + """ + return WignerD(j, m, mp, alpha, beta, gamma) + + @classmethod + def d(cls, j, m, mp, beta): + """Wigner small-d function. + + Returns an instance of the WignerD class corresponding to the Wigner-D + function specified by the parameters with the alpha and gamma angles + given as 0. + + Parameters + =========== + + j : Number + Total angular momentum + m : Number + Eigenvalue of angular momentum along axis after rotation + mp : Number + Eigenvalue of angular momentum along rotated axis + beta : Number, Symbol + Second Euler angle of rotation + + Examples + ======== + + Return the Wigner-D matrix element for a defined rotation, both + numerical and symbolic: + + >>> from sympy.physics.quantum.spin import Rotation + >>> from sympy import pi, symbols + >>> beta = symbols('beta') + >>> Rotation.d(1, 1, 0, pi/2) + WignerD(1, 1, 0, 0, pi/2, 0) + + See Also + ======== + + WignerD: Symbolic Wigner-D function + + """ + 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) + return result + + def _represent_base(self, basis, **options): + j = sympify(options.get('j', S.Half)) + # TODO: move evaluation up to represent function/implement elsewhere + evaluate = sympify(options.get('doit')) + size, mvals = m_values(j) + result = zeros(size, size) + for p in range(size): + for q in range(size): + me = self.matrix_element(j, mvals[p], j, mvals[q]) + if evaluate: + result[p, q] = me.doit() + else: + result[p, q] = me + return result + + def _represent_default_basis(self, **options): + return self._represent_JzOp(None, **options) + + def _represent_JzOp(self, basis, **options): + return self._represent_base(basis, **options) + + def _apply_operator_uncoupled(self, state, ket, *, dummy=True, **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 dummy: + 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, *, dummy=True, **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 dummy: + 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): + r"""Wigner-D function + + The Wigner D-function gives the matrix elements of the rotation + operator in the jm-representation. For the Euler angles `\alpha`, + `\beta`, `\gamma`, the D-function is defined such that: + + .. math :: + = \delta_{jj'} D(j, m, m', \alpha, \beta, \gamma) + + Where the rotation operator is as defined by the Rotation class [1]_. + + The Wigner D-function defined in this way gives: + + .. math :: + D(j, m, m', \alpha, \beta, \gamma) = e^{-i m \alpha} d(j, m, m', \beta) e^{-i m' \gamma} + + Where d is the Wigner small-d function, which is given by Rotation.d. + + The Wigner small-d function gives the component of the Wigner + D-function that is determined by the second Euler angle. That is the + Wigner D-function is: + + .. math :: + D(j, m, m', \alpha, \beta, \gamma) = e^{-i m \alpha} d(j, m, m', \beta) e^{-i m' \gamma} + + Where d is the small-d function. The Wigner D-function is given by + Rotation.D. + + Note that to evaluate the D-function, the j, m and mp parameters must + be integer or half integer numbers. + + Parameters + ========== + + j : Number + Total angular momentum + m : Number + Eigenvalue of angular momentum along axis after rotation + mp : Number + Eigenvalue of angular momentum along rotated axis + alpha : Number, Symbol + First Euler angle of rotation + beta : Number, Symbol + Second Euler angle of rotation + gamma : Number, Symbol + Third Euler angle of rotation + + Examples + ======== + + Evaluate the Wigner-D matrix elements of a simple rotation: + + >>> from sympy.physics.quantum.spin import Rotation + >>> from sympy import pi + >>> rot = Rotation.D(1, 1, 0, pi, pi/2, 0) + >>> rot + WignerD(1, 1, 0, pi, pi/2, 0) + >>> rot.doit() + sqrt(2)/2 + + Evaluate the Wigner-d matrix elements of a simple rotation + + >>> rot = Rotation.d(1, 1, 0, pi/2) + >>> rot + WignerD(1, 1, 0, 0, pi/2, 0) + >>> rot.doit() + -sqrt(2)/2 + + See Also + ======== + + Rotation: Rotation operator + + References + ========== + + .. [1] Varshalovich, D A, Quantum Theory of Angular Momentum. 1988. + """ + + is_commutative = True + + def __new__(cls, *args, **hints): + if not len(args) == 6: + raise ValueError('6 parameters expected, got %s' % args) + args = sympify(args) + evaluate = hints.get('evaluate', False) + if evaluate: + return Expr.__new__(cls, *args)._eval_wignerd() + return Expr.__new__(cls, *args) + + @property + def j(self): + return self.args[0] + + @property + def m(self): + return self.args[1] + + @property + def mp(self): + return self.args[2] + + @property + def alpha(self): + return self.args[3] + + @property + def beta(self): + return self.args[4] + + @property + def gamma(self): + return self.args[5] + + 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) ) + 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) ) + + def _pretty(self, printer, *args): + top = printer._print(self.j) + + bot = printer._print(self.m) + bot = prettyForm(*bot.right(',')) + bot = prettyForm(*bot.right(printer._print(self.mp))) + + pad = max(top.width(), bot.width()) + top = prettyForm(*top.left(' ')) + bot = prettyForm(*bot.left(' ')) + if pad > top.width(): + top = prettyForm(*top.right(' '*(pad - top.width()))) + if 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) + else: + args = printer._print(self.alpha) + args = prettyForm(*args.right(',')) + args = prettyForm(*args.right(printer._print(self.beta))) + args = prettyForm(*args.right(',')) + args = prettyForm(*args.right(printer._print(self.gamma))) + + s = stringPict('D' + ' '*pad) + + args = prettyForm(*args.parens()) + s = prettyForm(*s.above(top)) + s = prettyForm(*s.below(bot)) + s = prettyForm(*s.right(args)) + return s + + def doit(self, **hints): + hints['evaluate'] = True + return WignerD(*self.args, **hints) + + def _eval_wignerd(self): + j = self.j + m = self.m + mp = self.mp + alpha = self.alpha + beta = self.beta + gamma = self.gamma + if alpha == 0 and beta == 0 and gamma == 0: + return KroneckerDelta(m, mp) + if not j.is_number: + 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: + continue + r += (S.NegativeOne)**k*binomial(j + mp, k)*binomial(j - mp, k + m - mp) + r *= (S.NegativeOne)**(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, + # then we use the Eq. (1), Section 4.4. page 79, to simplify: + # d(j, m, mp, beta+pi) = (-1)**(j-mp)*d(j, m, -mp, beta) + # This happens to be almost the same as in Eq.(10), Section 4.16, + # 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))*\ + 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) + # Finally, simplify the whole expression + r = simplify(r) + r *= exp(-I*m*alpha)*exp(-I*mp*gamma) + return r + + +Jx = JxOp('J') +Jy = JyOp('J') +Jz = JzOp('J') +J2 = J2Op('J') +Jplus = JplusOp('J') +Jminus = JminusOp('J') + + +#----------------------------------------------------------------------------- +# Spin States +#----------------------------------------------------------------------------- + + +class SpinState(State): + """Base class for angular momentum states.""" + + _label_separator = ',' + + def __new__(cls, j, m): + j = sympify(j) + 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) + 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) + 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: + 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) + + @property + def j(self): + return self.label[0] + + @property + def m(self): + return self.label[1] + + @classmethod + def _eval_hilbert_space(cls, label): + return ComplexSpace(2*label[0] + 1) + + def _represent_base(self, **options): + j = self.j + m = self.m + alpha = sympify(options.get('alpha', 0)) + beta = sympify(options.get('beta', 0)) + gamma = sympify(options.get('gamma', 0)) + size, mvals = m_values(j) + result = zeros(size, 1) + # 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() + else: + result[p, 0] = Rotation.D(self.j, mval, + self.m, alpha, beta, gamma) + return result + + def _eval_rewrite_as_Jx(self, *args, **options): + if isinstance(self, Bra): + return self._rewrite_basis(Jx, JxBra, **options) + return self._rewrite_basis(Jx, JxKet, **options) + + def _eval_rewrite_as_Jy(self, *args, **options): + if isinstance(self, Bra): + return self._rewrite_basis(Jy, JyBra, **options) + return self._rewrite_basis(Jy, JyKet, **options) + + def _eval_rewrite_as_Jz(self, *args, **options): + if isinstance(self, Bra): + return self._rewrite_basis(Jz, JzBra, **options) + return self._rewrite_basis(Jz, JzKet, **options) + + def _rewrite_basis(self, basis, evect, **options): + from sympy.physics.quantum.represent import represent + j = self.j + args = self.args[2:] + if j.is_number: + if isinstance(self, CoupledSpinState): + if j == int(j): + start = j**2 + else: + 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)]) + if isinstance(self, CoupledSpinState) and options.get('coupled') is False: + return uncouple(result) + return result + else: + i = 0 + mi = symbols('mi') + # make sure not to introduce a symbol already in the state + 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)) + else: + test_args = (0, mi) + if isinstance(self, Ket): + 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): + return self + else: + state = evect(j, mi, *args) + lt = Rotation.D(j, mi, self.m, *angles) + 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] + else: + 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] + else: + 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] + else: + result *= KroneckerDelta( + self.j, bra.j)*KroneckerDelta(self.m, bra.m) + return result + + def _eval_trace(self, bra, **hints): + + # One way to implement this method is to assume the basis set k is + # passed. + # Then we can apply the discrete form of Trace formula here + # Tr(|i> + #then we do qapply() on each each inner product and sum over them. + + # OR + + # Inner product of |i>>> from sympy.physics.quantum.spin import JzKet, JxKet + >>> from sympy import symbols + >>> JzKet(1, 0) + |1,0> + >>> j, m = symbols('j m') + >>> JzKet(j, m) + |j,m> + + Rewriting the JzKet in terms of eigenkets of the Jx operator: + Note: that the resulting eigenstates are JxKet's + + >>> JzKet(1,1).rewrite("Jx") + |1,-1>/2 - sqrt(2)*|1,0>/2 + |1,1>/2 + + Get the vector representation of a state in terms of the basis elements + of the Jx operator: + + >>> from sympy.physics.quantum.represent import represent + >>> from sympy.physics.quantum.spin import Jx, Jz + >>> represent(JzKet(1,-1), basis=Jx) + Matrix([ + [ 1/2], + [sqrt(2)/2], + [ 1/2]]) + + Apply innerproducts between states: + + >>> from sympy.physics.quantum.innerproduct import InnerProduct + >>> from sympy.physics.quantum.spin import JxBra + >>> i = InnerProduct(JxBra(1,1), JzKet(1,1)) + >>> i + <1,1|1,1> + >>> i.doit() + 1/2 + + *Uncoupled States:* + + Define an uncoupled state as a TensorProduct between two Jz eigenkets: + + >>> from sympy.physics.quantum.tensorproduct import TensorProduct + >>> j1,m1,j2,m2 = symbols('j1 m1 j2 m2') + >>> TensorProduct(JzKet(1,0), JzKet(1,1)) + |1,0>x|1,1> + >>> TensorProduct(JzKet(j1,m1), JzKet(j2,m2)) + |j1,m1>x|j2,m2> + + A TensorProduct can be rewritten, in which case the eigenstates that make + up the tensor product is rewritten to the new basis: + + >>> TensorProduct(JzKet(1,1),JxKet(1,1)).rewrite('Jz') + |1,1>x|1,-1>/2 + sqrt(2)*|1,1>x|1,0>/2 + |1,1>x|1,1>/2 + + The represent method for TensorProduct's gives the vector representation of + the state. Note that the state in the product basis is the equivalent of the + tensor product of the vector representation of the component eigenstates: + + >>> represent(TensorProduct(JzKet(1,0),JzKet(1,1))) + Matrix([ + [0], + [0], + [0], + [1], + [0], + [0], + [0], + [0], + [0]]) + >>> represent(TensorProduct(JzKet(1,1),JxKet(1,1)), basis=Jz) + Matrix([ + [ 1/2], + [sqrt(2)/2], + [ 1/2], + [ 0], + [ 0], + [ 0], + [ 0], + [ 0], + [ 0]]) + + See Also + ======== + + JzKetCoupled: Coupled eigenstates + sympy.physics.quantum.tensorproduct.TensorProduct: Used to specify uncoupled states + uncouple: Uncouples states given coupling parameters + couple: Couples uncoupled states + + """ + + @classmethod + def dual_class(self): + return JzBra + + @classmethod + def coupled_class(self): + return JzKetCoupled + + def _represent_default_basis(self, **options): + return self._represent_JzOp(None, **options) + + def _represent_JxOp(self, basis, **options): + return self._represent_base(beta=pi*Rational(3, 2), **options) + + def _represent_JyOp(self, basis, **options): + return self._represent_base(alpha=pi*Rational(3, 2), beta=pi/2, gamma=pi/2, **options) + + def _represent_JzOp(self, basis, **options): + return self._represent_base(**options) + + +class JzBra(SpinState, Bra): + """Eigenbra of Jz. + + See the JzKet for the usage of spin eigenstates. + + See Also + ======== + + JzKet: Usage of spin states + + """ + + @classmethod + def dual_class(self): + return JzKet + + @classmethod + def coupled_class(self): + return JzBraCoupled + + +# Method used primarily to create coupled_n and coupled_jn by __new__ in +# CoupledSpinState +# 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) ] + coupled_jn = [] + coupled_n = [] + 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 + return coupled_n, coupled_jn + + +class CoupledSpinState(SpinState): + """Base class for coupled angular momentum states.""" + + def __new__(cls, j, m, jn, *jcoupling): + # Check j and m values using SpinState + SpinState(j, m) + # Build and check coupling scheme from arguments + 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) ) + 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) ) + # Check arguments have correct form + if not isinstance(jn, (list, tuple, Tuple)): + raise TypeError('jn must be Tuple, list or tuple, got %s' % + jn.__class__.__name__) + if not isinstance(jcoupling, (list, tuple, Tuple)): + raise TypeError('jcoupling must be Tuple, list or tuple, got %s' % + jcoupling.__class__.__name__) + if not all(isinstance(term, (list, tuple, 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))) + 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] ) + # 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) + if any(n1 != int(n1) or n2 != int(n2) for (n1, n2, _) in jcoupling): + raise ValueError('Indices in jcoupling must be integers') + if any(n1 < 1 or n2 < 1 or n1 > len(jn) or n2 > len(jn) for (n1, n2, _) in jcoupling): + raise ValueError('Indices must be between 1 and the number of coupled spin spaces') + if any(2*ji != int(2*ji) for (_, _, ji) in jcoupling if ji.is_number): + 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] + 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_valued(j1 + j2): + pass + 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 + return State.__new__(cls, j, m, jn, jcoupling) + + def _print_label(self, printer, *args): + label = [printer._print(self.j), printer._print(self.m)] + for i, ji in enumerate(self.jn, start=1): + label.append('j%d=%s' % ( + i, printer._print(ji) + )) + 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) + )) + return ','.join(label) + + def _print_label_pretty(self, printer, *args): + label = [self.j, self.m] + for i, ji in enumerate(self.jn, start=1): + symb = 'j%d' % i + 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)) + symb = prettyForm('j' + n + '=') + item = prettyForm(*symb.right(printer._print(jn))) + label.append(item) + return self._print_sequence_pretty( + label, self._label_separator, printer, *args + ) + + def _print_label_latex(self, printer, *args): + label = [ + printer._print(self.j, *args), + printer._print(self.m, *args) + ] + for i, ji in enumerate(self.jn, start=1): + label.append('j_{%d}=%s' % (i, printer._print(ji, *args)) ) + 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, *args)) ) + return self._label_separator.join(label) + + @property + def jn(self): + return self.label[2] + + @property + def coupling(self): + return self.label[3] + + @property + def coupled_jn(self): + return _build_coupled(self.label[3], len(self.label[2]))[1] + + @property + def coupled_n(self): + return _build_coupled(self.label[3], len(self.label[2]))[0] + + @classmethod + 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) ]) + else: + # TODO: Need hilbert space fix, see issue 5732 + # Desired behavior: + #ji = symbols('ji') + #ret = Sum(ComplexSpace(2*ji + 1), (ji, 0, j)) + # Temporary fix: + 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') + if not self.hilbert_space.dimension.is_number: + 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) + return result + + def _eval_rewrite_as_Jx(self, *args, **options): + if isinstance(self, Bra): + return self._rewrite_basis(Jx, JxBraCoupled, **options) + return self._rewrite_basis(Jx, JxKetCoupled, **options) + + def _eval_rewrite_as_Jy(self, *args, **options): + if isinstance(self, Bra): + return self._rewrite_basis(Jy, JyBraCoupled, **options) + return self._rewrite_basis(Jy, JyKetCoupled, **options) + + def _eval_rewrite_as_Jz(self, *args, **options): + if isinstance(self, Bra): + return self._rewrite_basis(Jz, JzBraCoupled, **options) + return self._rewrite_basis(Jz, JzKetCoupled, **options) + + +class JxKetCoupled(CoupledSpinState, Ket): + """Coupled eigenket of Jx. + + See JzKetCoupled for the usage of coupled spin eigenstates. + + See Also + ======== + + JzKetCoupled: Usage of coupled spin states + + """ + + @classmethod + def dual_class(self): + return JxBraCoupled + + @classmethod + def uncoupled_class(self): + return JxKet + + def _represent_default_basis(self, **options): + return self._represent_JzOp(None, **options) + + def _represent_JxOp(self, basis, **options): + return self._represent_coupled_base(**options) + + def _represent_JyOp(self, basis, **options): + return self._represent_coupled_base(alpha=pi*Rational(3, 2), **options) + + def _represent_JzOp(self, basis, **options): + return self._represent_coupled_base(beta=pi/2, **options) + + +class JxBraCoupled(CoupledSpinState, Bra): + """Coupled eigenbra of Jx. + + See JzKetCoupled for the usage of coupled spin eigenstates. + + See Also + ======== + + JzKetCoupled: Usage of coupled spin states + + """ + + @classmethod + def dual_class(self): + return JxKetCoupled + + @classmethod + def uncoupled_class(self): + return JxBra + + +class JyKetCoupled(CoupledSpinState, Ket): + """Coupled eigenket of Jy. + + See JzKetCoupled for the usage of coupled spin eigenstates. + + See Also + ======== + + JzKetCoupled: Usage of coupled spin states + + """ + + @classmethod + def dual_class(self): + return JyBraCoupled + + @classmethod + def uncoupled_class(self): + return JyKet + + def _represent_default_basis(self, **options): + return self._represent_JzOp(None, **options) + + def _represent_JxOp(self, basis, **options): + return self._represent_coupled_base(gamma=pi/2, **options) + + def _represent_JyOp(self, basis, **options): + return self._represent_coupled_base(**options) + + def _represent_JzOp(self, basis, **options): + return self._represent_coupled_base(alpha=pi*Rational(3, 2), beta=-pi/2, gamma=pi/2, **options) + + +class JyBraCoupled(CoupledSpinState, Bra): + """Coupled eigenbra of Jy. + + See JzKetCoupled for the usage of coupled spin eigenstates. + + See Also + ======== + + JzKetCoupled: Usage of coupled spin states + + """ + + @classmethod + def dual_class(self): + return JyKetCoupled + + @classmethod + def uncoupled_class(self): + return JyBra + + +class JzKetCoupled(CoupledSpinState, Ket): + r"""Coupled eigenket of Jz + + Spin state that is an eigenket of Jz which represents the coupling of + separate spin spaces. + + The arguments for creating instances of JzKetCoupled are ``j``, ``m``, + ``jn`` and an optional ``jcoupling`` argument. The ``j`` and ``m`` options + are the total angular momentum quantum numbers, as used for normal states + (e.g. JzKet). + + The other required parameter in ``jn``, which is a tuple defining the `j_n` + angular momentum quantum numbers of the product spaces. So for example, if + a state represented the coupling of the product basis state + `\left|j_1,m_1\right\rangle\times\left|j_2,m_2\right\rangle`, the ``jn`` + for this state would be ``(j1,j2)``. + + The final option is ``jcoupling``, which is used to define how the spaces + specified by ``jn`` are coupled, which includes both the order these spaces + are coupled together and the quantum numbers that arise from these + couplings. The ``jcoupling`` parameter itself is a list of lists, such that + each of the sublists defines a single coupling between the spin spaces. If + there are N coupled angular momentum spaces, that is ``jn`` has N elements, + then there must be N-1 sublists. Each of these sublists making up the + ``jcoupling`` parameter have length 3. The first two elements are the + indices of the product spaces that are considered to be coupled together. + For example, if we want to couple `j_1` and `j_4`, the indices would be 1 + and 4. If a state has already been coupled, it is referenced by the + smallest index that is coupled, so if `j_2` and `j_4` has already been + coupled to some `j_{24}`, then this value can be coupled by referencing it + with index 2. The final element of the sublist is the quantum number of the + coupled state. So putting everything together, into a valid sublist for + ``jcoupling``, if `j_1` and `j_2` are coupled to an angular momentum space + with quantum number `j_{12}` with the value ``j12``, the sublist would be + ``(1,2,j12)``, N-1 of these sublists are used in the list for + ``jcoupling``. + + Note the ``jcoupling`` parameter is optional, if it is not specified, the + default coupling is taken. This default value is to coupled the spaces in + order and take the quantum number of the coupling to be the maximum value. + For example, if the spin spaces are `j_1`, `j_2`, `j_3`, `j_4`, then the + default coupling couples `j_1` and `j_2` to `j_{12}=j_1+j_2`, then, + `j_{12}` and `j_3` are coupled to `j_{123}=j_{12}+j_3`, and finally + `j_{123}` and `j_4` to `j=j_{123}+j_4`. The jcoupling value that would + correspond to this is: + + ``((1,2,j1+j2),(1,3,j1+j2+j3))`` + + Parameters + ========== + + args : tuple + The arguments that must be passed are ``j``, ``m``, ``jn``, and + ``jcoupling``. The ``j`` value is the total angular momentum. The ``m`` + value is the eigenvalue of the Jz spin operator. The ``jn`` list are + the j values of argular momentum spaces coupled together. The + ``jcoupling`` parameter is an optional parameter defining how the spaces + are coupled together. See the above description for how these coupling + parameters are defined. + + Examples + ======== + + Defining simple spin states, both numerical and symbolic: + + >>> from sympy.physics.quantum.spin import JzKetCoupled + >>> from sympy import symbols + >>> JzKetCoupled(1, 0, (1, 1)) + |1,0,j1=1,j2=1> + >>> j, m, j1, j2 = symbols('j m j1 j2') + >>> JzKetCoupled(j, m, (j1, j2)) + |j,m,j1=j1,j2=j2> + + Defining coupled spin states for more than 2 coupled spaces with various + coupling parameters: + + >>> JzKetCoupled(2, 1, (1, 1, 1)) + |2,1,j1=1,j2=1,j3=1,j(1,2)=2> + >>> JzKetCoupled(2, 1, (1, 1, 1), ((1,2,2),(1,3,2)) ) + |2,1,j1=1,j2=1,j3=1,j(1,2)=2> + >>> JzKetCoupled(2, 1, (1, 1, 1), ((2,3,1),(1,2,2)) ) + |2,1,j1=1,j2=1,j3=1,j(2,3)=1> + + Rewriting the JzKetCoupled in terms of eigenkets of the Jx operator: + Note: that the resulting eigenstates are JxKetCoupled + + >>> JzKetCoupled(1,1,(1,1)).rewrite("Jx") + |1,-1,j1=1,j2=1>/2 - sqrt(2)*|1,0,j1=1,j2=1>/2 + |1,1,j1=1,j2=1>/2 + + The rewrite method can be used to convert a coupled state to an uncoupled + state. This is done by passing coupled=False to the rewrite function: + + >>> JzKetCoupled(1, 0, (1, 1)).rewrite('Jz', coupled=False) + -sqrt(2)*|1,-1>x|1,1>/2 + sqrt(2)*|1,1>x|1,-1>/2 + + Get the vector representation of a state in terms of the basis elements + of the Jx operator: + + >>> from sympy.physics.quantum.represent import represent + >>> from sympy.physics.quantum.spin import Jx + >>> from sympy import S + >>> represent(JzKetCoupled(1,-1,(S(1)/2,S(1)/2)), basis=Jx) + Matrix([ + [ 0], + [ 1/2], + [sqrt(2)/2], + [ 1/2]]) + + See Also + ======== + + JzKet: Normal spin eigenstates + uncouple: Uncoupling of coupling spin states + couple: Coupling of uncoupled spin states + + """ + + @classmethod + def dual_class(self): + return JzBraCoupled + + @classmethod + def uncoupled_class(self): + return JzKet + + def _represent_default_basis(self, **options): + return self._represent_JzOp(None, **options) + + def _represent_JxOp(self, basis, **options): + return self._represent_coupled_base(beta=pi*Rational(3, 2), **options) + + def _represent_JyOp(self, basis, **options): + return self._represent_coupled_base(alpha=pi*Rational(3, 2), beta=pi/2, gamma=pi/2, **options) + + def _represent_JzOp(self, basis, **options): + return self._represent_coupled_base(**options) + + +class JzBraCoupled(CoupledSpinState, Bra): + """Coupled eigenbra of Jz. + + See the JzKetCoupled for the usage of coupled spin eigenstates. + + See Also + ======== + + JzKetCoupled: Usage of coupled spin states + + """ + + @classmethod + def dual_class(self): + return JzKetCoupled + + @classmethod + def uncoupled_class(self): + return JzBra + +#----------------------------------------------------------------------------- +# Coupling/uncoupling +#----------------------------------------------------------------------------- + + +def couple(expr, jcoupling_list=None): + """ Couple a tensor product of spin states + + This function can be used to couple an uncoupled tensor product of spin + states. All of the eigenstates to be coupled must be of the same class. It + will return a linear combination of eigenstates that are subclasses of + CoupledSpinState determined by Clebsch-Gordan angular momentum coupling + coefficients. + + Parameters + ========== + + expr : Expr + An expression involving TensorProducts of spin states to be coupled. + Each state must be a subclass of SpinState and they all must be the + same class. + + jcoupling_list : list or tuple + Elements of this list are sub-lists of length 2 specifying the order of + the coupling of the spin spaces. The length of this must be N-1, where N + is the number of states in the tensor product to be coupled. The + elements of this sublist are the same as the first two elements of each + sublist in the ``jcoupling`` parameter defined for JzKetCoupled. If this + parameter is not specified, the default value is taken, which couples + the first and second product basis spaces, then couples this new coupled + space to the third product space, etc + + Examples + ======== + + Couple a tensor product of numerical states for two spaces: + + >>> from sympy.physics.quantum.spin import JzKet, couple + >>> from sympy.physics.quantum.tensorproduct import TensorProduct + >>> couple(TensorProduct(JzKet(1,0), JzKet(1,1))) + -sqrt(2)*|1,1,j1=1,j2=1>/2 + sqrt(2)*|2,1,j1=1,j2=1>/2 + + + Numerical coupling of three spaces using the default coupling method, i.e. + first and second spaces couple, then this couples to the third space: + + >>> couple(TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,0))) + sqrt(6)*|2,2,j1=1,j2=1,j3=1,j(1,2)=2>/3 + sqrt(3)*|3,2,j1=1,j2=1,j3=1,j(1,2)=2>/3 + + Perform this same coupling, but we define the coupling to first couple + the first and third spaces: + + >>> couple(TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,0)), ((1,3),(1,2)) ) + sqrt(2)*|2,2,j1=1,j2=1,j3=1,j(1,3)=1>/2 - sqrt(6)*|2,2,j1=1,j2=1,j3=1,j(1,3)=2>/6 + sqrt(3)*|3,2,j1=1,j2=1,j3=1,j(1,3)=2>/3 + + Couple a tensor product of symbolic states: + + >>> from sympy import symbols + >>> j1,m1,j2,m2 = symbols('j1 m1 j2 m2') + >>> couple(TensorProduct(JzKet(j1,m1), JzKet(j2,m2))) + Sum(CG(j1, m1, j2, m2, j, m1 + m2)*|j,m1 + m2,j1=j1,j2=j2>, (j, m1 + m2, j1 + j2)) + + """ + a = expr.atoms(TensorProduct) + for tp in a: + # Allow other tensor products to be in expression + if not all(isinstance(state, SpinState) for state in tp.args): + continue + # If tensor product has all spin states, raise error for invalid tensor product state + if not all(state.__class__ is tp.args[0].__class__ for state in tp.args): + raise TypeError('All states must be the same basis') + expr = expr.subs(tp, _couple(tp, jcoupling_list)) + return expr + + +def _couple(tp, jcoupling_list): + states = tp.args + coupled_evect = states[0].coupled_class() + + # Define default coupling if none is specified + if jcoupling_list is None: + jcoupling_list = [] + for n in range(1, len(states)): + 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 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): + j_test = [0]*len(states) + for n1, n2 in jcoupling_list: + 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 values of states to be coupled together + jn = [state.j for state in states] + mn = [state.m for state in states] + + # 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)) ] + 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]) + 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) + + 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 ] + result = [] + for diff in range(diff_max[-1] + 1): + # Determine available configurations + n = len(coupling_list) + tot = binomial(diff + n - 1, diff) + + for config_num in range(tot): + diff_list = _confignum_to_difflist(config_num, diff, n) + + # Skip the configuration if non-physical + # This is a lazy check for physical states given the loose restrictions of diff_max + if any(d > m for d, m in zip(diff_list, diff_max)): + continue + + # Determine term + 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 ] + 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] ) + m3 = m1 + m2 + cg_terms.append( (j1, m1, j2, m2, j3, m3) ) + jcoupling.append( (min(j1_n), min(j2_n), j3) ) + # Better checks that state is physical + if any(abs(term[5]) > term[4] for term in cg_terms): + continue + if any(term[0] + term[2] < term[4] for term in cg_terms): + continue + if any(abs(term[0] - term[2]) > term[4] for term in cg_terms): + continue + coeff = Mul( *[ CG(*term).doit() for term in cg_terms] ) + state = coupled_evect(j3, m3, jn, jcoupling) + result.append(coeff*state) + return Add(*result) + else: + # Symbolic coupling + cg_terms = [] + 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): + j3 = symbols('j') + else: + 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] ) + 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)) + coeff = Mul( *[ CG(*term) for term in cg_terms] ) + state = coupled_evect(j3, m3, jn, jcoupling) + return Sum(coeff*state, *sum_terms) + + +def uncouple(expr, jn=None, jcoupling_list=None): + """ Uncouple a coupled spin state + + Gives the uncoupled representation of a coupled spin state. Arguments must + be either a spin state that is a subclass of CoupledSpinState or a spin + state that is a subclass of SpinState and an array giving the j values + of the spaces that are to be coupled + + Parameters + ========== + + expr : Expr + The expression containing states that are to be coupled. If the states + are a subclass of SpinState, the ``jn`` and ``jcoupling`` parameters + must be defined. If the states are a subclass of CoupledSpinState, + ``jn`` and ``jcoupling`` will be taken from the state. + + jn : list or tuple + The list of the j-values that are coupled. If state is a + CoupledSpinState, this parameter is ignored. This must be defined if + state is not a subclass of CoupledSpinState. The syntax of this + parameter is the same as the ``jn`` parameter of JzKetCoupled. + + jcoupling_list : list or tuple + The list defining how the j-values are coupled together. If state is a + CoupledSpinState, this parameter is ignored. This must be defined if + state is not a subclass of CoupledSpinState. The syntax of this + parameter is the same as the ``jcoupling`` parameter of JzKetCoupled. + + Examples + ======== + + Uncouple a numerical state using a CoupledSpinState state: + + >>> from sympy.physics.quantum.spin import JzKetCoupled, uncouple + >>> from sympy import S + >>> uncouple(JzKetCoupled(1, 0, (S(1)/2, S(1)/2))) + sqrt(2)*|1/2,-1/2>x|1/2,1/2>/2 + sqrt(2)*|1/2,1/2>x|1/2,-1/2>/2 + + Perform the same calculation using a SpinState state: + + >>> from sympy.physics.quantum.spin import JzKet + >>> uncouple(JzKet(1, 0), (S(1)/2, S(1)/2)) + sqrt(2)*|1/2,-1/2>x|1/2,1/2>/2 + sqrt(2)*|1/2,1/2>x|1/2,-1/2>/2 + + Uncouple a numerical state of three coupled spaces using a CoupledSpinState state: + + >>> uncouple(JzKetCoupled(1, 1, (1, 1, 1), ((1,3,1),(1,2,1)) )) + |1,-1>x|1,1>x|1,1>/2 - |1,0>x|1,0>x|1,1>/2 + |1,1>x|1,0>x|1,0>/2 - |1,1>x|1,1>x|1,-1>/2 + + Perform the same calculation using a SpinState state: + + >>> uncouple(JzKet(1, 1), (1, 1, 1), ((1,3,1),(1,2,1)) ) + |1,-1>x|1,1>x|1,1>/2 - |1,0>x|1,0>x|1,1>/2 + |1,1>x|1,0>x|1,0>/2 - |1,1>x|1,1>x|1,-1>/2 + + Uncouple a symbolic state using a CoupledSpinState state: + + >>> from sympy import symbols + >>> j,m,j1,j2 = symbols('j m j1 j2') + >>> uncouple(JzKetCoupled(j, m, (j1, j2))) + Sum(CG(j1, m1, j2, m2, j, m)*|j1,m1>x|j2,m2>, (m1, -j1, j1), (m2, -j2, j2)) + + Perform the same calculation using a SpinState state + + >>> uncouple(JzKet(j, m), (j1, j2)) + Sum(CG(j1, m1, j2, m2, j, m)*|j1,m1>x|j2,m2>, (m1, -j1, j1), (m2, -j2, j2)) + + """ + a = expr.atoms(SpinState) + for state in a: + expr = expr.subs(state, _uncouple(state, jn, jcoupling_list)) + return expr + + +def _uncouple(state, jn, jcoupling_list): + if isinstance(state, CoupledSpinState): + jn = state.jn + coupled_n = state.coupled_n + coupled_jn = state.coupled_jn + evect = state.uncoupled_class() + elif isinstance(state, SpinState): + if jn is None: + raise ValueError("Must specify j-values for coupled state") + if not isinstance(jn, (list, 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, tuple)): + raise TypeError("jcoupling must be a list or tuple") + 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__ + else: + raise TypeError("state must be a spin state") + j = state.j + m = state.m + coupling_list = [] + 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): + # j's which are coupled as first and second spaces + 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 + + 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) + + result = [] + for config_num in range(tot): + diff_list = _confignum_to_difflist(config_num, diff, n) + if any(d > p for d, p in zip(diff_list, diff_max)): + continue + + 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 + 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) ] ) + result.append(coeff*state) + return Add(*result) + else: + # Symbolic coupling + 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_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) + + +def _confignum_to_difflist(config_num, diff, list_len): + # Determines configuration of diffs into list_len number of slots + diff_list = [] + for n in range(list_len): + prev_diff = diff + # Number of spots after current one + rem_spots = list_len - n - 1 + # Number of configurations of distributing diff among the remaining spots + 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) + return diff_list diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/state.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/state.py new file mode 100644 index 0000000000000000000000000000000000000000..4ccd1ce9b9875b59a5d1293ab3026808bdc85b27 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/state.py @@ -0,0 +1,987 @@ +"""Dirac notation for states.""" + +from sympy.core.cache import cacheit +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import Function +from sympy.core.numbers import oo, equal_valued +from sympy.core.singleton import S +from sympy.functions.elementary.complexes import conjugate +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.integrals.integrals import integrate +from sympy.printing.pretty.stringpict import stringPict +from sympy.physics.quantum.qexpr import QExpr, dispatch_method +from sympy.physics.quantum.kind import KetKind, BraKind + + +__all__ = [ + 'KetBase', + 'BraBase', + 'StateBase', + 'State', + 'Ket', + 'Bra', + 'TimeDepState', + 'TimeDepBra', + 'TimeDepKet', + 'OrthogonalKet', + 'OrthogonalBra', + 'OrthogonalState', + 'Wavefunction' +] + + +#----------------------------------------------------------------------------- +# States, bras and kets. +#----------------------------------------------------------------------------- + +# ASCII brackets +_lbracket = "<" +_rbracket = ">" +_straight_bracket = "|" + + +# Unicode brackets +# MATHEMATICAL ANGLE BRACKETS +_lbracket_ucode = "\N{MATHEMATICAL LEFT ANGLE BRACKET}" +_rbracket_ucode = "\N{MATHEMATICAL RIGHT ANGLE BRACKET}" +# LIGHT VERTICAL BAR +_straight_bracket_ucode = "\N{LIGHT VERTICAL BAR}" + +# Other options for unicode printing of <, > and | for Dirac notation. + +# LEFT-POINTING ANGLE BRACKET +# _lbracket = "\u2329" +# _rbracket = "\u232A" + +# LEFT ANGLE BRACKET +# _lbracket = "\u3008" +# _rbracket = "\u3009" + +# VERTICAL LINE +# _straight_bracket = "\u007C" + + +class StateBase(QExpr): + """Abstract base class for general abstract states in quantum mechanics. + + All other state classes defined will need to inherit from this class. It + carries the basic structure for all other states such as dual, _eval_adjoint + and label. + + This is an abstract base class and you should not instantiate it directly, + instead use State. + """ + + @classmethod + def _operators_to_state(self, ops, **options): + """ Returns the eigenstate instance for the passed operators. + + This method should be overridden in subclasses. It will handle being + passed either an Operator instance or set of Operator instances. It + should return the corresponding state INSTANCE or simply raise a + NotImplementedError. See cartesian.py for an example. + """ + + raise NotImplementedError("Cannot map operators to states in this class. Method not implemented!") + + def _state_to_operators(self, op_classes, **options): + """ Returns the operators which this state instance is an eigenstate + of. + + This method should be overridden in subclasses. It will be called on + state instances and be passed the operator classes that we wish to make + into instances. The state instance will then transform the classes + appropriately, or raise a NotImplementedError if it cannot return + operator instances. See cartesian.py for examples, + """ + + 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 + return state_to_operators(self) + + def _enumerate_state(self, num_states, **options): + raise NotImplementedError("Cannot enumerate this state!") + + def _represent_default_basis(self, **options): + return self._represent(basis=self.operators) + + def _apply_operator(self, op, **options): + return None + + #------------------------------------------------------------------------- + # Dagger/dual + #------------------------------------------------------------------------- + + @property + def dual(self): + """Return the dual state of this one.""" + return self.dual_class()._new_rawargs(self.hilbert_space, *self.args) + + @classmethod + def dual_class(self): + """Return the class used to construct the dual.""" + raise NotImplementedError( + 'dual_class must be implemented in a subclass' + ) + + def _eval_adjoint(self): + """Compute the dagger of this state using the dual.""" + return self.dual + + #------------------------------------------------------------------------- + # Printing + #------------------------------------------------------------------------- + + def _pretty_brackets(self, height, use_unicode=True): + # Return pretty printed brackets for the state + # Ideally, this could be done by pform.parens but it does not support the angled < and > + + # Setup for unicode vs ascii + if use_unicode: + lbracket, rbracket = getattr(self, 'lbracket_ucode', ""), getattr(self, 'rbracket_ucode', "") + slash, bslash, vert = '\N{BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT}', \ + '\N{BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT}', \ + '\N{BOX DRAWINGS LIGHT VERTICAL}' + else: + lbracket, rbracket = getattr(self, 'lbracket', ""), getattr(self, 'rbracket', "") + slash, bslash, vert = '/', '\\', '|' + + # If height is 1, just return brackets + if height == 1: + return stringPict(lbracket), stringPict(rbracket) + # Make height even + height += (height % 2) + + brackets = [] + for bracket in lbracket, rbracket: + # Create left bracket + if bracket in {_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)]) + # Create right bracket + elif bracket in {_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)]) + # Create straight bracket + elif bracket in {_straight_bracket, _straight_bracket_ucode}: + bracket_args = [vert] * height + else: + raise ValueError(bracket) + brackets.append( + stringPict('\n'.join(bracket_args), baseline=height//2)) + return brackets + + def _sympystr(self, printer, *args): + contents = self._print_contents(printer, *args) + return '%s%s%s' % (getattr(self, 'lbracket', ""), contents, getattr(self, 'rbracket', "")) + + def _pretty(self, printer, *args): + 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) + # Put together state + pform = prettyForm(*pform.left(lbracket)) + pform = prettyForm(*pform.right(rbracket)) + return pform + + def _latex(self, printer, *args): + contents = self._print_contents_latex(printer, *args) + # The extra {} brackets are needed to get matplotlib's latex + # rendered to render this properly. + return '{%s%s%s}' % (getattr(self, 'lbracket_latex', ""), contents, getattr(self, 'rbracket_latex', "")) + + +class KetBase(StateBase): + """Base class for Kets. + + This class defines the dual property and the brackets for printing. This is + an abstract base class and you should not instantiate it directly, instead + use Ket. + """ + + kind = KetKind + + lbracket = _straight_bracket + rbracket = _rbracket + lbracket_ucode = _straight_bracket_ucode + rbracket_ucode = _rbracket_ucode + lbracket_latex = r'\left|' + rbracket_latex = r'\right\rangle ' + + @classmethod + def default_args(self): + return ("psi",) + + @classmethod + def dual_class(self): + return BraBase + + #------------------------------------------------------------------------- + # _eval_* methods + #------------------------------------------------------------------------- + + def _eval_innerproduct(self, bra, **hints): + """Evaluate the inner product between this ket and a bra. + + This is called to compute , where the ket is ``self``. + + This method will dispatch to sub-methods having the format:: + + ``def _eval_innerproduct_BraClass(self, **hints):`` + + Subclasses should define these methods (one for each BraClass) to + teach the ket how to take inner products with bras. + """ + return dispatch_method(self, '_eval_innerproduct', bra, **hints) + + def _apply_from_right_to(self, op, **options): + """Apply an Operator to this Ket as Operator*Ket + + This method will dispatch to methods having the format:: + + ``def _apply_from_right_to_OperatorName(op, **options):`` + + Subclasses should define these methods (one for each OperatorName) to + teach the Ket how to implement OperatorName*Ket + + Parameters + ========== + + op : Operator + The Operator that is acting on the Ket as op*Ket + options : dict + A dict of key/value pairs that control how the operator is applied + to the Ket. + """ + return dispatch_method(self, '_apply_from_right_to', op, **options) + + +class BraBase(StateBase): + """Base class for Bras. + + This class defines the dual property and the brackets for printing. This + is an abstract base class and you should not instantiate it directly, + instead use Bra. + """ + + kind = BraKind + + lbracket = _lbracket + rbracket = _straight_bracket + lbracket_ucode = _lbracket_ucode + rbracket_ucode = _straight_bracket_ucode + lbracket_latex = r'\left\langle ' + rbracket_latex = r'\right|' + + @classmethod + def _operators_to_state(self, ops, **options): + state = self.dual_class()._operators_to_state(ops, **options) + return state.dual + + def _state_to_operators(self, op_classes, **options): + return self.dual._state_to_operators(op_classes, **options) + + def _enumerate_state(self, num_states, **options): + dual_states = self.dual._enumerate_state(num_states, **options) + return [x.dual for x in dual_states] + + @classmethod + def default_args(self): + return self.dual_class().default_args() + + @classmethod + def dual_class(self): + return KetBase + + def _represent(self, **options): + """A default represent that uses the Ket's version.""" + from sympy.physics.quantum.dagger import Dagger + return Dagger(self.dual._represent(**options)) + + +class State(StateBase): + """General abstract quantum state used as a base class for Ket and Bra.""" + pass + + +class Ket(State, KetBase): + """A general time-independent Ket in quantum mechanics. + + Inherits from State and KetBase. This class should be used as the base + class for all physical, time-independent Kets in a system. This class + and its subclasses will be the main classes that users will use for + expressing Kets in Dirac notation [1]_. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the + ket. This will usually be its symbol or its quantum numbers. For + time-dependent state, this will include the time. + + Examples + ======== + + Create a simple Ket and looking at its properties:: + + >>> from sympy.physics.quantum import Ket + >>> from sympy import symbols, I + >>> k = Ket('psi') + >>> k + |psi> + >>> k.hilbert_space + H + >>> k.is_commutative + False + >>> k.label + (psi,) + + Ket's know about their associated bra:: + + >>> k.dual + >> k.dual_class() + + + Take a linear combination of two kets:: + + >>> k0 = Ket(0) + >>> k1 = Ket(1) + >>> 2*I*k0 - 4*k1 + 2*I*|0> - 4*|1> + + Compound labels are passed as tuples:: + + >>> n, m = symbols('n,m') + >>> k = Ket(n,m) + >>> k + |nm> + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Bra-ket_notation + """ + + @classmethod + def dual_class(self): + return Bra + + +class Bra(State, BraBase): + """A general time-independent Bra in quantum mechanics. + + Inherits from State and BraBase. A Bra is the dual of a Ket [1]_. This + class and its subclasses will be the main classes that users will use for + expressing Bras in Dirac notation. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the + ket. This will usually be its symbol or its quantum numbers. For + time-dependent state, this will include the time. + + Examples + ======== + + Create a simple Bra and look at its properties:: + + >>> from sympy.physics.quantum import Bra + >>> from sympy import symbols, I + >>> b = Bra('psi') + >>> b + >> b.hilbert_space + H + >>> b.is_commutative + False + + Bra's know about their dual Ket's:: + + >>> b.dual + |psi> + >>> b.dual_class() + + + Like Kets, Bras can have compound labels and be manipulated in a similar + manner:: + + >>> n, m = symbols('n,m') + >>> b = Bra(n,m) - I*Bra(m,n) + >>> b + -I*>> b.subs(n,m) + >> from sympy.physics.quantum import TimeDepKet + >>> k = TimeDepKet('psi', 't') + >>> k + |psi;t> + >>> k.time + t + >>> k.label + (psi,) + >>> k.hilbert_space + H + + TimeDepKets know about their dual bra:: + + >>> k.dual + >> k.dual_class() + + """ + + @classmethod + def dual_class(self): + return TimeDepBra + + +class TimeDepBra(TimeDepState, BraBase): + """General time-dependent Bra in quantum mechanics. + + This inherits from TimeDepState and BraBase and is the main class that + should be used for Bras that vary with time. Its dual is a TimeDepBra. + + Parameters + ========== + + args : tuple + The list of numbers or parameters that uniquely specify the ket. This + will usually be its symbol or its quantum numbers. For time-dependent + state, this will include the time as the final argument. + + Examples + ======== + + >>> from sympy.physics.quantum import TimeDepBra + >>> b = TimeDepBra('psi', 't') + >>> b + >> b.time + t + >>> b.label + (psi,) + >>> b.hilbert_space + H + >>> b.dual + |psi;t> + """ + + @classmethod + def dual_class(self): + return TimeDepKet + + +class OrthogonalState(State): + """General abstract quantum state used as a base class for Ket and Bra.""" + pass + +class OrthogonalKet(OrthogonalState, KetBase): + """Orthogonal Ket in quantum mechanics. + + The inner product of two states with different labels will give zero, + states with the same label will give one. + + >>> from sympy.physics.quantum import OrthogonalBra, OrthogonalKet + >>> from sympy.abc import m, n + >>> (OrthogonalBra(n)*OrthogonalKet(n)).doit() + 1 + >>> (OrthogonalBra(n)*OrthogonalKet(n+1)).doit() + 0 + >>> (OrthogonalBra(n)*OrthogonalKet(m)).doit() + + """ + + @classmethod + def dual_class(self): + return OrthogonalBra + + def _eval_innerproduct(self, bra, **hints): + + if len(self.args) != len(bra.args): + raise ValueError('Cannot multiply a ket that has a different number of labels.') + + for arg, bra_arg in zip(self.args, bra.args): + diff = arg - bra_arg + diff = diff.expand() + + is_zero = diff.is_zero + + if is_zero is False: + return S.Zero # i.e. Integer(0) + + if is_zero is None: + return None + + return S.One # i.e. Integer(1) + + +class OrthogonalBra(OrthogonalState, BraBase): + """Orthogonal Bra in quantum mechanics. + """ + + @classmethod + def dual_class(self): + return OrthogonalKet + + +class Wavefunction(Function): + """Class for representations in continuous bases + + This class takes an expression and coordinates in its constructor. It can + be used to easily calculate normalizations and probabilities. + + Parameters + ========== + + expr : Expr + The expression representing the functional form of the w.f. + + coords : Symbol or tuple + The coordinates to be integrated over, and their bounds + + Examples + ======== + + Particle in a box, specifying bounds in the more primitive way of using + Piecewise: + + >>> from sympy import Symbol, Piecewise, pi, N + >>> from sympy.functions import sqrt, sin + >>> from sympy.physics.quantum.state import Wavefunction + >>> x = Symbol('x', real=True) + >>> n = 1 + >>> L = 1 + >>> g = Piecewise((0, x < 0), (0, x > L), (sqrt(2//L)*sin(n*pi*x/L), True)) + >>> f = Wavefunction(g, x) + >>> f.norm + 1 + >>> f.is_normalized + True + >>> p = f.prob() + >>> p(0) + 0 + >>> p(L) + 0 + >>> p(0.5) + 2 + >>> p(0.85*L) + 2*sin(0.85*pi)**2 + >>> N(p(0.85*L)) + 0.412214747707527 + + Additionally, you can specify the bounds of the function and the indices in + a more compact way: + + >>> from sympy import symbols, pi, diff + >>> 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, positive=True) + >>> g = sqrt(2/L)*sin(n*pi*x/L) + >>> f = Wavefunction(g, (x, 0, L)) + >>> f.norm + 1 + >>> f(L+1) + 0 + >>> f(L-1) + sqrt(2)*sin(pi*n*(L - 1)/L)/sqrt(L) + >>> f(-1) + 0 + >>> f(0.85) + sqrt(2)*sin(0.85*pi*n/L)/sqrt(L) + >>> f(0.85, n=1, L=1) + sqrt(2)*sin(0.85*pi) + >>> f.is_commutative + False + + All arguments are automatically sympified, so you can define the variables + as strings rather than symbols: + + >>> expr = x**2 + >>> f = Wavefunction(expr, 'x') + >>> type(f.variables[0]) + + + Derivatives of Wavefunctions will return Wavefunctions: + + >>> diff(f, x) + Wavefunction(2*x, x) + + """ + + #Any passed tuples for coordinates and their bounds need to be + #converted to Tuples before Function's constructor is called, to + #avoid errors from calling is_Float in the constructor + def __new__(cls, *args, **options): + new_args = [None for i in args] + ct = 0 + for arg in args: + if isinstance(arg, tuple): + new_args[ct] = Tuple(*arg) + else: + new_args[ct] = arg + ct += 1 + + return super().__new__(cls, *new_args, **options) + + def __call__(self, *args, **options): + var = self.variables + + if len(args) != len(var): + 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] + + #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): + continue + + if (args[ct] < lower) == True or (args[ct] > upper) == True: + return S.Zero + + ct += 1 + + expr = self.expr + + #Allows user to make a call like f(2, 4, m=1, n=1) + for symbol in list(expr.free_symbols): + if str(symbol) in options.keys(): + val = options[str(symbol)] + expr = expr.subs(symbol, val) + + return expr.subs(zip(var, args)) + + def _eval_derivative(self, symbol): + expr = self.expr + deriv = expr._eval_derivative(symbol) + + return Wavefunction(deriv, *self.args[1:]) + + def _eval_conjugate(self): + return Wavefunction(conjugate(self.expr), *self.args[1:]) + + def _eval_transpose(self): + return self + + @property + def is_commutative(self): + """ + Override Function's is_commutative so that order is preserved in + represented expressions + """ + return False + + @classmethod + def eval(self, *args): + return None + + @property + def variables(self): + """ + Return the coordinates which the wavefunction depends on + + Examples + ======== + + >>> from sympy.physics.quantum.state import Wavefunction + >>> from sympy import symbols + >>> x,y = symbols('x,y') + >>> f = Wavefunction(x*y, x, y) + >>> f.variables + (x, y) + >>> g = Wavefunction(x*y, x) + >>> g.variables + (x,) + + """ + var = [g[0] if isinstance(g, Tuple) else g for g in self._args[1:]] + return tuple(var) + + @property + def limits(self): + """ + Return the limits of the coordinates which the w.f. depends on If no + limits are specified, defaults to ``(-oo, oo)``. + + Examples + ======== + + >>> from sympy.physics.quantum.state import Wavefunction + >>> from sympy import symbols + >>> x, y = symbols('x, y') + >>> f = Wavefunction(x**2, (x, 0, 1)) + >>> f.limits + {x: (0, 1)} + >>> f = Wavefunction(x**2, x) + >>> f.limits + {x: (-oo, oo)} + >>> f = Wavefunction(x**2 + y**2, x, (y, -1, 2)) + >>> f.limits + {x: (-oo, oo), y: (-1, 2)} + + """ + limits = [(g[1], g[2]) if isinstance(g, Tuple) else (-oo, oo) + for g in self._args[1:]] + return dict(zip(self.variables, tuple(limits))) + + @property + def expr(self): + """ + Return the expression which is the functional form of the Wavefunction + + Examples + ======== + + >>> from sympy.physics.quantum.state import Wavefunction + >>> from sympy import symbols + >>> x, y = symbols('x, y') + >>> f = Wavefunction(x**2, x) + >>> f.expr + x**2 + + """ + return self._args[0] + + @property + def is_normalized(self): + """ + Returns true if the Wavefunction is properly normalized + + Examples + ======== + + >>> from sympy import symbols, pi + >>> 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, positive=True) + >>> g = sqrt(2/L)*sin(n*pi*x/L) + >>> f = Wavefunction(g, (x, 0, L)) + >>> f.is_normalized + True + + """ + + return equal_valued(self.norm, 1) + + @property # type: ignore + @cacheit + def norm(self): + """ + Return the normalization of the specified functional form. + + This function integrates over the coordinates of the Wavefunction, with + the bounds specified. + + Examples + ======== + + >>> from sympy import symbols, pi + >>> 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, positive=True) + >>> g = sqrt(2/L)*sin(n*pi*x/L) + >>> f = Wavefunction(g, (x, 0, L)) + >>> f.norm + 1 + >>> g = sin(n*pi*x/L) + >>> f = Wavefunction(g, (x, 0, L)) + >>> f.norm + sqrt(2)*sqrt(L)/2 + + """ + + exp = self.expr*conjugate(self.expr) + var = self.variables + limits = self.limits + + for v in var: + curr_limits = limits[v] + exp = integrate(exp, (v, curr_limits[0], curr_limits[1])) + + return sqrt(exp) + + def normalize(self): + """ + Return a normalized version of the Wavefunction + + Examples + ======== + + >>> from sympy import symbols, pi + >>> from sympy.functions import sin + >>> from sympy.physics.quantum.state import Wavefunction + >>> 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() + Wavefunction(sqrt(2)*sin(pi*n*x/L)/sqrt(L), (x, 0, L)) + + """ + const = self.norm + + if const is oo: + raise NotImplementedError("The function is not normalizable!") + else: + return Wavefunction((const)**(-1)*self.expr, *self.args[1:]) + + def prob(self): + r""" + Return the absolute magnitude of the w.f., `|\psi(x)|^2` + + Examples + ======== + + >>> from sympy import symbols, pi + >>> from sympy.functions import sin + >>> from sympy.physics.quantum.state import Wavefunction + >>> x, L = symbols('x,L', real=True) + >>> n = symbols('n', integer=True) + >>> g = sin(n*pi*x/L) + >>> f = Wavefunction(g, (x, 0, L)) + >>> f.prob() + Wavefunction(sin(pi*n*x/L)**2, x) + + """ + + return Wavefunction(self.expr*conjugate(self.expr), *self.variables) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tensorproduct.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tensorproduct.py new file mode 100644 index 0000000000000000000000000000000000000000..058b3459227e5a020e2d0397fc66f56a2f917293 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tensorproduct.py @@ -0,0 +1,363 @@ +"""Abstract tensor product.""" + +from sympy.core.add import Add +from sympy.core.expr import Expr +from sympy.core.kind import KindDispatcher +from sympy.core.mul import Mul +from sympy.core.power import Pow +from sympy.core.sympify import sympify +from sympy.matrices.dense import DenseMatrix as Matrix +from sympy.matrices.immutable import ImmutableDenseMatrix as ImmutableMatrix +from sympy.printing.pretty.stringpict import prettyForm +from sympy.utilities.exceptions import sympy_deprecation_warning + +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.kind import ( + KetKind, _KetKind, + BraKind, _BraKind, + OperatorKind, _OperatorKind +) +from sympy.physics.quantum.matrixutils import ( + numpy_ndarray, + scipy_sparse_matrix, + matrix_tensor_product +) +from sympy.physics.quantum.state import Ket, Bra +from sympy.physics.quantum.trace import Tr + + +__all__ = [ + 'TensorProduct', + 'tensor_product_simp' +] + +#----------------------------------------------------------------------------- +# Tensor product +#----------------------------------------------------------------------------- + +_combined_printing = False + + +def combined_tensor_printing(combined): + """Set flag controlling whether tensor products of states should be + printed as a combined bra/ket or as an explicit tensor product of different + bra/kets. This is a global setting for all TensorProduct class instances. + + Parameters + ---------- + combine : bool + When true, tensor product states are combined into one ket/bra, and + when false explicit tensor product notation is used between each + ket/bra. + """ + global _combined_printing + _combined_printing = combined + + +class TensorProduct(Expr): + """The tensor product of two or more arguments. + + For matrices, this uses ``matrix_tensor_product`` to compute the Kronecker + or tensor product matrix. For other objects a symbolic ``TensorProduct`` + instance is returned. The tensor product is a non-commutative + multiplication that is used primarily with operators and states in quantum + mechanics. + + Currently, the tensor product distinguishes between commutative and + non-commutative arguments. Commutative arguments are assumed to be scalars + and are pulled out in front of the ``TensorProduct``. Non-commutative + arguments remain in the resulting ``TensorProduct``. + + Parameters + ========== + + args : tuple + A sequence of the objects to take the tensor product of. + + Examples + ======== + + Start with a simple tensor product of SymPy matrices:: + + >>> from sympy import Matrix + >>> from sympy.physics.quantum import TensorProduct + + >>> m1 = Matrix([[1,2],[3,4]]) + >>> m2 = Matrix([[1,0],[0,1]]) + >>> TensorProduct(m1, m2) + Matrix([ + [1, 0, 2, 0], + [0, 1, 0, 2], + [3, 0, 4, 0], + [0, 3, 0, 4]]) + >>> TensorProduct(m2, m1) + 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: + + >>> from sympy import Symbol + >>> A = Symbol('A',commutative=False) + >>> B = Symbol('B',commutative=False) + >>> tp = TensorProduct(A, B) + >>> tp + AxB + + We can take the dagger of a tensor product (note the order does NOT reverse + like the dagger of a normal product): + + >>> from sympy.physics.quantum import Dagger + >>> Dagger(tp) + Dagger(A)xDagger(B) + + Expand can be used to distribute a tensor product across addition: + + >>> C = Symbol('C',commutative=False) + >>> tp = TensorProduct(A+B,C) + >>> tp + (A + B)xC + >>> tp.expand(tensorproduct=True) + AxC + BxC + """ + is_commutative = False + + _kind_dispatcher = KindDispatcher("TensorProduct_kind_dispatcher", commutative=True) + + @property + def kind(self): + """Calculate the kind of a tensor product by looking at its children.""" + arg_kinds = (a.kind for a in self.args) + return self._kind_dispatcher(*arg_kinds) + + def __new__(cls, *args): + if isinstance(args[0], (Matrix, ImmutableMatrix, numpy_ndarray, + scipy_sparse_matrix)): + return matrix_tensor_product(*args) + c_part, new_args = cls.flatten(sympify(args)) + c_part = Mul(*c_part) + if len(new_args) == 0: + return c_part + elif len(new_args) == 1: + return c_part * new_args[0] + else: + tp = Expr.__new__(cls, *new_args) + return c_part * tp + + @classmethod + def flatten(cls, args): + # TODO: disallow nested TensorProducts. + c_part = [] + nc_parts = [] + for arg in args: + cp, ncp = arg.args_cnc() + c_part.extend(list(cp)) + nc_parts.append(Mul._from_args(ncp)) + return c_part, nc_parts + + def _eval_adjoint(self): + return TensorProduct(*[Dagger(i) for i in self.args]) + + def _eval_rewrite(self, rule, args, **hints): + return TensorProduct(*args).expand(tensorproduct=True) + + def _sympystr(self, printer, *args): + length = len(self.args) + s = '' + for i in range(length): + if isinstance(self.args[i], (Add, Pow, Mul)): + s = s + '(' + s = s + printer._print(self.args[i]) + if isinstance(self.args[i], (Add, Pow, Mul)): + s = s + ')' + if i != length - 1: + s = s + 'x' + return s + + def _pretty(self, printer, *args): + + if (_combined_printing and + (all(isinstance(arg, Ket) for arg in self.args) or + all(isinstance(arg, Bra) for arg in self.args))): + + length = len(self.args) + pform = printer._print('', *args) + for i in range(length): + next_pform = printer._print('', *args) + length_i = len(self.args[i].args) + for j in range(length_i): + part_pform = printer._print(self.args[i].args[j], *args) + next_pform = prettyForm(*next_pform.right(part_pform)) + if j != length_i - 1: + next_pform = prettyForm(*next_pform.right(', ')) + + if len(self.args[i].args) > 1: + next_pform = prettyForm( + *next_pform.parens(left='{', right='}')) + pform = prettyForm(*pform.right(next_pform)) + if i != length - 1: + pform = prettyForm(*pform.right(',' + ' ')) + + pform = prettyForm(*pform.left(self.args[0].lbracket)) + pform = prettyForm(*pform.right(self.args[0].rbracket)) + return pform + + length = len(self.args) + pform = printer._print('', *args) + for i in range(length): + next_pform = printer._print(self.args[i], *args) + if isinstance(self.args[i], (Add, Mul)): + next_pform = prettyForm( + *next_pform.parens(left='(', right=')') + ) + pform = prettyForm(*pform.right(next_pform)) + if i != length - 1: + if printer._use_unicode: + pform = prettyForm(*pform.right('\N{N-ARY CIRCLED TIMES OPERATOR}' + ' ')) + else: + pform = prettyForm(*pform.right('x' + ' ')) + return pform + + def _latex(self, printer, *args): + + if (_combined_printing and + (all(isinstance(arg, Ket) for arg in self.args) or + all(isinstance(arg, Bra) for arg in self.args))): + + def _label_wrap(label, nlabels): + return label if nlabels == 1 else r"\left\{%s\right\}" % label + + s = r", ".join([_label_wrap(arg._print_label_latex(printer, *args), + len(arg.args)) for arg in self.args]) + + return r"{%s%s%s}" % (self.args[0].lbracket_latex, s, + self.args[0].rbracket_latex) + + length = len(self.args) + s = '' + for i in range(length): + if isinstance(self.args[i], (Add, Mul)): + s = s + '\\left(' + # The extra {} brackets are needed to get matplotlib's latex + # rendered to render this properly. + s = s + '{' + printer._print(self.args[i], *args) + '}' + if isinstance(self.args[i], (Add, Mul)): + s = s + '\\right)' + if i != length - 1: + s = s + '\\otimes ' + return s + + def doit(self, **hints): + return TensorProduct(*[item.doit(**hints) for item in self.args]) + + def _eval_expand_tensorproduct(self, **hints): + """Distribute TensorProducts across addition.""" + args = self.args + add_args = [] + 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:]) + c_part, nc_part = tp.args_cnc() + # Check for TensorProduct object: is the one object in nc_part, if any: + # (Note: any other object type to be expanded must be added here) + if len(nc_part) == 1 and isinstance(nc_part[0], TensorProduct): + nc_part = (nc_part[0]._eval_expand_tensorproduct(), ) + add_args.append(Mul(*c_part)*Mul(*nc_part)) + break + + if add_args: + return Add(*add_args) + else: + return self + + def _eval_trace(self, **kwargs): + indices = kwargs.get('indices', None) + exp = self + + if indices is None or len(indices) == 0: + return Mul(*[Tr(arg).doit() for arg in exp.args]) + else: + 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 tensor products. + + .. deprecated:: 1.14. + The transformations applied by this function are not done automatically + when tensor products are combined. + + Originally, the main use of this function is to simplify a ``Mul`` of + ``TensorProduct``s to a ``TensorProduct`` of ``Muls``. + """ + sympy_deprecation_warning( + """ + tensor_product_simp_Mul has been deprecated. The transformations + performed by this function are now done automatically when + tensor products are multiplied. + """, + deprecated_since_version="1.14", + active_deprecations_target='deprecated-tensorproduct-simp' + ) + return e + +def tensor_product_simp_Pow(e): + """Evaluates ``Pow`` expressions whose base is ``TensorProduct`` + + .. deprecated:: 1.14. + The transformations applied by this function are not done automatically + when tensor products are combined. + """ + sympy_deprecation_warning( + """ + tensor_product_simp_Pow has been deprecated. The transformations + performed by this function are now done automatically when + tensor products are exponentiated. + """, + deprecated_since_version="1.14", + active_deprecations_target='deprecated-tensorproduct-simp' + ) + return e + + +def tensor_product_simp(e, **hints): + """Try to simplify and combine tensor products. + + .. deprecated:: 1.14. + The transformations applied by this function are not done automatically + when tensor products are combined. + + Originally, this function tried to pull expressions inside of ``TensorProducts``. + It only worked for relatively simple cases where the products have + only scalars, raw ``TensorProducts``, not ``Add``, ``Pow``, ``Commutators`` + of ``TensorProducts``. + """ + sympy_deprecation_warning( + """ + tensor_product_simp has been deprecated. The transformations + performed by this function are now done automatically when + tensor products are combined. + """, + deprecated_since_version="1.14", + active_deprecations_target='deprecated-tensorproduct-simp' + ) + return e + + +@TensorProduct._kind_dispatcher.register(_OperatorKind, _OperatorKind) +def find_op_kind(e1, e2): + return OperatorKind + + +@TensorProduct._kind_dispatcher.register(_KetKind, _KetKind) +def find_ket_kind(e1, e2): + return KetKind + + +@TensorProduct._kind_dispatcher.register(_BraKind, _BraKind) +def find_bra_kind(e1, e2): + return BraKind diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfe33796c1f89cd1f5df57f4856dd1e7aeb08eed Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_anticommutator.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_anticommutator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4224bc0bf1202988dbd2d1713f9f5c4822015b87 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_anticommutator.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_boson.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_boson.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..49d70a139e66d8ced974384c3ca392da578b82b1 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_boson.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_cartesian.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_cartesian.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..94e0fa187d2cfd2c3e84afc313e7294dec50e30b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_cartesian.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_cg.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_cg.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c9391c1f389120ebc869e98f752ddd90df20661 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_cg.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_circuitplot.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_circuitplot.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7865084af16d08d11d194843ed27dccf6326c42d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_circuitplot.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_circuitutils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_circuitutils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..773ec5d222bc5aa597021ec7431bcc0521056916 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_circuitutils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_commutator.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_commutator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a475224fb0997002971b4b93a04a83f283ecdb07 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_commutator.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_constants.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_constants.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff59206313001bc001b653852ef8c383467f6294 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_constants.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_dagger.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_dagger.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b11dd78bda25e4edcbd9c9b458e422eb2f06775 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_dagger.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_density.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_density.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..79dcabec50a637d32a42ac0b764a2e09745f1bc1 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_density.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_fermion.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_fermion.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37ea5d20045141b713b6ad74b9a93da488f6ccab Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_fermion.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_gate.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_gate.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11fb56ec38fd9384054c9b72a89f870b723fec80 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_gate.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_grover.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_grover.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6b7498d9bea4a6abd6bc4958b3890b4e77c5bdd Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_grover.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_hilbert.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_hilbert.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b1380906eb29e6abf16a6b224856f6ec2fed210 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_hilbert.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_identitysearch.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_identitysearch.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e3a753628b2c96fc735eee3b8877a441e7d240bd Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_identitysearch.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_innerproduct.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_innerproduct.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c77b434bfec7fe174337b284b97f9fd783dfc1b7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_innerproduct.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_kind.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_kind.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d235c81602002a21818018bfc9abd9409f8a2a0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_kind.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_matrixutils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_matrixutils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c4f1dabbdf975f647f03d87c5a523a16011b2407 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_matrixutils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_operator.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_operator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ee548a4e55edfae3e2a04291446a76370af96ac Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_operator.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_operatorordering.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_operatorordering.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..212a2131393ca25b5f266d29cfef6b9f67267553 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_operatorordering.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_operatorset.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_operatorset.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..324cf41b6e937bc3c3f1b12d0ea16984998f68ec Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_operatorset.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_pauli.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_pauli.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf040e9c05e6b9f78e87309f7b0225f39d672123 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_pauli.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_piab.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_piab.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2210004aead21a980187ebb18afeebfd1acba712 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_piab.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_printing.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_printing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..867e50929c99cee9c46147a00fec8ab39ba15498 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_printing.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qapply.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qapply.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0813b671e829fa9976d93927ebb03c69d8dcc61d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qapply.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qasm.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qasm.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..713cddd60f10f6a7afe308eb92f7d88ecf8b009a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qasm.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qexpr.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qexpr.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a5e23aa4f0d7fae0cff634e7d1880b9ce630143 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qexpr.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qft.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qft.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..46ecfb2466e1bc7921eda78dbca3c4bfde72dc45 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qft.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qubit.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qubit.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d801ec4b88c60ab2ab21514747d59378de139e9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_qubit.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_represent.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_represent.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aee41144ad3a9062cb3d9d09d0ee48021372c7a7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_represent.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_sho1d.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_sho1d.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..843a1e37127e2944219820f0f6879983c68c79eb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_sho1d.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_shor.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_shor.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0826e72794625e455e76afc25756695fb2e8056 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_shor.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_state.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_state.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..920be7d3a8b57f7a9bfedc51d5add09f212409d7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_state.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_tensorproduct.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_tensorproduct.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e29ddff3dbc3f2bd73f9cf2a9687554338d3b85 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_tensorproduct.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_trace.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_trace.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1703ab69a244eea55d77a5925858b46e42bb3d97 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_trace.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_transforms.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_transforms.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd4f471186298567b9315addb79657c1f24a2e98 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/__pycache__/test_transforms.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_anticommutator.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_anticommutator.py new file mode 100644 index 0000000000000000000000000000000000000000..0e6b6cbc50651742fcbbbe6adce3f20dfadc2ec5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_anticommutator.py @@ -0,0 +1,56 @@ +from sympy.core.numbers import Integer +from sympy.core.symbol import symbols + +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.anticommutator import AntiCommutator as AComm +from sympy.physics.quantum.operator import Operator + + +a, b, c = symbols('a,b,c') +A, B, C, D = symbols('A,B,C,D', commutative=False) + + +def test_anticommutator(): + ac = AComm(A, B) + assert isinstance(ac, AComm) + 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) == 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 + + +def test_anticommutator_dagger(): + assert Dagger(AComm(A, B)) == AComm(Dagger(A), Dagger(B)) + + +class Foo(Operator): + + def _eval_anticommutator_Bar(self, bar): + return Integer(0) + + +class Bar(Operator): + pass + + +class Tam(Operator): + + def _eval_anticommutator_Foo(self, foo): + return Integer(1) + + +def test_eval_commutator(): + 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 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_boson.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_boson.py new file mode 100644 index 0000000000000000000000000000000000000000..cd8dab745bede8b1c70303917dae81146fc03395 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_boson.py @@ -0,0 +1,50 @@ +from math import prod + +from sympy.core.numbers import Rational +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.physics.quantum import Dagger, Commutator, qapply +from sympy.physics.quantum.boson import BosonOp +from sympy.physics.quantum.boson import ( + BosonFockKet, BosonFockBra, BosonCoherentKet, BosonCoherentBra) + + +def test_bosonoperator(): + a = BosonOp('a') + b = BosonOp('b') + + assert isinstance(a, BosonOp) + assert isinstance(Dagger(a), BosonOp) + + assert a.is_annihilation + assert not Dagger(a).is_annihilation + + assert BosonOp("a") == BosonOp("a", True) + assert BosonOp("a") != BosonOp("c") + assert BosonOp("a", True) != BosonOp("a", False) + + assert Commutator(a, Dagger(a)).doit() == 1 + + assert Commutator(a, Dagger(b)).doit() == a * Dagger(b) - Dagger(b) * a + + assert Dagger(exp(a)) == exp(Dagger(a)) + + +def test_boson_states(): + a = BosonOp("a") + + # Fock states + n = 3 + assert (BosonFockBra(0) * BosonFockKet(1)).doit() == 0 + assert (BosonFockBra(1) * BosonFockKet(1)).doit() == 1 + assert qapply(BosonFockBra(n) * Dagger(a)**n * BosonFockKet(0)) \ + == sqrt(prod(range(1, n+1))) + + # Coherent states + alpha1, alpha2 = 1.2, 4.3 + assert (BosonCoherentBra(alpha1) * BosonCoherentKet(alpha1)).doit() == 1 + assert (BosonCoherentBra(alpha2) * BosonCoherentKet(alpha2)).doit() == 1 + assert abs((BosonCoherentBra(alpha1) * BosonCoherentKet(alpha2)).doit() - + exp((alpha1 - alpha2) ** 2 * Rational(-1, 2))) < 1e-12 + assert qapply(a * BosonCoherentKet(alpha1)) == \ + alpha1 * BosonCoherentKet(alpha1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_cartesian.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_cartesian.py new file mode 100644 index 0000000000000000000000000000000000000000..f1dd435fab68c9c71ac3602bc4c53847cbe39d57 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_cartesian.py @@ -0,0 +1,113 @@ +"""Tests for cartesian.py""" + +from sympy.core.numbers import (I, pi) +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.special.delta_functions import DiracDelta +from sympy.sets.sets import Interval +from sympy.testing.pytest import XFAIL + +from sympy.physics.quantum import qapply, represent, L2, Dagger +from sympy.physics.quantum import Commutator, hbar +from sympy.physics.quantum.cartesian import ( + XOp, YOp, ZOp, PxOp, X, Y, Z, Px, XKet, XBra, PxKet, PxBra, + PositionKet3D, PositionBra3D +) +from sympy.physics.quantum.operator import DifferentialOperator + +x, y, z, x_1, x_2, x_3, y_1, z_1 = symbols('x,y,z,x_1,x_2,x_3,y_1,z_1') +px, py, px_1, px_2 = symbols('px py px_1 px_2') + + +def test_x(): + assert X.hilbert_space == L2(Interval(S.NegativeInfinity, S.Infinity)) + assert Commutator(X, Px).doit() == I*hbar + 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() == \ + exp(-I*x*px/hbar)/sqrt(2*pi*hbar) + 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(XBra("y")*XKet()) == DiracDelta(x - y) + assert represent( + XKet()*XBra()) == DiracDelta(x - x_2) * DiracDelta(x_1 - x) + + 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 represent(XOp()*PxKet(), basis=PxKet) == \ + hbar*I*DiracDelta(px - px_2)*DifferentialOperator(px) + + +@XFAIL +def _text_x_broken(): + # represent has some broken logic that is relying in particular + # forms of input, rather than a full and proper handling of + # all valid quantum expressions. Marking this test as XFAIL until + # we can refactor represent. + assert represent(XOp()*XKet()*XBra('y')) == \ + x*DiracDelta(x - x_3)*DiracDelta(x_1 - y) + + +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() == \ + exp(I*x*px/hbar)/sqrt(2*pi*hbar) + assert represent(PxKet(px)) == DiracDelta(px - px_1) + + 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 represent(PxOp()*XKet(), basis=XKet) == \ + -hbar*I*DiracDelta(x - x_2)*DifferentialOperator(x) + assert represent(XBra("y")*PxOp()*XKet(), basis=XKet) == \ + -hbar*I*DiracDelta(x - y)*DifferentialOperator(x) + + +def test_3dpos(): + assert Y.hilbert_space == L2(Interval(S.NegativeInfinity, S.Infinity)) + assert Z.hilbert_space == L2(Interval(S.NegativeInfinity, S.Infinity)) + + test_ket = PositionKet3D(x, y, z) + assert qapply(X*test_ket) == x*test_ket + assert qapply(Y*test_ket) == y*test_ket + assert qapply(Z*test_ket) == z*test_ket + assert qapply(X*Y*test_ket) == x*y*test_ket + assert qapply(X*Y*Z*test_ket) == x*y*z*test_ket + assert qapply(Y*Z*test_ket) == y*z*test_ket + + assert PositionKet3D() == test_ket + assert YOp() == Y + assert ZOp() == Z + + assert PositionKet3D.dual_class() == PositionBra3D + assert PositionBra3D.dual_class() == PositionKet3D + + 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) + + assert test_ket.position_x == x + assert test_ket.position_y == y + assert test_ket.position_z == z + assert other_ket.position_x == x_1 + assert other_ket.position_y == y_1 + assert other_ket.position_z == z_1 + + # TODO: Add tests for representations diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_cg.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_cg.py new file mode 100644 index 0000000000000000000000000000000000000000..384512aaac7a8d984ff2a733e6349161dc9414a0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_cg.py @@ -0,0 +1,183 @@ +from sympy.concrete.summations import Sum +from sympy.core.numbers import Rational +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.physics.quantum.cg import Wigner3j, Wigner6j, Wigner9j, CG, cg_simp +from sympy.functions.special.tensor_functions import KroneckerDelta + + +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.Half, S.Half, 0, 0, S.Half, S.Half) + b = CG(S.Half, Rational(-1, 2), 0, 0, S.Half, Rational(-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.Half, S.Half, j, 0, S.Half, S.Half) + b = CG(S.Half, Rational(-1, 2), j, 0, S.Half, Rational(-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.Half, S.Half, S.Half, Rational(-1, 2), 0, 0) + b = CG(S.Half, Rational(-1, 2), S.Half, S.Half, 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.Half, S.Half, S.Half, Rational(-1, 2), j, 0) + b = CG(S.Half, Rational(-1, 2), S.Half, S.Half, 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.Half, S.Half, S.Half, Rational(-1, 2), 1, 0)**2 + b = CG(S.Half, S.Half, S.Half, Rational(-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.Half, m1, S.Half, m2, 1, 1)**2 + b = CG(S.Half, m1, S.Half, m2, 1, 0)**2 + c = CG(S.Half, m1, S.Half, m2, 1, -1)**2 + d = CG(S.Half, m1, S.Half, 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.Half, S( + 1)/2, S.Half, Rational(-1, 2), 1, 0)*CG(S.Half, Rational(-1, 2), S.Half, S.Half, 1, 0) + b = CG(S.Half, S( + 1)/2, S.Half, Rational(-1, 2), 0, 0)*CG(S.Half, Rational(-1, 2), S.Half, S.Half, 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.Half, m1, S.Half, m2, 1, 1)*CG(S.Half, m1p, S.Half, m2p, 1, 1) + b = CG(S.Half, m1, S.Half, m2, 1, 0)*CG(S.Half, m1p, S.Half, m2p, 1, 0) + c = CG(S.Half, m1, S.Half, m2, 1, -1)*CG(S.Half, m1p, S.Half, m2p, 1, -1) + d = CG(S.Half, m1, S.Half, m2, 0, 0)*CG(S.Half, m1p, S.Half, 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') + # 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 + # 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) + # 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) + + +def test_doit(): + assert Wigner3j(S.Half, Rational(-1, 2), S.Half, S.Half, 0, 0).doit() == -sqrt(2)/2 + assert Wigner3j(1/2,1/2,1/2,1/2,1/2,1/2).doit() == 0 + assert Wigner3j(9/2,9/2,9/2,9/2,9/2,9/2).doit() == 0 + assert Wigner6j(1, 2, 3, 2, 1, 2).doit() == sqrt(21)/105 + assert Wigner6j(3, 1, 2, 2, 2, 1).doit() == sqrt(21) / 105 + assert Wigner9j( + 2, 1, 1, Rational(3, 2), S.Half, 1, S.Half, S.Half, 0).doit() == sqrt(2)/12 + assert CG(S.Half, S.Half, S.Half, Rational(-1, 2), 1, 0).doit() == sqrt(2)/2 + # J minus M is not integer + assert Wigner3j(1, -1, S.Half, S.Half, 1, S.Half).doit() == 0 + assert CG(4, -1, S.Half, S.Half, 4, Rational(-1, 2)).doit() == 0 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_circuitplot.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_circuitplot.py new file mode 100644 index 0000000000000000000000000000000000000000..fcc89f77047450ad3f8663f371f483654dc70ea9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_circuitplot.py @@ -0,0 +1,69 @@ +from sympy.physics.quantum.circuitplot import labeller, render_label, Mz, CreateOneQubitGate,\ + CreateCGate +from sympy.physics.quantum.gate import CNOT, H, SWAP, CGate, S, T +from sympy.external import import_module +from sympy.testing.pytest import skip + +mpl = import_module('matplotlib') + +def test_render_label(): + assert render_label('q0') == r'$\left|q0\right\rangle$' + assert render_label('q0', {'q0': '0'}) == r'$\left|q0\right\rangle=\left|0\right\rangle$' + +def test_Mz(): + assert str(Mz(0)) == 'Mz(0)' + +def test_create1(): + Qgate = CreateOneQubitGate('Q') + assert str(Qgate(0)) == 'Q(0)' + +def test_createc(): + Qgate = CreateCGate('Q') + assert str(Qgate([1],0)) == 'C((1),Q(0))' + +def test_labeller(): + """Test the labeller utility""" + assert labeller(2) == ['q_1', 'q_0'] + assert labeller(3,'j') == ['j_2', 'j_1', 'j_0'] + +def test_cnot(): + """Test a simple cnot circuit. Right now this only makes sure the code doesn't + raise an exception, and some simple properties + """ + if not mpl: + skip("matplotlib not installed") + else: + from sympy.physics.quantum.circuitplot import CircuitPlot + + c = CircuitPlot(CNOT(1,0),2,labels=labeller(2)) + assert c.ngates == 2 + assert c.nqubits == 2 + assert c.labels == ['q_1', 'q_0'] + + c = CircuitPlot(CNOT(1,0),2) + assert c.ngates == 2 + assert c.nqubits == 2 + assert c.labels == [] + +def test_ex1(): + if not mpl: + skip("matplotlib not installed") + else: + from sympy.physics.quantum.circuitplot import CircuitPlot + + c = CircuitPlot(CNOT(1,0)*H(1),2,labels=labeller(2)) + assert c.ngates == 2 + assert c.nqubits == 2 + assert c.labels == ['q_1', 'q_0'] + +def test_ex4(): + if not mpl: + skip("matplotlib not installed") + else: + from sympy.physics.quantum.circuitplot import CircuitPlot + + c = CircuitPlot(SWAP(0,2)*H(0)* CGate((0,),S(1)) *H(1)*CGate((0,),T(2))\ + *CGate((1,),S(2))*H(2),3,labels=labeller(3,'j')) + assert c.ngates == 7 + assert c.nqubits == 3 + assert c.labels == ['j_2', 'j_1', 'j_0'] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_circuitutils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_circuitutils.py new file mode 100644 index 0000000000000000000000000000000000000000..8ea7232320417db8bf745871cff0e77aaf1901e7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_circuitutils.py @@ -0,0 +1,402 @@ +from sympy.core.mul import Mul +from sympy.core.numbers import Integer +from sympy.core.symbol import Symbol +from sympy.utilities import numbered_symbols +from sympy.physics.quantum.gate import X, Y, Z, H, CNOT, CGate +from sympy.physics.quantum.identitysearch import bfs_identity_search +from sympy.physics.quantum.circuitutils import (kmp_table, find_subcircuit, + replace_subcircuit, convert_to_symbolic_indices, + convert_to_real_indices, random_reduce, random_insert, + flatten_ids) +from sympy.testing.pytest import slow + + +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] + assert expected_table == kmp_table(word) + + 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] + assert expected_table == kmp_table(word) + + x = X(0) + y = Y(0) + z = Z(0) + h = H(0) + word = (x, y, y, x, z) + expected_table = [-1, 0, 0, 0, 1] + assert expected_table == kmp_table(word) + + word = (x, x, y, h, z) + expected_table = [-1, 0, 1, 0, 0] + assert expected_table == kmp_table(word) + + +def test_find_subcircuit(): + x = X(0) + y = Y(0) + z = Z(0) + h = H(0) + x1 = X(1) + y1 = Y(1) + + i0 = Symbol('i0') + x_i0 = X(i0) + y_i0 = Y(i0) + z_i0 = Z(i0) + h_i0 = H(i0) + + circuit = (x, y, z) + + assert find_subcircuit(circuit, (x,)) == 0 + assert find_subcircuit(circuit, (x1,)) == -1 + assert find_subcircuit(circuit, (y,)) == 1 + assert find_subcircuit(circuit, (h,)) == -1 + assert find_subcircuit(circuit, Mul(x, h)) == -1 + assert find_subcircuit(circuit, Mul(x, y, z)) == 0 + assert find_subcircuit(circuit, Mul(y, z)) == 1 + assert find_subcircuit(Mul(*circuit), (x, y, z, h)) == -1 + assert find_subcircuit(Mul(*circuit), (z, y, x)) == -1 + assert find_subcircuit(circuit, (x,), start=2, end=1) == -1 + + circuit = (x, y, x, y, z) + assert find_subcircuit(Mul(*circuit), Mul(x, y, z)) == 2 + assert find_subcircuit(circuit, (x,), start=1) == 2 + assert find_subcircuit(circuit, (x, y), start=1, end=2) == -1 + assert find_subcircuit(Mul(*circuit), (x, y), start=1, end=3) == -1 + assert find_subcircuit(circuit, (x, y), start=1, end=4) == 2 + assert find_subcircuit(circuit, (x, y), start=2, end=4) == 2 + + circuit = (x, y, z, x1, x, y, z, h, x, y, x1, + x, y, z, h, y1, h) + assert find_subcircuit(circuit, (x, y, z, h, y1)) == 11 + + circuit = (x, y, x_i0, y_i0, z_i0, z) + assert find_subcircuit(circuit, (x_i0, y_i0, z_i0)) == 2 + + circuit = (x_i0, y_i0, z_i0, x_i0, y_i0, h_i0) + subcircuit = (x_i0, y_i0, z_i0) + 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) + cgate_z = CGate((0,), Z(1)) + + # Standard cases + circuit = (z, y, x, x) + remove = (z, y, x) + assert replace_subcircuit(circuit, Mul(*remove)) == (x,) + assert replace_subcircuit(circuit, remove + (x,)) == () + assert replace_subcircuit(circuit, remove, pos=1) == circuit + assert replace_subcircuit(circuit, remove, pos=0) == (x,) + assert replace_subcircuit(circuit, (x, x), pos=2) == (z, y) + assert replace_subcircuit(circuit, (h,)) == circuit + + circuit = (x, y, x, y, z) + remove = (x, y, z) + assert replace_subcircuit(Mul(*circuit), Mul(*remove)) == (x, y) + remove = (x, y, x, y) + assert replace_subcircuit(circuit, remove) == (z,) + + circuit = (x, h, cgate_z, h, cnot) + remove = (x, h, cgate_z) + assert replace_subcircuit(circuit, Mul(*remove), pos=-1) == (h, cnot) + assert replace_subcircuit(circuit, remove, pos=1) == circuit + remove = (h, h) + assert replace_subcircuit(circuit, remove) == circuit + remove = (h, cgate_z, h, cnot) + assert replace_subcircuit(circuit, remove) == (x,) + + replace = (h, x) + actual = replace_subcircuit(circuit, remove, + replace=replace) + assert actual == (x, h, x) + + circuit = (x, y, h, x, y, z) + remove = (x, y) + replace = (cnot, cgate_z) + actual = replace_subcircuit(circuit, remove, + replace=Mul(*replace)) + assert actual == (cnot, cgate_z, h, x, y, z) + + actual = replace_subcircuit(circuit, remove, + 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)} + 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)} + actual, act_map, sndx, gen = convert_to_symbolic_indices((x, y, z, h)) + assert actual == expected + assert exp_map == act_map + + (x1, y1, z1, h1) = create_gate_sequence(1) + i1 = Symbol('i1') + + expected = (X(i0), Y(i0), Z(i0), H(i0)) + 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)} + 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)} + 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)} + 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)} + actual, act_map, sndx, gen = convert_to_symbolic_indices((x1, x, y1, y, + z1, z, h1, h)) + assert actual == expected + assert act_map == exp_map + + cnot_10 = CNOT(1, 0) + cnot_01 = CNOT(0, 1) + cgate_z_10 = CGate(1, Z(0)) + cgate_z_01 = CGate(0, Z(1)) + + 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)} + 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) + assert actual == expected + assert act_map == exp_map + + args = (x1, x, y1, y, z1, z, h1, h, cnot_10, cnot_01, + cgate_z_10, cgate_z_01) + 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)} + 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)} + 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)} + 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)} + actual, act_map, sndx, gen = convert_to_symbolic_indices(args) + assert actual == expected + assert act_map == exp_map + + i2 = Symbol('i2') + ccgate_z = CGate(0, CGate(1, Z(2))) + ccgate_x = CGate(1, CGate(2, X(0))) + 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)} + actual, act_map, sndx, gen = convert_to_symbolic_indices(args) + assert actual == expected + assert act_map == exp_map + + 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) + 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)} + 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') + + (x, y, z, h) = create_gate_sequence() + + x_i0 = X(i0) + y_i0 = Y(i0) + z_i0 = Z(i0) + + 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) + cgate_z_10 = CGate(1, Z(0)) + cgate_z_01 = CGate(0, Z(1)) + + cnot_i1_i0 = CNOT(i1, i0) + cnot_i0_i1 = CNOT(i0, i1) + cgate_z_i1_i0 = CGate(i1, Z(i0)) + + qubit_map = {i0: 0, i1: 1} + args = (cnot_i1_i0,) + expected = (cnot_10,) + actual = convert_to_real_indices(args, qubit_map) + assert actual == expected + + args = (cgate_z_i1_i0,) + expected = (cgate_z_10,) + actual = convert_to_real_indices(args, qubit_map) + assert actual == expected + + args = (cnot_i0_i1,) + expected = (cnot_01,) + actual = convert_to_real_indices(args, qubit_map) + assert actual == expected + + qubit_map = {i0: 1, i1: 0} + args = (cgate_z_i1_i0,) + expected = (cgate_z_01,) + actual = convert_to_real_indices(args, qubit_map) + assert actual == expected + + i2 = Symbol('i2') + ccgate_z = CGate(i0, CGate(i1, Z(i2))) + ccgate_x = CGate(i1, CGate(i2, X(i0))) + + 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} + 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 + + +@slow +def test_random_reduce(): + x = X(0) + y = Y(0) + z = Z(0) + h = H(0) + cnot = CNOT(1, 0) + cgate_z = CGate((0,), Z(1)) + + gate_list = [x, y, z] + ids = list(bfs_identity_search(gate_list, 1, max_depth=4)) + + circuit = (x, y, h, z, cnot) + assert random_reduce(circuit, []) == circuit + assert random_reduce(circuit, ids) == circuit + + seq = [2, 11, 9, 3, 5] + circuit = (x, y, z, x, y, h) + assert random_reduce(circuit, ids, seed=seq) == (x, y, h) + + circuit = (x, x, y, y, z, z) + assert random_reduce(circuit, ids, seed=seq) == (x, x, y, y) + + seq = [14, 13, 0] + assert random_reduce(circuit, ids, seed=seq) == (y, y, z, z) + + gate_list = [x, y, z, h, cnot, cgate_z] + ids = list(bfs_identity_search(gate_list, 2, max_depth=4)) + + seq = [25] + circuit = (x, y, z, y, h, y, h, cgate_z, h, cnot) + expected = (x, y, z, cgate_z, h, cnot) + assert random_reduce(circuit, ids, seed=seq) == expected + circuit = Mul(*circuit) + assert random_reduce(circuit, ids, seed=seq) == expected + + +@slow +def test_random_insert(): + x = X(0) + y = Y(0) + z = Z(0) + h = H(0) + cnot = CNOT(1, 0) + cgate_z = CGate((0,), Z(1)) + + choices = [(x, x)] + circuit = (y, y) + loc, choice = 0, 0 + actual = random_insert(circuit, choices, seed=[loc, choice]) + assert actual == (x, x, y, y) + + circuit = (x, y, z, h) + choices = [(h, h), (x, y, z)] + expected = (x, x, y, z, y, z, h) + loc, choice = 1, 1 + actual = random_insert(circuit, choices, seed=[loc, choice]) + assert actual == expected + + gate_list = [x, y, z, h, cnot, cgate_z] + ids = list(bfs_identity_search(gate_list, 2, max_depth=4)) + + eq_ids = flatten_ids(ids) + + circuit = (x, y, h, cnot, cgate_z) + expected = (x, z, x, z, x, y, h, cnot, cgate_z) + loc, choice = 1, 30 + actual = random_insert(circuit, eq_ids, seed=[loc, choice]) + assert actual == expected + circuit = Mul(*circuit) + actual = random_insert(circuit, eq_ids, seed=[loc, choice]) + assert actual == expected diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_commutator.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_commutator.py new file mode 100644 index 0000000000000000000000000000000000000000..04f45feddaca63d7306363a9235c63f534d11430 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_commutator.py @@ -0,0 +1,81 @@ +from sympy.core.numbers import Integer +from sympy.core.symbol import symbols + +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.commutator import Commutator as Comm +from sympy.physics.quantum.operator import Operator + + +a, b, c = symbols('a,b,c') +n = symbols('n', integer=True) +A, B, C, D = symbols('A,B,C,D', commutative=False) + + +def test_commutator(): + c = Comm(A, B) + assert c.is_commutative is False + assert isinstance(c, Comm) + 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) == 0 + assert Comm(a, b) == 0 + assert Comm(A, B) == -Comm(B, A) + assert Comm(A, B).doit() == A*B - B*A + assert Comm(A, B*C).expand(commutator=True) == Comm(A, B)*C + B*Comm(A, C) + assert Comm(A*B, C*D).expand(commutator=True) == \ + A*C*Comm(B, D) + A*Comm(B, C)*D + C*Comm(A, D)*B + Comm(A, C)*D*B + assert Comm(A, B**2).expand(commutator=True) == Comm(A, B)*B + B*Comm(A, B) + assert Comm(A**2, C**2).expand(commutator=True) == \ + Comm(A*B, C*D).expand(commutator=True).replace(B, A).replace(D, C) == \ + A*C*Comm(A, C) + A*Comm(A, C)*C + C*Comm(A, C)*A + Comm(A, C)*C*A + assert Comm(A, C**-2).expand(commutator=True) == \ + Comm(A, (1/C)*(1/D)).expand(commutator=True).replace(D, C) + 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) + assert Comm(A**n, B).expand(commutator=True) == Comm(A**n, 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)) + + +class Foo(Operator): + + def _eval_commutator_Bar(self, bar): + return Integer(0) + + +class Bar(Operator): + pass + + +class Tam(Operator): + + def _eval_commutator_Foo(self, foo): + return Integer(1) + + +def test_eval_commutator(): + 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**2, B).expand(commutator=True).doit() == 0 + assert Comm(F**2, T).expand(commutator=True).doit() == -2*F + assert Comm(F, T**2).expand(commutator=True).doit() == -2*T + assert Comm(T**2, F).expand(commutator=True).doit() == 2*T + assert Comm(T**2, F**3).expand(commutator=True).doit() == 2*F*T*F + 2*F**2*T + 2*T*F**2 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_constants.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_constants.py new file mode 100644 index 0000000000000000000000000000000000000000..48a773ea6b5afbaf956143b50b16b3b18aaf5beb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_constants.py @@ -0,0 +1,13 @@ +from sympy.core.numbers import Float + +from sympy.physics.quantum.constants import hbar + + +def test_hbar(): + 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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_dagger.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_dagger.py new file mode 100644 index 0000000000000000000000000000000000000000..1357c9320a20afa2ba905a117d90ed1ac2e9642c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_dagger.py @@ -0,0 +1,103 @@ +from sympy.core.expr import Expr +from sympy.core.mul import Mul +from sympy.core.numbers import (I, Integer) +from sympy.core.symbol import symbols +from sympy.functions.elementary.complexes import conjugate +from sympy.matrices.dense import Matrix + +from sympy.physics.quantum.dagger import adjoint, Dagger +from sympy.external import import_module +from sympy.testing.pytest import skip, warns_deprecated_sympy +from sympy.physics.quantum.operator import Operator, IdentityOperator + + +def test_scalars(): + x = symbols('x', complex=True) + assert Dagger(x) == conjugate(x) + assert Dagger(I*x) == -I*conjugate(x) + + i = symbols('i', real=True) + assert Dagger(i) == i + + p = symbols('p') + assert isinstance(Dagger(p), conjugate) + + i = Integer(3) + assert Dagger(i) == i + + A = symbols('A', commutative=False) + assert Dagger(A).is_commutative is False + + +def test_matrix(): + x = symbols('x') + m = Matrix([[I, x*I], [2, 4]]) + assert Dagger(m) == m.H + + +def test_dagger_mul(): + O = Operator('O') + assert Dagger(O)*O == Dagger(O)*O + with warns_deprecated_sympy(): + I = IdentityOperator() + assert Dagger(O)*O*I == Mul(Dagger(O), O)*I + assert Dagger(O)*Dagger(O) == Dagger(O)**2 + assert Dagger(O)*Dagger(I) == Dagger(O) + + +class Foo(Expr): + + def _eval_adjoint(self): + return I + + +def test_eval_adjoint(): + f = Foo() + d = Dagger(f) + assert d == I + +np = import_module('numpy') + + +def test_numpy_dagger(): + if not np: + skip("numpy not installed.") + + a = np.array([[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']}) + + +def test_scipy_sparse_dagger(): + if not np: + skip("numpy not installed.") + if not scipy: + skip("scipy not installed.") + else: + sparse = scipy.sparse + + 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 + + +def test_unknown(): + """Check treatment of unknown objects. + Objects without adjoint or conjugate/transpose methods + are sympified and wrapped in dagger. + """ + x = symbols("x", commutative=False) + result = Dagger(x) + assert result.args == (x,) and isinstance(result, adjoint) + + +def test_unevaluated(): + """Check that evaluate=False returns unevaluated Dagger. + """ + x = symbols("x", real=True) + assert Dagger(x) == x + result = Dagger(x, evaluate=False) + assert result.args == (x,) and isinstance(result, adjoint) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_density.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_density.py new file mode 100644 index 0000000000000000000000000000000000000000..399acce6e201b39f65ea674048198fd2f087b4d0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_density.py @@ -0,0 +1,289 @@ +from sympy.core.numbers import Rational +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import log +from sympy.external import import_module +from sympy.physics.quantum.density import Density, entropy, fidelity +from sympy.physics.quantum.state import Ket, TimeDepKet +from sympy.physics.quantum.qubit import Qubit +from sympy.physics.quantum.represent import represent +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.cartesian import XKet, PxKet, PxOp, XOp +from sympy.physics.quantum.spin import JzKet +from sympy.physics.quantum.operator import OuterProduct +from sympy.physics.quantum.trace import Tr +from sympy.functions import sqrt +from sympy.testing.pytest import raises +from sympy.physics.quantum.matrixutils import scipy_sparse_matrix +from sympy.physics.quantum.tensorproduct import TensorProduct + + +def test_eval_args(): + # check instance created + assert isinstance(Density([Ket(0), 0.5], [Ket(1), 0.5]), Density) + assert isinstance(Density([Qubit('00'), 1/sqrt(2)], + [Qubit('11'), 1/sqrt(2)]), Density) + + #test if Qubit object type preserved + d = Density([Qubit('00'), 1/sqrt(2)], [Qubit('11'), 1/sqrt(2)]) + for (state, prob) in d.args: + assert isinstance(state, Qubit) + + # 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]) + 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]) + 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]) + 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)) + + # Density with multiple Tensorproducts as states + 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]) + 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)) + d = Density([tp1, 1]) + + # full trace + 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)) + t = Tr(d, [1]) + assert t.doit() == JzKet(1, 1) * Dagger(JzKet(1, 1)) + + # with another spin state + tp2 = TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) + d = Density([tp2, 1]) + + #full trace + t = Tr(d) + assert t.doit() == 1 + + #Partial trace on density operators with spin states + t = Tr(d, [0]) + assert t.doit() == JzKet(S.Half, Rational(-1, 2)) * Dagger(JzKet(S.Half, Rational(-1, 2))) + t = Tr(d, [1]) + assert t.doit() == JzKet(S.Half, S.Half) * Dagger(JzKet(S.Half, S.Half)) + + +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]) + + +def test_represent(): + 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]) + 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) + + # check when given explicit basis + assert (represent(0.5*(XKet()*Dagger(XKet())), basis=PxOp()) + + 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') + 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') + 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') + 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.Half, S.Half) + down = JzKet(S.Half, Rational(-1, 2)) + d = Density((up, S.Half), (down, S.Half)) + + # test for density object + ent = entropy(d) + assert entropy(d) == log(2)/2 + assert d.entropy() == log(2)/2 + + np = import_module('numpy', 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.ndarray) + assert ent.real == 0.69314718055994529 + assert ent.imag == 0 + + 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) + assert ent.real == 0.69314718055994529 + assert ent.imag == 0 + + +def test_eval_trace(): + up = JzKet(S.Half, S.Half) + down = JzKet(S.Half, Rational(-1, 2)) + d = Density((up, 0.5), (down, 0.5)) + + t = Tr(d) + assert t.doit() == 1.0 + + #test dummy time dependent states + class TestTimeDepKet(TimeDepKet): + def _eval_trace(self, bra, **options): + return 1 + + x, t = symbols('x t') + 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)) + + t = Tr(d) + assert t.doit() == 1.0 + + +def test_fidelity(): + #test with kets + up = JzKet(S.Half, S.Half) + down = JzKet(S.Half, Rational(-1, 2)) + updown = (S.One/sqrt(2))*up + (S.One/sqrt(2))*down + + #check with matrices + up_dm = represent(up * Dagger(up)) + down_dm = represent(down * Dagger(down)) + updown_dm = represent(updown * Dagger(updown)) + + assert abs(fidelity(up_dm, up_dm) - 1) < 1e-3 + assert fidelity(up_dm, down_dm) < 1e-3 + assert abs(fidelity(up_dm, updown_dm) - (S.One/sqrt(2))) < 1e-3 + assert abs(fidelity(updown_dm, down_dm) - (S.One/sqrt(2))) < 1e-3 + + #check with density + up_dm = Density([up, 1.0]) + down_dm = Density([down, 1.0]) + updown_dm = Density([updown, 1.0]) + + assert abs(fidelity(up_dm, up_dm) - 1) < 1e-3 + assert abs(fidelity(up_dm, down_dm)) < 1e-3 + assert abs(fidelity(up_dm, updown_dm) - (S.One/sqrt(2))) < 1e-3 + assert abs(fidelity(updown_dm, down_dm) - (S.One/sqrt(2))) < 1e-3 + + #check mixed states with density + updown2 = sqrt(3)/2*up + S.Half*down + d1 = Density([updown, 0.25], [updown2, 0.75]) + d2 = Density([updown, 0.75], [updown2, 0.25]) + 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') + state3 = S.One/sqrt(2)*state1 + S.One/sqrt(2)*state2 + state4 = sqrt(Rational(2, 3))*state1 + S.One/sqrt(3)*state2 + + state1_dm = Density([state1, 1]) + state2_dm = Density([state2, 1]) + state3_dm = Density([state3, 1]) + + assert fidelity(state1_dm, state1_dm) == 1 + assert fidelity(state1_dm, state2_dm) == 0 + assert abs(fidelity(state1_dm, state3_dm) - 1/sqrt(2)) < 1e-3 + assert abs(fidelity(state3_dm, state2_dm) - 1/sqrt(2)) < 1e-3 + + #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, d2) - 0.996) < 1e-3 + assert abs(fidelity(d1, d2) - fidelity(d2, d1)) < 1e-3 + + #TODO: test for invalid arguments + # non-square matrix + mat1 = [[0, 0], + [0, 0], + [0, 0]] + + mat2 = [[0, 0], + [0, 0]] + raises(ValueError, lambda: fidelity(mat1, mat2)) + + # unequal dimensions + mat1 = [[0, 0], + [0, 0]] + mat2 = [[0, 0, 0], + [0, 0, 0], + [0, 0, 0]] + raises(ValueError, lambda: fidelity(mat1, mat2)) + + # unsupported data-type + x, y = 1, 2 # random values that is not a matrix + raises(ValueError, lambda: fidelity(x, y)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_fermion.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_fermion.py new file mode 100644 index 0000000000000000000000000000000000000000..061648c2d5578481196949c38e90ff169fcea972 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_fermion.py @@ -0,0 +1,62 @@ +from pytest import raises + +import sympy +from sympy.physics.quantum import Dagger, AntiCommutator, qapply +from sympy.physics.quantum.fermion import FermionOp +from sympy.physics.quantum.fermion import FermionFockKet, FermionFockBra +from sympy import Symbol + + +def test_fermionoperator(): + c = FermionOp('c') + d = FermionOp('d') + + assert isinstance(c, FermionOp) + assert isinstance(Dagger(c), FermionOp) + + assert c.is_annihilation + assert not Dagger(c).is_annihilation + + assert FermionOp("c") == FermionOp("c", True) + assert FermionOp("c") != FermionOp("d") + assert FermionOp("c", True) != FermionOp("c", False) + + assert AntiCommutator(c, Dagger(c)).doit() == 1 + + assert AntiCommutator(c, Dagger(d)).doit() == c * Dagger(d) + Dagger(d) * c + + +def test_fermion_states(): + c = FermionOp("c") + + # Fock states + assert (FermionFockBra(0) * FermionFockKet(1)).doit() == 0 + assert (FermionFockBra(1) * FermionFockKet(1)).doit() == 1 + + assert qapply(c * FermionFockKet(1)) == FermionFockKet(0) + assert qapply(c * FermionFockKet(0)) == 0 + + assert qapply(Dagger(c) * FermionFockKet(0)) == FermionFockKet(1) + assert qapply(Dagger(c) * FermionFockKet(1)) == 0 + + +def test_power(): + c = FermionOp("c") + assert c**0 == 1 + assert c**1 == c + assert c**2 == 0 + assert c**3 == 0 + assert Dagger(c)**1 == Dagger(c) + assert Dagger(c)**2 == 0 + + assert (c**Symbol('a')).func == sympy.core.power.Pow + assert (c**Symbol('a')).args == (c, Symbol('a')) + + with raises(ValueError): + c**-1 + + with raises(ValueError): + c**3.2 + + with raises(TypeError): + c**1j diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_gate.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_gate.py new file mode 100644 index 0000000000000000000000000000000000000000..2d7bf1d624faca8afe4b10699d23acc161ca0cdd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_gate.py @@ -0,0 +1,360 @@ +from sympy.core.mul import Mul +from sympy.core.numbers import (I, Integer, Rational, pi) +from sympy.core.symbol import (Wild, symbols) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices import Matrix, ImmutableMatrix + +from sympy.physics.quantum.gate import (XGate, YGate, ZGate, random_circuit, + CNOT, IdentityGate, H, X, Y, S, T, Z, SwapGate, gate_simp, gate_sort, + CNotGate, TGate, HadamardGate, PhaseGate, UGate, CGate) +from sympy.physics.quantum.commutator import Commutator +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.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) + assert h.min_qubits == 2 + assert h.nqubits == 1 + + i0 = Wild('i0') + i1 = Wild('i1') + h0_w1 = HadamardGate(i0) + h0_w2 = HadamardGate(i0) + h1_w1 = HadamardGate(i1) + + assert h0_w1 == h0_w2 + assert h0_w1 != h1_w1 + assert h1_w1 != h0_w2 + + cnot_10_w1 = CNOT(i1, i0) + cnot_10_w2 = CNOT(i1, i0) + cnot_01_w1 = CNOT(i0, i1) + + assert cnot_10_w1 == cnot_10_w2 + 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]]) + + # Test basic case where gate exists in 1-qubit space + u1 = UGate((0,), 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') + + # Test case where gate exists in a larger space + 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))) + + +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]]) + assert represent(CGate(1, XGate(0)), nqubits=2) == CNOTMatrix + + # Test multiple control bit functionality + 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]]) + + ToffoliGate = CGate((3, 0), XGate(1)) + assert qapply(ToffoliGate*Qubit('1001')) == \ + matrix_to_qubit(represent(ToffoliGate*Qubit('1001'), nqubits=4)) + assert qapply(ToffoliGate*Qubit('0000')) == \ + 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))) + # 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))) + assert qapply(CZGate*Qubit('11')) == -Qubit('11') + 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')) == \ + I*Qubit('11') + assert matrix_to_qubit(represent(CPhaseGate*Qubit('11'), nqubits=2)) == \ + I*Qubit('11') + + # Test that the dagger, inverse, and power of CGate is evaluated properly + assert Dagger(CZGate) == CZGate + assert pow(CZGate, 1) == Dagger(CZGate) + assert Dagger(CZGate) == CZGate.inverse() + assert Dagger(CPhaseGate) != CPhaseGate + assert Dagger(CPhaseGate) == CPhaseGate.inverse() + 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]]) + + # 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 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') + assert qapply(cu1*Qubit('00')) == Qubit('00') + + # Test case where gate exists in a larger space. + 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))) + +def test_UGate_OneQubitGate_combo(): + v, w, f, g = symbols('v w f g') + uMat1 = ImmutableMatrix([[v, w], [f, g]]) + cMat1 = Matrix([[v, w + 1, 0, 0], [f + 1, g, 0, 0], [0, 0, v, w + 1], [0, 0, f + 1, g]]) + u1 = X(0) + UGate(0, uMat1) + assert represent(u1, nqubits=2) == cMat1 + + uMat2 = ImmutableMatrix([[1/sqrt(2), 1/sqrt(2)], [I/sqrt(2), -I/sqrt(2)]]) + cMat2_1 = Matrix([[Rational(1, 2) + I/2, Rational(1, 2) - I/2], + [Rational(1, 2) - I/2, Rational(1, 2) + I/2]]) + cMat2_2 = Matrix([[1, 0], [0, I]]) + u2 = UGate(0, uMat2) + assert represent(H(0)*u2, nqubits=1) == cMat2_1 + assert represent(u2*H(0), nqubits=1) == cMat2_2 + +def test_represent_hadamard(): + """Test the representation of the hadamard gate.""" + circuit = HadamardGate(0)*Qubit('00') + answer = represent(circuit, nqubits=2) + # 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') + answer = represent(circuit, nqubits=2) + assert Matrix([0, 1, 0, 0]) == answer + + +def test_represent_ygate(): + """Test the representation of the Y gate.""" + 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 + + +def test_represent_zgate(): + """Test the representation of the Z gate.""" + circuit = ZGate(0)*Qubit('00') + answer = represent(circuit, nqubits=2) + assert Matrix([1, 0, 0, 0]) == answer + + +def test_represent_phasegate(): + """Test the representation of the S gate.""" + circuit = PhaseGate(0)*Qubit('01') + answer = represent(circuit, nqubits=2) + assert Matrix([0, I, 0, 0]) == answer + + +def test_represent_tgate(): + """Test the representation of the T gate.""" + circuit = TGate(0)*Qubit('01') + assert Matrix([0, exp(I*pi/4), 0, 0]) == represent(circuit, nqubits=2) + + +def test_compound_gates(): + """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 + + +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 = circuit*Qubit('111') + assert matrix_to_qubit(represent(circuit, nqubits=3)) == \ + qapply(circuit) + + 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 + 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) + assert gate_sort(Y(0)*X(0)) == -X(0)*Y(0) + assert gate_sort(Z(0)*Y(0)) == -Y(0)*Z(0) + 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) + # 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) == \ + # 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) + assert gate_simp(X(0)*X(0)) == 1 + assert gate_simp(Y(0)*Y(0)) == 1 + assert gate_simp(Z(0)*Z(0)) == 1 + assert gate_simp(H(0)*H(0)) == 1 + assert gate_simp(T(0)*T(0)) == S(0) + assert gate_simp(S(0)*S(0)) == Z(0) + assert gate_simp(Integer(1)) == Integer(1) + assert gate_simp(X(0)**2 + Y(0)**2) == Integer(2) + + +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') + 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) + + +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)) + 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)) + 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)) + 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)) + a = matrix_to_zero(represent(e, nqubits=2, format='sympy')) + b = matrix_to_zero(represent(e.doit(), nqubits=2, format='sympy')) + assert a == b + + +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 + + +def test_random_circuit(): + c = random_circuit(10, 3) + assert isinstance(c, Mul) + m = represent(c, nqubits=3) + 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) + + assert (z*z_dagger == 1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_grover.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_grover.py new file mode 100644 index 0000000000000000000000000000000000000000..b93a5bc5e59380a993dc34e4a160e75f799b3493 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_grover.py @@ -0,0 +1,92 @@ +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices.dense import Matrix +from sympy.physics.quantum.represent import represent +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.qubit import IntQubit +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, nqubits=qubits.nqubits) + + +def test_superposition_basis(): + nbits = 2 + first_half_state = IntQubit(0, nqubits=nbits)/2 + IntQubit(1, nqubits=nbits)/2 + second_half_state = IntQubit(2, nbits)/2 + IntQubit(3, nbits)/2 + assert first_half_state + second_half_state == superposition_basis(nbits) + + nbits = 3 + firstq = (1/sqrt(8))*IntQubit(0, nqubits=nbits) + (1/sqrt(8))*IntQubit(1, nqubits=nbits) + secondq = (1/sqrt(8))*IntQubit(2, nbits) + (1/sqrt(8))*IntQubit(3, nbits) + thirdq = (1/sqrt(8))*IntQubit(4, nbits) + (1/sqrt(8))*IntQubit(5, nbits) + 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) + assert qapply(v*IntQubit(1)) == IntQubit(1) + + nbits = 2 + v = OracleGate(2, return_one_on_two) + assert qapply(v*IntQubit(0, nbits)) == IntQubit(0, nqubits=nbits) + assert qapply(v*IntQubit(1, nbits)) == IntQubit(1, nqubits=nbits) + assert qapply(v*IntQubit(2, nbits)) == -IntQubit(2, nbits) + assert qapply(v*IntQubit(3, nbits)) == IntQubit(3, nbits) + + assert represent(OracleGate(1, lambda qubits: qubits == IntQubit(0)), nqubits=1) == \ + Matrix([[-1, 0], [0, 1]]) + assert represent(v, nqubits=2) == Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]]) + + +def test_WGate(): + nqubits = 2 + basis_states = superposition_basis(nqubits) + assert qapply(WGate(nqubits)*basis_states) == basis_states + + expected = ((2/sqrt(pow(2, nqubits)))*basis_states) - IntQubit(1, nqubits=nqubits) + assert qapply(WGate(nqubits)*IntQubit(1, nqubits=nqubits)) == expected + + +def test_grover_iteration_1(): + numqubits = 2 + basis_states = superposition_basis(numqubits) + v = OracleGate(numqubits, return_one_on_one) + expected = IntQubit(1, nqubits=numqubits) + assert qapply(grover_iteration(basis_states, v)) == expected + + +def test_grover_iteration_2(): + numqubits = 4 + basis_states = superposition_basis(numqubits) + v = OracleGate(numqubits, return_one_on_two) + # After (pi/4)sqrt(pow(2, n)), IntQubit(2) should have highest prob + # In this case, after around pi times (3 or 4) + iterated = grover_iteration(basis_states, v) + iterated = qapply(iterated) + iterated = grover_iteration(iterated, v) + iterated = qapply(iterated) + iterated = grover_iteration(iterated, v) + iterated = qapply(iterated) + # In this case, probability was highest after 3 iterations + # Probability of Qubit('0010') was 251/256 (3) vs 781/1024 (4) + # Ask about measurement + 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=nqubits) + + nqubits = 4 + basis_states = superposition_basis(nqubits) + expected = (-13*basis_states)/64 + 264*IntQubit(2, nqubits)/256 + assert apply_grover(return_one_on_two, 4) == qapply(expected) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_hilbert.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_hilbert.py new file mode 100644 index 0000000000000000000000000000000000000000..9a0e5c4187c6c62e14505efb1597a5cd63c23fea --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_hilbert.py @@ -0,0 +1,110 @@ +from sympy.physics.quantum.hilbert import ( + HilbertSpace, ComplexSpace, L2, FockSpace, TensorProductHilbertSpace, + DirectSumHilbertSpace, TensorPowerHilbertSpace +) + +from sympy.core.numbers import oo +from sympy.core.symbol import Symbol +from sympy.printing.repr import srepr +from sympy.printing.str import sstr +from sympy.sets.sets import Interval + + +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) + assert c1.dimension == 2 + assert sstr(c1) == 'C(2)' + assert srepr(c1) == 'ComplexSpace(Integer(2))' + + n = Symbol('n') + c2 = ComplexSpace(n) + assert isinstance(c2, ComplexSpace) + assert c2.dimension == n + assert sstr(c2) == 'C(n)' + assert srepr(c2) == "ComplexSpace(Symbol('n'))" + assert c2.subs(n, 2) == ComplexSpace(2) + + +def test_L2(): + b1 = L2(Interval(-oo, 1)) + assert isinstance(b1, L2) + assert b1.dimension is oo + assert b1.interval == Interval(-oo, 1) + + x = Symbol('x', real=True) + y = Symbol('y', real=True) + b2 = L2(Interval(x, y)) + assert b2.dimension is oo + assert b2.interval == Interval(x, y) + assert b2.subs(x, -1) == L2(Interval(-1, y)) + + +def test_fock_space(): + f1 = FockSpace() + f2 = FockSpace() + assert isinstance(f1, FockSpace) + assert f1.dimension is oo + assert f1 == f2 + + +def test_tensor_product(): + n = Symbol('n') + hs1 = ComplexSpace(2) + hs2 = ComplexSpace(n) + + h = hs1*hs2 + assert isinstance(h, TensorProductHilbertSpace) + assert h.dimension == 2*n + assert h.spaces == (hs1, hs2) + + h = hs2*hs2 + assert isinstance(h, TensorPowerHilbertSpace) + assert h.base == hs2 + assert h.exp == 2 + assert h.dimension == n**2 + + f = FockSpace() + h = hs1*hs2*f + assert h.dimension is oo + + +def test_tensor_power(): + n = Symbol('n') + hs1 = ComplexSpace(2) + hs2 = ComplexSpace(n) + + h = hs1**2 + assert isinstance(h, TensorPowerHilbertSpace) + assert h.base == hs1 + assert h.exp == 2 + assert h.dimension == 4 + + h = hs2**3 + assert isinstance(h, TensorPowerHilbertSpace) + assert h.base == hs2 + 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 + assert isinstance(h, DirectSumHilbertSpace) + assert h.dimension == 2 + n + assert h.spaces == (hs1, hs2) + + f = FockSpace() + h = hs1 + f + hs2 + assert h.dimension is oo + assert h.spaces == (hs1, f, hs2) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_identitysearch.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_identitysearch.py new file mode 100644 index 0000000000000000000000000000000000000000..8747b1f9d9630e699695f67734333f9d61581fb8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_identitysearch.py @@ -0,0 +1,492 @@ +from sympy.external import import_module +from sympy.core.mul import Mul +from sympy.core.numbers import Integer +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.gate import (X, Y, Z, H, CNOT, + IdentityGate, CGate, PhaseGate, TGate) +from sympy.physics.quantum.identitysearch import (generate_gate_rules, + generate_equivalent_ids, GateIdentity, bfs_identity_search, + is_scalar_sparse_matrix, + is_scalar_nonsparse_matrix, is_degenerate, is_reducible) +from sympy.testing.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() + ph = PhaseGate(0) + cgate_t = CGate(0, TGate(1)) + + assert generate_gate_rules((x,)) == {((x,), ())} + + gate_rules = {((x, x), ()), + ((x,), (x,))} + assert generate_gate_rules((x, x)) == gate_rules + + gate_rules = {((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 = {((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 = { + ((), (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 + + gate_rules = {((), (cgate_t**(-1), ph**(-1), x)), + ((), (ph**(-1), x, cgate_t**(-1))), + ((), (x, cgate_t**(-1), ph**(-1))), + ((cgate_t,), (ph**(-1), x)), + ((ph,), (x, cgate_t**(-1))), + ((x,), (cgate_t**(-1), ph**(-1))), + ((cgate_t, x), (ph**(-1),)), + ((ph, cgate_t), (x,)), + ((x, ph), (cgate_t**(-1),)), + ((cgate_t, x, ph), ()), + ((ph, cgate_t, x), ()), + ((x, ph, cgate_t), ())} + actual = generate_gate_rules((x, ph, cgate_t)) + assert actual == gate_rules + + gate_rules = {(Integer(1), cgate_t**(-1)*ph**(-1)*x), + (Integer(1), ph**(-1)*x*cgate_t**(-1)), + (Integer(1), x*cgate_t**(-1)*ph**(-1)), + (cgate_t, ph**(-1)*x), + (ph, x*cgate_t**(-1)), + (x, cgate_t**(-1)*ph**(-1)), + (cgate_t*x, ph**(-1)), + (ph*cgate_t, x), + (x*ph, cgate_t**(-1)), + (cgate_t*x*ph, Integer(1)), + (ph*cgate_t*x, Integer(1)), + (x*ph*cgate_t, Integer(1))} + 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() + ph = PhaseGate(0) + cgate_t = CGate(0, TGate(1)) + + # Note: 1 (type int) is not the same as 1 (type One) + expected = {(x, Integer(1))} + assert generate_gate_rules((x,), return_as_muls=True) == expected + + expected = {(Integer(1), Integer(1))} + assert generate_gate_rules(x*x, return_as_muls=True) == expected + + expected = {((), ())} + assert generate_gate_rules(x*x, return_as_muls=False) == expected + + gate_rules = {(x*y*x, Integer(1)), + (y, Integer(1)), + (y*x, x), + (x*y, x)} + assert generate_gate_rules(x*y*x, return_as_muls=True) == gate_rules + + gate_rules = {(x*y*z, Integer(1)), + (y*z*x, Integer(1)), + (z*x*y, Integer(1)), + (Integer(1), x*z*y), + (Integer(1), y*x*z), + (Integer(1), 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, return_as_muls=True) + assert actual == gate_rules + + gate_rules = {(Integer(1), h*z*y*x), + (Integer(1), x*h*z*y), + (Integer(1), y*x*h*z), + (Integer(1), z*y*x*h), + (h, z*y*x), (x, h*z*y), + (y, x*h*z), (z, y*x*h), + (h*x, z*y), (z*h, y*x), + (x*y, h*z), (y*z, x*h), + (h*x*y, z), (x*y*z, h), + (y*z*h, x), (z*h*x, y), + (h*x*y*z, Integer(1)), + (x*y*z*h, Integer(1)), + (y*z*h*x, Integer(1)), + (z*h*x*y, Integer(1))} + actual = generate_gate_rules(x*y*z*h, return_as_muls=True) + assert actual == gate_rules + + gate_rules = {(Integer(1), cgate_t**(-1)*ph**(-1)*x), + (Integer(1), ph**(-1)*x*cgate_t**(-1)), + (Integer(1), x*cgate_t**(-1)*ph**(-1)), + (cgate_t, ph**(-1)*x), + (ph, x*cgate_t**(-1)), + (x, cgate_t**(-1)*ph**(-1)), + (cgate_t*x, ph**(-1)), + (ph*cgate_t, x), + (x*ph, cgate_t**(-1)), + (cgate_t*x*ph, Integer(1)), + (ph*cgate_t*x, Integer(1)), + (x*ph*cgate_t, Integer(1))} + actual = generate_gate_rules(x*ph*cgate_t, return_as_muls=True) + assert actual == gate_rules + + gate_rules = {((), (cgate_t**(-1), ph**(-1), x)), + ((), (ph**(-1), x, cgate_t**(-1))), + ((), (x, cgate_t**(-1), ph**(-1))), + ((cgate_t,), (ph**(-1), x)), + ((ph,), (x, cgate_t**(-1))), + ((x,), (cgate_t**(-1), ph**(-1))), + ((cgate_t, x), (ph**(-1),)), + ((ph, cgate_t), (x,)), + ((x, ph), (cgate_t**(-1),)), + ((cgate_t, x, ph), ()), + ((ph, cgate_t, x), ()), + ((x, ph, cgate_t), ())} + 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,)) == {(x,)} + assert generate_equivalent_ids((x, x)) == {(x, x)} + assert generate_equivalent_ids((x, y)) == {(x, y), (y, x)} + + gate_seq = (x, y, z) + gate_ids = {(x, y, z), (y, z, x), (z, x, y), (z, y, x), + (y, x, z), (x, z, y)} + assert generate_equivalent_ids(gate_seq) == gate_ids + + gate_ids = {Mul(x, y, z), Mul(y, z, x), Mul(z, x, y), + Mul(z, y, x), Mul(y, x, z), Mul(x, z, y)} + assert generate_equivalent_ids(gate_seq, return_as_muls=True) == gate_ids + + gate_seq = (x, y, z, h) + gate_ids = {(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)} + assert generate_equivalent_ids(gate_seq) == gate_ids + + gate_seq = (x, y, x, y) + gate_ids = {(x, y, x, y), (y, x, y, x)} + assert generate_equivalent_ids(gate_seq) == gate_ids + + cgate_y = CGate((1,), y) + gate_seq = (y, cgate_y, y, cgate_y) + gate_ids = {(y, cgate_y, y, cgate_y), (cgate_y, y, cgate_y, y)} + assert generate_equivalent_ids(gate_seq) == gate_ids + + cnot = CNOT(1, 0) + cgate_z = CGate((0,), Z(1)) + gate_seq = (cnot, h, cgate_z, h) + gate_ids = {(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() + + assert generate_equivalent_ids((x,), return_as_muls=True) == {x} + + gate_ids = {Integer(1)} + assert generate_equivalent_ids(x*x, return_as_muls=True) == gate_ids + + gate_ids = {x*y, y*x} + assert generate_equivalent_ids(x*y, return_as_muls=True) == gate_ids + + gate_ids = {(x, y), (y, x)} + assert generate_equivalent_ids(x*y) == gate_ids + + circuit = Mul(*(x, y, z)) + gate_ids = {x*y*z, y*z*x, z*x*y, z*y*x, + y*x*z, x*z*y} + assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids + + circuit = Mul(*(x, y, z, h)) + gate_ids = {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} + assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids + + circuit = Mul(*(x, y, x, y)) + gate_ids = {x*y*x*y, y*x*y*x} + assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids + + cgate_y = CGate((1,), y) + circuit = Mul(*(y, cgate_y, y, cgate_y)) + gate_ids = {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) + cgate_z = CGate((0,), Z(1)) + circuit = Mul(*(cnot, h, cgate_z, h)) + gate_ids = {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 is True + + x0 = X(0) + xx_circuit = (x0, x0) + actual = is_scalar_nonsparse_matrix(xx_circuit, numqubits, id_only) + 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 is False + + z1 = Z(1) + xyz_circuit = (x1, y1, z1) + actual = is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only) + assert actual is True + + cnot = CNOT(1, 0) + cnot_circuit = (cnot, cnot) + actual = is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only) + assert actual is True + + h = H(0) + hh_circuit = (h, h) + actual = is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only) + 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 is True + + id_only = True + actual = is_scalar_nonsparse_matrix(xhzh_circuit, numqubits, id_only) + assert actual is True + actual = is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only) + assert actual is False + actual = is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only) + assert actual is True + actual = is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only) + assert actual is True + + +def test_is_scalar_sparse_matrix(): + np = import_module('numpy') + if not np: + skip("numpy not installed.") + + scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) + if not scipy: + skip("scipy not installed.") + + numqubits = 2 + id_only = False + + id_gate = (IdentityGate(1),) + 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) is True + + x1 = X(1) + y1 = Y(1) + xy_circuit = (x1, y1) + 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) is True + + cnot = CNOT(1, 0) + cnot_circuit = (cnot, cnot) + 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) 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) is True + + 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() + + gate_id = GateIdentity(x, y, z) + ids = {gate_id} + + another_id = (z, y, x) + 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) is True + + circuit = (x, y, x) + assert is_reducible(circuit, nqubits, 1, 3) is False + + circuit = (x, y, y, x) + assert is_reducible(circuit, nqubits, 0, 4) is True + + circuit = (x, y, y, x) + assert is_reducible(circuit, nqubits, 1, 3) is True + + circuit = (x, y, z, y, y) + assert is_reducible(circuit, nqubits, 1, 5) is True + + +def test_bfs_identity_search(): + assert bfs_identity_search([], 1) == set() + + (x, y, z, h) = create_gate_sequence() + + gate_list = [x] + id_set = {GateIdentity(x, x)} + assert bfs_identity_search(gate_list, 1, max_depth=2) == id_set + + # Set should not contain degenerate quantum circuits + gate_list = [x, y, z] + id_set = {GateIdentity(x, x), + GateIdentity(y, y), + GateIdentity(z, z), + GateIdentity(x, y, z)} + assert bfs_identity_search(gate_list, 1) == id_set + + id_set = {GateIdentity(x, x), + GateIdentity(y, y), + GateIdentity(z, z), + GateIdentity(x, y, z), + GateIdentity(x, y, x, y), + GateIdentity(x, z, x, z), + GateIdentity(y, z, y, z)} + assert bfs_identity_search(gate_list, 1, max_depth=4) == id_set + assert bfs_identity_search(gate_list, 1, max_depth=5) == id_set + + gate_list = [x, y, z, h] + id_set = {GateIdentity(x, x), + GateIdentity(y, y), + GateIdentity(z, z), + GateIdentity(h, h), + GateIdentity(x, y, z), + GateIdentity(x, y, x, y), + GateIdentity(x, z, x, z), + GateIdentity(x, h, z, h), + GateIdentity(y, z, y, z), + GateIdentity(y, h, y, h)} + assert bfs_identity_search(gate_list, 1) == id_set + + id_set = {GateIdentity(x, x), + GateIdentity(y, y), + GateIdentity(z, z), + GateIdentity(h, h)} + assert id_set == bfs_identity_search(gate_list, 1, max_depth=3, + identity_only=True) + + id_set = {GateIdentity(x, x), + GateIdentity(y, y), + GateIdentity(z, z), + GateIdentity(h, h), + GateIdentity(x, y, z), + GateIdentity(x, y, x, y), + GateIdentity(x, z, x, z), + GateIdentity(x, h, z, h), + GateIdentity(y, z, y, z), + GateIdentity(y, h, y, h), + GateIdentity(x, y, h, x, h), + GateIdentity(x, z, h, y, h), + GateIdentity(y, z, h, z, h)} + assert bfs_identity_search(gate_list, 1, max_depth=5) == id_set + + id_set = {GateIdentity(x, x), + GateIdentity(y, y), + GateIdentity(z, z), + GateIdentity(h, h), + GateIdentity(x, h, z, h)} + assert id_set == bfs_identity_search(gate_list, 1, max_depth=4, + identity_only=True) + + cnot = CNOT(1, 0) + gate_list = [x, cnot] + id_set = {GateIdentity(x, x), + GateIdentity(cnot, cnot), + GateIdentity(x, cnot, x, cnot)} + assert bfs_identity_search(gate_list, 2, max_depth=4) == id_set + + cgate_x = CGate((1,), x) + gate_list = [x, cgate_x] + id_set = {GateIdentity(x, x), + GateIdentity(cgate_x, cgate_x), + GateIdentity(x, cgate_x, x, cgate_x)} + assert bfs_identity_search(gate_list, 2, max_depth=4) == id_set + + cgate_z = CGate((0,), Z(1)) + gate_list = [cnot, cgate_z, h] + id_set = {GateIdentity(h, h), + GateIdentity(cgate_z, cgate_z), + GateIdentity(cnot, cnot), + GateIdentity(cnot, h, cgate_z, h)} + assert bfs_identity_search(gate_list, 2, max_depth=4) == id_set + + s = PhaseGate(0) + t = TGate(0) + gate_list = [s, t] + id_set = {GateIdentity(s, s, s, s)} + assert bfs_identity_search(gate_list, 1, max_depth=4) == id_set + + +def test_bfs_identity_search_xfail(): + s = PhaseGate(0) + t = TGate(0) + gate_list = [Dagger(s), t] + id_set = {GateIdentity(Dagger(s), t, t)} + assert bfs_identity_search(gate_list, 1, max_depth=3) == id_set diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_innerproduct.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_innerproduct.py new file mode 100644 index 0000000000000000000000000000000000000000..2632031f8a9a9ec65dfab6d834eb704a00b621d3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_innerproduct.py @@ -0,0 +1,71 @@ +from sympy.core.numbers import (I, Integer) + +from sympy.physics.quantum.innerproduct import InnerProduct +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.state import Bra, Ket, StateBase + + +def test_innerproduct(): + k = Ket('k') + b = Bra('b') + 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 + + +def test_innerproduct_dagger(): + k = Ket('k') + b = Bra('b') + ip = b*k + assert Dagger(ip) == Dagger(k)*Dagger(b) + + +class FooState(StateBase): + pass + + +class FooKet(Ket, FooState): + + @classmethod + def dual_class(self): + return FooBra + + def _eval_innerproduct_FooBra(self, bra): + return Integer(1) + + def _eval_innerproduct_BarBra(self, bra): + return I + + +class FooBra(Bra, FooState): + @classmethod + def dual_class(self): + return FooKet + + +class BarState(StateBase): + pass + + +class BarKet(Ket, BarState): + @classmethod + def dual_class(self): + return BarBra + + +class BarBra(Bra, BarState): + @classmethod + def dual_class(self): + return BarKet + + +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) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_kind.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_kind.py new file mode 100644 index 0000000000000000000000000000000000000000..e50467db4c2d9bd8e19f4ea883c26bd5ac5bc8d8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_kind.py @@ -0,0 +1,75 @@ +"""Tests for sympy.physics.quantum.kind.""" + +from sympy.core.kind import NumberKind, UndefinedKind +from sympy.core.symbol import symbols + +from sympy.physics.quantum.kind import ( + OperatorKind, KetKind, BraKind +) +from sympy.physics.quantum.anticommutator import AntiCommutator +from sympy.physics.quantum.commutator import Commutator +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.operator import Operator +from sympy.physics.quantum.state import Ket, Bra +from sympy.physics.quantum.tensorproduct import TensorProduct + +k = Ket('k') +b = Bra('k') +A = Operator('A') +B = Operator('B') +x, y, z = symbols('x y z', integer=True) + +def test_bra_ket(): + assert k.kind == KetKind + assert b.kind == BraKind + assert (b*k).kind == NumberKind # inner product + assert (x*k).kind == KetKind + assert (x*b).kind == BraKind + + +def test_operator_kind(): + assert A.kind == OperatorKind + assert (A*B).kind == OperatorKind + assert (x*A).kind == OperatorKind + assert (x*A*B).kind == OperatorKind + assert (x*k*b).kind == OperatorKind # outer product + + +def test_undefind_kind(): + # Because of limitations in the kind dispatcher API, we are currently + # unable to have OperatorKind*KetKind -> KetKind (and similar for bras). + assert (A*k).kind == UndefinedKind + assert (b*A).kind == UndefinedKind + assert (x*b*A*k).kind == UndefinedKind + + +def test_dagger_kind(): + assert Dagger(k).kind == BraKind + assert Dagger(b).kind == KetKind + assert Dagger(A).kind == OperatorKind + + +def test_commutator_kind(): + assert Commutator(A, B).kind == OperatorKind + assert Commutator(A, x*B).kind == OperatorKind + assert Commutator(x*A, B).kind == OperatorKind + assert Commutator(x*A, x*B).kind == OperatorKind + + +def test_anticommutator_kind(): + assert AntiCommutator(A, B).kind == OperatorKind + assert AntiCommutator(A, x*B).kind == OperatorKind + assert AntiCommutator(x*A, B).kind == OperatorKind + assert AntiCommutator(x*A, x*B).kind == OperatorKind + + +def test_tensorproduct_kind(): + assert TensorProduct(k,k).kind == KetKind + assert TensorProduct(b,b).kind == BraKind + assert TensorProduct(x*k,y*k).kind == KetKind + assert TensorProduct(x*b,y*b).kind == BraKind + assert TensorProduct(x*b*k, y*b*k).kind == NumberKind + assert TensorProduct(x*k*b, y*k*b).kind == OperatorKind + assert TensorProduct(A, B).kind == OperatorKind + assert TensorProduct(A, x*B).kind == OperatorKind + assert TensorProduct(x*A, B).kind == OperatorKind diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_matrixutils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_matrixutils.py new file mode 100644 index 0000000000000000000000000000000000000000..4d4fa8a0a2a4374d200473fa03c68fc453262a4c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_matrixutils.py @@ -0,0 +1,136 @@ +from sympy.core.random import randint + +from sympy.core.numbers import Integer +from sympy.matrices.dense import (Matrix, ones, zeros) + +from sympy.physics.quantum.matrixutils import ( + to_sympy, to_numpy, to_scipy_sparse, matrix_tensor_product, + matrix_to_zero, matrix_zeros, numpy_ndarray, scipy_sparse_matrix +) + +from sympy.external import import_module +from sympy.testing.pytest import skip + +m = Matrix([[1, 2], [3, 4]]) + + +def test_sympy_to_sympy(): + assert to_sympy(m) == m + + +def test_matrix_to_zero(): + assert matrix_to_zero(m) == m + assert matrix_to_zero(Matrix([[0, 0], [0, 0]])) == Integer(0) + +np = import_module('numpy') + + +def test_to_numpy(): + if not np: + skip("numpy not installed.") + + result = np.array([[1, 2], [3, 4]], dtype='complex') + assert (to_numpy(m) == result).all() + + +def test_matrix_tensor_product(): + if not np: + skip("numpy not installed.") + + l1 = zeros(4) + for i in range(16): + l1[i] = 2**i + l2 = zeros(4) + for i in range(16): + l2[i] = i + l3 = zeros(2) + for i in range(4): + l3[i] = i + vec = Matrix([1, 2, 3]) + + #test for Matrix known 4x4 matrices + numpyl1 = np.array(l1.tolist()) + numpyl2 = np.array(l2.tolist()) + 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) + 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.array(l3.tolist()) + 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) + args = [l3, l1] + sympy_product = matrix_tensor_product(*args) + assert numpy_product.tolist() == sympy_product.tolist() + + #test for non square matrix + numpyl2 = np.array(vec.tolist()) + 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) + 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(randint(1, 5), randint(1, 5)) + random_matrix2 = np.random.rand(randint(1, 5), randint(1, 5)) + 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() + + #test for three matrix kronecker + sympy_product = matrix_tensor_product(l1, 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']}) + + +def test_to_scipy_sparse(): + if not np: + skip("numpy not installed.") + if not scipy: + skip("scipy not installed.") + else: + sparse = scipy.sparse + + 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.") + + num = matrix_zeros(4, 4, format='numpy') + assert isinstance(num, numpy_ndarray) + +def test_matrix_zeros_scipy(): + if not np: + skip("numpy not installed.") + if not scipy: + skip("scipy not installed.") + + sci = matrix_zeros(4, 4, format='scipy.sparse') + assert isinstance(sci, scipy_sparse_matrix) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_operator.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_operator.py new file mode 100644 index 0000000000000000000000000000000000000000..100cacd9a800f7c4435b93672ef77877a3a99e5e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_operator.py @@ -0,0 +1,269 @@ +from sympy.core.function import (Derivative, Function, diff) +from sympy.core.mul import Mul +from sympy.core.numbers import (Integer, pi) +from sympy.core.symbol import (Symbol, symbols) +from sympy.core.sympify import sympify +from sympy.functions.elementary.trigonometric import sin +from sympy.physics.quantum.qexpr import QExpr +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.hilbert import HilbertSpace +from sympy.physics.quantum.operator import (Operator, UnitaryOperator, + HermitianOperator, OuterProduct, + DifferentialOperator, + IdentityOperator) +from sympy.physics.quantum.state import Ket, Bra, Wavefunction +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.represent import represent +from sympy.physics.quantum.spin import JzKet, JzBra +from sympy.physics.quantum.trace import Tr +from sympy.matrices import eye + +from sympy.testing.pytest import warns_deprecated_sympy + + +class CustomKet(Ket): + @classmethod + def default_args(self): + return ("t",) + + +class CustomOp(HermitianOperator): + @classmethod + def default_args(self): + return ("T",) + +t_ket = CustomKet() +t_op = CustomOp() + + +def test_operator(): + A = Operator('A') + B = Operator('B') + C = Operator('C') + + assert isinstance(A, Operator) + assert isinstance(A, QExpr) + + assert A.label == (Symbol('A'),) + 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 t_op.label[0] == Symbol(t_op.default_args()[0]) + + assert Operator() == Operator("O") + with warns_deprecated_sympy(): + assert A*IdentityOperator() == A + + +def test_operator_inv(): + A = Operator('A') + assert A*A.inv() == 1 + assert A.inv()*A == 1 + + +def test_hermitian(): + H = HermitianOperator('H') + + assert isinstance(H, HermitianOperator) + assert isinstance(H, Operator) + + assert Dagger(H) == H + assert H.inv() != H + assert H.is_commutative is False + assert Dagger(H).is_commutative is False + + +def test_unitary(): + U = UnitaryOperator('U') + + assert isinstance(U, UnitaryOperator) + assert isinstance(U, Operator) + + assert U.inv() == Dagger(U) + assert U*Dagger(U) == 1 + assert Dagger(U)*U == 1 + assert U.is_commutative is False + assert Dagger(U).is_commutative is False + + +def test_identity(): + with warns_deprecated_sympy(): + I = IdentityOperator() + O = Operator('O') + x = Symbol("x") + three = sympify(3) + + assert isinstance(I, IdentityOperator) + assert isinstance(I, Operator) + + assert I * O == O + assert O * I == O + assert I * Dagger(O) == Dagger(O) + assert Dagger(O) * I == Dagger(O) + assert isinstance(I * I, IdentityOperator) + assert three * I == three + assert I * x == x + assert I.inv() == I + assert Dagger(I) == I + assert qapply(I * O) == O + assert qapply(O * I) == O + + for n in [2, 3, 5]: + assert represent(IdentityOperator(n)) == eye(n) + + +def test_outer_product(): + k = Ket('k') + b = Bra('b') + op = OuterProduct(k, b) + + assert isinstance(op, OuterProduct) + assert isinstance(op, Operator) + + assert op.ket == k + assert op.bra == b + assert op.label == (k, b) + assert op.is_commutative is False + + op = k*b + + assert isinstance(op, OuterProduct) + assert isinstance(op, Operator) + + assert op.ket == k + assert op.bra == b + assert op.label == (k, b) + assert op.is_commutative is False + + op = 2*k*b + + assert op == Mul(Integer(2), k, b) + + op = 2*(k*b) + + assert op == Mul(Integer(2), OuterProduct(k, b)) + + 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 + + # test scaled kets and bras + assert OuterProduct(2 * k, b) == 2 * OuterProduct(k, b) + assert OuterProduct(k, 2 * b) == 2 * OuterProduct(k, b) + + # test sums of kets and bras + k1, k2 = Ket('k1'), Ket('k2') + b1, b2 = Bra('b1'), Bra('b2') + assert (OuterProduct(k1 + k2, b1) == + OuterProduct(k1, b1) + OuterProduct(k2, b1)) + assert (OuterProduct(k1, b1 + b2) == + OuterProduct(k1, b1) + OuterProduct(k1, b2)) + assert (OuterProduct(1 * k1 + 2 * k2, 3 * b1 + 4 * b2) == + 3 * OuterProduct(k1, b1) + + 4 * OuterProduct(k1, b2) + + 6 * OuterProduct(k2, b1) + + 8 * OuterProduct(k2, b2)) + + +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**2) == Dagger(A)**2 + + +def test_differential_operator(): + x = Symbol('x') + f = Function('f') + d = DifferentialOperator(Derivative(f(x), x), f(x)) + g = Wavefunction(x**2, x) + assert qapply(d*g) == Wavefunction(2*x, x) + assert d.expr == Derivative(f(x), x) + assert d.function == f(x) + assert d.variables == (x,) + assert diff(d, x) == DifferentialOperator(Derivative(f(x), x, 2), f(x)) + + d = DifferentialOperator(Derivative(f(x), x, 2), f(x)) + g = Wavefunction(x**3, x) + assert qapply(d*g) == Wavefunction(6*x, x) + assert d.expr == Derivative(f(x), x, 2) + assert d.function == f(x) + assert d.variables == (x,) + assert diff(d, x) == DifferentialOperator(Derivative(f(x), x, 3), f(x)) + + d = DifferentialOperator(1/x*Derivative(f(x), x), f(x)) + assert d.expr == 1/x*Derivative(f(x), x) + assert d.function == f(x) + assert d.variables == (x,) + assert diff(d, 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) + + 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)) + 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, + x, y) + + # 2D polar Laplacian (th = theta) + r, th = symbols('r th') + 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) + assert d.function == f(r, th) + assert d.variables == (r, th) + assert diff(d, r) == \ + DifferentialOperator(Derivative(d.expr, r), f(r, th)) + assert diff(d, th) == \ + DifferentialOperator(Derivative(d.expr, th), f(r, th)) + assert qapply(d*w) == Wavefunction(3*sin(th), r, (th, 0, pi)) + + +def test_eval_power(): + from sympy.core import Pow + from sympy.core.expr import unchanged + O = Operator('O') + U = UnitaryOperator('U') + H = HermitianOperator('H') + assert O**-1 == O.inv() # same as doc test + assert U**-1 == U.inv() + assert H**-1 == H.inv() + x = symbols("x", commutative = True) + assert unchanged(Pow, H, x) # verify Pow(H,x)=="X^n" + assert H**x == Pow(H, x) + assert Pow(H,x) == Pow(H, x, evaluate=False) # Just check + from sympy.physics.quantum.gate import XGate + X = XGate(0) # is hermitian and unitary + assert unchanged(Pow, X, x) # verify Pow(X,x)=="X^x" + assert X**x == Pow(X, x) + assert Pow(X, x, evaluate=False) == Pow(X, x) # Just check + n = symbols("n", integer=True, even=True) + assert X**n == 1 + n = symbols("n", integer=True, odd=True) + assert X**n == X + n = symbols("n", integer=True) + assert unchanged(Pow, X, n) # verify Pow(X,n)=="X^n" + assert X**n == Pow(X, n) + assert Pow(X, n, evaluate=False)==Pow(X, n) # Just check + assert X**4 == 1 + assert X**7 == X diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_operatorordering.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_operatorordering.py new file mode 100644 index 0000000000000000000000000000000000000000..f5255d555d1582b694dfe4ed681d894136ea0b70 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_operatorordering.py @@ -0,0 +1,50 @@ +from sympy.physics.quantum import Dagger +from sympy.physics.quantum.boson import BosonOp +from sympy.physics.quantum.fermion import FermionOp +from sympy.physics.quantum.operatorordering import (normal_order, + normal_ordered_form) + + +def test_normal_order(): + a = BosonOp('a') + + c = FermionOp('c') + + assert normal_order(a * Dagger(a)) == Dagger(a) * a + assert normal_order(Dagger(a) * a) == Dagger(a) * a + assert normal_order(a * Dagger(a) ** 2) == Dagger(a) ** 2 * a + + assert normal_order(c * Dagger(c)) == - Dagger(c) * c + assert normal_order(Dagger(c) * c) == Dagger(c) * c + assert normal_order(c * Dagger(c) ** 2) == Dagger(c) ** 2 * c + + +def test_normal_ordered_form(): + a = BosonOp('a') + b = BosonOp('b') + + c = FermionOp('c') + d = FermionOp('d') + + assert normal_ordered_form(Dagger(a) * a) == Dagger(a) * a + assert normal_ordered_form(a * Dagger(a)) == 1 + Dagger(a) * a + assert normal_ordered_form(a ** 2 * Dagger(a)) == \ + 2 * a + Dagger(a) * a ** 2 + assert normal_ordered_form(a ** 3 * Dagger(a)) == \ + 3 * a ** 2 + Dagger(a) * a ** 3 + + assert normal_ordered_form(Dagger(c) * c) == Dagger(c) * c + assert normal_ordered_form(c * Dagger(c)) == 1 - Dagger(c) * c + assert normal_ordered_form(c ** 2 * Dagger(c)) == Dagger(c) * c ** 2 + assert normal_ordered_form(c ** 3 * Dagger(c)) == \ + c ** 2 - Dagger(c) * c ** 3 + + assert normal_ordered_form(a * Dagger(b), True) == Dagger(b) * a + assert normal_ordered_form(Dagger(a) * b, True) == Dagger(a) * b + assert normal_ordered_form(b * a, True) == a * b + assert normal_ordered_form(Dagger(b) * Dagger(a), True) == Dagger(a) * Dagger(b) + + assert normal_ordered_form(c * Dagger(d), True) == -Dagger(d) * c + assert normal_ordered_form(Dagger(c) * d, True) == Dagger(c) * d + assert normal_ordered_form(d * c, True) == -c * d + assert normal_ordered_form(Dagger(d) * Dagger(c), True) == -Dagger(c) * Dagger(d) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_operatorset.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_operatorset.py new file mode 100644 index 0000000000000000000000000000000000000000..fff038bb12a7e6aa100ac00b0e145dc323a77e4d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_operatorset.py @@ -0,0 +1,68 @@ +from sympy.core.singleton import S + +from sympy.physics.quantum.operatorset import ( + operators_to_state, state_to_operators +) + +from sympy.physics.quantum.cartesian import ( + XOp, XKet, PxOp, PxKet, XBra, PxBra +) + +from sympy.physics.quantum.state import Ket, Bra +from sympy.physics.quantum.operator import Operator +from sympy.physics.quantum.spin import ( + JxKet, JyKet, JzKet, JxBra, JyBra, JzBra, + JxOp, JyOp, JzOp, J2Op +) + +from sympy.testing.pytest import raises + + +def test_spin(): + assert operators_to_state({J2Op, JxOp}) == JxKet + assert operators_to_state({J2Op, JyOp}) == JyKet + assert operators_to_state({J2Op, JzOp}) == JzKet + assert operators_to_state({J2Op(), JxOp()}) == JxKet + assert operators_to_state({J2Op(), JyOp()}) == JyKet + assert operators_to_state({J2Op(), JzOp()}) == JzKet + + assert state_to_operators(JxKet) == {J2Op, JxOp} + assert state_to_operators(JyKet) == {J2Op, JyOp} + assert state_to_operators(JzKet) == {J2Op, JzOp} + assert state_to_operators(JxBra) == {J2Op, JxOp} + assert state_to_operators(JyBra) == {J2Op, JyOp} + assert state_to_operators(JzBra) == {J2Op, JzOp} + + assert state_to_operators(JxKet(S.Half, S.Half)) == {J2Op(), JxOp()} + assert state_to_operators(JyKet(S.Half, S.Half)) == {J2Op(), JyOp()} + assert state_to_operators(JzKet(S.Half, S.Half)) == {J2Op(), JzOp()} + assert state_to_operators(JxBra(S.Half, S.Half)) == {J2Op(), JxOp()} + assert state_to_operators(JyBra(S.Half, S.Half)) == {J2Op(), JyOp()} + assert state_to_operators(JzBra(S.Half, S.Half)) == {J2Op(), JzOp()} + + +def test_op_to_state(): + assert operators_to_state(XOp) == XKet() + assert operators_to_state(PxOp) == PxKet() + assert operators_to_state(Operator) == Ket() + + assert state_to_operators(operators_to_state(XOp("Q"))) == XOp("Q") + assert state_to_operators(operators_to_state(XOp())) == XOp() + + raises(NotImplementedError, lambda: operators_to_state(XKet)) + + +def test_state_to_op(): + assert state_to_operators(XKet) == XOp() + assert state_to_operators(PxKet) == PxOp() + assert state_to_operators(XBra) == XOp() + assert state_to_operators(PxBra) == PxOp() + assert state_to_operators(Ket) == Operator() + assert state_to_operators(Bra) == Operator() + + assert operators_to_state(state_to_operators(XKet("test"))) == XKet("test") + assert operators_to_state(state_to_operators(XBra("test"))) == XKet("test") + assert operators_to_state(state_to_operators(XKet())) == XKet() + assert operators_to_state(state_to_operators(XBra())) == XKet() + + raises(NotImplementedError, lambda: state_to_operators(XOp)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_pauli.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_pauli.py new file mode 100644 index 0000000000000000000000000000000000000000..77bbed93ac5b4b49680be01aefa2f779b62fc7ee --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_pauli.py @@ -0,0 +1,159 @@ +from sympy.core.mul import Mul +from sympy.core.numbers import I +from sympy.matrices.dense import Matrix +from sympy.printing.latex import latex +from sympy.physics.quantum import (Dagger, Commutator, AntiCommutator, qapply, + Operator, represent) +from sympy.physics.quantum.pauli import (SigmaOpBase, SigmaX, SigmaY, SigmaZ, + SigmaMinus, SigmaPlus, + qsimplify_pauli) +from sympy.physics.quantum.pauli import SigmaZKet, SigmaZBra +from sympy.testing.pytest import raises + + +sx, sy, sz = SigmaX(), SigmaY(), SigmaZ() +sx1, sy1, sz1 = SigmaX(1), SigmaY(1), SigmaZ(1) +sx2, sy2, sz2 = SigmaX(2), SigmaY(2), SigmaZ(2) + +sm, sp = SigmaMinus(), SigmaPlus() +sm1, sp1 = SigmaMinus(1), SigmaPlus(1) +A, B = Operator("A"), Operator("B") + + +def test_pauli_operators_types(): + + assert isinstance(sx, SigmaOpBase) and isinstance(sx, SigmaX) + assert isinstance(sy, SigmaOpBase) and isinstance(sy, SigmaY) + assert isinstance(sz, SigmaOpBase) and isinstance(sz, SigmaZ) + assert isinstance(sm, SigmaOpBase) and isinstance(sm, SigmaMinus) + assert isinstance(sp, SigmaOpBase) and isinstance(sp, SigmaPlus) + + +def test_pauli_operators_commutator(): + + assert Commutator(sx, sy).doit() == 2 * I * sz + assert Commutator(sy, sz).doit() == 2 * I * sx + assert Commutator(sz, sx).doit() == 2 * I * sy + + +def test_pauli_operators_commutator_with_labels(): + + assert Commutator(sx1, sy1).doit() == 2 * I * sz1 + assert Commutator(sy1, sz1).doit() == 2 * I * sx1 + assert Commutator(sz1, sx1).doit() == 2 * I * sy1 + + assert Commutator(sx2, sy2).doit() == 2 * I * sz2 + assert Commutator(sy2, sz2).doit() == 2 * I * sx2 + assert Commutator(sz2, sx2).doit() == 2 * I * sy2 + + assert Commutator(sx1, sy2).doit() == 0 + assert Commutator(sy1, sz2).doit() == 0 + assert Commutator(sz1, sx2).doit() == 0 + + +def test_pauli_operators_anticommutator(): + + assert AntiCommutator(sy, sz).doit() == 0 + assert AntiCommutator(sz, sx).doit() == 0 + assert AntiCommutator(sx, sm).doit() == 1 + assert AntiCommutator(sx, sp).doit() == 1 + + +def test_pauli_operators_adjoint(): + + assert Dagger(sx) == sx + assert Dagger(sy) == sy + assert Dagger(sz) == sz + + +def test_pauli_operators_adjoint_with_labels(): + + assert Dagger(sx1) == sx1 + assert Dagger(sy1) == sy1 + assert Dagger(sz1) == sz1 + + assert Dagger(sx1) != sx2 + assert Dagger(sy1) != sy2 + assert Dagger(sz1) != sz2 + + +def test_pauli_operators_multiplication(): + + assert qsimplify_pauli(sx * sx) == 1 + assert qsimplify_pauli(sy * sy) == 1 + assert qsimplify_pauli(sz * sz) == 1 + + assert qsimplify_pauli(sx * sy) == I * sz + assert qsimplify_pauli(sy * sz) == I * sx + assert qsimplify_pauli(sz * sx) == I * sy + + assert qsimplify_pauli(sy * sx) == - I * sz + assert qsimplify_pauli(sz * sy) == - I * sx + assert qsimplify_pauli(sx * sz) == - I * sy + + +def test_pauli_operators_multiplication_with_labels(): + + assert qsimplify_pauli(sx1 * sx1) == 1 + assert qsimplify_pauli(sy1 * sy1) == 1 + assert qsimplify_pauli(sz1 * sz1) == 1 + + assert isinstance(sx1 * sx2, Mul) + assert isinstance(sy1 * sy2, Mul) + assert isinstance(sz1 * sz2, Mul) + + assert qsimplify_pauli(sx1 * sy1 * sx2 * sy2) == - sz1 * sz2 + assert qsimplify_pauli(sy1 * sz1 * sz2 * sx2) == - sx1 * sy2 + + +def test_pauli_states(): + sx, sz = SigmaX(), SigmaZ() + + up = SigmaZKet(0) + down = SigmaZKet(1) + + assert qapply(sx * up) == down + assert qapply(sx * down) == up + assert qapply(sz * up) == up + assert qapply(sz * down) == - down + + up = SigmaZBra(0) + down = SigmaZBra(1) + + assert qapply(up * sx, dagger=True) == down + assert qapply(down * sx, dagger=True) == up + assert qapply(up * sz, dagger=True) == up + assert qapply(down * sz, dagger=True) == - down + + assert Dagger(SigmaZKet(0)) == SigmaZBra(0) + assert Dagger(SigmaZBra(1)) == SigmaZKet(1) + raises(ValueError, lambda: SigmaZBra(2)) + raises(ValueError, lambda: SigmaZKet(2)) + + +def test_use_name(): + assert sm.use_name is False + assert sm1.use_name is True + assert sx.use_name is False + assert sx1.use_name is True + + +def test_printing(): + assert latex(sx) == r'{\sigma_x}' + assert latex(sx1) == r'{\sigma_x^{(1)}}' + assert latex(sy) == r'{\sigma_y}' + assert latex(sy1) == r'{\sigma_y^{(1)}}' + assert latex(sz) == r'{\sigma_z}' + assert latex(sz1) == r'{\sigma_z^{(1)}}' + assert latex(sm) == r'{\sigma_-}' + assert latex(sm1) == r'{\sigma_-^{(1)}}' + assert latex(sp) == r'{\sigma_+}' + assert latex(sp1) == r'{\sigma_+^{(1)}}' + + +def test_represent(): + assert represent(sx) == Matrix([[0, 1], [1, 0]]) + assert represent(sy) == Matrix([[0, -I], [I, 0]]) + assert represent(sz) == Matrix([[1, 0], [0, -1]]) + assert represent(sm) == Matrix([[0, 0], [1, 0]]) + assert represent(sp) == Matrix([[0, 1], [0, 0]]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_piab.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_piab.py new file mode 100644 index 0000000000000000000000000000000000000000..3a4c2540b3269593c74bdbae93bf72d131a94ed9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_piab.py @@ -0,0 +1,29 @@ +"""Tests for piab.py""" + +from sympy.core.numbers import pi +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin +from sympy.sets.sets import Interval +from sympy.functions.special.tensor_functions import KroneckerDelta +from sympy.physics.quantum import L2, qapply, hbar, represent +from sympy.physics.quantum.piab import PIABHamiltonian, PIABKet, PIABBra, m, L + +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)) == \ + (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 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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_printing.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_printing.py new file mode 100644 index 0000000000000000000000000000000000000000..ce4004cee2f9e57b1c9e435f13a6850b92d929b3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_printing.py @@ -0,0 +1,900 @@ +# -*- encoding: utf-8 -*- +""" +TODO: +* Address Issue 2251, printing of spin states +""" +from __future__ import annotations +from typing import Any + +from sympy.physics.quantum.anticommutator import AntiCommutator +from sympy.physics.quantum.cg import CG, Wigner3j, Wigner6j, Wigner9j +from sympy.physics.quantum.commutator import Commutator +from sympy.physics.quantum.constants import hbar +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.gate import CGate, CNotGate, IdentityGate, UGate, XGate +from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace, HilbertSpace, L2 +from sympy.physics.quantum.innerproduct import InnerProduct +from sympy.physics.quantum.operator import Operator, OuterProduct, DifferentialOperator +from sympy.physics.quantum.qexpr import QExpr +from sympy.physics.quantum.qubit import Qubit, IntQubit +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.core.function import (Derivative, Function) +from sympy.core.numbers import oo +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.matrices.dense import Matrix +from sympy.sets.sets import Interval +from sympy.testing.pytest import XFAIL + +# Imports used in srepr strings +from sympy.physics.quantum.spin import JzOp + +from sympy.printing import srepr +from sympy.printing.pretty import pretty as xpretty +from sympy.printing.latex import latex + +MutableDenseMatrix = Matrix + + +ENV: dict[str, Any] = {} +exec('from sympy import *', ENV) +exec('from sympy.physics.quantum import *', ENV) +exec('from sympy.physics.quantum.cg import *', ENV) +exec('from sympy.physics.quantum.spin import *', ENV) +exec('from sympy.physics.quantum.hilbert import *', ENV) +exec('from sympy.physics.quantum.qubit import *', ENV) +exec('from sympy.physics.quantum.qexpr import *', ENV) +exec('from sympy.physics.quantum.gate import *', ENV) +exec('from sympy.physics.quantum.constants import *', ENV) + + +def sT(expr, string): + """ + sT := sreprTest + from sympy/printing/tests/test_repr.py + """ + assert srepr(expr) == string + assert eval(string, ENV) == 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) + + +def test_anticommutator(): + A = Operator('A') + B = Operator('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}' + assert latex(ac) == r'\left\{A,B\right\}' + sT(ac, "AntiCommutator(Operator(Symbol('A')),Operator(Symbol('B')))") + assert str(ac_tall) == '{A**2,B}' + ascii_str = \ +"""\ +/ 2 \\\n\ +\n\ +\\ /\ +""" + ucode_str = \ +"""\ +⎧ 2 ⎫\n\ +⎨A ,B⎬\n\ +⎩ ⎭\ +""" + assert pretty(ac_tall) == ascii_str + assert upretty(ac_tall) == ucode_str + assert latex(ac_tall) == r'\left\{A^{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) + 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) + assert str(cg) == 'CG(1, 2, 3, 4, 5, 6)' + ascii_str = \ +"""\ + 5,6 \n\ +C \n\ + 1,2,3,4\ +""" + ucode_str = \ +"""\ + 5,6 \n\ +C \n\ + 1,2,3,4\ +""" + assert pretty(cg) == ascii_str + assert upretty(cg) == ucode_str + assert latex(cg) == 'C^{5,6}_{1,2,3,4}' + assert latex(cg ** 2) == R'\left(C^{5,6}_{1,2,3,4}\right)^{2}' + sT(cg, "CG(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6))") + assert str(wigner3j) == 'Wigner3j(1, 2, 3, 4, 5, 6)' + ascii_str = \ +"""\ +/1 3 5\\\n\ +| |\n\ +\\2 4 6/\ +""" + ucode_str = \ +"""\ +⎛1 3 5⎞\n\ +⎜ ⎟\n\ +⎝2 4 6⎠\ +""" + assert pretty(wigner3j) == ascii_str + assert upretty(wigner3j) == ucode_str + assert latex(wigner3j) == \ + r'\left(\begin{array}{ccc} 1 & 3 & 5 \\ 2 & 4 & 6 \end{array}\right)' + sT(wigner3j, "Wigner3j(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6))") + assert str(wigner6j) == 'Wigner6j(1, 2, 3, 4, 5, 6)' + ascii_str = \ +"""\ +/1 2 3\\\n\ +< >\n\ +\\4 5 6/\ +""" + ucode_str = \ +"""\ +⎧1 2 3⎫\n\ +⎨ ⎬\n\ +⎩4 5 6⎭\ +""" + assert pretty(wigner6j) == ascii_str + assert upretty(wigner6j) == ucode_str + assert latex(wigner6j) == \ + r'\left\{\begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \end{array}\right\}' + sT(wigner6j, "Wigner6j(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6))") + assert str(wigner9j) == 'Wigner9j(1, 2, 3, 4, 5, 6, 7, 8, 9)' + ascii_str = \ +"""\ +/1 2 3\\\n\ +| |\n\ +<4 5 6>\n\ +| |\n\ +\\7 8 9/\ +""" + ucode_str = \ +"""\ +⎧1 2 3⎫\n\ +⎪ ⎪\n\ +⎨4 5 6⎬\n\ +⎪ ⎪\n\ +⎩7 8 9⎭\ +""" + assert pretty(wigner9j) == ascii_str + assert upretty(wigner9j) == ucode_str + assert latex(wigner9j) == \ + 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') + c = Commutator(A, B) + c_tall = Commutator(A**2, B) + assert str(c) == '[A,B]' + assert pretty(c) == '[A,B]' + assert upretty(c) == '[A,B]' + assert latex(c) == r'\left[A,B\right]' + sT(c, "Commutator(Operator(Symbol('A')),Operator(Symbol('B')))") + assert str(c_tall) == '[A**2,B]' + ascii_str = \ +"""\ +[ 2 ]\n\ +[A ,B]\ +""" + ucode_str = \ +"""\ +⎡ 2 ⎤\n\ +⎣A ,B⎦\ +""" + assert pretty(c_tall) == ascii_str + assert upretty(c_tall) == ucode_str + assert latex(c_tall) == r'\left[A^{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' + assert upretty(hbar) == 'ℏ' + assert latex(hbar) == r'\hbar' + sT(hbar, "HBar()") + + +def test_dagger(): + x = symbols('x', commutative=False) + expr = Dagger(x) + assert str(expr) == 'Dagger(x)' + ascii_str = \ +"""\ + +\n\ +x \ +""" + ucode_str = \ +"""\ + †\n\ +x \ +""" + assert pretty(expr) == ascii_str + assert upretty(expr) == ucode_str + assert latex(expr) == r'x^{\dagger}' + sT(expr, "Dagger(Symbol('x', commutative=False))") + + +@XFAIL +def test_gate_failing(): + 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) + g1 = IdentityGate(2) + 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' + assert upretty(g1) == '1 \n 2' + assert latex(g1) == r'1_{2}' + sT(g1, "IdentityGate(Integer(2))") + assert str(g1*q) == '1(2)*|10101>' + ascii_str = \ +"""\ +1 *|10101>\n\ + 2 \ +""" + ucode_str = \ +"""\ +1 ⋅❘10101⟩\n\ + 2 \ +""" + assert pretty(g1*q) == ascii_str + assert upretty(g1*q) == ucode_str + assert latex(g1*q) == r'1_{2} {\left|10101\right\rangle }' + sT(g1*q, "Mul(IdentityGate(Integer(2)), Qubit(Integer(1),Integer(0),Integer(1),Integer(0),Integer(1)))") + assert str(g2) == 'C((3,0),X(1))' + ascii_str = \ +"""\ +C /X \\\n\ + 3,0\\ 1/\ +""" + ucode_str = \ +"""\ +C ⎛X ⎞\n\ + 3,0⎝ 1⎠\ +""" + assert pretty(g2) == ascii_str + assert upretty(g2) == ucode_str + assert latex(g2) == r'C_{3,0}{\left(X_{1}\right)}' + sT(g2, "CGate(Tuple(Integer(3), Integer(0)),XGate(Integer(1)))") + assert str(g3) == 'CNOT(1,0)' + ascii_str = \ +"""\ +CNOT \n\ + 1,0\ +""" + ucode_str = \ +"""\ +CNOT \n\ + 1,0\ +""" + assert pretty(g3) == ascii_str + assert upretty(g3) == ucode_str + assert latex(g3) == r'\text{CNOT}_{1,0}' + sT(g3, "CNotGate(Integer(1),Integer(0))") + ascii_str = \ +"""\ +U \n\ + 0\ +""" + ucode_str = \ +"""\ +U \n\ + 0\ +""" + assert str(g4) == \ +"""\ +U((0,),Matrix([\n\ +[a, b],\n\ +[c, d]]))\ +""" + assert pretty(g4) == ascii_str + assert upretty(g4) == ucode_str + assert latex(g4) == r'U_{0}' + sT(g4, "UGate(Tuple(Integer(0)),ImmutableDenseMatrix([[Symbol('a'), Symbol('b')], [Symbol('c'), Symbol('d')]]))") + + +def test_hilbert(): + h1 = HilbertSpace() + h2 = ComplexSpace(2) + h3 = FockSpace() + h4 = L2(Interval(0, oo)) + assert str(h1) == 'H' + assert pretty(h1) == 'H' + assert upretty(h1) == 'H' + assert latex(h1) == r'\mathcal{H}' + sT(h1, "HilbertSpace()") + assert str(h2) == 'C(2)' + ascii_str = \ +"""\ + 2\n\ +C \ +""" + ucode_str = \ +"""\ + 2\n\ +C \ +""" + assert pretty(h2) == ascii_str + assert upretty(h2) == ucode_str + assert latex(h2) == r'\mathcal{C}^{2}' + sT(h2, "ComplexSpace(Integer(2))") + assert str(h3) == 'F' + assert pretty(h3) == 'F' + assert upretty(h3) == 'F' + assert latex(h3) == r'\mathcal{F}' + sT(h3, "FockSpace()") + assert str(h4) == 'L2(Interval(0, oo))' + ascii_str = \ +"""\ + 2\n\ +L \ +""" + ucode_str = \ +"""\ + 2\n\ +L \ +""" + assert pretty(h4) == ascii_str + 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)' + ascii_str = \ +"""\ + 2\n\ +H + C \ +""" + ucode_str = \ +"""\ + 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 str(h1*h2) == "H*C(2)" + ascii_str = \ +"""\ + 2\n\ +H x C \ +""" + ucode_str = \ +"""\ + 2\n\ +H ⨂ C \ +""" + assert pretty(h1*h2) == ascii_str + assert upretty(h1*h2) == ucode_str + assert latex(h1*h2) + sT(h1*h2, + "TensorProductHilbertSpace(HilbertSpace(),ComplexSpace(Integer(2)))") + assert str(h1**2) == 'H**2' + ascii_str = \ +"""\ + x2\n\ +H \ +""" + ucode_str = \ +"""\ + ⨂2\n\ +H \ +""" + assert pretty(h1**2) == ascii_str + assert upretty(h1**2) == ucode_str + 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))) + 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 }' + sT(ip1, "InnerProduct(Bra(Symbol('psi')),Ket(Symbol('psi')))") + assert str(ip2) == '' + assert pretty(ip2) == '' + assert upretty(ip2) == '⟨ψ;t❘ψ;t⟩' + assert latex(ip2) == \ + r'\left\langle \psi;t \right. {\left|\psi;t\right\rangle }' + sT(ip2, "InnerProduct(TimeDepBra(Symbol('psi'),Symbol('t')),TimeDepKet(Symbol('psi'),Symbol('t')))") + assert str(ip3) == "<1,1|1,1>" + assert pretty(ip3) == '<1,1|1,1>' + assert upretty(ip3) == '⟨1,1❘1,1⟩' + assert latex(ip3) == r'\left\langle 1,1 \right. {\left|1,1\right\rangle }' + sT(ip3, "InnerProduct(JzBra(Integer(1),Integer(1)),JzKet(Integer(1),Integer(1)))") + assert str(ip4) == "<1,1,j1=1,j2=1|1,1,j1=1,j2=1>" + assert pretty(ip4) == '<1,1,j1=1,j2=1|1,1,j1=1,j2=1>' + assert upretty(ip4) == '⟨1,1,j₁=1,j₂=1❘1,1,j₁=1,j₂=1⟩' + assert latex(ip4) == \ + r'\left\langle 1,1,j_{1}=1,j_{2}=1 \right. {\left|1,1,j_{1}=1,j_{2}=1\right\rangle }' + sT(ip4, "InnerProduct(JzBraCoupled(Integer(1),Integer(1),Tuple(Integer(1), Integer(1)),Tuple(Tuple(Integer(1), Integer(2), Integer(1)))),JzKetCoupled(Integer(1),Integer(1),Tuple(Integer(1), Integer(1)),Tuple(Tuple(Integer(1), Integer(2), Integer(1)))))") + assert str(ip_tall1) == '' + ascii_str = \ +"""\ + / | \\ \n\ +/ x|x \\\n\ +\\ -|- /\n\ + \\2|2/ \ +""" + ucode_str = \ +"""\ + ╱ │ ╲ \n\ +╱ x│x ╲\n\ +╲ ─│─ ╱\n\ + ╲2│2╱ \ +""" + assert pretty(ip_tall1) == ascii_str + assert upretty(ip_tall1) == ucode_str + assert latex(ip_tall1) == \ + 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 = \ +"""\ + / | \\ \n\ +/ |x \\\n\ +\\ x|- /\n\ + \\ |2/ \ +""" + ucode_str = \ +"""\ + ╱ │ ╲ \n\ +╱ │x ╲\n\ +╲ x│─ ╱\n\ + ╲ │2╱ \ +""" + assert pretty(ip_tall2) == ascii_str + assert upretty(ip_tall2) == ucode_str + assert latex(ip_tall2) == \ + 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 = \ +"""\ + / | \\ \n\ +/ x| \\\n\ +\\ -|x /\n\ + \\2| / \ +""" + ucode_str = \ +"""\ + ╱ │ ╲ \n\ +╱ x│ ╲\n\ +╲ ─│x ╱\n\ + ╲2│ ╱ \ +""" + assert pretty(ip_tall3) == ascii_str + assert upretty(ip_tall3) == ucode_str + assert latex(ip_tall3) == \ + 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') + b = Operator('B', Symbol('t'), S.Half) + inv = a.inv() + f = Function('f') + x = symbols('x') + d = DifferentialOperator(Derivative(f(x), x), f(x)) + op = OuterProduct(Ket(), Bra()) + assert str(a) == 'A' + assert pretty(a) == 'A' + assert upretty(a) == 'A' + assert latex(a) == 'A' + sT(a, "Operator(Symbol('A'))") + assert str(inv) == 'A**(-1)' + ascii_str = \ +"""\ + -1\n\ +A \ +""" + ucode_str = \ +"""\ + -1\n\ +A \ +""" + assert pretty(inv) == ascii_str + assert upretty(inv) == ucode_str + assert latex(inv) == r'A^{-1}' + sT(inv, "Pow(Operator(Symbol('A')), Integer(-1))") + assert str(d) == 'DifferentialOperator(Derivative(f(x), x),f(x))' + ascii_str = \ +"""\ + /d \\\n\ +DifferentialOperator|--(f(x)),f(x)|\n\ + \\dx /\ +""" + ucode_str = \ +"""\ + ⎛d ⎞\n\ +DifferentialOperator⎜──(f(x)),f(x)⎟\n\ + ⎝dx ⎠\ +""" + assert pretty(d) == ascii_str + assert upretty(d) == ucode_str + assert latex(d) == \ + r'DifferentialOperator\left(\frac{d}{d x} f{\left(x \right)},f{\left(x \right)}\right)' + sT(d, "DifferentialOperator(Derivative(Function('f')(Symbol('x')), Tuple(Symbol('x'), Integer(1))),Function('f')(Symbol('x')))") + assert str(b) == 'Operator(B,t,1/2)' + assert pretty(b) == 'Operator(B,t,1/2)' + assert upretty(b) == 'Operator(B,t,1/2)' + assert latex(b) == r'Operator\left(B,t,\frac{1}{2}\right)' + sT(b, "Operator(Symbol('B'),Symbol('t'),Rational(1, 2))") + assert str(op) == '|psi>' + 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))") + 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) + assert str(lz) == 'Lz' + ascii_str = \ +"""\ +L \n\ + z\ +""" + ucode_str = \ +"""\ +L \n\ + z\ +""" + assert pretty(lz) == ascii_str + assert upretty(lz) == ucode_str + assert latex(lz) == 'L_z' + sT(lz, "JzOp(Symbol('L'))") + assert str(J2) == 'J2' + ascii_str = \ +"""\ + 2\n\ +J \ +""" + ucode_str = \ +"""\ + 2\n\ +J \ +""" + assert pretty(J2) == ascii_str + assert upretty(J2) == ucode_str + assert latex(J2) == r'J^2' + sT(J2, "J2Op(Symbol('J'))") + assert str(Jz) == 'Jz' + ascii_str = \ +"""\ +J \n\ + z\ +""" + ucode_str = \ +"""\ +J \n\ + z\ +""" + assert pretty(Jz) == ascii_str + assert upretty(Jz) == ucode_str + assert latex(Jz) == 'J_z' + sT(Jz, "JzOp(Symbol('J'))") + assert str(ket) == '|1,0>' + assert pretty(ket) == '|1,0>' + assert upretty(ket) == '❘1,0⟩' + assert latex(ket) == r'{\left|1,0\right\rangle }' + sT(ket, "JzKet(Integer(1),Integer(0))") + assert str(bra) == '<1,0|' + assert pretty(bra) == '<1,0|' + assert upretty(bra) == '⟨1,0❘' + assert latex(bra) == r'{\left\langle 1,0\right|}' + sT(bra, "JzBra(Integer(1),Integer(0))") + assert str(cket) == '|1,0,j1=1,j2=2>' + assert pretty(cket) == '|1,0,j1=1,j2=2>' + assert upretty(cket) == '❘1,0,j₁=1,j₂=2⟩' + assert latex(cket) == r'{\left|1,0,j_{1}=1,j_{2}=2\right\rangle }' + sT(cket, "JzKetCoupled(Integer(1),Integer(0),Tuple(Integer(1), Integer(2)),Tuple(Tuple(Integer(1), Integer(2), Integer(1))))") + assert str(cbra) == '<1,0,j1=1,j2=2|' + assert pretty(cbra) == '<1,0,j1=1,j2=2|' + assert upretty(cbra) == '⟨1,0,j₁=1,j₂=2❘' + assert latex(cbra) == r'{\left\langle 1,0,j_{1}=1,j_{2}=2\right|}' + sT(cbra, "JzBraCoupled(Integer(1),Integer(0),Tuple(Integer(1), Integer(2)),Tuple(Tuple(Integer(1), Integer(2), Integer(1))))") + assert str(cket_big) == '|1,0,j1=1,j2=2,j3=3,j(1,2)=3>' + # TODO: Fix non-unicode pretty printing + # i.e. j1,2 -> j(1,2) + assert pretty(cket_big) == '|1,0,j1=1,j2=2,j3=3,j1,2=3>' + assert upretty(cket_big) == '❘1,0,j₁=1,j₂=2,j₃=3,j₁,₂=3⟩' + assert latex(cket_big) == \ + r'{\left|1,0,j_{1}=1,j_{2}=2,j_{3}=3,j_{1,2}=3\right\rangle }' + sT(cket_big, "JzKetCoupled(Integer(1),Integer(0),Tuple(Integer(1), Integer(2), Integer(3)),Tuple(Tuple(Integer(1), Integer(2), Integer(3)), Tuple(Integer(1), Integer(3), Integer(1))))") + assert str(cbra_big) == '<1,0,j1=1,j2=2,j3=3,j(1,2)=3|' + assert pretty(cbra_big) == '<1,0,j1=1,j2=2,j3=3,j1,2=3|' + assert upretty(cbra_big) == '⟨1,0,j₁=1,j₂=2,j₃=3,j₁,₂=3❘' + assert latex(cbra_big) == \ + r'{\left\langle 1,0,j_{1}=1,j_{2}=2,j_{3}=3,j_{1,2}=3\right|}' + sT(cbra_big, "JzBraCoupled(Integer(1),Integer(0),Tuple(Integer(1), Integer(2), Integer(3)),Tuple(Tuple(Integer(1), Integer(2), Integer(3)), Tuple(Integer(1), Integer(3), Integer(1))))") + assert str(rot) == 'R(1,2,3)' + assert pretty(rot) == 'R (1,2,3)' + assert upretty(rot) == 'ℛ (1,2,3)' + assert latex(rot) == r'\mathcal{R}\left(1,2,3\right)' + sT(rot, "Rotation(Integer(1),Integer(2),Integer(3))") + assert str(bigd) == 'WignerD(1, 2, 3, 4, 5, 6)' + ascii_str = \ +"""\ + 1 \n\ +D (4,5,6)\n\ + 2,3 \ +""" + ucode_str = \ +"""\ + 1 \n\ +D (4,5,6)\n\ + 2,3 \ +""" + assert pretty(bigd) == ascii_str + assert upretty(bigd) == ucode_str + assert latex(bigd) == r'D^{1}_{2,3}\left(4,5,6\right)' + sT(bigd, "WignerD(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6))") + assert str(smalld) == 'WignerD(1, 2, 3, 0, 4, 0)' + ascii_str = \ +"""\ + 1 \n\ +d (4)\n\ + 2,3 \ +""" + ucode_str = \ +"""\ + 1 \n\ +d (4)\n\ + 2,3 \ +""" + assert pretty(smalld) == ascii_str + assert upretty(smalld) == ucode_str + 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() + ket = Ket() + bra_tall = Bra(x/2) + ket_tall = Ket(x/2) + tbra = TimeDepBra() + tket = TimeDepKet() + assert str(bra) == '' + assert pretty(ket) == '|psi>' + assert upretty(ket) == '❘ψ⟩' + assert latex(ket) == r'{\left|\psi\right\rangle }' + sT(ket, "Ket(Symbol('psi'))") + assert str(bra_tall) == '' + ascii_str = \ +"""\ +| \\ \n\ +|x \\\n\ +|- /\n\ +|2/ \ +""" + ucode_str = \ +"""\ +│ ╲ \n\ +│x ╲\n\ +│─ ╱\n\ +│2╱ \ +""" + assert pretty(ket_tall) == ascii_str + assert upretty(ket_tall) == ucode_str + assert latex(ket_tall) == r'{\left|\frac{x}{2}\right\rangle }' + sT(ket_tall, "Ket(Mul(Rational(1, 2), Symbol('x')))") + assert str(tbra) == '' + assert pretty(tket) == '|psi;t>' + assert upretty(tket) == '❘ψ;t⟩' + assert latex(tket) == r'{\left|\psi;t\right\rangle }' + sT(tket, "TimeDepKet(Symbol('psi'),Symbol('t'))") + + +def test_tensorproduct(): + tp = TensorProduct(JzKet(1, 1), JzKet(1, 0)) + assert str(tp) == '|1,1>x|1,0>' + assert pretty(tp) == '|1,1>x |1,0>' + assert upretty(tp) == '❘1,1⟩⨂ ❘1,0⟩' + assert latex(tp) == \ + 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()) + 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 = \ +"""\ + / 3 \\ \n\ + |/ +\\ | \n\ + 2 / + +\\ <| /d \\ | + +> \n\ +/J \\ x \\A + B /*||DifferentialOperator|--(f(x)),f(x)| | ,A + B |*(<1,0| + <1,1|)*(|0,0> + |1,-1>)\n\ +\\ z/ \\\\ \\dx / / / \ +""" + ucode_str = \ +"""\ + ⎧ 3 ⎫ \n\ + ⎪⎛ †⎞ ⎪ \n\ + 2 ⎛ † †⎞ ⎨⎜ ⎛d ⎞ ⎟ † †⎬ \n\ +⎛J ⎞ ⨂ ⎝A + B ⎠⋅⎪⎜DifferentialOperator⎜──(f(x)),f(x)⎟ ⎟ ,A + B ⎪⋅(⟨1,0❘ + ⟨1,1❘)⋅(❘0,0⟩ + ❘1,-1⟩)\n\ +⎝ z⎠ ⎩⎝ ⎝dx ⎠ ⎠ ⎭ \ +""" + assert pretty(e1) == ascii_str + assert upretty(e1) == ucode_str + assert latex(e1) == \ + r'{J_z^{2}}\otimes \left({A^{\dagger} + B^{\dagger}}\right) \left\{\left(DifferentialOperator\left(\frac{d}{d x} f{\left(x \right)},f{\left(x \right)}\right)^{\dagger}\right)^{3},A^{\dagger} + B^{\dagger}\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')), Tuple(Symbol('x'), Integer(1))),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 = \ +"""\ +[ 2 ] / -2 + +\\ [ 2 ]\n\ +[/J \\ ,A + B]**[J ,J ]\n\ +[\\ z/ ] \\ / [ z]\ +""" + ucode_str = \ +"""\ +⎡ 2 ⎤ ⎧ -2 † †⎫ ⎡ 2 ⎤\n\ +⎢⎛J ⎞ ,A + B⎥⋅⎨E ,D ⋅C ⎬⋅⎢J ,J ⎥\n\ +⎣⎝ z⎠ ⎦ ⎩ ⎭ ⎣ z⎦\ +""" + assert pretty(e2) == ascii_str + assert upretty(e2) == ucode_str + assert latex(e2) == \ + r'\left[J_z^{2},A + B\right] \left\{E^{-2},D^{\dagger} C^{\dagger}\right\} \left[J^2,J_z\right]' + sT(e2, "Mul(Commutator(Pow(JzOp(Symbol('J')), Integer(2)),Add(Operator(Symbol('A')), Operator(Symbol('B')))), AntiCommutator(Pow(Operator(Symbol('E')), Integer(-2)),Mul(Dagger(Operator(Symbol('D'))), Dagger(Operator(Symbol('C'))))), Commutator(J2Op(Symbol('J')),JzOp(Symbol('J'))))") + assert str(e3) == \ + "Wigner3j(1, 2, 3, 4, 5, 6)*[Dagger(B) + A,C + D]x(-J2 + Jz)*|1,0><1,1|*(|1,0,j1=1,j2=1> + |1,1,j1=1,j2=1>)x|1,-1,j1=1,j2=1>" + ascii_str = \ +"""\ + [ + ] / 2 \\ \n\ +/1 3 5\\*[B + A,C + D]x |- J + J |*|1,0><1,1|*(|1,0,j1=1,j2=1> + |1,1,j1=1,j2=1>)x |1,-1,j1=1,j2=1>\n\ +| | \\ z/ \n\ +\\2 4 6/ \ +""" + ucode_str = \ +"""\ + ⎡ † ⎤ ⎛ 2 ⎞ \n\ +⎛1 3 5⎞⋅⎣B + A,C + D⎦⨂ ⎜- J + J ⎟⋅❘1,0⟩⟨1,1❘⋅(❘1,0,j₁=1,j₂=1⟩ + ❘1,1,j₁=1,j₂=1⟩)⨂ ❘1,-1,j₁=1,j₂=1⟩\n\ +⎜ ⎟ ⎝ z⎠ \n\ +⎝2 4 6⎠ \ +""" + assert pretty(e3) == ascii_str + assert upretty(e3) == ucode_str + assert latex(e3) == \ + r'\left(\begin{array}{ccc} 1 & 3 & 5 \\ 2 & 4 & 6 \end{array}\right) {\left[B^{\dagger} + A,C + D\right]}\otimes \left({- J^2 + J_z}\right) {\left|1,0\right\rangle }{\left\langle 1,1\right|} \left({{\left|1,0,j_{1}=1,j_{2}=1\right\rangle } + {\left|1,1,j_{1}=1,j_{2}=1\right\rangle }}\right)\otimes {{\left|1,-1,j_{1}=1,j_{2}=1\right\rangle }}' + sT(e3, "Mul(Wigner3j(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6)), TensorProduct(Commutator(Add(Dagger(Operator(Symbol('B'))), Operator(Symbol('A'))),Add(Operator(Symbol('C')), Operator(Symbol('D')))), Add(Mul(Integer(-1), J2Op(Symbol('J'))), JzOp(Symbol('J')))), OuterProduct(JzKet(Integer(1),Integer(0)),JzBra(Integer(1),Integer(1))), TensorProduct(Add(JzKetCoupled(Integer(1),Integer(0),Tuple(Integer(1), Integer(1)),Tuple(Tuple(Integer(1), Integer(2), Integer(1)))), JzKetCoupled(Integer(1),Integer(1),Tuple(Integer(1), Integer(1)),Tuple(Tuple(Integer(1), Integer(2), Integer(1))))), JzKetCoupled(Integer(1),Integer(-1),Tuple(Integer(1), Integer(1)),Tuple(Tuple(Integer(1), Integer(2), Integer(1))))))") + assert str(e4) == '(C(1)*C(2)+F**2)*(L2(Interval(0, oo))+H)' + ascii_str = \ +"""\ +// 1 2\\ x2\\ / 2 \\\n\ +\\\\C x C / + F / x \\L + H/\ +""" + ucode_str = \ +"""\ +⎛⎛ 1 2⎞ ⨂2⎞ ⎛ 2 ⎞\n\ +⎝⎝C ⨂ C ⎠ ⊕ F ⎠ ⨂ ⎝L ⊕ H⎠\ +""" + assert pretty(e4) == ascii_str + assert upretty(e4) == ucode_str + 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) == ' \N{DAGGER}\na ' + assert latex(ad) == 'a^{\\dagger}' diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qapply.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qapply.py new file mode 100644 index 0000000000000000000000000000000000000000..be6f68d9869df84bc25bd0ebdfcde9ff49adc508 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qapply.py @@ -0,0 +1,152 @@ +from sympy.core.mul import Mul +from sympy.core.numbers import (I, Integer, Rational) +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.miscellaneous import sqrt + +from sympy.physics.quantum.anticommutator import AntiCommutator +from sympy.physics.quantum.commutator import Commutator +from sympy.physics.quantum.constants import hbar +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.gate import H, XGate, IdentityGate +from sympy.physics.quantum.operator import Operator, IdentityOperator +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.spin import Jx, Jy, Jz, Jplus, Jminus, J2, JzKet +from sympy.physics.quantum.tensorproduct import TensorProduct +from sympy.physics.quantum.state import Ket +from sympy.physics.quantum.density import Density +from sympy.physics.quantum.qubit import Qubit, QubitBra +from sympy.physics.quantum.boson import BosonOp, BosonFockKet, BosonFockBra +from sympy.testing.pytest import warns_deprecated_sympy + + +j, jp, m, mp = symbols("j j' m m'") + +z = JzKet(1, 0) +po = JzKet(1, 1) +mo = JzKet(1, -1) + +A = Operator('A') + + +class Foo(Operator): + def _apply_operator_JzKet(self, ket, **options): + return ket + + +def test_basic(): + assert qapply(Jz*po) == hbar*po + assert qapply(Jx*z) == hbar*po/sqrt(2) + hbar*mo/sqrt(2) + assert qapply((Jplus + Jminus)*z/sqrt(2)) == hbar*po + hbar*mo + assert qapply(Jz*(po + mo)) == hbar*po - hbar*mo + assert qapply(Jz*po + Jz*mo) == hbar*po - hbar*mo + assert qapply(Jminus*Jminus*po) == 2*hbar**2*mo + assert qapply(Jplus**2*mo) == 2*hbar**2*po + assert qapply(Jplus**2*Jminus**2*po) == 4*hbar**4*po + + +def test_extra(): + 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(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 + assert qapply(Jplus**2*mo*extra) == 2*hbar**2*po*extra + assert qapply(Jplus**2*Jminus**2*po*extra) == 4*hbar**4*po*extra + + +def test_innerproduct(): + assert qapply(po.dual*Jz*po, ip_doit=False) == hbar*(po.dual*po) + assert qapply(po.dual*Jz*po) == hbar + + +def test_zero(): + assert qapply(0) == 0 + assert qapply(Integer(0)) == 0 + + +def test_commutator(): + 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 + + +def test_anticommutator(): + assert qapply(AntiCommutator(Jz, Foo('F'))*po) == 2*hbar*po + assert qapply(AntiCommutator(Foo('F'), Jz)*po) == 2*hbar*po + + +def test_outerproduct(): + e = Jz*(mo*po.dual)*Jz*po + assert qapply(e) == -hbar**2*mo + assert qapply(e, ip_doit=False) == -hbar**2*(po.dual*po)*mo + assert qapply(e).doit() == -hbar**2*mo + + +def test_tensorproduct(): + a = BosonOp("a") + b = BosonOp("b") + ket1 = TensorProduct(BosonFockKet(1), BosonFockKet(2)) + ket2 = TensorProduct(BosonFockKet(0), BosonFockKet(0)) + ket3 = TensorProduct(BosonFockKet(0), BosonFockKet(2)) + bra1 = TensorProduct(BosonFockBra(0), BosonFockBra(0)) + bra2 = TensorProduct(BosonFockBra(1), BosonFockBra(2)) + assert qapply(TensorProduct(a, b ** 2) * ket1) == sqrt(2) * ket2 + assert qapply(TensorProduct(a, Dagger(b) * b) * ket1) == 2 * ket3 + assert qapply(bra1 * TensorProduct(a, b * b), + dagger=True) == sqrt(2) * bra2 + assert qapply(bra2 * ket1).doit() == S.One + assert qapply(TensorProduct(a, b * b) * ket1) == sqrt(2) * ket2 + assert qapply(Dagger(TensorProduct(a, b * b) * ket1), + dagger=True) == sqrt(2) * Dagger(ket2) + + +def test_dagger(): + lhs = Dagger(Qubit(0))*Dagger(H(0)) + rhs = Dagger(Qubit(1))/sqrt(2) + Dagger(Qubit(0))/sqrt(2) + assert qapply(lhs, dagger=True) == rhs + + +def test_issue_6073(): + x, y = symbols('x y', commutative=False) + 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]) + + +def test_issue3044(): + expr1 = TensorProduct(Jz*JzKet(S(2),S.NegativeOne)/sqrt(2), Jz*JzKet(S.Half,S.Half)) + result = Mul(S.NegativeOne, Rational(1, 4), 2**S.Half, hbar**2) + result *= TensorProduct(JzKet(2,-1), JzKet(S.Half,S.Half)) + assert qapply(expr1) == result + + +# Issue 24158: Tests whether qapply incorrectly evaluates some ket*op as op*ket +def test_issue24158_ket_times_op(): + P = BosonFockKet(0) * BosonOp("a") # undefined term + # Does lhs._apply_operator_BosonOp(rhs) still evaluate ket*op as op*ket? + assert qapply(P) == P # qapply(P) -> BosonOp("a")*BosonFockKet(0) = 0 before fix + P = Qubit(1) * XGate(0) # undefined term + # Does rhs._apply_operator_Qubit(lhs) still evaluate ket*op as op*ket? + assert qapply(P) == P # qapply(P) -> Qubit(0) before fix + P1 = Mul(QubitBra(0), Mul(QubitBra(0), Qubit(0)), XGate(0)) # legal expr <0| * (<1|*|1>) * X + assert qapply(P1) == QubitBra(0) * XGate(0) # qapply(P1) -> 0 before fix + P1 = qapply(P1, dagger = True) # unsatisfactorily -> <0|*X(0), expect <1| since dagger=True + assert qapply(P1, dagger = True) == QubitBra(1) # qapply(P1, dagger=True) -> 0 before fix + P2 = QubitBra(0) * (QubitBra(0) * Qubit(0)) * XGate(0) # 'forgot' to set brackets + P2 = qapply(P2, dagger = True) # unsatisfactorily -> <0|*X(0), expect <1| since dagger=True + assert P2 == QubitBra(1) # qapply(P1) -> 0 before fix + # Pull Request 24237: IdentityOperator from the right without dagger=True option + with warns_deprecated_sympy(): + assert qapply(QubitBra(1)*IdentityOperator()) == QubitBra(1) + assert qapply(IdentityGate(0)*(Qubit(0) + Qubit(1))) == Qubit(0) + Qubit(1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qasm.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qasm.py new file mode 100644 index 0000000000000000000000000000000000000000..81c7ee8523e732d336211f7739a6e8f7fbab5220 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qasm.py @@ -0,0 +1,89 @@ +from sympy.physics.quantum.qasm import Qasm, flip_index, trim,\ + get_index, nonblank, fullsplit, fixcommand, stripquotes, read_qasm +from sympy.physics.quantum.gate import X, Z, H, S, T +from sympy.physics.quantum.gate import CNOT, SWAP, CPHASE, CGate, CGateS +from sympy.physics.quantum.circuitplot import Mz + +def test_qasm_readqasm(): + qasm_lines = """\ + qubit q_0 + qubit q_1 + h q_0 + cnot q_0,q_1 + """ + q = read_qasm(qasm_lines) + assert q.get_circuit() == CNOT(1,0)*H(1) + +def test_qasm_ex1(): + q = Qasm('qubit q0', 'qubit q1', 'h q0', 'cnot q0,q1') + assert q.get_circuit() == CNOT(1,0)*H(1) + +def test_qasm_ex1_methodcalls(): + q = Qasm() + q.qubit('q_0') + q.qubit('q_1') + q.h('q_0') + q.cnot('q_0', 'q_1') + assert q.get_circuit() == CNOT(1,0)*H(1) + +def test_qasm_swap(): + q = Qasm('qubit q0', 'qubit q1', 'cnot q0,q1', 'cnot q1,q0', 'cnot q0,q1') + assert q.get_circuit() == CNOT(1,0)*CNOT(0,1)*CNOT(1,0) + + +def test_qasm_ex2(): + q = Qasm('qubit q_0', 'qubit q_1', 'qubit q_2', 'h q_1', + 'cnot q_1,q_2', 'cnot q_0,q_1', 'h q_0', + 'measure q_1', 'measure q_0', + 'c-x q_1,q_2', 'c-z q_0,q_2') + assert q.get_circuit() == CGate(2,Z(0))*CGate(1,X(0))*Mz(2)*Mz(1)*H(2)*CNOT(2,1)*CNOT(1,0)*H(1) + +def test_qasm_1q(): + for symbol, gate in [('x', X), ('z', Z), ('h', H), ('s', S), ('t', T), ('measure', Mz)]: + q = Qasm('qubit q_0', '%s q_0' % symbol) + assert q.get_circuit() == gate(0) + +def test_qasm_2q(): + for symbol, gate in [('cnot', CNOT), ('swap', SWAP), ('cphase', CPHASE)]: + q = Qasm('qubit q_0', 'qubit q_1', '%s q_0,q_1' % symbol) + assert q.get_circuit() == gate(1,0) + +def test_qasm_3q(): + q = Qasm('qubit q0', 'qubit q1', 'qubit q2', 'toffoli q2,q1,q0') + assert q.get_circuit() == CGateS((0,1),X(2)) + +def test_qasm_flip_index(): + assert flip_index(0, 2) == 1 + assert flip_index(1, 2) == 0 + +def test_qasm_trim(): + assert trim('nothing happens here') == 'nothing happens here' + assert trim("Something #happens here") == "Something " + +def test_qasm_get_index(): + assert get_index('q0', ['q0', 'q1']) == 1 + assert get_index('q1', ['q0', 'q1']) == 0 + +def test_qasm_nonblank(): + assert list(nonblank('abcd')) == list('abcd') + assert list(nonblank('abc ')) == list('abc') + +def test_qasm_fullsplit(): + assert fullsplit('g q0,q1,q2, q3') == ('g', ['q0', 'q1', 'q2', 'q3']) + +def test_qasm_fixcommand(): + assert fixcommand('foo') == 'foo' + assert fixcommand('def') == 'qdef' + +def test_qasm_stripquotes(): + assert stripquotes("'S'") == 'S' + assert stripquotes('"S"') == 'S' + assert stripquotes('S') == 'S' + +def test_qasm_qdef(): + # weaker test condition (str) since we don't have access to the actual class + q = Qasm("def Q,0,Q",'qubit q0','Q q0') + assert str(q.get_circuit()) == 'Q(0)' + + q = Qasm("def CQ,1,Q", 'qubit q0', 'qubit q1', 'CQ q0,q1') + assert str(q.get_circuit()) == 'C((1),Q(0))' diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qexpr.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qexpr.py new file mode 100644 index 0000000000000000000000000000000000000000..c01817935a0f977e44c8e0dc29746e070b2cb693 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qexpr.py @@ -0,0 +1,64 @@ +from sympy.core.numbers import Integer +from sympy.core.symbol import Symbol +from sympy.concrete import Sum +from sympy.physics.quantum.qexpr import QExpr, _qsympify_sequence +from sympy.physics.quantum.hilbert import HilbertSpace +from sympy.core.containers import Tuple + +x = Symbol('x') +y = Symbol('y') +n = Symbol('n', integer=True) +m = Symbol('m', integer=True) + + +def test_qexpr_new(): + q = QExpr(0) + assert q.label == (0,) + assert q.hilbert_space == HilbertSpace() + assert q.is_commutative is False + + 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.hilbert_space == HilbertSpace() + + +def test_qexpr_commutative(): + q1 = QExpr(x) + q2 = QExpr(y) + assert q1.is_commutative is False + assert q2.is_commutative is False + assert q1*q2 != q2*q1 + + q = QExpr._new_rawargs(Integer(0), Integer(1), HilbertSpace()) + assert q.is_commutative is False + + +def test_qexpr_free_symbols(): + q1 = QExpr(x, y) + assert q1.free_symbols == {x, y} + + +def test_qexpr_sum(): + q1 = Sum(QExpr(n), (n,0,2)) + assert q1.doit() == QExpr(0) + QExpr(1) + QExpr(2) + + q2 = Sum(QExpr(n, m), (n, 0, 2), (m, 0, 2)) + assert q2.doit() == QExpr(0, 0) + QExpr(0, 1) + QExpr(0, 2) + \ + QExpr(1, 0) + QExpr(1, 1) + QExpr(1, 2) + \ + QExpr(2, 0) + QExpr(2, 1) + QExpr(2, 2) + + +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) + + +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,)) == (1,) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qft.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qft.py new file mode 100644 index 0000000000000000000000000000000000000000..832f0194702b2031cfdff9d061a259e85476a88d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qft.py @@ -0,0 +1,52 @@ +from sympy.core.numbers import (I, pi) +from sympy.core.symbol import Symbol +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices.dense import Matrix + +from sympy.physics.quantum.qft import QFT, IQFT, RkGate +from sympy.physics.quantum.gate import (ZGate, SwapGate, HadamardGate, CGate, + PhaseGate, TGate) +from sympy.physics.quantum.qubit import Qubit +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.represent import represent + +from sympy.functions.elementary.complexes import sign + + +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 represent( + RkGate(0, x), nqubits=1) == Matrix([[1, 0], [0, exp(sign(x)*2*pi*I/(2**abs(x)))]]) + + +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 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) + assert a.evalf(n=10) == b.evalf(n=10) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qubit.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qubit.py new file mode 100644 index 0000000000000000000000000000000000000000..b4c236008a6b8cf85b5a45c5167b9dc36fb21019 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_qubit.py @@ -0,0 +1,264 @@ +import random + +from sympy.core.numbers import (Integer, Rational) +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices.dense import Matrix +from sympy.physics.quantum.qubit import (measure_all, measure_all_oneshot, measure_partial, + matrix_to_qubit, matrix_to_density, + qubit_to_matrix, IntQubit, + IntQubitBra, QubitBra) +from sympy.physics.quantum.gate import (HadamardGate, CNOT, XGate, YGate, + ZGate, PhaseGate) +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.represent import represent +from sympy.physics.quantum.shor import Qubit +from sympy.testing.pytest import raises +from sympy.physics.quantum.density import Density +from sympy.physics.quantum.trace import Tr + +x, y = symbols('x,y') + +epsilon = .000001 + + +def test_Qubit(): + 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.qubit_values == (0, 0, 1, 1, 0) + assert qb.dimension == 5 + for i in range(5): + assert qb[i] == array[4 - i] + assert len(qb) == 5 + qb = Qubit('110') + + +def test_QubitBra(): + qb = Qubit(0) + qb_bra = QubitBra(0) + assert qb.dual_class() == QubitBra + assert qb_bra.dual_class() == Qubit + + qb = Qubit(1, 1, 0) + qb_bra = QubitBra(1, 1, 0) + assert represent(qb, nqubits=3).H == represent(qb_bra, nqubits=3) + + qb = Qubit(0, 1) + qb_bra = QubitBra(1,0) + assert qb._eval_innerproduct_QubitBra(qb_bra) == Integer(0) + + qb_bra = QubitBra(0, 1) + assert qb._eval_innerproduct_QubitBra(qb_bra) == Integer(1) + + +def test_IntQubit(): + # issue 9136 + iqb = IntQubit(0, nqubits=1) + assert qubit_to_matrix(Qubit('0')) == qubit_to_matrix(iqb) + + qb = Qubit('1010') + assert qubit_to_matrix(IntQubit(qb)) == qubit_to_matrix(qb) + + iqb = IntQubit(1, nqubits=1) + assert qubit_to_matrix(Qubit('1')) == qubit_to_matrix(iqb) + assert qubit_to_matrix(IntQubit(1)) == qubit_to_matrix(iqb) + + iqb = IntQubit(7, nqubits=4) + assert qubit_to_matrix(Qubit('0111')) == qubit_to_matrix(iqb) + assert qubit_to_matrix(IntQubit(7, 4)) == qubit_to_matrix(iqb) + + iqb = IntQubit(8) + assert iqb.as_int() == 8 + assert iqb.qubit_values == (1, 0, 0, 0) + + iqb = IntQubit(7, 4) + assert iqb.qubit_values == (0, 1, 1, 1) + assert IntQubit(3) == IntQubit(3, 2) + + #test Dual Classes + iqb = IntQubit(3) + iqb_bra = IntQubitBra(3) + assert iqb.dual_class() == IntQubitBra + assert iqb_bra.dual_class() == IntQubit + + iqb = IntQubit(5) + iqb_bra = IntQubitBra(5) + assert iqb._eval_innerproduct_IntQubitBra(iqb_bra) == Integer(1) + + iqb = IntQubit(4) + iqb_bra = IntQubitBra(5) + assert iqb._eval_innerproduct_IntQubitBra(iqb_bra) == Integer(0) + raises(ValueError, lambda: IntQubit(4, 1)) + + raises(ValueError, lambda: IntQubit('5')) + raises(ValueError, lambda: IntQubit(5, '5')) + raises(ValueError, lambda: IntQubit(5, nqubits='5')) + raises(TypeError, lambda: IntQubit(5, bad_arg=True)) + +def test_superposition_of_states(): + state = 1/sqrt(2)*Qubit('01') + 1/sqrt(2)*Qubit('10') + state_gate = CNOT(0, 1)*HadamardGate(0)*state + state_expanded = Qubit('01')/2 + Qubit('00')/2 - Qubit('11')/2 + Qubit('10')/2 + assert qapply(state_gate).expand() == state_expanded + assert matrix_to_qubit(represent(state_gate, nqubits=2)) == state_expanded + + +#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)) + 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) + states = states.expand() + state_rep = state_rep.expand() + assert state_rep == states + + +def test_matrix_to_qubits(): + qb = Qubit(0, 0, 0, 0) + mat = Matrix([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + assert matrix_to_qubit(mat) == qb + assert qubit_to_matrix(qb) == mat + + state = 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)) + ones = sqrt(2)*2*Matrix([1, 1, 1, 1, 1, 1, 1, 1]) + assert matrix_to_qubit(ones) == state.expand() + assert qubit_to_matrix(state) == ones + + +def test_measure_normalize(): + 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())] + + +def test_measure_partial(): + #Basic test of collapse of entangled two qubits (Bell States) + state = Qubit('01') + Qubit('10') + assert measure_partial(state, (0,)) == \ + [(Qubit('10'), S.Half), (Qubit('01'), S.Half)] + assert measure_partial(state, int(0)) == \ + [(Qubit('10'), S.Half), (Qubit('01'), S.Half)] + assert measure_partial(state, (0,)) == \ + measure_partial(state, (1,))[::-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))] + + #test of measuring multiple bits at once + state2 = Qubit('1111') + Qubit('1101') + Qubit('1011') + Qubit('1000') + assert measure_partial(state2, (0, 1, 3)) == \ + [(Qubit('1000'), Rational(1, 4)), (Qubit('1101'), Rational(1, 4)), + (Qubit('1011')/sqrt(2) + Qubit('1111')/sqrt(2), S.Half)] + assert measure_partial(state2, (0,)) == \ + [(Qubit('1000'), Rational(1, 4)), + (Qubit('1111')/sqrt(3) + Qubit('1101')/sqrt(3) + + Qubit('1011')/sqrt(3), Rational(3, 4))] + + +def test_measure_all(): + assert measure_all(Qubit('11')) == [(Qubit('11'), 1)] + state = Qubit('11') + Qubit('10') + assert measure_all(state) == [(Qubit('10'), S.Half), + (Qubit('11'), S.Half)] + state2 = Qubit('11')/sqrt(5) + 2*Qubit('00')/sqrt(5) + assert measure_all(state2) == \ + [(Qubit('00'), Rational(4, 5)), (Qubit('11'), Rational(1, 5))] + + # from issue #12585 + assert measure_all(qapply(Qubit('0'))) == [(Qubit('0'), 1)] + + +def test_measure_all_oneshot(): + random.seed(42) + # for issue #27092 + assert measure_all_oneshot(Qubit('11')) == Qubit('11') + assert measure_all_oneshot(Qubit('1')) == Qubit('1') + assert measure_all_oneshot(Qubit('0')/sqrt(2) + Qubit('1')/sqrt(2)) == \ + Qubit('0') + + +def test_eval_trace(): + q1 = Qubit('10110') + q2 = Qubit('01010') + d = Density([q1, 0.6], [q2, 0.4]) + + t = Tr(d) + assert t.doit() == 1.0 + + # extreme bits + t = Tr(d, 0) + assert t.doit() == (0.4*Density([Qubit('0101'), 1]) + + 0.6*Density([Qubit('1011'), 1])) + t = Tr(d, 4) + assert t.doit() == (0.4*Density([Qubit('1010'), 1]) + + 0.6*Density([Qubit('0110'), 1])) + # index somewhere in between + t = Tr(d, 2) + 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]) + assert t.doit() == 1.0 + + # trace some indices, initialized in + # non-canonical order + t = Tr(d, [2, 1, 3]) + assert t.doit() == (0.4*Density([Qubit('00'), 1]) + + 0.6*Density([Qubit('10'), 1])) + + # mixed states + q = (1/sqrt(2)) * (Qubit('00') + Qubit('11')) + 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]) + + mat = Matrix([[1, 0], [0, 0]]) + assert matrix_to_density(mat) == Density([Qubit('0'), 1]) + + mat = Matrix([[0, 0], [0, 0]]) + assert matrix_to_density(mat) == 0 + + mat = Matrix([[0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, 0]]) + + assert matrix_to_density(mat) == Density([Qubit('10'), 1]) + + mat = Matrix([[1, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0]]) + + assert matrix_to_density(mat) == Density([Qubit('00'), 1]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_represent.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_represent.py new file mode 100644 index 0000000000000000000000000000000000000000..c49dcbd7e7876f30cbe8e5426c91419903add5ff --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_represent.py @@ -0,0 +1,186 @@ +from sympy.core.numbers import (Float, I, Integer) +from sympy.matrices.dense import Matrix +from sympy.external import import_module +from sympy.testing.pytest import skip + +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.represent import (represent, rep_innerproduct, + rep_expectation, enumerate_states) +from sympy.physics.quantum.state import Bra, Ket +from sympy.physics.quantum.operator import Operator, OuterProduct +from sympy.physics.quantum.tensorproduct import TensorProduct +from sympy.physics.quantum.tensorproduct import matrix_tensor_product +from sympy.physics.quantum.commutator import Commutator +from sympy.physics.quantum.anticommutator import AntiCommutator +from sympy.physics.quantum.innerproduct import InnerProduct +from sympy.physics.quantum.matrixutils import (numpy_ndarray, + scipy_sparse_matrix, to_numpy, + to_scipy_sparse, to_sympy) +from sympy.physics.quantum.cartesian import XKet, XOp, XBra +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.operatorset import operators_to_state +from sympy.testing.pytest import raises + +Amat = Matrix([[1, I], [-I, 1]]) +Bmat = Matrix([[1, 2], [3, 4]]) +Avec = Matrix([[1], [I]]) + + +class AKet(Ket): + + @classmethod + def dual_class(self): + return ABra + + def _represent_default_basis(self, **options): + return self._represent_AOp(None, **options) + + def _represent_AOp(self, basis, **options): + return Avec + + +class ABra(Bra): + + @classmethod + def dual_class(self): + return AKet + + +class AOp(Operator): + + def _represent_default_basis(self, **options): + return self._represent_AOp(None, **options) + + def _represent_AOp(self, basis, **options): + return Amat + + +class BOp(Operator): + + def _represent_default_basis(self, **options): + return self._represent_AOp(None, **options) + + def _represent_AOp(self, basis, **options): + return Bmat + + +k = AKet('a') +b = ABra('a') +A = AOp('A') +B = BOp('B') + +_tests = [ + # Bra + (b, Dagger(Avec)), + (Dagger(b), Avec), + # Ket + (k, Avec), + (Dagger(k), Dagger(Avec)), + # Operator + (A, Amat), + (Dagger(A), Dagger(Amat)), + # OuterProduct + (OuterProduct(k, b), Avec*Avec.H), + # TensorProduct + (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), + # AntiCommutator + (AntiCommutator(A, B), Amat*Bmat + Bmat*Amat), + # InnerProduct + (InnerProduct(b, k), (Avec.H*Avec)[0]) +] + + +def test_format_sympy(): + for test in _tests: + lhs = represent(test[0], basis=A, format='sympy') + 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 + + +np = import_module('numpy') + + +def test_format_numpy(): + if not np: + skip("numpy not installed.") + + for test in _tests: + lhs = represent(test[0], basis=A, format='numpy') + rhs = to_numpy(test[1]) + if isinstance(lhs, numpy_ndarray): + assert (lhs == rhs).all() + else: + assert lhs == rhs + + +def test_scalar_numpy(): + if not np: + skip("numpy not installed.") + + 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 + + +scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) + + +def test_format_scipy_sparse(): + if not np: + skip("numpy not installed.") + if not scipy: + skip("scipy not installed.") + + for test in _tests: + 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 + else: + assert lhs == rhs + + +def test_scalar_scipy_sparse(): + if not np: + skip("numpy not installed.") + if not scipy: + skip("scipy not installed.") + + 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 + +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() + raises(TypeError, lambda: rep_innerproduct(x_op)) + + +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]) + + +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")] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_sho1d.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_sho1d.py new file mode 100644 index 0000000000000000000000000000000000000000..6acb1f1e7044ac278061cf3b4f04c3c8c09d1848 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_sho1d.py @@ -0,0 +1,176 @@ +"""Tests for sho1d.py""" + +from sympy.concrete import Sum +from sympy.core import oo +from sympy.core.numbers import (I, Integer) +from sympy.core.singleton import S +from sympy.core.symbol import Symbol, symbols +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.complexes import Abs +from sympy.functions.special.tensor_functions import KroneckerDelta +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.physics.quantum.hilbert import ComplexSpace +from sympy.physics.quantum.represent import represent +from sympy.simplify import simplify +from sympy.external import import_module +from sympy.tensor import IndexedBase, Idx +from sympy.testing.pytest import skip, raises + +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) +p = Symbol('p', integer=True) +q = Symbol('q', nonnegative=True, integer=True) + + +np = import_module('numpy') +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.") + + 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.") + if not scipy: + skip("scipy not installed.") + + 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) + +def test_sho_sums(): + e1 = Sum(SHOKet(p)*SHOBra(p), (p, 0, 1)) + assert e1.doit() == SHOKet(0)*SHOBra(0) + SHOKet(1)*SHOBra(1) + + # Test qapply with Sum on the left + assert qapply( + Sum(SHOKet(p)*SHOBra(p), (p, 0, oo))*SHOKet(q), + sum_doit=True + ) == SHOKet(q) + + # Test qapply with Sum on the right + a = IndexedBase('a') + n = symbols('n', cls=Idx) + result = qapply(SHOBra(q)*Sum(a[n]*SHOKet(n), (n,0,oo)), sum_doit=True) + assert result == a[q] + + # Test qapply with a product of Sums + result = qapply( + SHOBra(q)*Sum(SHOKet(p)*SHOBra(p), (p, 0, oo))*Sum(a[n]*SHOKet(n), (n,0,oo)), + sum_doit=True + ) + assert result == a[q] + + with raises(ValueError): + result = qapply( + SHOBra(q)*Sum(SHOKet(p)*SHOBra(p), (p, 0, oo))*Sum(a[p]*SHOKet(p), (p,0,oo)), + sum_doit=True + ) + +def test_sho_coherant_state(): + alpha = Symbol('alpha', is_complex=True) + cstate = exp(-Abs(alpha)**2/S(2))*Sum(((alpha**p)/sqrt(factorial(p)))*SHOKet(p), (p,0,oo)) + # Projection onto the number eigenstate + assert qapply(SHOBra(q)*cstate, sum_doit=True) == exp(-Abs(alpha)**2/S(2))*alpha**q/sqrt(factorial(q)) + # Ensure that the coherent state is an eigenstate of annihilation operator + assert simplify(qapply(SHOBra(q)*a*cstate, sum_doit=True)) == simplify(qapply(SHOBra(q)*alpha*cstate, sum_doit=True)) + +def test_issue_26495(): + nbar = Symbol('nbar', real=True, nonnegative=True) + n = Symbol('n', integer=True) + i = Symbol('i', integer=True, nonnegative=True) + j = Symbol('j', integer=True, nonnegative=True) + rho = Sum((nbar/(1+nbar))**n*SHOKet(n)*SHOBra(n), (n,0,oo)) + result = qapply(SHOBra(i)*rho*SHOKet(j), sum_doit=True) + assert simplify(result) == (nbar/(nbar+1))**i*KroneckerDelta(i,j) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_shor.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_shor.py new file mode 100644 index 0000000000000000000000000000000000000000..0ebccbc199be8640f2021933abbe58716c68f788 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_shor.py @@ -0,0 +1,21 @@ +from sympy.testing.pytest import XFAIL + +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.qubit import Qubit +from sympy.physics.quantum.shor import CMod, 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) + + +def test_continued_frac(): + assert getr(513, 1024, 10) == 2 + assert getr(169, 1024, 11) == 6 + assert getr(314, 4096, 16) == 13 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_spin.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_spin.py new file mode 100644 index 0000000000000000000000000000000000000000..f905a7de5aed31e24a6d7c882b6a768a787c61cb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_spin.py @@ -0,0 +1,4333 @@ +from sympy.concrete.summations import Sum +from sympy.core.function import expand +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.matrices.dense import Matrix +from sympy.abc import alpha, beta, gamma, j, m +from sympy.simplify import simplify + +from sympy.physics.quantum import hbar, represent, Commutator, InnerProduct +from sympy.physics.quantum.qapply import qapply +from sympy.physics.quantum.tensorproduct import TensorProduct +from sympy.physics.quantum.cg import CG +from sympy.physics.quantum.spin import ( + Jx, Jy, Jz, Jplus, Jminus, J2, + JxBra, JyBra, JzBra, + JxKet, JyKet, JzKet, + JxKetCoupled, JyKetCoupled, JzKetCoupled, + couple, uncouple, + Rotation, WignerD +) + +from sympy.testing.pytest import raises, slow + +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 assert_simplify_expand(e1, e2): + """Helper for simplifying and expanding results. + + This is needed to help us test complex expressions whose form + might change in subtle ways as the rest of sympy evolves. + """ + assert simplify(e1.expand(tensorproduct=True)) == \ + simplify(e2.expand(tensorproduct=True)) + + +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]]) + + +def test_represent_spin_states(): + # Jx basis + assert represent(JxKet(S.Half, S.Half), basis=Jx) == Matrix([1, 0]) + assert represent(JxKet(S.Half, Rational(-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.Half, S.Half), basis=Jx) == Matrix([exp(-I*pi/4), 0]) + assert represent( + JyKet(S.Half, Rational(-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.Half, S.Half), basis=Jx) == sqrt(2)*Matrix([-1, 1])/2 + assert represent( + JzKet(S.Half, Rational(-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.Half, S.Half), basis=Jy) == Matrix([exp(I*pi*Rational(-3, 4)), 0]) + assert represent( + JxKet(S.Half, Rational(-1, 2)), basis=Jy) == Matrix([0, exp(I*pi*Rational(3, 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.Half, S.Half), basis=Jy) == Matrix([1, 0]) + assert represent(JyKet(S.Half, Rational(-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.Half, S.Half), basis=Jy) == sqrt(2)*Matrix([-1, I])/2 + assert represent( + JzKet(S.Half, Rational(-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.Half, S.Half), basis=Jz) == sqrt(2)*Matrix([1, 1])/2 + assert represent( + JxKet(S.Half, Rational(-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.Half, S.Half), basis=Jz) == sqrt(2)*Matrix([-1, -I])/2 + assert represent( + JyKet(S.Half, Rational(-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.Half, S.Half), basis=Jz) == Matrix([1, 0]) + assert represent(JzKet(S.Half, Rational(-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.Half, S.Half), JxKet(S.Half, S.Half)), basis=Jx) == \ + Matrix([1, 0, 0, 0]) + assert represent(TensorProduct(JxKet(S.Half, S.Half), JxKet(S.Half, Rational(-1, 2))), basis=Jx) == \ + Matrix([0, 1, 0, 0]) + assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, S.Half)), basis=Jx) == \ + Matrix([0, 0, 1, 0]) + assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, Rational(-1, 2))), basis=Jx) == \ + Matrix([0, 0, 0, 1]) + assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, S.Half)), basis=Jx) == \ + Matrix([-I, 0, 0, 0]) + assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, Rational(-1, 2))), basis=Jx) == \ + Matrix([0, 1, 0, 0]) + assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, S.Half)), basis=Jx) == \ + Matrix([0, 0, 1, 0]) + assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, Rational(-1, 2))), basis=Jx) == \ + Matrix([0, 0, 0, I]) + assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), basis=Jx) == \ + Matrix([S.Half, Rational(-1, 2), Rational(-1, 2), S.Half]) + assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), basis=Jx) == \ + Matrix([S.Half, S.Half, Rational(-1, 2), Rational(-1, 2)]) + assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), basis=Jx) == \ + Matrix([S.Half, Rational(-1, 2), S.Half, Rational(-1, 2)]) + assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), basis=Jx) == \ + Matrix([S.Half, S.Half, S.Half, S.Half]) + # Jy basis + assert represent(TensorProduct(JxKet(S.Half, S.Half), JxKet(S.Half, S.Half)), basis=Jy) == \ + Matrix([I, 0, 0, 0]) + assert represent(TensorProduct(JxKet(S.Half, S.Half), JxKet(S.Half, Rational(-1, 2))), basis=Jy) == \ + Matrix([0, 1, 0, 0]) + assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, S.Half)), basis=Jy) == \ + Matrix([0, 0, 1, 0]) + assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, Rational(-1, 2))), basis=Jy) == \ + Matrix([0, 0, 0, -I]) + assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, S.Half)), basis=Jy) == \ + Matrix([1, 0, 0, 0]) + assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, Rational(-1, 2))), basis=Jy) == \ + Matrix([0, 1, 0, 0]) + assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, S.Half)), basis=Jy) == \ + Matrix([0, 0, 1, 0]) + assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, Rational(-1, 2))), basis=Jy) == \ + Matrix([0, 0, 0, 1]) + assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), basis=Jy) == \ + Matrix([S.Half, -I/2, -I/2, Rational(-1, 2)]) + assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), basis=Jy) == \ + Matrix([-I/2, S.Half, Rational(-1, 2), -I/2]) + assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), basis=Jy) == \ + Matrix([-I/2, Rational(-1, 2), S.Half, -I/2]) + assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), basis=Jy) == \ + Matrix([Rational(-1, 2), -I/2, -I/2, S.Half]) + # Jz basis + assert represent(TensorProduct(JxKet(S.Half, S.Half), JxKet(S.Half, S.Half)), basis=Jz) == \ + Matrix([S.Half, S.Half, S.Half, S.Half]) + assert represent(TensorProduct(JxKet(S.Half, S.Half), JxKet(S.Half, Rational(-1, 2))), basis=Jz) == \ + Matrix([Rational(-1, 2), S.Half, Rational(-1, 2), S.Half]) + assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, S.Half)), basis=Jz) == \ + Matrix([Rational(-1, 2), Rational(-1, 2), S.Half, S.Half]) + assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, Rational(-1, 2))), basis=Jz) == \ + Matrix([S.Half, Rational(-1, 2), Rational(-1, 2), S.Half]) + assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, S.Half)), basis=Jz) == \ + Matrix([S.Half, I/2, I/2, Rational(-1, 2)]) + assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, Rational(-1, 2))), basis=Jz) == \ + Matrix([I/2, S.Half, Rational(-1, 2), I/2]) + assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, S.Half)), basis=Jz) == \ + Matrix([I/2, Rational(-1, 2), S.Half, I/2]) + assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, Rational(-1, 2))), basis=Jz) == \ + Matrix([Rational(-1, 2), I/2, I/2, S.Half]) + assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), basis=Jz) == \ + Matrix([1, 0, 0, 0]) + assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), basis=Jz) == \ + Matrix([0, 1, 0, 0]) + assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), basis=Jz) == \ + Matrix([0, 0, 1, 0]) + assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), basis=Jz) == \ + Matrix([0, 0, 0, 1]) + + +def test_represent_coupled_states(): + # Jx basis + assert represent(JxKetCoupled(0, 0, (S.Half, S.Half)), basis=Jx) == \ + Matrix([1, 0, 0, 0]) + assert represent(JxKetCoupled(1, 1, (S.Half, S.Half)), basis=Jx) == \ + Matrix([0, 1, 0, 0]) + assert represent(JxKetCoupled(1, 0, (S.Half, S.Half)), basis=Jx) == \ + Matrix([0, 0, 1, 0]) + assert represent(JxKetCoupled(1, -1, (S.Half, S.Half)), basis=Jx) == \ + Matrix([0, 0, 0, 1]) + assert represent(JyKetCoupled(0, 0, (S.Half, S.Half)), basis=Jx) == \ + Matrix([1, 0, 0, 0]) + assert represent(JyKetCoupled(1, 1, (S.Half, S.Half)), basis=Jx) == \ + Matrix([0, -I, 0, 0]) + assert represent(JyKetCoupled(1, 0, (S.Half, S.Half)), basis=Jx) == \ + Matrix([0, 0, 1, 0]) + assert represent(JyKetCoupled(1, -1, (S.Half, S.Half)), basis=Jx) == \ + Matrix([0, 0, 0, I]) + assert represent(JzKetCoupled(0, 0, (S.Half, S.Half)), basis=Jx) == \ + Matrix([1, 0, 0, 0]) + assert represent(JzKetCoupled(1, 1, (S.Half, S.Half)), basis=Jx) == \ + Matrix([0, S.Half, -sqrt(2)/2, S.Half]) + assert represent(JzKetCoupled(1, 0, (S.Half, S.Half)), basis=Jx) == \ + Matrix([0, sqrt(2)/2, 0, -sqrt(2)/2]) + assert represent(JzKetCoupled(1, -1, (S.Half, S.Half)), basis=Jx) == \ + Matrix([0, S.Half, sqrt(2)/2, S.Half]) + # Jy basis + assert represent(JxKetCoupled(0, 0, (S.Half, S.Half)), basis=Jy) == \ + Matrix([1, 0, 0, 0]) + assert represent(JxKetCoupled(1, 1, (S.Half, S.Half)), basis=Jy) == \ + Matrix([0, I, 0, 0]) + assert represent(JxKetCoupled(1, 0, (S.Half, S.Half)), basis=Jy) == \ + Matrix([0, 0, 1, 0]) + assert represent(JxKetCoupled(1, -1, (S.Half, S.Half)), basis=Jy) == \ + Matrix([0, 0, 0, -I]) + assert represent(JyKetCoupled(0, 0, (S.Half, S.Half)), basis=Jy) == \ + Matrix([1, 0, 0, 0]) + assert represent(JyKetCoupled(1, 1, (S.Half, S.Half)), basis=Jy) == \ + Matrix([0, 1, 0, 0]) + assert represent(JyKetCoupled(1, 0, (S.Half, S.Half)), basis=Jy) == \ + Matrix([0, 0, 1, 0]) + assert represent(JyKetCoupled(1, -1, (S.Half, S.Half)), basis=Jy) == \ + Matrix([0, 0, 0, 1]) + assert represent(JzKetCoupled(0, 0, (S.Half, S.Half)), basis=Jy) == \ + Matrix([1, 0, 0, 0]) + assert represent(JzKetCoupled(1, 1, (S.Half, S.Half)), basis=Jy) == \ + Matrix([0, S.Half, -I*sqrt(2)/2, Rational(-1, 2)]) + assert represent(JzKetCoupled(1, 0, (S.Half, S.Half)), basis=Jy) == \ + Matrix([0, -I*sqrt(2)/2, 0, -I*sqrt(2)/2]) + assert represent(JzKetCoupled(1, -1, (S.Half, S.Half)), basis=Jy) == \ + Matrix([0, Rational(-1, 2), -I*sqrt(2)/2, S.Half]) + # Jz basis + assert represent(JxKetCoupled(0, 0, (S.Half, S.Half)), basis=Jz) == \ + Matrix([1, 0, 0, 0]) + assert represent(JxKetCoupled(1, 1, (S.Half, S.Half)), basis=Jz) == \ + Matrix([0, S.Half, sqrt(2)/2, S.Half]) + assert represent(JxKetCoupled(1, 0, (S.Half, S.Half)), basis=Jz) == \ + Matrix([0, -sqrt(2)/2, 0, sqrt(2)/2]) + assert represent(JxKetCoupled(1, -1, (S.Half, S.Half)), basis=Jz) == \ + Matrix([0, S.Half, -sqrt(2)/2, S.Half]) + assert represent(JyKetCoupled(0, 0, (S.Half, S.Half)), basis=Jz) == \ + Matrix([1, 0, 0, 0]) + assert represent(JyKetCoupled(1, 1, (S.Half, S.Half)), basis=Jz) == \ + Matrix([0, S.Half, I*sqrt(2)/2, Rational(-1, 2)]) + assert represent(JyKetCoupled(1, 0, (S.Half, S.Half)), basis=Jz) == \ + Matrix([0, I*sqrt(2)/2, 0, I*sqrt(2)/2]) + assert represent(JyKetCoupled(1, -1, (S.Half, S.Half)), basis=Jz) == \ + Matrix([0, Rational(-1, 2), I*sqrt(2)/2, S.Half]) + assert represent(JzKetCoupled(0, 0, (S.Half, S.Half)), basis=Jz) == \ + Matrix([1, 0, 0, 0]) + assert represent(JzKetCoupled(1, 1, (S.Half, S.Half)), basis=Jz) == \ + Matrix([0, 1, 0, 0]) + assert represent(JzKetCoupled(1, 0, (S.Half, S.Half)), basis=Jz) == \ + Matrix([0, 0, 1, 0]) + assert represent(JzKetCoupled(1, -1, (S.Half, S.Half)), 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.Half, S.Half, Rational(-1, 2), 0, pi/2, 0)], + [WignerD(S.Half, Rational(-1, 2), S.Half, 0, pi/2, 0), WignerD(S.Half, Rational(-1, 2), Rational(-1, 2), 0, pi/2, 0)]]) + assert represent(Rotation(0, pi/2, 0), doit=True) == \ + 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) + + +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, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2) * JzBra(j, mi), (mi, -j, j)) + assert JzBra(j, m).rewrite('Jx') == Sum( + WignerD(j, mi, m, 0, pi*Rational(3, 2), 0) * JxBra(j, mi), (mi, -j, j)) + assert JzBra(j, m).rewrite('Jy') == Sum( + WignerD(j, mi, m, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2) * JzKet(j, mi), (mi, -j, j)) + assert JzKet(j, m).rewrite('Jx') == Sum( + WignerD(j, mi, m, 0, pi*Rational(3, 2), 0) * JxKet(j, mi), (mi, -j, j)) + assert JzKet(j, m).rewrite('Jy') == Sum( + WignerD(j, mi, m, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 2), pi/2, pi/2) * JyKet(j2, mi), (mi, -j2, j2))) + + +def test_rewrite_coupled_state(): + # Numerical + assert JyKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jx') == \ + JxKetCoupled(0, 0, (S.Half, S.Half)) + assert JyKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jx') == \ + -I*JxKetCoupled(1, 1, (S.Half, S.Half)) + assert JyKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jx') == \ + JxKetCoupled(1, 0, (S.Half, S.Half)) + assert JyKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jx') == \ + I*JxKetCoupled(1, -1, (S.Half, S.Half)) + assert JzKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jx') == \ + JxKetCoupled(0, 0, (S.Half, S.Half)) + assert JzKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jx') == \ + JxKetCoupled(1, 1, (S.Half, S.Half))/2 - sqrt(2)*JxKetCoupled(1, 0, ( + S.Half, S.Half))/2 + JxKetCoupled(1, -1, (S.Half, S.Half))/2 + assert JzKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jx') == \ + sqrt(2)*JxKetCoupled(1, 1, (S( + 1)/2, S.Half))/2 - sqrt(2)*JxKetCoupled(1, -1, (S.Half, S.Half))/2 + assert JzKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jx') == \ + JxKetCoupled(1, 1, (S.Half, S.Half))/2 + sqrt(2)*JxKetCoupled(1, 0, ( + S.Half, S.Half))/2 + JxKetCoupled(1, -1, (S.Half, S.Half))/2 + assert JxKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jy') == \ + JyKetCoupled(0, 0, (S.Half, S.Half)) + assert JxKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jy') == \ + I*JyKetCoupled(1, 1, (S.Half, S.Half)) + assert JxKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jy') == \ + JyKetCoupled(1, 0, (S.Half, S.Half)) + assert JxKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jy') == \ + -I*JyKetCoupled(1, -1, (S.Half, S.Half)) + assert JzKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jy') == \ + JyKetCoupled(0, 0, (S.Half, S.Half)) + assert JzKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jy') == \ + JyKetCoupled(1, 1, (S.Half, S.Half))/2 - I*sqrt(2)*JyKetCoupled(1, 0, ( + S.Half, S.Half))/2 - JyKetCoupled(1, -1, (S.Half, S.Half))/2 + assert JzKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jy') == \ + -I*sqrt(2)*JyKetCoupled(1, 1, (S.Half, S.Half))/2 - I*sqrt( + 2)*JyKetCoupled(1, -1, (S.Half, S.Half))/2 + assert JzKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jy') == \ + -JyKetCoupled(1, 1, (S.Half, S.Half))/2 - I*sqrt(2)*JyKetCoupled(1, 0, (S.Half, S.Half))/2 + JyKetCoupled(1, -1, (S.Half, S.Half))/2 + assert JxKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jz') == \ + JzKetCoupled(0, 0, (S.Half, S.Half)) + assert JxKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jz') == \ + JzKetCoupled(1, 1, (S.Half, S.Half))/2 + sqrt(2)*JzKetCoupled(1, 0, ( + S.Half, S.Half))/2 + JzKetCoupled(1, -1, (S.Half, S.Half))/2 + assert JxKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jz') == \ + -sqrt(2)*JzKetCoupled(1, 1, (S( + 1)/2, S.Half))/2 + sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half))/2 + assert JxKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jz') == \ + JzKetCoupled(1, 1, (S.Half, S.Half))/2 - sqrt(2)*JzKetCoupled(1, 0, ( + S.Half, S.Half))/2 + JzKetCoupled(1, -1, (S.Half, S.Half))/2 + assert JyKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jz') == \ + JzKetCoupled(0, 0, (S.Half, S.Half)) + assert JyKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jz') == \ + JzKetCoupled(1, 1, (S.Half, S.Half))/2 + I*sqrt(2)*JzKetCoupled(1, 0, ( + S.Half, S.Half))/2 - JzKetCoupled(1, -1, (S.Half, S.Half))/2 + assert JyKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jz') == \ + I*sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half))/2 + I*sqrt( + 2)*JzKetCoupled(1, -1, (S.Half, S.Half))/2 + assert JyKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jz') == \ + -JzKetCoupled(1, 1, (S.Half, S.Half))/2 + I*sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half))/2 + JzKetCoupled(1, -1, (S.Half, S.Half))/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, pi*Rational(3, 2), 0) * JxKetCoupled(j, mi, ( + j1, j2)), (mi, -j, j)) + assert JxKetCoupled(j, m, (j1, j2)).rewrite('Jy') == \ + Sum(WignerD(j, mi, m, pi*Rational(3, 2), 0, 0) * JyKetCoupled(j, mi, ( + j1, j2)), (mi, -j, j)) + assert JzKetCoupled(j, m, (j1, j2)).rewrite('Jy') == \ + Sum(WignerD(j, mi, m, pi*Rational(3, 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, pi*Rational(3, 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 + + +def test_uncouple_2_coupled_states(): + # j1=1/2, j2=1/2 + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( + TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( + TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) + # j1=1/2, j2=1 + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)) == \ + expand(uncouple( + couple( TensorProduct(JzKet(S.Half, Rational(-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)) ))) + + +def test_uncouple_3_coupled_states(): + # Default coupling + # j1=1/2, j2=1/2, j3=1/2 + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet( + S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S( + 1)/2, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.NegativeOne/ + 2), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) + # j1=1/2, j2=1, j3=1/2 + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct( + JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) ))) + # Coupling j1+j3=j13, j13+j2=j + # j1=1/2, j2=1/2, j3=1/2 + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( + S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( + S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( + S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( + S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( + S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( + S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( + S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( + S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) + # j1=1/2, j2=1, j3=1/2 + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( + 1)/2), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( + 1)/2), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( + 1)/2), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( + 1)/2), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( + 1)/2), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( + 1)/2), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( + -1)/2), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( + -1)/2), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( + -1)/2), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( + -1)/2), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( + -1)/2), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.NegativeOne/ + 2), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) + + +@slow +def test_uncouple_4_coupled_states(): + # j1=1/2, j2=1/2, j3=1/2, j4=1/2 + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( + S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( + 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( + 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( + 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( + 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( + 1)/2, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( + S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( + 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( + 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( + 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( + 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( + 1)/2, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) + # j1=1/2, j2=1/2, j3=1, j4=1/2 + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), + JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), + JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), + JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), + JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), + JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( + S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), + JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( + S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), + JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( + S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( + S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( + S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), + JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), + JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), + JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), + JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), + JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( + S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), + JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( + S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), + JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( + S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( + S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( + S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-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.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + # j1=1/2, j2=1/2, j3=1, j4=1/2 + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) + assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ + expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-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.Half, S.Half))) == \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))/2 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))/2 + assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half))) == \ + TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) + assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half))) == \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))/2 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))/2 + assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half))) == \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) + # j1=1, j2=1/2 + assert uncouple(JzKetCoupled(S.Half, S.Half, (1, S.Half))) == \ + -sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(S.Half, S.Half))/3 + \ + sqrt(6)*TensorProduct(JzKet(1, 1), JzKet(S.Half, Rational(-1, 2)))/3 + assert uncouple(JzKetCoupled(S.Half, Rational(-1, 2), (1, S.Half))) == \ + sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(S.Half, Rational(-1, 2)))/3 - \ + sqrt(6)*TensorProduct(JzKet(1, -1), JzKet(S.Half, S.Half))/3 + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(3, 2), (1, S.Half))) == \ + TensorProduct(JzKet(1, 1), JzKet(S.Half, S.Half)) + assert uncouple(JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half))) == \ + sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(S.Half, Rational(-1, 2)))/3 + \ + sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(S.Half, S.Half))/3 + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half))) == \ + sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(S.Half, Rational(-1, 2)))/3 + \ + sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(S.Half, S.Half))/3 + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-3, 2), (1, S.Half))) == \ + TensorProduct(JzKet(1, -1), JzKet(S.Half, Rational(-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)) + + +def test_uncouple_3_coupled_states_numerical(): + # Default coupling + # j1=1/2, j2=1/2, j3=1/2 + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half))) == \ + TensorProduct(JzKet( + S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) + assert uncouple(JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half))) == \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))/3 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))/3 + \ + sqrt(3)*TensorProduct(JzKet( + S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))/3 + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half))) == \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))/3 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))/3 + \ + sqrt(3)*TensorProduct(JzKet( + S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))/3 + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half))) == \ + TensorProduct(JzKet( + S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) + # j1=1/2, j2=1/2, j3=1 + assert uncouple(JzKetCoupled(2, 2, (S.Half, S.Half, 1))) == \ + TensorProduct( + JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1)) + assert uncouple(JzKetCoupled(2, 1, (S.Half, S.Half, 1))) == \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))/2 + \ + sqrt(2)*TensorProduct( + JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))/2 + assert uncouple(JzKetCoupled(2, 0, (S.Half, S.Half, 1))) == \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0))/3 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))/3 + \ + sqrt(6)*TensorProduct( + JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(2, -1, (S.Half, S.Half, 1))) == \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))/2 + \ + TensorProduct( + JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(2, -2, (S.Half, S.Half, 1))) == \ + TensorProduct( + JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)) + assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half, 1))) == \ + -TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))/2 + \ + sqrt(2)*TensorProduct( + JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))/2 + assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half, 1))) == \ + -sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))/2 + \ + sqrt(2)*TensorProduct( + JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half, 1))) == \ + -sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1))/2 + \ + TensorProduct( + JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))/2 + # j1=1/2, j2=1, j3=1 + assert uncouple(JzKetCoupled(Rational(5, 2), Rational(5, 2), (S.Half, 1, 1))) == \ + TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1)) + assert uncouple(JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, 1, 1))) == \ + sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/5 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/5 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), + JzKet(1, 0))/5 + assert uncouple(JzKetCoupled(Rational(5, 2), S.Half, (S.Half, 1, 1))) == \ + sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/5 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/5 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(10)*TensorProduct( + JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/10 + assert uncouple(JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1))) == \ + sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/5 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), + JzKet(1, -1))/5 + assert uncouple(JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1))) == \ + sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/5 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/5 + \ + sqrt(5)*TensorProduct( + JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/5 + assert uncouple(JzKetCoupled(Rational(5, 2), Rational(-5, 2), (S.Half, 1, 1))) == \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1)) + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1))) == \ + -sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/15 - \ + 2*sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), + JzKet(1, 0))/5 + assert uncouple(JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1))) == \ + -4*sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/15 - \ + 2*sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/15 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), + JzKet(1, -1))/5 + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1))) == \ + -sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/5 - \ + sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 + \ + 2*sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/15 - \ + sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/15 + \ + 4*sqrt(5)*TensorProduct( + JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1))) == \ + -sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/5 + \ + 2*sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(30)*TensorProduct( + JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1))) == \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/3 - \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/3 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/6 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/3 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), + JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1))) == \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/2 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/3 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/6 - \ + TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/3 + \ + TensorProduct(JzKet(S.Half, S.Half), 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 + # Defined j13 + # j1=1/2, j2=1/2, j3=1, j13=1/2 + assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )) == \ + -sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))/3 + \ + sqrt(3)*TensorProduct( + JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )) == \ + -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))/3 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0))/6 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct( + JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )) == \ + -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))/3 + \ + sqrt(6)*TensorProduct( + JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))/3 + # j1=1/2, j2=1, j3=1, j13=1/2 + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))))) == \ + -sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/3 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), + JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))))) == \ + -2*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/3 - \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/3 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/3 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), + JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))))) == \ + -sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/3 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/3 + \ + TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/3 + \ + 2*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))))) == \ + -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/3 + \ + sqrt(6)*TensorProduct( + JzKet(S.Half, S.Half), 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 + + +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.Half, S.Half, 1, 1))) == \ + TensorProduct(JzKet( + S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1)) + assert uncouple(JzKetCoupled(3, 2, (S.Half, S.Half, 1, 1))) == \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/3 + \ + sqrt(3)*TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(3, 1, (S.Half, S.Half, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), JzKet(1, 1), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(3, 0, (S.Half, S.Half, 1, 1))) == \ + sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/10 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/10 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), JzKet(1, 0), JzKet(1, -1))/10 + assert uncouple(JzKetCoupled(3, -1, (S.Half, S.Half, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), JzKet(1, -1), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(3, -2, (S.Half, S.Half, 1, 1))) == \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/3 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/3 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(3, -3, (S.Half, S.Half, 1, 1))) == \ + TensorProduct(JzKet(S.Half, -S( + 1)/2), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1)) + assert uncouple(JzKetCoupled(2, 2, (S.Half, S.Half, 1, 1))) == \ + -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1))/6 - \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/6 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(2, 1, (S.Half, S.Half, 1, 1))) == \ + -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/6 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/12 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/12 - \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(2, 0, (S.Half, S.Half, 1, 1))) == \ + -TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/2 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/4 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/4 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/4 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/4 + \ + TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(2, -1, (S.Half, S.Half, 1, 1))) == \ + -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/3 - \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/6 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/12 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/6 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/12 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), JzKet(1, -1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(2, -2, (S.Half, S.Half, 1, 1))) == \ + -sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/3 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/30 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/20 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/20 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/30 - \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/10 + \ + sqrt(15)*TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/5 + assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/10 - \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/20 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/20 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/20 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/20 - \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), JzKet(1, 0), JzKet(1, -1))/10 + assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half, 1, 1))) == \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/5 - \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/10 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/20 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/20 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/30 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), 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.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ + -sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/2 + \ + sqrt(2)*TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/2 + assert uncouple(JzKetCoupled(2, 1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ + -sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/4 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/4 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/4 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/4 - \ + TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(2, 0, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ + -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/6 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/6 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/6 - \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/6 + \ + sqrt(3)*TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(2, -1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ + -TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/2 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/4 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/4 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/4 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/4 + assert uncouple(JzKetCoupled(2, -2, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ + -sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/2 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, + Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 1)))) == \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/4 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/4 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/4 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/4 - \ + TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/2 + \ + TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 1)))) == \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/2 - \ + TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 1)))) == \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/2 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/4 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/4 - \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/4 + \ + sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + Rational(-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.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + TensorProduct(JzKet( + S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1)) + assert uncouple(JzKetCoupled(3, 2, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/3 + \ + sqrt(3)*TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/3 + assert uncouple(JzKetCoupled(3, 1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), JzKet(1, 1), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(3, 0, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/10 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/10 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/5 + \ + sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/10 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/10 + \ + sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), JzKet(1, 0), JzKet(1, -1))/10 + assert uncouple(JzKetCoupled(3, -1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/15 + \ + 2*sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/15 + \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), JzKet(1, -1), JzKet(1, -1))/15 + assert uncouple(JzKetCoupled(3, -2, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/3 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/3 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(3, -3, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ + TensorProduct(JzKet(S.Half, -S( + 1)/2), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1)) + assert uncouple(JzKetCoupled(2, 2, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ + -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1))/3 - \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/3 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/6 + assert uncouple(JzKetCoupled(2, 1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ + -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/3 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/12 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/12 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/12 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/12 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/3 + \ + sqrt(3)*TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/6 + assert uncouple(JzKetCoupled(2, 0, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ + -TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/2 - \ + TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/2 + \ + TensorProduct(JzKet(S( + 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/2 + assert uncouple(JzKetCoupled(2, -1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ + -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/6 - \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/3 - \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/6 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/12 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/12 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/12 + \ + sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/12 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), JzKet(1, -1), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(2, -2, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ + -sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/6 - \ + sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/6 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/3 + \ + sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1))/3 + assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 1)))) == \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/5 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/20 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/20 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/20 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/20 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/30 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), JzKet(1, 1), JzKet(1, -1))/30 + assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 1)))) == \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/10 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/10 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/30 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/10 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), JzKet(1, 0), JzKet(1, -1))/10 + assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 1)))) == \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/30 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/30 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/20 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/20 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/20 - \ + sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/20 + \ + sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, + S.Half), 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)), + (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)) + + +def test_couple_2_states(): + # j1=1/2, j2=1/2 + assert JzKetCoupled(0, 0, (S.Half, S.Half)) == \ + expand(couple(uncouple( JzKetCoupled(0, 0, (S.Half, S.Half)) ))) + assert JzKetCoupled(1, 1, (S.Half, S.Half)) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, S.Half)) ))) + assert JzKetCoupled(1, 0, (S.Half, S.Half)) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, S.Half)) ))) + assert JzKetCoupled(1, -1, (S.Half, S.Half)) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, S.Half)) ))) + # j1=1, j2=1/2 + assert JzKetCoupled(S.Half, S.Half, (1, S.Half)) == \ + expand(couple(uncouple( JzKetCoupled(S.Half, S.Half, (1, S.Half)) ))) + assert JzKetCoupled(S.Half, Rational(-1, 2), (1, S.Half)) == \ + expand(couple(uncouple( JzKetCoupled(S.Half, Rational(-1, 2), (1, S.Half)) ))) + assert JzKetCoupled(Rational(3, 2), Rational(3, 2), (1, S.Half)) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(3, 2), (1, S.Half)) ))) + assert JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half)) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half)) ))) + assert JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half)) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half)) ))) + assert JzKetCoupled(Rational(3, 2), Rational(-3, 2), (1, S.Half)) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-3, 2), (1, S.Half)) ))) + # 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)) ))) + # j1=1/2, j2=3/2 + assert JzKetCoupled(1, 1, (S.Half, Rational(3, 2))) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, Rational(3, 2))) ))) + assert JzKetCoupled(1, 0, (S.Half, Rational(3, 2))) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, Rational(3, 2))) ))) + assert JzKetCoupled(1, -1, (S.Half, Rational(3, 2))) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, Rational(3, 2))) ))) + assert JzKetCoupled(2, 2, (S.Half, Rational(3, 2))) == \ + expand(couple(uncouple( JzKetCoupled(2, 2, (S.Half, Rational(3, 2))) ))) + assert JzKetCoupled(2, 1, (S.Half, Rational(3, 2))) == \ + expand(couple(uncouple( JzKetCoupled(2, 1, (S.Half, Rational(3, 2))) ))) + assert JzKetCoupled(2, 0, (S.Half, Rational(3, 2))) == \ + expand(couple(uncouple( JzKetCoupled(2, 0, (S.Half, Rational(3, 2))) ))) + assert JzKetCoupled(2, -1, (S.Half, Rational(3, 2))) == \ + expand(couple(uncouple( JzKetCoupled(2, -1, (S.Half, Rational(3, 2))) ))) + assert JzKetCoupled(2, -2, (S.Half, Rational(3, 2))) == \ + expand(couple(uncouple( JzKetCoupled(2, -2, (S.Half, Rational(3, 2))) ))) + + +def test_couple_3_states(): + # Default coupling + # j1=1/2, j2=1/2, j3=1/2 + assert JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half)) == \ + expand(couple(uncouple( + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half)) == \ + expand(couple(uncouple( + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half)) ))) + # j1=1/2, j2=1/2, j3=1 + assert JzKetCoupled(0, 0, (S.Half, S.Half, 1)) == \ + expand(couple(uncouple( JzKetCoupled(0, 0, (S.Half, S.Half, 1)) ))) + assert JzKetCoupled(1, 1, (S.Half, S.Half, 1)) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, S.Half, 1)) ))) + assert JzKetCoupled(1, 0, (S.Half, S.Half, 1)) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, S.Half, 1)) ))) + assert JzKetCoupled(1, -1, (S.Half, S.Half, 1)) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, S.Half, 1)) ))) + assert JzKetCoupled(2, 2, (S.Half, S.Half, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, 2, (S.Half, S.Half, 1)) ))) + assert JzKetCoupled(2, 1, (S.Half, S.Half, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, 1, (S.Half, S.Half, 1)) ))) + assert JzKetCoupled(2, 0, (S.Half, S.Half, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, 0, (S.Half, S.Half, 1)) ))) + assert JzKetCoupled(2, -1, (S.Half, S.Half, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, -1, (S.Half, S.Half, 1)) ))) + assert JzKetCoupled(2, -2, (S.Half, S.Half, 1)) == \ + expand(couple(uncouple( JzKetCoupled(2, -2, (S.Half, S.Half, 1)) ))) + # Couple j1+j3=j13, j13+j2=j + # j1=1/2, j2=1/2, j3=1/2, j13=0 + assert JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half))) == \ + expand(couple(uncouple( JzKetCoupled(S.Half, S.Half, (S.Half, S( + 1)/2, S.Half), ((1, 3, 0), (1, 2, S.Half))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half))) == \ + expand(couple(uncouple( JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S( + 1)/2, S.Half), ((1, 3, 0), (1, 2, S.Half))) ), ((1, 3), (1, 2)) )) + # j1=1, j2=1/2, j3=1, j13=1 + assert JzKetCoupled(S.Half, S.Half, (1, S.Half, 1), ((1, 3, 1), (1, 2, S.Half))) == \ + expand(couple(uncouple( JzKetCoupled(S.Half, S.Half, ( + 1, S.Half, 1), ((1, 3, 1), (1, 2, S.Half))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(S.Half, Rational(-1, 2), (1, S.Half, 1), ((1, 3, 1), (1, 2, S.Half))) == \ + expand(couple(uncouple( JzKetCoupled(S.Half, Rational(-1, 2), ( + 1, S.Half, 1), ((1, 3, 1), (1, 2, S.Half))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(Rational(3, 2), Rational(3, 2), (1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(3, 2), ( + 1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), S.Half, ( + 1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-1, 2), ( + 1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) ), ((1, 3), (1, 2)) )) + assert JzKetCoupled(Rational(3, 2), Rational(-3, 2), (1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-3, 2), ( + 1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(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.Half, S.Half, S.Half, S.Half)) == \ + expand(couple( + uncouple( JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half)) == \ + expand(couple( + uncouple( JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half)) == \ + expand(couple(uncouple( + JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(2, 2, (S.Half, S.Half, S.Half, S.Half)) == \ + expand(couple( + uncouple( JzKetCoupled(2, 2, (S.Half, S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(2, 1, (S.Half, S.Half, S.Half, S.Half)) == \ + expand(couple( + uncouple( JzKetCoupled(2, 1, (S.Half, S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.Half)) == \ + expand(couple( + uncouple( JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(2, -1, (S.Half, S.Half, S.Half, S.Half)) == \ + expand(couple(uncouple( + JzKetCoupled(2, -1, (S.Half, S.Half, S.Half, S.Half)) ))) + assert JzKetCoupled(2, -2, (S.Half, S.Half, S.Half, S.Half)) == \ + expand(couple(uncouple( + JzKetCoupled(2, -2, (S.Half, S.Half, S.Half, S.Half)) ))) + # j1=1/2, j2=1/2, j3=1/2, j4=1 + assert JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1)) ))) + assert JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) ))) + assert JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1)) ))) + assert JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1)) ))) + assert JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) ))) + assert JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1)) ))) + assert JzKetCoupled(Rational(5, 2), Rational(5, 2), (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(5, 2), Rational(5, 2), (S.Half, S.Half, S.Half, 1)) ))) + assert JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1)) ))) + assert JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S.Half, S.Half, 1)) ))) + assert JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) ))) + assert JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1)) ))) + assert JzKetCoupled(Rational(5, 2), Rational(-5, 2), (S.Half, S.Half, S.Half, 1)) == \ + expand(couple(uncouple( + JzKetCoupled(Rational(5, 2), Rational(-5, 2), (S.Half, S.Half, S.Half, 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.Half, S.Half, S.Half, S.Half), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((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.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, S.Half)) ) == \ + expand(couple(uncouple( JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, S.Half)) )), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, S.Half)) ) == \ + expand(couple(uncouple( JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, S.Half)) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) == \ + expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(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.Half, 1, S.Half, 1), ((1, 3, 0), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, 1, S.Half, 1), ( + (1, 3, 0), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, 0, (S.Half, 1, S.Half, 1), ((1, 3, 0), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, 1, S.Half, 1), ( + (1, 3, 0), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, -1, (S.Half, 1, S.Half, 1), ((1, 3, 0), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, 1, S.Half, 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.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 0)) ) == \ + expand(couple(uncouple( JzKetCoupled(0, 0, (S.Half, 1, S.Half, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 0))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, 1, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, 1, S.Half, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, 0, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, 1, S.Half, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(1, -1, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 1)) ) == \ + expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, 1, S.Half, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(2, 2, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ + expand(couple(uncouple( JzKetCoupled(2, 2, (S.Half, 1, S.Half, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(2, 1, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ + expand(couple(uncouple( JzKetCoupled(2, 1, (S.Half, 1, S.Half, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(2, 0, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ + expand(couple(uncouple( JzKetCoupled(2, 0, (S.Half, 1, S.Half, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(2, -1, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ + expand(couple(uncouple( JzKetCoupled(2, -1, (S.Half, 1, S.Half, 1), ( + (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) + assert JzKetCoupled(2, -2, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ + expand(couple(uncouple( JzKetCoupled(2, -2, (S.Half, 1, S.Half, 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.Half, S.Half), JzKet(S.Half, S.Half))) == \ + JzKetCoupled(1, 1, (S.Half, S.Half)) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ + sqrt(2)*JzKetCoupled(0, 0, (S( + 1)/2, S.Half))/2 + sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half))/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ + -sqrt(2)*JzKetCoupled(0, 0, (S( + 1)/2, S.Half))/2 + sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half))/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ + JzKetCoupled(1, -1, (S.Half, S.Half)) + # j1=1, j2=1/2 + assert couple(TensorProduct(JzKet(1, 1), JzKet(S.Half, S.Half))) == \ + JzKetCoupled(Rational(3, 2), Rational(3, 2), (1, S.Half)) + assert couple(TensorProduct(JzKet(1, 1), JzKet(S.Half, Rational(-1, 2)))) == \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (1, S.Half))/3 + sqrt( + 3)*JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half))/3 + assert couple(TensorProduct(JzKet(1, 0), JzKet(S.Half, S.Half))) == \ + -sqrt(3)*JzKetCoupled(S.Half, S.Half, (1, S.Half))/3 + \ + sqrt(6)*JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half))/3 + assert couple(TensorProduct(JzKet(1, 0), JzKet(S.Half, Rational(-1, 2)))) == \ + sqrt(3)*JzKetCoupled(S.Half, Rational(-1, 2), (1, S.Half))/3 + \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half))/3 + assert couple(TensorProduct(JzKet(1, -1), JzKet(S.Half, S.Half))) == \ + -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (1, S( + 1)/2))/3 + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half))/3 + assert couple(TensorProduct(JzKet(1, -1), JzKet(S.Half, Rational(-1, 2)))) == \ + JzKetCoupled(Rational(3, 2), Rational(-3, 2), (1, S.Half)) + # 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)) + # j1=3/2, j2=1/2 + assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(3, 2)), JzKet(S.Half, S.Half))) == \ + JzKetCoupled(2, 2, (Rational(3, 2), S.Half)) + assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(3, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ + sqrt(3)*JzKetCoupled( + 1, 1, (Rational(3, 2), S.Half))/2 + JzKetCoupled(2, 1, (Rational(3, 2), S.Half))/2 + assert couple(TensorProduct(JzKet(Rational(3, 2), S.Half), JzKet(S.Half, S.Half))) == \ + -JzKetCoupled(1, 1, (S( + 3)/2, S.Half))/2 + sqrt(3)*JzKetCoupled(2, 1, (Rational(3, 2), S.Half))/2 + assert couple(TensorProduct(JzKet(Rational(3, 2), S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ + sqrt(2)*JzKetCoupled(1, 0, (S( + 3)/2, S.Half))/2 + sqrt(2)*JzKetCoupled(2, 0, (Rational(3, 2), S.Half))/2 + assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ + -sqrt(2)*JzKetCoupled(1, 0, (S( + 3)/2, S.Half))/2 + sqrt(2)*JzKetCoupled(2, 0, (Rational(3, 2), S.Half))/2 + assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ + JzKetCoupled(1, -1, (S( + 3)/2, S.Half))/2 + sqrt(3)*JzKetCoupled(2, -1, (Rational(3, 2), S.Half))/2 + assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(-3, 2)), JzKet(S.Half, S.Half))) == \ + -sqrt(3)*JzKetCoupled(1, -1, (Rational(3, 2), S.Half))/2 + \ + JzKetCoupled(2, -1, (Rational(3, 2), S.Half))/2 + assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(-3, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ + JzKetCoupled(2, -2, (Rational(3, 2), S.Half)) + + +def test_couple_3_states_numerical(): + # Default coupling + # j1=1/2,j2=1/2,j3=1/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ + JzKetCoupled(Rational(3, 2), S( + 3)/2, (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2))) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/3 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ + 2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half)) )/2 - \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ + 2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half)) )/2 + \ + sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One + /2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ + -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half)) )/2 - \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ + 2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ + -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half)) )/2 + \ + sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One + /2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ + -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/3 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One + /2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ + JzKetCoupled(Rational(3, 2), -S( + 3)/2, (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2))) ) + # j1=S.Half, j2=S.Half, j3=1 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ + JzKetCoupled(2, 2, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ + sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(2)*JzKetCoupled( + 2, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 0)) )/3 + \ + sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled( + 2, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ + sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ + -sqrt(6)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 0)) )/6 + \ + sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ + sqrt(3)*JzKetCoupled( + 2, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/3 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ + -sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ + -sqrt(6)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 0)) )/6 - \ + sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ + sqrt(3)*JzKetCoupled( + 2, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/3 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ + -sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 0)) )/3 - \ + sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled( + 2, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ + -sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ + sqrt(2)*JzKetCoupled( + 2, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ + JzKetCoupled(2, -2, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) ) + # j1=S.Half, j2=1, j3=1 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1))) == \ + JzKetCoupled( + Rational(5, 2), Rational(5, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))) == \ + sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/2 + \ + sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, 1, 1), ((1, + 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))) == \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))) == \ + JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 - \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 + \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ + JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + 4*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, + 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))) == \ + -2*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/6 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, 1, 1), ((1, + 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))) == \ + -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 - \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ + 2*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, + 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))) == \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, + 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))) == \ + -sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))) == \ + -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 - \ + JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ + 2*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))) == \ + -2*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, + 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))) == \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 + \ + JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ + JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + 4*sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))) == \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 - \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, + 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))) == \ + -sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, + 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))) == \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/2 - \ + sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, + 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))) == \ + -sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, + 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1))) == \ + JzKetCoupled(S( + 5)/2, Rational(-5, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(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)) ) + # j1=S.Half, j2=S.Half, j3=Rational(3, 2) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(3, 2)))) == \ + JzKetCoupled(Rational(5, 2), S( + 5)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), S.Half))) == \ + sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/5 + \ + sqrt(15)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3) + /2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-1, 2)))) == \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ + 2*sqrt(30)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-3, 2)))) == \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/2 + \ + sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), -S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(3, 2)))) == \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/10 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3)/ + 2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), S.Half))) == \ + -sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/30 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-1, 2)))) == \ + -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/30 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), -S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-3, 2)))) == \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/10 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S(3) + /2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(3, 2)))) == \ + -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/10 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3)/ + 2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), S.Half))) == \ + -sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/30 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-1, 2)))) == \ + -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/30 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), -S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-3, 2)))) == \ + -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/10 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S(3) + /2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(3, 2)))) == \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/2 - \ + sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), S.Half))) == \ + sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 - \ + 2*sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), -S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-1, 2)))) == \ + -sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/5 + \ + sqrt(15)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S( + 3)/2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-3, 2)))) == \ + JzKetCoupled(Rational(5, 2), -S( + 5)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) ) + # Couple j1 to j3 + # j1=1/2, j2=1/2, j3=1/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(Rational(3, 2), S( + 3)/2, (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, Rational(3, 2))) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half)) )/2 - \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ + 2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/3 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ + 2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half)) )/2 + \ + sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One + /2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half)) )/2 - \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ + 2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/3 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One + /2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half)) )/2 + \ + sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One + /2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(Rational(3, 2), -S( + 3)/2, (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, Rational(3, 2))) ) + # j1=1/2, j2=1/2, j3=1 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(2, 2, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 - \ + sqrt(6)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ + sqrt(2)*JzKetCoupled( + 2, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 0)) )/3 + \ + sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 - \ + sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ + sqrt(6)*JzKetCoupled( + 2, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/2 + \ + JzKetCoupled(2, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 0)) )/6 + \ + sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/6 + \ + sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/3 + \ + sqrt(3)*JzKetCoupled( + 2, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/3 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 + \ + sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ + JzKetCoupled( + 2, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 - \ + sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ + JzKetCoupled(2, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 0)) )/6 - \ + sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/6 - \ + sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/3 + \ + sqrt(3)*JzKetCoupled( + 2, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/3 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/2 + \ + JzKetCoupled( + 2, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 0)) )/3 - \ + sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 + \ + sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ + sqrt(6)*JzKetCoupled( + 2, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 + \ + sqrt(6)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ + sqrt(2)*JzKetCoupled( + 2, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(2, -2, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) ) + # j 1=1/2, j 2=1, j 3=1 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled( + Rational(5, 2), Rational(5, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ + 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -2*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/6 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, 1, 1), ((1, + 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 - \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ + sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(S( + 5)/2, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 - \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 + \ + 2*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ + sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, + 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/2 + \ + sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, 1, 1), ((1, + 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 + \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 + \ + JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ + 4*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, + 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, + 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 + \ + JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 - \ + JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ + 4*sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/2 - \ + sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, + 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 - \ + JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 - \ + 2*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ + sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(S( + 5)/2, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 - \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ + sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, + 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + -sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, + 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ + -2*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, + 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ + 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, + 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(S( + 5)/2, Rational(-5, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(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)) ) + # j1=1/2, j2=1/2, j3=3/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(3, 2))), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(Rational(5, 2), S( + 5)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), S.Half)), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 - \ + sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ + sqrt(15)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3) + /2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 - \ + sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-3, 2))), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/2 + \ + JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 - \ + sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), -S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(3, 2))), ((1, 3), (1, 2)) ) == \ + 2*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3)/ + 2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), S.Half)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/6 + \ + 3*sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 + \ + sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), -S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-3, 2))), ((1, 3), (1, 2)) ) == \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 + \ + sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S(3) + /2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(3, 2))), ((1, 3), (1, 2)) ) == \ + -sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 - \ + sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3)/ + 2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), S.Half)), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 - \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 - \ + sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ + sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 - \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/6 - \ + 3*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), -S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-3, 2))), ((1, 3), (1, 2)) ) == \ + -2*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S(3) + /2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(3, 2))), ((1, 3), (1, 2)) ) == \ + -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/2 - \ + JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 + \ + sqrt(15)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), S.Half)), ((1, 3), (1, 2)) ) == \ + -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 - \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 + \ + sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ + sqrt(30)*JzKetCoupled(Rational(5, 2), -S( + 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ + -JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 + \ + sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ + sqrt(15)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S( + 3)/2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-3, 2))), ((1, 3), (1, 2)) ) == \ + JzKetCoupled(Rational(5, 2), -S( + 5)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(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.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ + JzKetCoupled(2, 2, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ + sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/2 + \ + JzKetCoupled(2, 1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ + sqrt(6)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/3 - \ + sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, 1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)) )/3 + \ + sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/3 + \ + sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ + sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 - \ + sqrt(6)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 - \ + sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, 1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), + JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ + JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), + ((1, 2, 0), (1, 3, S.Half), (1, 4, 0)))/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), + ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)))/6 + \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), + ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)))/2 - \ + sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), + ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)))/6 + \ + sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), + ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)))/6 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.Half), + ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)))/6 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ + -JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)) )/6 + \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 + \ + sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 - \ + sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ + sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 + \ + sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, -1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ + -sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 - \ + sqrt(6)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 - \ + sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, 1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ + -JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)) )/6 - \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 - \ + sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ + JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)) )/6 - \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 + \ + sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 - \ + sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ + -sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 + \ + sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, -1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)) )/3 - \ + sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/3 - \ + sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ + -sqrt(6)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/3 + \ + sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ + JzKetCoupled(2, -1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ + -sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/2 + \ + JzKetCoupled(2, -1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ + JzKetCoupled(2, -2, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) ) + # j1=S.Half, S.Half, S.Half, 1 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ + JzKetCoupled(Rational(5, 2), Rational(5, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ + sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/2 + \ + sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 + \ + 2*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ + sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ + 2*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/2 - \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ + JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ + sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ + sqrt(3)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 + \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ + -sqrt(3)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 + \ + sqrt(6)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ + -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ + JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ + sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/2 + \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ + -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/2 - \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ + -sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 - \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ + JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ + sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ + -sqrt(3)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 - \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ + sqrt(3)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 - \ + sqrt(6)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ + sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 - \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ + JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ + sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ + -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/2 + \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ + 2*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 - \ + 2*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ + sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ + -sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/2 - \ + sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ + -sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ + JzKetCoupled(Rational(5, 2), Rational(-5, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(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.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(2, 2, (S( + 1)/2, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/3 + \ + sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 + \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ + -JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 + \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, 1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ + -JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 - \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 - \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/3 - \ + sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ + 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 - \ + JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ + JzKetCoupled(2, -1, (S.Half, S( + 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(2, -2, (S( + 1)/2, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) ) + # j1=S.Half, S.Half, S.Half, 1 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(Rational(5, 2), Rational(5, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) ) + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + 2*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ + JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + 4*sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/2 + \ + sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/2 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/10 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/3 + \ + JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(3)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 - \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 + \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/6 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/30 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(3)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 - \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 + \ + sqrt(6)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/6 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/30 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/3 - \ + JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/2 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/10 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/2 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/10 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ + sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/3 + \ + JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(3)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 - \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 - \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/6 + \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/30 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(3)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ + JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 - \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 - \ + sqrt(6)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/6 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/30 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/3 - \ + JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ + sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/2 + \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/10 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/2 - \ + sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ + JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ + JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + 4*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ + 2*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ + sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 - \ + sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ + -sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ + 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ + sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 + assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ + JzKetCoupled(Rational(5, 2), Rational(-5, 2), (S.Half, S( + 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(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)) ), + (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)) + + +def test_innerproduct(): + assert InnerProduct(JzBra(1, 1), JzKet(1, 1)).doit() == 1 + assert InnerProduct( + JzBra(S.Half, S.Half), JzKet(S.Half, Rational(-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.Half, S.Half), JzKet(S.Half, S.Half)).doit() == -sqrt(2)/2 + assert InnerProduct(JyBra(1, 1), JzKet(1, 1)).doit() == S.Half + assert InnerProduct(JxBra(1, -1), JyKet(1, 1)).doit() == 0 + + +def test_rotation_small_d(): + # Symbolic tests + # j = 1/2 + assert Rotation.d(S.Half, S.Half, S.Half, beta).doit() == cos(beta/2) + assert Rotation.d(S.Half, S.Half, Rational(-1, 2), beta).doit() == -sin(beta/2) + assert Rotation.d(S.Half, Rational(-1, 2), S.Half, beta).doit() == sin(beta/2) + assert Rotation.d(S.Half, Rational(-1, 2), Rational(-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 + # j = 3/2 + assert Rotation.d(S( + 3)/2, Rational(3, 2), Rational(3, 2), beta).doit() == (3*cos(beta/2) + cos(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), S( + 3)/2, S.Half, beta).doit() == -sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), S( + 3)/2, Rational(-1, 2), beta).doit() == sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), S( + 3)/2, Rational(-3, 2), beta).doit() == (-3*sin(beta/2) + sin(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), S( + 1)/2, Rational(3, 2), beta).doit() == sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4 + assert Rotation.d(S( + 3)/2, S.Half, S.Half, beta).doit() == (cos(beta/2) + 3*cos(beta*Rational(3, 2)))/4 + assert Rotation.d(S( + 3)/2, S.Half, Rational(-1, 2), beta).doit() == (sin(beta/2) - 3*sin(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), S( + 1)/2, Rational(-3, 2), beta).doit() == sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), -S( + 1)/2, Rational(3, 2), beta).doit() == sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), -S( + 1)/2, S.Half, beta).doit() == (-sin(beta/2) + 3*sin(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), -S( + 1)/2, Rational(-1, 2), beta).doit() == (cos(beta/2) + 3*cos(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), -S( + 1)/2, Rational(-3, 2), beta).doit() == -sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4 + assert Rotation.d(S( + 3)/2, Rational(-3, 2), Rational(3, 2), beta).doit() == (3*sin(beta/2) - sin(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), -S( + 3)/2, S.Half, beta).doit() == sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), -S( + 3)/2, Rational(-1, 2), beta).doit() == sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4 + assert Rotation.d(Rational(3, 2), -S( + 3)/2, Rational(-3, 2), beta).doit() == (3*cos(beta/2) + cos(beta*Rational(3, 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() == -((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.Half, S.Half, S.Half, pi/2).doit() == sqrt(2)/2 + assert Rotation.d(S.Half, S.Half, Rational(-1, 2), pi/2).doit() == -sqrt(2)/2 + assert Rotation.d(S.Half, Rational(-1, 2), S.Half, pi/2).doit() == sqrt(2)/2 + assert Rotation.d(S.Half, Rational(-1, 2), Rational(-1, 2), pi/2).doit() == sqrt(2)/2 + # j = 1 + assert Rotation.d(1, 1, 1, pi/2).doit() == S.Half + assert Rotation.d(1, 1, 0, pi/2).doit() == -sqrt(2)/2 + assert Rotation.d(1, 1, -1, pi/2).doit() == S.Half + 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() == S.Half + assert Rotation.d(1, -1, 0, pi/2).doit() == sqrt(2)/2 + assert Rotation.d(1, -1, -1, pi/2).doit() == S.Half + # j = 3/2 + assert Rotation.d(Rational(3, 2), Rational(3, 2), Rational(3, 2), pi/2).doit() == sqrt(2)/4 + assert Rotation.d(Rational(3, 2), Rational(3, 2), S.Half, pi/2).doit() == -sqrt(6)/4 + assert Rotation.d(Rational(3, 2), Rational(3, 2), Rational(-1, 2), pi/2).doit() == sqrt(6)/4 + assert Rotation.d(Rational(3, 2), Rational(3, 2), Rational(-3, 2), pi/2).doit() == -sqrt(2)/4 + assert Rotation.d(Rational(3, 2), S.Half, Rational(3, 2), pi/2).doit() == sqrt(6)/4 + assert Rotation.d(Rational(3, 2), S.Half, S.Half, pi/2).doit() == -sqrt(2)/4 + assert Rotation.d(Rational(3, 2), S.Half, Rational(-1, 2), pi/2).doit() == -sqrt(2)/4 + assert Rotation.d(Rational(3, 2), S.Half, Rational(-3, 2), pi/2).doit() == sqrt(6)/4 + assert Rotation.d(Rational(3, 2), Rational(-1, 2), Rational(3, 2), pi/2).doit() == sqrt(6)/4 + assert Rotation.d(Rational(3, 2), Rational(-1, 2), S.Half, pi/2).doit() == sqrt(2)/4 + assert Rotation.d(Rational(3, 2), Rational(-1, 2), Rational(-1, 2), pi/2).doit() == -sqrt(2)/4 + assert Rotation.d(Rational(3, 2), Rational(-1, 2), Rational(-3, 2), pi/2).doit() == -sqrt(6)/4 + assert Rotation.d(Rational(3, 2), Rational(-3, 2), Rational(3, 2), pi/2).doit() == sqrt(2)/4 + assert Rotation.d(Rational(3, 2), Rational(-3, 2), S.Half, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(Rational(3, 2), Rational(-3, 2), Rational(-1, 2), pi/2).doit() == sqrt(6)/4 + assert Rotation.d(Rational(3, 2), Rational(-3, 2), Rational(-3, 2), pi/2).doit() == sqrt(2)/4 + # j = 2 + assert Rotation.d(2, 2, 2, pi/2).doit() == Rational(1, 4) + assert Rotation.d(2, 2, 1, pi/2).doit() == Rational(-1, 2) + assert Rotation.d(2, 2, 0, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(2, 2, -1, pi/2).doit() == Rational(-1, 2) + assert Rotation.d(2, 2, -2, pi/2).doit() == Rational(1, 4) + assert Rotation.d(2, 1, 2, pi/2).doit() == S.Half + assert Rotation.d(2, 1, 1, pi/2).doit() == Rational(-1, 2) + assert Rotation.d(2, 1, 0, pi/2).doit() == 0 + assert Rotation.d(2, 1, -1, pi/2).doit() == S.Half + assert Rotation.d(2, 1, -2, pi/2).doit() == Rational(-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() == Rational(-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() == S.Half + assert Rotation.d(2, -1, 1, pi/2).doit() == S.Half + assert Rotation.d(2, -1, 0, pi/2).doit() == 0 + assert Rotation.d(2, -1, -1, pi/2).doit() == Rational(-1, 2) + assert Rotation.d(2, -1, -2, pi/2).doit() == Rational(-1, 2) + assert Rotation.d(2, -2, 2, pi/2).doit() == Rational(1, 4) + assert Rotation.d(2, -2, 1, pi/2).doit() == S.Half + assert Rotation.d(2, -2, 0, pi/2).doit() == sqrt(6)/4 + assert Rotation.d(2, -2, -1, pi/2).doit() == S.Half + assert Rotation.d(2, -2, -2, pi/2).doit() == Rational(1, 4) + + +def test_rotation_d(): + # Symbolic tests + # j = 1/2 + assert Rotation.D(S.Half, S.Half, S.Half, alpha, beta, gamma).doit() == \ + cos(beta/2)*exp(-I*alpha/2)*exp(-I*gamma/2) + assert Rotation.D(S.Half, S.Half, Rational(-1, 2), alpha, beta, gamma).doit() == \ + -sin(beta/2)*exp(-I*alpha/2)*exp(I*gamma/2) + assert Rotation.D(S.Half, Rational(-1, 2), S.Half, alpha, beta, gamma).doit() == \ + sin(beta/2)*exp(I*alpha/2)*exp(-I*gamma/2) + assert Rotation.D(S.Half, Rational(-1, 2), Rational(-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) + # j = 3/2 + assert Rotation.D(Rational(3, 2), Rational(3, 2), Rational(3, 2), alpha, beta, gamma).doit() == \ + (3*cos(beta/2) + cos(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(-3, 2))*exp(I*gamma*Rational(-3, 2)) + assert Rotation.D(Rational(3, 2), Rational(3, 2), S.Half, alpha, beta, gamma).doit() == \ + -sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(-3, 2))*exp(-I*gamma/2) + assert Rotation.D(Rational(3, 2), Rational(3, 2), Rational(-1, 2), alpha, beta, gamma).doit() == \ + sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(-3, 2))*exp(I*gamma/2) + assert Rotation.D(Rational(3, 2), Rational(3, 2), Rational(-3, 2), alpha, beta, gamma).doit() == \ + (-3*sin(beta/2) + sin(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(-3, 2))*exp(I*gamma*Rational(3, 2)) + assert Rotation.D(Rational(3, 2), S.Half, Rational(3, 2), alpha, beta, gamma).doit() == \ + sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4*exp(-I*alpha/2)*exp(I*gamma*Rational(-3, 2)) + assert Rotation.D(Rational(3, 2), S.Half, S.Half, alpha, beta, gamma).doit() == \ + (cos(beta/2) + 3*cos(beta*Rational(3, 2)))/4*exp(-I*alpha/2)*exp(-I*gamma/2) + assert Rotation.D(Rational(3, 2), S.Half, Rational(-1, 2), alpha, beta, gamma).doit() == \ + (sin(beta/2) - 3*sin(beta*Rational(3, 2)))/4*exp(-I*alpha/2)*exp(I*gamma/2) + assert Rotation.D(Rational(3, 2), S.Half, Rational(-3, 2), alpha, beta, gamma).doit() == \ + sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4*exp(-I*alpha/2)*exp(I*gamma*Rational(3, 2)) + assert Rotation.D(Rational(3, 2), Rational(-1, 2), Rational(3, 2), alpha, beta, gamma).doit() == \ + sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4*exp(I*alpha/2)*exp(I*gamma*Rational(-3, 2)) + assert Rotation.D(Rational(3, 2), Rational(-1, 2), S.Half, alpha, beta, gamma).doit() == \ + (-sin(beta/2) + 3*sin(beta*Rational(3, 2)))/4*exp(I*alpha/2)*exp(-I*gamma/2) + assert Rotation.D(Rational(3, 2), Rational(-1, 2), Rational(-1, 2), alpha, beta, gamma).doit() == \ + (cos(beta/2) + 3*cos(beta*Rational(3, 2)))/4*exp(I*alpha/2)*exp(I*gamma/2) + assert Rotation.D(Rational(3, 2), Rational(-1, 2), Rational(-3, 2), alpha, beta, gamma).doit() == \ + -sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4*exp(I*alpha/2)*exp(I*gamma*Rational(3, 2)) + assert Rotation.D(Rational(3, 2), Rational(-3, 2), Rational(3, 2), alpha, beta, gamma).doit() == \ + (3*sin(beta/2) - sin(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(3, 2))*exp(I*gamma*Rational(-3, 2)) + assert Rotation.D(Rational(3, 2), Rational(-3, 2), S.Half, alpha, beta, gamma).doit() == \ + sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(3, 2))*exp(-I*gamma/2) + assert Rotation.D(Rational(3, 2), Rational(-3, 2), Rational(-1, 2), alpha, beta, gamma).doit() == \ + sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(3, 2))*exp(I*gamma/2) + assert Rotation.D(Rational(3, 2), Rational(-3, 2), Rational(-3, 2), alpha, beta, gamma).doit() == \ + (3*cos(beta/2) + cos(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(3, 2))*exp(I*gamma*Rational(3, 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() == \ + -((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.Half, S.Half, S.Half, pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/2 + assert Rotation.D( + S.Half, S.Half, Rational(-1, 2), pi/2, pi/2, pi/2).doit() == -sqrt(2)/2 + assert Rotation.D( + S.Half, Rational(-1, 2), S.Half, pi/2, pi/2, pi/2).doit() == sqrt(2)/2 + assert Rotation.D( + S.Half, Rational(-1, 2), Rational(-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() == Rational(-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() == S.Half + 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() == S.Half + 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() == Rational(-1, 2) + # j = 3/2 + assert Rotation.D( + Rational(3, 2), Rational(3, 2), Rational(3, 2), pi/2, pi/2, pi/2).doit() == I*sqrt(2)/4 + assert Rotation.D( + Rational(3, 2), Rational(3, 2), S.Half, pi/2, pi/2, pi/2).doit() == sqrt(6)/4 + assert Rotation.D( + Rational(3, 2), Rational(3, 2), Rational(-1, 2), pi/2, pi/2, pi/2).doit() == -I*sqrt(6)/4 + assert Rotation.D( + Rational(3, 2), Rational(3, 2), Rational(-3, 2), pi/2, pi/2, pi/2).doit() == -sqrt(2)/4 + assert Rotation.D( + Rational(3, 2), S.Half, Rational(3, 2), pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 + assert Rotation.D( + Rational(3, 2), S.Half, S.Half, pi/2, pi/2, pi/2).doit() == I*sqrt(2)/4 + assert Rotation.D( + Rational(3, 2), S.Half, Rational(-1, 2), pi/2, pi/2, pi/2).doit() == -sqrt(2)/4 + assert Rotation.D( + Rational(3, 2), S.Half, Rational(-3, 2), pi/2, pi/2, pi/2).doit() == I*sqrt(6)/4 + assert Rotation.D( + Rational(3, 2), Rational(-1, 2), Rational(3, 2), pi/2, pi/2, pi/2).doit() == -I*sqrt(6)/4 + assert Rotation.D( + Rational(3, 2), Rational(-1, 2), S.Half, pi/2, pi/2, pi/2).doit() == sqrt(2)/4 + assert Rotation.D( + Rational(3, 2), Rational(-1, 2), Rational(-1, 2), pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/4 + assert Rotation.D( + Rational(3, 2), Rational(-1, 2), Rational(-3, 2), pi/2, pi/2, pi/2).doit() == sqrt(6)/4 + assert Rotation.D( + Rational(3, 2), Rational(-3, 2), Rational(3, 2), pi/2, pi/2, pi/2).doit() == sqrt(2)/4 + assert Rotation.D( + Rational(3, 2), Rational(-3, 2), S.Half, pi/2, pi/2, pi/2).doit() == I*sqrt(6)/4 + assert Rotation.D( + Rational(3, 2), Rational(-3, 2), Rational(-1, 2), pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 + assert Rotation.D( + Rational(3, 2), Rational(-3, 2), Rational(-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() == Rational(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() == Rational(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() == S.Half + 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() == S.Half + 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() == Rational(-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() == S.Half + 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() == S.Half + 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() == Rational(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() == Rational(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, beta) == WignerD(j, m, mp, 0, beta, 0) + +def test_wignerD(): + i,j=symbols('i j') + assert Rotation.D(1, 1, 1, 0, 0, 0) == WignerD(1, 1, 1, 0, 0, 0) + assert Rotation.D(1, 1, 2, 0, 0, 0) == WignerD(1, 1, 2, 0, 0, 0) + assert Rotation.D(1, i**2 - j**2, i**2 - j**2, 0, 0, 0) == WignerD(1, i**2 - j**2, i**2 - j**2, 0, 0, 0) + assert Rotation.D(1, i, i, 0, 0, 0) == WignerD(1, i, i, 0, 0, 0) + assert Rotation.D(1, i, i+1, 0, 0, 0) == WignerD(1, i, i+1, 0, 0, 0) + assert Rotation.D(1, 0, 0, 0, 0, 0) == WignerD(1, 0, 0, 0, 0, 0) + +def test_jplus(): + assert Commutator(Jplus, Jminus).doit() == 2*hbar*Jz + 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, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2) * + Sum(WignerD(j, mi1, mi + 1, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2) * + Sum( + WignerD(j, mi1, mi + 1, pi*Rational(3, 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 + e1 = qapply(TensorProduct(Jplus, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) + e2 = -hbar*sqrt(2)*TensorProduct(JxKet(1, 0), JxKet(1, -1))/2 + \ + hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + assert_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(1, Jplus)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) + e2 = -hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + \ + hbar*sqrt(2)*TensorProduct(JxKet(1, 1), JxKet(1, 0))/2 + assert_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(Jplus, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) + e2 = hbar*sqrt(2)*TensorProduct(JyKet(1, 0), JyKet(1, -1))/2 + \ + hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + assert_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(1, Jplus)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) + e2 = -hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + \ + hbar*sqrt(2)*TensorProduct(JyKet(1, 1), JyKet(1, 0))/2 + assert_simplify_expand(e1, e2) + 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2) * + Sum(WignerD(j1, mi1, mi + 1, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2) * + Sum(WignerD(j2, mi1, mi + 1, pi*Rational(3, 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 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, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2) * + Sum(WignerD(j, mi1, mi - 1, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2) * + Sum( + WignerD(j, mi1, mi - 1, pi*Rational(3, 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 + e1 = qapply(TensorProduct(Jminus, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) + e2 = hbar*sqrt(2)*TensorProduct(JxKet(1, 0), JxKet(1, -1))/2 + \ + hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + assert_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(1, Jminus)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) + e2 = -hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) - \ + hbar*sqrt(2)*TensorProduct(JxKet(1, 1), JxKet(1, 0))/2 + assert_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(Jminus, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) + e2 = hbar*sqrt(2)*TensorProduct(JyKet(1, 0), JyKet(1, -1))/2 - \ + hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + assert_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(1, Jminus)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) + e2 = hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + \ + hbar*sqrt(2)*TensorProduct(JyKet(1, 1), JyKet(1, 0))/2 + assert_simplify_expand(e1, e2) + 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2) * + Sum(WignerD(j1, mi1, mi - 1, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2) * + Sum(WignerD(j2, mi1, mi - 1, pi*Rational(3, 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 + # 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) + # 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)) + # 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 + e1 = qapply(TensorProduct(J2, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) + e2 = hbar**2*j1**2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + \ + hbar**2*j1*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + assert_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(1, J2)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) + e2 = hbar**2*j2**2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + \ + hbar**2*j2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + assert_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(J2, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) + e2 = hbar**2*j1**2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + \ + hbar**2*j1*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + assert_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(1, J2)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) + e2 = hbar**2*j2**2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + \ + hbar**2*j2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + assert_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(J2, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) + e2 = hbar**2*j1**2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + \ + hbar**2*j1*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + assert_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(1, J2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) + e2 = hbar**2*j2**2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + \ + hbar**2*j2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + assert_simplify_expand(e1, e2) + + +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 + # 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 2), 0, 0)*JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + e1 = qapply(TensorProduct(Jx, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) + e2 = 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_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(1, Jx)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) + e2 = 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_simplify_expand(e1, e2) + + +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) + # 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 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)) + e1 = qapply(TensorProduct(Jy, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) + e2 = -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_simplify_expand(e1, e2) + e1 = qapply(TensorProduct(1, Jy)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) + e2 = -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_simplify_expand(e1, e2) + + +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, pi*Rational(3, 2), 0)*JxKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) + assert qapply(Jz*JyKet(j, m)) == \ + Sum(hbar*mi*WignerD(j, mi, m, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j, mi1, + mi, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j, mi1, mi, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j2, mi1, mi, pi*Rational(3, 2), pi/2, pi/2)*JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + \ + TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j1, mi1, mi, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j1, mi1, mi, pi*Rational(3, 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, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j2, mi1, mi, pi*Rational(3, 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(Rational(2, 3), Rational(-1, 3))) + raises(ValueError, lambda: JzKet(Rational(2, 3), m)) + # j < 0 + raises(ValueError, lambda: JzKet(-1, 1)) + raises(ValueError, lambda: JzKet(-1, m)) + # m not integer or half integer + raises(ValueError, lambda: JzKet(j, Rational(-1, 3))) + # abs(m) > j + raises(ValueError, lambda: JzKet(1, 2)) + raises(ValueError, lambda: JzKet(1, -2)) + # j-m not integer + raises(ValueError, lambda: JzKet(1, S.Half)) + + +def test_jzketcoupled(): + j, m = symbols('j m') + # j not integer or half integer + raises(ValueError, lambda: JzKetCoupled(Rational(2, 3), Rational(-1, 3), (1,))) + raises(ValueError, lambda: JzKetCoupled(Rational(2, 3), m, (1,))) + # j < 0 + raises(ValueError, lambda: JzKetCoupled(-1, 1, (1,))) + raises(ValueError, lambda: JzKetCoupled(-1, m, (1,))) + # m not integer or half integer + raises(ValueError, lambda: JzKetCoupled(j, Rational(-1, 3), (1,))) + # abs(m) > j + raises(ValueError, lambda: JzKetCoupled(1, 2, (1,))) + raises(ValueError, lambda: JzKetCoupled(1, -2, (1,))) + # j-m not integer + raises(ValueError, lambda: JzKetCoupled(1, S.Half, (1,))) + # 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))) + # 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),))) + # all jn are integer or half-integer + raises(ValueError, lambda: JzKetCoupled(1, 1, (Rational(1, 3), Rational(2, 3)))) + # indices in coupling scheme must be integers + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((S.Half, 1, 2),) )) + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, S.Half, 2),) )) + # indices 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),) )) + # 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)) )) + # 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))) + # final j of coupling must be j of the state + raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, 2, 2),) )) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_state.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_state.py new file mode 100644 index 0000000000000000000000000000000000000000..c9fd5029fa3d77c2ddfc6899187624da02796ffa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_state.py @@ -0,0 +1,248 @@ +from sympy.core.add import Add +from sympy.core.function import diff +from sympy.core.mul import Mul +from sympy.core.numbers import (I, Integer, Rational, oo, pi) +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.core.sympify import sympify +from sympy.functions.elementary.complexes import conjugate +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin +from sympy.testing.pytest import raises + +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.qexpr import QExpr +from sympy.physics.quantum.state import ( + Ket, Bra, TimeDepKet, TimeDepBra, + KetBase, BraBase, StateBase, Wavefunction, + OrthogonalKet, OrthogonalBra +) +from sympy.physics.quantum.hilbert import HilbertSpace + +x, y, t = symbols('x,y,t') + + +class CustomKet(Ket): + @classmethod + def default_args(self): + return ("test",) + + +class CustomKetMultipleLabels(Ket): + @classmethod + def default_args(self): + return ("r", "theta", "phi") + + +class CustomTimeDepKet(TimeDepKet): + @classmethod + def default_args(self): + return ("test", "t") + + +class CustomTimeDepKetMultipleLabels(TimeDepKet): + @classmethod + def default_args(self): + return ("r", "theta", "phi", "t") + + +def test_ket(): + k = Ket('0') + + assert isinstance(k, Ket) + assert isinstance(k, KetBase) + assert isinstance(k, StateBase) + assert isinstance(k, QExpr) + + assert k.label == (Symbol('0'),) + assert k.hilbert_space == HilbertSpace() + 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) + assert k.hilbert_space == HilbertSpace() + 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) + + k = CustomKet() + assert k == CustomKet("test") + + k = CustomKetMultipleLabels() + assert k == CustomKetMultipleLabels("r", "theta", "phi") + + assert Ket() == Ket('psi') + + +def test_bra(): + b = Bra('0') + + assert isinstance(b, Bra) + assert isinstance(b, BraBase) + assert isinstance(b, StateBase) + assert isinstance(b, QExpr) + + assert b.label == (Symbol('0'),) + assert b.hilbert_space == HilbertSpace() + 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) + assert b.hilbert_space == HilbertSpace() + 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 Bra() == Bra('psi') + + +def test_ops(): + k0 = Ket(0) + k1 = Ket(1) + k = 2*I*k0 - (x/sqrt(2))*k1 + assert k == Add(Mul(2, I, k0), + Mul(Rational(-1, 2), x, Pow(2, S.Half), k1)) + + +def test_time_dep_ket(): + k = TimeDepKet(0, t) + + assert isinstance(k, TimeDepKet) + assert isinstance(k, KetBase) + assert isinstance(k, StateBase) + assert isinstance(k, QExpr) + + assert k.label == (Integer(0),) + assert k.args == (Integer(0), t) + assert k.time == t + + assert k.dual_class() == TimeDepBra + assert k.dual == TimeDepBra(0, t) + + assert k.subs(t, 2) == TimeDepKet(0, 2) + + k = TimeDepKet(x, 0.5) + assert k.label == (x,) + assert k.args == (x, sympify(0.5)) + + k = CustomTimeDepKet() + assert k.label == (Symbol("test"),) + assert k.time == Symbol("t") + assert k == CustomTimeDepKet("test", "t") + + k = CustomTimeDepKetMultipleLabels() + assert k.label == (Symbol("r"), Symbol("theta"), Symbol("phi")) + assert k.time == Symbol("t") + assert k == CustomTimeDepKetMultipleLabels("r", "theta", "phi", "t") + + assert TimeDepKet() == TimeDepKet("psi", "t") + + +def test_time_dep_bra(): + b = TimeDepBra(0, t) + + assert isinstance(b, TimeDepBra) + assert isinstance(b, BraBase) + assert isinstance(b, StateBase) + assert isinstance(b, QExpr) + + assert b.label == (Integer(0),) + assert b.args == (Integer(0), t) + assert b.time == t + + assert b.dual_class() == TimeDepKet + assert b.dual == TimeDepKet(0, t) + + k = TimeDepBra(x, 0.5) + assert k.label == (x,) + assert k.args == (x, sympify(0.5)) + + assert TimeDepBra() == TimeDepBra("psi", "t") + + +def test_bra_ket_dagger(): + 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 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 = 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 is False + assert f.norm is oo + assert f(10) == 100 + assert p(10) == 10000 + assert lims[x] == (-oo, oo) + assert diff(f, x) == Wavefunction(2*x, x) + raises(NotImplementedError, lambda: f.normalize()) + 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)) + lims_g = g.limits + + assert lims_g[x] == (0, 1) + assert lims_g[y] == (0, 2) + assert g.is_normalized is False + assert g.norm == sqrt(42)/3 + 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 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(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)) + assert conjugate(piab) == Wavefunction(conjugate(piab.expr), (x, 0, L)) + assert conjugate(piab) == Dagger(piab) + + k = Wavefunction(x**2, 'x') + assert type(k.variables[0]) == Symbol + +def test_orthogonal_states(): + bracket = OrthogonalBra(x) * OrthogonalKet(x) + assert bracket.doit() == 1 + + bracket = OrthogonalBra(x) * OrthogonalKet(x+1) + assert bracket.doit() == 0 + + bracket = OrthogonalBra(x) * OrthogonalKet(y) + assert bracket.doit() == bracket diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_tensorproduct.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_tensorproduct.py new file mode 100644 index 0000000000000000000000000000000000000000..c17d533ae6d4ae97cb313eb345219fd82c6e483c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_tensorproduct.py @@ -0,0 +1,142 @@ +from sympy.core.numbers import I +from sympy.core.symbol import symbols +from sympy.core.expr import unchanged +from sympy.matrices import Matrix, SparseMatrix, ImmutableMatrix +from sympy.testing.pytest import warns_deprecated_sympy + +from sympy.physics.quantum.commutator import Commutator as Comm +from sympy.physics.quantum.tensorproduct import TensorProduct +from sympy.physics.quantum.tensorproduct import TensorProduct as TP +from sympy.physics.quantum.tensorproduct import tensor_product_simp +from sympy.physics.quantum.dagger import Dagger +from sympy.physics.quantum.qubit import Qubit, QubitBra +from sympy.physics.quantum.operator import OuterProduct, Operator +from sympy.physics.quantum.density import Density +from sympy.physics.quantum.trace import Tr + +A = Operator('A') +B = Operator('B') +C = Operator('C') +D = Operator('D') +x = symbols('x') +y = symbols('y', integer=True, positive=True) + +mat1 = Matrix([[1, 2*I], [1 + I, 3]]) +mat2 = Matrix([[2*I, 3], [4*I, 2]]) + + +def test_sparse_matrices(): + spm = SparseMatrix.diag(1, 0) + assert unchanged(TensorProduct, spm, spm) + + +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)) + + +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 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) + #Tests for fix of issue #24142 + assert TP(A-B, B-A).expand(tensorproduct=True) == \ + TP(A, B) - TP(A, A) - TP(B, B) + TP(B, A) + assert TP(2*A + B, A + B).expand(tensorproduct=True) == \ + 2 * TP(A, A) + 2 * TP(A, B) + TP(B, A) + TP(B, B) + assert TP(2 * A * B + A, A + B).expand(tensorproduct=True) == \ + 2 * TP(A*B, A) + 2 * TP(A*B, B) + TP(A, A) + TP(A, B) + + +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) + + +def test_tensor_product_simp(): + with warns_deprecated_sympy(): + assert tensor_product_simp(TP(A, B)*TP(B, C)) == TP(A*B, B*C) + # tests for Pow-expressions + assert TP(A, B)**y == TP(A**y, B**y) + assert tensor_product_simp(TP(A, B)**y) == TP(A**y, B**y) + assert tensor_product_simp(x*TP(A, B)**2) == x*TP(A**2,B**2) + assert tensor_product_simp(x*(TP(A, B)**2)*TP(C,D)) == x*TP(A**2*C,B**2*D) + assert tensor_product_simp(TP(A,B)-TP(C,D)**y) == TP(A,B)-TP(C**y,D**y) + + +def test_issue_5923(): + # 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))) + + +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 + + # Density with simple tensor products as args + t = TensorProduct(A, B) + d = Density([t, 1.0]) + tr = Tr(d) + assert tr.doit() == 1.0*Tr(A*Dagger(A))*Tr(B*Dagger(B)) + + ## partial trace with simple tensor products as args + t = TensorProduct(A, B, C) + d = Density([t, 1.0]) + tr = Tr(d, [1]) + assert tr.doit() == 1.0*A*Dagger(A)*Tr(B*Dagger(B))*C*Dagger(C) + + tr = Tr(d, [0, 2]) + assert tr.doit() == 1.0*Tr(A*Dagger(A))*B*Dagger(B)*Tr(C*Dagger(C)) + + # Density with multiple Tensorproducts as states + t2 = TensorProduct(A, B) + t3 = TensorProduct(C, D) + + d = Density([t2, 0.5], [t3, 0.5]) + t = Tr(d) + assert t.doit() == (0.5*Tr(A*Dagger(A))*Tr(B*Dagger(B)) + + 0.5*Tr(C*Dagger(C))*Tr(D*Dagger(D))) + + t = Tr(d, [0]) + assert t.doit() == (0.5*Tr(A*Dagger(A))*B*Dagger(B) + + 0.5*Tr(C*Dagger(C))*D*Dagger(D)) + + #Density with mixed states + 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)) + + 1.0*Tr(C*Dagger(A))*Tr(D*Dagger(B)) + + 1.0*Tr(C*Dagger(C))*Tr(D*Dagger(D))) + + t = Tr(d, [1] ) + assert t.doit() == ( 1.0*A*Dagger(A)*Tr(B*Dagger(B)) + + 1.0*A*Dagger(C)*Tr(B*Dagger(D)) + + 1.0*C*Dagger(A)*Tr(D*Dagger(B)) + + 1.0*C*Dagger(C)*Tr(D*Dagger(D))) + + +def test_pr24993(): + from sympy.matrices.expressions.kronecker import matrix_kronecker_product + from sympy.physics.quantum.matrixutils import matrix_tensor_product + X = Matrix([[0, 1], [1, 0]]) + Xi = ImmutableMatrix(X) + assert TensorProduct(Xi, Xi) == TensorProduct(X, X) + assert TensorProduct(Xi, Xi) == matrix_tensor_product(X, X) + assert TensorProduct(Xi, Xi) == matrix_kronecker_product(X, X) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_trace.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_trace.py new file mode 100644 index 0000000000000000000000000000000000000000..85db6c60ad9d2bd1fbfafcf5d84b97d2fe304250 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_trace.py @@ -0,0 +1,109 @@ +from sympy.core.containers import Tuple +from sympy.core.symbol import symbols +from sympy.matrices.dense import Matrix +from sympy.physics.quantum.trace import Tr +from sympy.testing.pytest import raises, warns_deprecated_sympy + + +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) + + #check trace args not implicitly permuted + assert Tr(C*D*A*B).args[0].args == (C, D, A, B) + + # check for mul and adds + assert Tr((a*b) + ( c*d)) == (a*b) + (c*d) + # Tr(scalar*A) = scalar*Tr(A) + assert Tr(a*A) == a*Tr(A) + assert Tr(a*A*B*b) == a*b*Tr(A*B) + + # since A is symbol and not commutative + assert isinstance(Tr(A), Tr) + + #POW + assert Tr(pow(a, b)) == a**b + assert isinstance(Tr(pow(A, a)), Tr) + + #Matrix + M = Matrix([[1, 1], [2, 2]]) + assert Tr(M) == 3 + + ##test indices in different forms + #no index + t = Tr(A) + assert t.args[1] == Tuple() + + #single index + t = Tr(A, 0) + assert t.args[1] == Tuple(0) + + #index in a list + t = Tr(A, [0]) + assert t.args[1] == Tuple(0) + + t = Tr(A, [0, 1, 2]) + assert t.args[1] == Tuple(0, 1, 2) + + #index is tuple + t = Tr(A, (0)) + assert t.args[1] == Tuple(0) + + t = Tr(A, (1, 2)) + assert t.args[1] == Tuple(1, 2) + + #trace indices test + 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) + + #class with trace method defined + #to simulate numpy objects + class Foo: + def trace(self): + return 1 + assert Tr(Foo()) == 1 + + #argument test + # check for value error, when either/both arguments are not provided + 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) + + assert t.permute(0).args[0].args == (A, B, C, D, E, F, G) + assert t.permute(2).args[0].args == (F, G, A, B, C, D, E) + assert t.permute(4).args[0].args == (D, E, F, G, A, B, C) + assert t.permute(6).args[0].args == (B, C, D, E, F, G, A) + assert t.permute(8).args[0].args == t.permute(1).args[0].args + + assert t.permute(-1).args[0].args == (B, C, D, E, F, G, A) + assert t.permute(-3).args[0].args == (D, E, F, G, A, B, C) + 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)) + + t1 = Tr(A*B) + t2 = t1.permute(1) + assert id(t1) != id(t2) and t1 == t2 + +def test_deprecated_core_trace(): + with warns_deprecated_sympy(): + from sympy.core.trace import Tr # noqa:F401 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_transforms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_transforms.py new file mode 100644 index 0000000000000000000000000000000000000000..55349ebe3b8003b5a107648516706034beaf22af --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/tests/test_transforms.py @@ -0,0 +1,75 @@ +"""Tests of transforms of quantum expressions for Mul and Pow.""" + +from sympy.core.symbol import symbols +from sympy.testing.pytest import raises + +from sympy.physics.quantum.operator import ( + Operator, OuterProduct +) +from sympy.physics.quantum.state import Ket, Bra +from sympy.physics.quantum.innerproduct import InnerProduct +from sympy.physics.quantum.tensorproduct import TensorProduct + + +k1 = Ket('k1') +k2 = Ket('k2') +k3 = Ket('k3') +b1 = Bra('b1') +b2 = Bra('b2') +b3 = Bra('b3') +A = Operator('A') +B = Operator('B') +C = Operator('C') +x, y, z = symbols('x y z') + + +def test_bra_ket(): + assert b1*k1 == InnerProduct(b1, k1) + assert k1*b1 == OuterProduct(k1, b1) + # Test priority of inner product + assert OuterProduct(k1, b1)*k2 == InnerProduct(b1, k2)*k1 + assert b1*OuterProduct(k1, b2) == InnerProduct(b1, k1)*b2 + + +def test_tensor_product(): + # We are attempting to be rigourous and raise TypeError when a user tries + # to combine bras, kets, and operators in a manner that doesn't make sense. + # In particular, we are not trying to interpret regular ``*`` multiplication + # as a tensor product. + with raises(TypeError): + k1*k1 + with raises(TypeError): + b1*b1 + with raises(TypeError): + k1*TensorProduct(k2, k3) + with raises(TypeError): + b1*TensorProduct(b2, b3) + with raises(TypeError): + TensorProduct(k2, k3)*k1 + with raises(TypeError): + TensorProduct(b2, b3)*b1 + + assert TensorProduct(A, B, C)*TensorProduct(k1, k2, k3) == \ + TensorProduct(A*k1, B*k2, C*k3) + assert TensorProduct(b1, b2, b3)*TensorProduct(A, B, C) == \ + TensorProduct(b1*A, b2*B, b3*C) + assert TensorProduct(b1, b2, b3)*TensorProduct(k1, k2, k3) == \ + InnerProduct(b1, k1)*InnerProduct(b2, k2)*InnerProduct(b3, k3) + assert TensorProduct(b1, b2, b3)*TensorProduct(A, B, C)*TensorProduct(k1, k2, k3) == \ + TensorProduct(b1*A*k1, b2*B*k2, b3*C*k3) + + +def test_outer_product(): + assert OuterProduct(k1, b1)*OuterProduct(k2, b2) == \ + InnerProduct(b1, k2)*OuterProduct(k1, b2) + + +def test_compound(): + e1 = b1*A*B*k1*b2*k2*b3 + assert e1 == InnerProduct(b2, k2)*b1*A*B*OuterProduct(k1, b3) + + e2 = TensorProduct(k1, k2)*TensorProduct(b1, b2) + assert e2 == TensorProduct( + OuterProduct(k1, b1), + OuterProduct(k2, b2) + ) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/trace.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/trace.py new file mode 100644 index 0000000000000000000000000000000000000000..03ab18f78a1bfcf5bfcd679f00eac8685144fd8c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/trace.py @@ -0,0 +1,230 @@ +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.mul import Mul +from sympy.core.power import Pow +from sympy.core.sorting import default_sort_key +from sympy.core.sympify import sympify +from sympy.matrices import Matrix + + +def _is_scalar(e): + """ Helper method used in Tr""" + + # sympify to set proper attributes + e = sympify(e) + if isinstance(e, Expr): + if (e.is_Integer or e.is_Float or + e.is_Rational or e.is_Number or + (e.is_Symbol and e.is_commutative) + ): + return True + + return False + + +def _cycle_permute(l): + """ Cyclic permutations based on canonical ordering + + Explanation + =========== + + This method does the sort based ascii values while + a better approach would be to used lexicographic sort. + + TODO: Handle condition such as symbols have subscripts/superscripts + in case of lexicographic sort + + """ + + if len(l) == 1: + return l + + min_item = min(l, key=default_sort_key) + indices = [i for i, x in enumerate(l) if x == min_item] + + le = list(l) + le.extend(l) # duplicate and extend string for easy processing + + # adding the first min_item index back for easier looping + indices.append(len(l) + indices[0]) + + # create sublist of items with first item as min_item and last_item + # in each of the sublist is item just before the next occurrence of + # minitem in the cycle formed. + sublist = [[le[indices[i]:indices[i + 1]]] for i in + range(len(indices) - 1)] + + # we do comparison of strings by comparing elements + # in each sublist + idx = sublist.index(min(sublist)) + ordered_l = le[indices[idx]:indices[idx] + len(l)] + + return ordered_l + + +def _rearrange_args(l): + """ this just moves the last arg to first position + to enable expansion of args + A,B,A ==> A**2,B + """ + if len(l) == 1: + return l + + x = list(l[-1:]) + x.extend(l[0:-1]) + return Mul(*x).args + + +class Tr(Expr): + """ Generic Trace operation than can trace over: + + a) SymPy matrix + b) operators + c) outer products + + Parameters + ========== + o : operator, matrix, expr + i : tuple/list indices (optional) + + Examples + ======== + + # TODO: Need to handle printing + + a) Trace(A+B) = Tr(A) + Tr(B) + b) Trace(scalar*Operator) = scalar*Trace(Operator) + + >>> from sympy.physics.quantum.trace import Tr + >>> from sympy import symbols, Matrix + >>> a, b = symbols('a b', commutative=True) + >>> A, B = symbols('A B', commutative=False) + >>> Tr(a*A,[2]) + a*Tr(A) + >>> m = Matrix([[1,2],[1,1]]) + >>> Tr(m) + 2 + + """ + def __new__(cls, *args): + """ Construct a Trace object. + + Parameters + ========== + args = SymPy expression + indices = tuple/list if indices, optional + + """ + + # expect no indices,int or a tuple/list/Tuple + if (len(args) == 2): + if not isinstance(args[1], (list, Tuple, tuple)): + indices = Tuple(args[1]) + else: + indices = Tuple(*args[1]) + + expr = args[0] + elif (len(args) == 1): + indices = Tuple() + expr = args[0] + else: + raise ValueError("Arguments to Tr should be of form " + "(expr[, [indices]])") + + if isinstance(expr, Matrix): + return expr.trace() + elif hasattr(expr, 'trace') and callable(expr.trace): + #for any objects that have trace() defined e.g numpy + return expr.trace() + elif isinstance(expr, Add): + return Add(*[Tr(arg, indices) for arg in expr.args]) + elif isinstance(expr, Mul): + c_part, nc_part = expr.args_cnc() + if len(nc_part) == 0: + return Mul(*c_part) + else: + obj = Expr.__new__(cls, Mul(*nc_part), indices ) + #this check is needed to prevent cached instances + #being returned even if len(c_part)==0 + 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])): + return expr + else: + return Expr.__new__(cls, expr, indices) + else: + if (_is_scalar(expr)): + return expr + + return Expr.__new__(cls, expr, indices) + + @property + def kind(self): + expr = self.args[0] + expr_kind = expr.kind + return expr_kind.element_kind + + def doit(self, **hints): + """ Perform the trace operation. + + #TODO: Current version ignores the indices set for partial trace. + + >>> from sympy.physics.quantum.trace import Tr + >>> from sympy.physics.quantum.operator import OuterProduct + >>> from sympy.physics.quantum.spin import JzKet, JzBra + >>> t = Tr(OuterProduct(JzKet(1,1), JzBra(1,1))) + >>> t.doit() + 1 + + """ + if hasattr(self.args[0], '_eval_trace'): + return self.args[0]._eval_trace(indices=self.args[1]) + + return self + + @property + def is_number(self): + # TODO : improve this implementation + return True + + #TODO: Review if the permute method is needed + # and if it needs to return a new instance + def permute(self, pos): + """ Permute the arguments cyclically. + + Parameters + ========== + + pos : integer, if positive, shift-right, else shift-left + + Examples + ======== + + >>> from sympy.physics.quantum.trace import Tr + >>> from sympy import symbols + >>> A, B, C, D = symbols('A B C D', commutative=False) + >>> t = Tr(A*B*C*D) + >>> t.permute(2) + Tr(C*D*A*B) + >>> t.permute(-2) + Tr(C*D*A*B) + + """ + if pos > 0: + pos = pos % len(self.args[0].args) + else: + pos = -(abs(pos) % len(self.args[0].args)) + + args = list(self.args[0].args[-pos:] + self.args[0].args[0:-pos]) + + return Tr(Mul(*(args))) + + def _hashable_content(self): + if isinstance(self.args[0], Mul): + args = _cycle_permute(_rearrange_args(self.args[0].args)) + else: + args = [self.args[0]] + + return tuple(args) + (self.args[1], ) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/transforms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/transforms.py new file mode 100644 index 0000000000000000000000000000000000000000..dcbbcd9040b4f8f987375c2f903031610d6f9061 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/quantum/transforms.py @@ -0,0 +1,291 @@ +"""Transforms that are always applied to quantum expressions. + +This module uses the kind and _constructor_postprocessor_mapping APIs +to transform different combinations of Operators, Bras, and Kets into +Inner/Outer/TensorProducts. These transformations are registered +with the postprocessing API of core classes like `Mul` and `Pow` and +are always applied to any expression involving Bras, Kets, and +Operators. This API replaces the custom `__mul__` and `__pow__` +methods of the quantum classes, which were found to be inconsistent. + +THIS IS EXPERIMENTAL. +""" +from sympy.core.basic import Basic +from sympy.core.expr import Expr +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.multipledispatch.dispatcher import ( + Dispatcher, ambiguity_register_error_ignore_dup +) +from sympy.utilities.misc import debug + +from sympy.physics.quantum.innerproduct import InnerProduct +from sympy.physics.quantum.kind import KetKind, BraKind, OperatorKind +from sympy.physics.quantum.operator import ( + OuterProduct, IdentityOperator, Operator +) +from sympy.physics.quantum.state import BraBase, KetBase, StateBase +from sympy.physics.quantum.tensorproduct import TensorProduct + + +#----------------------------------------------------------------------------- +# Multipledispatch based transformed for Mul and Pow +#----------------------------------------------------------------------------- + +_transform_state_pair = Dispatcher('_transform_state_pair') +"""Transform a pair of expression in a Mul to their canonical form. + +All functions that are registered with this dispatcher need to take +two inputs and return either tuple of transformed outputs, or None if no +transform is applied. The output tuple is inserted into the right place +of the ``Mul`` that is being put into canonical form. It works something like +the following: + +``Mul(a, b, c, d, e, f) -> Mul(*(_transform_state_pair(a, b) + (c, d, e, f))))`` + +The transforms here are always applied when quantum objects are multiplied. + +THIS IS EXPERIMENTAL. + +However, users of ``sympy.physics.quantum`` can import this dispatcher and +register their own transforms to control the canonical form of products +of quantum expressions. +""" + +@_transform_state_pair.register(Expr, Expr) +def _transform_expr(a, b): + """Default transformer that does nothing for base types.""" + return None + + +# The identity times anything is the anything. +_transform_state_pair.add( + (IdentityOperator, Expr), + lambda x, y: (y,), + on_ambiguity=ambiguity_register_error_ignore_dup +) +_transform_state_pair.add( + (Expr, IdentityOperator), + lambda x, y: (x,), + on_ambiguity=ambiguity_register_error_ignore_dup +) +_transform_state_pair.add( + (IdentityOperator, IdentityOperator), + lambda x, y: S.One, + on_ambiguity=ambiguity_register_error_ignore_dup +) + +@_transform_state_pair.register(BraBase, KetBase) +def _transform_bra_ket(a, b): + """Transform a bra*ket -> InnerProduct(bra, ket).""" + return (InnerProduct(a, b),) + +@_transform_state_pair.register(KetBase, BraBase) +def _transform_ket_bra(a, b): + """Transform a keT*bra -> OuterProduct(ket, bra).""" + return (OuterProduct(a, b),) + +@_transform_state_pair.register(KetBase, KetBase) +def _transform_ket_ket(a, b): + """Raise a TypeError if a user tries to multiply two kets. + + Multiplication based on `*` is not a shorthand for tensor products. + """ + raise TypeError( + 'Multiplication of two kets is not allowed. Use TensorProduct instead.' + ) + +@_transform_state_pair.register(BraBase, BraBase) +def _transform_bra_bra(a, b): + """Raise a TypeError if a user tries to multiply two bras. + + Multiplication based on `*` is not a shorthand for tensor products. + """ + raise TypeError( + 'Multiplication of two bras is not allowed. Use TensorProduct instead.' + ) + +@_transform_state_pair.register(OuterProduct, KetBase) +def _transform_op_ket(a, b): + return (InnerProduct(a.bra, b), a.ket) + +@_transform_state_pair.register(BraBase, OuterProduct) +def _transform_bra_op(a, b): + return (InnerProduct(a, b.ket), b.bra) + +@_transform_state_pair.register(TensorProduct, KetBase) +def _transform_tp_ket(a, b): + """Raise a TypeError if a user tries to multiply TensorProduct(*kets)*ket. + + Multiplication based on `*` is not a shorthand for tensor products. + """ + if a.kind == KetKind: + raise TypeError( + 'Multiplication of TensorProduct(*kets)*ket is invalid.' + ) + +@_transform_state_pair.register(KetBase, TensorProduct) +def _transform_ket_tp(a, b): + """Raise a TypeError if a user tries to multiply ket*TensorProduct(*kets). + + Multiplication based on `*` is not a shorthand for tensor products. + """ + if b.kind == KetKind: + raise TypeError( + 'Multiplication of ket*TensorProduct(*kets) is invalid.' + ) + +@_transform_state_pair.register(TensorProduct, BraBase) +def _transform_tp_bra(a, b): + """Raise a TypeError if a user tries to multiply TensorProduct(*bras)*bra. + + Multiplication based on `*` is not a shorthand for tensor products. + """ + if a.kind == BraKind: + raise TypeError( + 'Multiplication of TensorProduct(*bras)*bra is invalid.' + ) + +@_transform_state_pair.register(BraBase, TensorProduct) +def _transform_bra_tp(a, b): + """Raise a TypeError if a user tries to multiply bra*TensorProduct(*bras). + + Multiplication based on `*` is not a shorthand for tensor products. + """ + if b.kind == BraKind: + raise TypeError( + 'Multiplication of bra*TensorProduct(*bras) is invalid.' + ) + +@_transform_state_pair.register(TensorProduct, TensorProduct) +def _transform_tp_tp(a, b): + """Combine a product of tensor products if their number of args matches.""" + debug('_transform_tp_tp', a, b) + if len(a.args) == len(b.args): + if a.kind == BraKind and b.kind == KetKind: + return tuple([InnerProduct(i, j) for (i, j) in zip(a.args, b.args)]) + else: + return (TensorProduct(*(i*j for (i, j) in zip(a.args, b.args))), ) + +@_transform_state_pair.register(OuterProduct, OuterProduct) +def _transform_op_op(a, b): + """Extract an inner produt from a product of outer products.""" + return (InnerProduct(a.bra, b.ket), OuterProduct(a.ket, b.bra)) + + +#----------------------------------------------------------------------------- +# Postprocessing transforms for Mul and Pow +#----------------------------------------------------------------------------- + + +def _postprocess_state_mul(expr): + """Transform a ``Mul`` of quantum expressions into canonical form. + + This function is registered ``_constructor_postprocessor_mapping`` as a + transformer for ``Mul``. This means that every time a quantum expression + is multiplied, this function will be called to transform it into canonical + form as defined by the binary functions registered with + ``_transform_state_pair``. + + The algorithm of this function is as follows. It walks the args + of the input ``Mul`` from left to right and calls ``_transform_state_pair`` + on every overlapping pair of args. Each time ``_transform_state_pair`` + is called it can return a tuple of items or None. If None, the pair isn't + transformed. If a tuple, then the last element of the tuple goes back into + the args to be transformed again and the others are extended onto the result + args list. + + The algorithm can be visualized in the following table: + + step result args + ============================================================================ + #0 [] [a, b, c, d, e, f] + #1 [] [T(a,b), c, d, e, f] + #2 [T(a,b)[:-1]] [T(a,b)[-1], c, d, e, f] + #3 [T(a,b)[:-1]] [T(T(a,b)[-1], c), d, e, f] + #4 [T(a,b)[:-1], T(T(a,b)[-1], c)[:-1]] [T(T(T(a,b)[-1], c)[-1], d), e, f] + #5 ... + + One limitation of the current implementation is that we assume that only the + last item of the transformed tuple goes back into the args to be transformed + again. These seems to handle the cases needed for Mul. However, we may need + to extend the algorithm to have the entire tuple go back into the args for + further transformation. + """ + args = list(expr.args) + result = [] + + # Continue as long as we have at least 2 elements + while len(args) > 1: + # Get first two elements + first = args.pop(0) + second = args[0] # Look at second element without popping yet + + transformed = _transform_state_pair(first, second) + + if transformed is None: + # If transform returns None, append first element + result.append(first) + else: + # This item was transformed, pop and discard + args.pop(0) + # The last item goes back to be transformed again + args.insert(0, transformed[-1]) + # All other items go directly into the result + result.extend(transformed[:-1]) + + # Append any remaining element + if args: + result.append(args[0]) + + return Mul._from_args(result, is_commutative=False) + + +def _postprocess_state_pow(expr): + """Handle bras and kets raised to powers. + + Under ``*`` multiplication this is invalid. Users should use a + TensorProduct instead. + """ + base, exp = expr.as_base_exp() + if base.kind == KetKind or base.kind == BraKind: + raise TypeError( + 'A bra or ket to a power is invalid, use TensorProduct instead.' + ) + + +def _postprocess_tp_pow(expr): + """Handle TensorProduct(*operators)**(positive integer). + + This handles a tensor product of operators, to an integer power. + The power here is interpreted as regular multiplication, not + tensor product exponentiation. The form of exponentiation performed + here leaves the space and dimension of the object the same. + + This operation does not make sense for tensor product's of states. + """ + base, exp = expr.as_base_exp() + debug('_postprocess_tp_pow: ', base, exp, expr.args) + if isinstance(base, TensorProduct) and exp.is_integer and exp.is_positive and base.kind == OperatorKind: + new_args = [a**exp for a in base.args] + return TensorProduct(*new_args) + + +#----------------------------------------------------------------------------- +# Register the transformers with Basic._constructor_postprocessor_mapping +#----------------------------------------------------------------------------- + + +Basic._constructor_postprocessor_mapping[StateBase] = { + "Mul": [_postprocess_state_mul], + "Pow": [_postprocess_state_pow] +} + +Basic._constructor_postprocessor_mapping[TensorProduct] = { + "Mul": [_postprocess_state_mul], + "Pow": [_postprocess_tp_pow] +} + +Basic._constructor_postprocessor_mapping[Operator] = { + "Mul": [_postprocess_state_mul] +} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d17009cd52a898feaee223170011caea66a84c04 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_clebsch_gordan.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_clebsch_gordan.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5079a2b1ae6eec217b331cd4ecf2c88b8adcaef2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_clebsch_gordan.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_hydrogen.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_hydrogen.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d28d2bdbf5fc2ac6c413d4e01220666aaecc00c7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_hydrogen.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_paulialgebra.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_paulialgebra.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36e3eedcc0a508d3d79a8ec55a6017d524505178 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_paulialgebra.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_physics_matrices.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_physics_matrices.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a74c5bba413a1cbb8c163ea448f03eced152b54e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_physics_matrices.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_pring.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_pring.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05ae006dbea4aa7e27f9d65f2ed9258efa2c6fa2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_pring.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_qho_1d.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_qho_1d.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e82bba4c40a344dae28992ec784b4d568af3f9b9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_qho_1d.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_secondquant.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_secondquant.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e69d738acd168634370eadb8a15c68a75b5d281f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_secondquant.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_sho.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_sho.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30d355b969a05f9b75989125e92077e3233464d8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/tests/__pycache__/test_sho.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bf4e3d1e83ee284b3a73e93df598fac19948d066 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/dimensions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/dimensions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..471e87178eaee300960f2ce364487ea5a921500f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/dimensions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/prefixes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/prefixes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c5e1f41e334f9c9063af87c523030d20d87f49c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/prefixes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/quantities.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/quantities.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e455658032742533c7f0eb19ed005e8b6d719ef4 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/quantities.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/unitsystem.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/unitsystem.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2f734bbe8df85f1a62dc79678ec41f458d8d351c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/unitsystem.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/util.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/util.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f9b24ff87ffd545e88583c6097277046b20ae86 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/__pycache__/util.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..759889695d38c6e78237cc64974da3ecca6425cd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__init__.py @@ -0,0 +1,265 @@ +from .unit_definitions import ( + percent, percents, + permille, + rad, radian, radians, + deg, degree, degrees, + sr, steradian, steradians, + mil, angular_mil, angular_mils, + m, meter, meters, + kg, kilogram, kilograms, + s, second, seconds, + A, ampere, amperes, + K, kelvin, kelvins, + mol, mole, moles, + cd, candela, candelas, + g, gram, grams, + mg, milligram, milligrams, + ug, microgram, micrograms, + t, tonne, metric_ton, + newton, newtons, N, + joule, joules, J, + watt, watts, W, + pascal, pascals, Pa, pa, + hertz, hz, Hz, + coulomb, coulombs, C, + volt, volts, v, V, + ohm, ohms, + siemens, S, mho, mhos, + farad, farads, F, + henry, henrys, H, + tesla, teslas, T, + weber, webers, Wb, wb, + optical_power, dioptre, D, + lux, lx, + katal, kat, + gray, Gy, + becquerel, Bq, + km, kilometer, kilometers, + dm, decimeter, decimeters, + cm, centimeter, centimeters, + mm, millimeter, millimeters, + um, micrometer, micrometers, micron, microns, + nm, nanometer, nanometers, + pm, picometer, picometers, + ft, foot, feet, + inch, inches, + yd, yard, yards, + mi, mile, miles, + nmi, nautical_mile, nautical_miles, + ha, hectare, + l, L, liter, liters, + dl, dL, deciliter, deciliters, + cl, cL, centiliter, centiliters, + ml, mL, milliliter, milliliters, + ms, millisecond, milliseconds, + us, microsecond, microseconds, + ns, nanosecond, nanoseconds, + ps, picosecond, picoseconds, + minute, minutes, + h, hour, hours, + day, days, + anomalistic_year, anomalistic_years, + sidereal_year, sidereal_years, + tropical_year, tropical_years, + common_year, common_years, + julian_year, julian_years, + draconic_year, draconic_years, + gaussian_year, gaussian_years, + full_moon_cycle, full_moon_cycles, + year, years, + G, gravitational_constant, + c, speed_of_light, + elementary_charge, + hbar, + planck, + eV, electronvolt, electronvolts, + avogadro_number, + avogadro, avogadro_constant, + boltzmann, boltzmann_constant, + stefan, stefan_boltzmann_constant, + R, molar_gas_constant, + faraday_constant, + josephson_constant, + von_klitzing_constant, + Da, dalton, amu, amus, atomic_mass_unit, atomic_mass_constant, + me, electron_rest_mass, + gee, gees, acceleration_due_to_gravity, + u0, magnetic_constant, vacuum_permeability, + e0, electric_constant, vacuum_permittivity, + Z0, vacuum_impedance, + coulomb_constant, coulombs_constant, electric_force_constant, + atmosphere, atmospheres, atm, + kPa, kilopascal, + bar, bars, + pound, pounds, + psi, + dHg0, + mmHg, torr, + mmu, mmus, milli_mass_unit, + quart, quarts, + angstrom, angstroms, + ly, lightyear, lightyears, + au, astronomical_unit, astronomical_units, + planck_mass, + planck_time, + planck_temperature, + planck_length, + planck_charge, + planck_area, + planck_volume, + planck_momentum, + planck_energy, + planck_force, + planck_power, + planck_density, + planck_energy_density, + planck_intensity, + planck_angular_frequency, + planck_pressure, + planck_current, + planck_voltage, + planck_impedance, + planck_acceleration, + bit, bits, + byte, + kibibyte, kibibytes, + mebibyte, mebibytes, + gibibyte, gibibytes, + tebibyte, tebibytes, + pebibyte, pebibytes, + exbibyte, exbibytes, + curie, rutherford +) + +__all__ = [ + 'percent', 'percents', + 'permille', + 'rad', 'radian', 'radians', + 'deg', 'degree', 'degrees', + 'sr', 'steradian', 'steradians', + 'mil', 'angular_mil', 'angular_mils', + 'm', 'meter', 'meters', + 'kg', 'kilogram', 'kilograms', + 's', 'second', 'seconds', + 'A', 'ampere', 'amperes', + 'K', 'kelvin', 'kelvins', + 'mol', 'mole', 'moles', + 'cd', 'candela', 'candelas', + 'g', 'gram', 'grams', + 'mg', 'milligram', 'milligrams', + 'ug', 'microgram', 'micrograms', + 't', 'tonne', 'metric_ton', + 'newton', 'newtons', 'N', + 'joule', 'joules', 'J', + 'watt', 'watts', 'W', + 'pascal', 'pascals', 'Pa', 'pa', + 'hertz', 'hz', 'Hz', + 'coulomb', 'coulombs', 'C', + 'volt', 'volts', 'v', 'V', + 'ohm', 'ohms', + 'siemens', 'S', 'mho', 'mhos', + 'farad', 'farads', 'F', + 'henry', 'henrys', 'H', + 'tesla', 'teslas', 'T', + 'weber', 'webers', 'Wb', 'wb', + 'optical_power', 'dioptre', 'D', + 'lux', 'lx', + 'katal', 'kat', + 'gray', 'Gy', + 'becquerel', 'Bq', + 'km', 'kilometer', 'kilometers', + 'dm', 'decimeter', 'decimeters', + 'cm', 'centimeter', 'centimeters', + 'mm', 'millimeter', 'millimeters', + 'um', 'micrometer', 'micrometers', 'micron', 'microns', + 'nm', 'nanometer', 'nanometers', + 'pm', 'picometer', 'picometers', + 'ft', 'foot', 'feet', + 'inch', 'inches', + 'yd', 'yard', 'yards', + 'mi', 'mile', 'miles', + 'nmi', 'nautical_mile', 'nautical_miles', + 'ha', 'hectare', + 'l', 'L', 'liter', 'liters', + 'dl', 'dL', 'deciliter', 'deciliters', + 'cl', 'cL', 'centiliter', 'centiliters', + 'ml', 'mL', 'milliliter', 'milliliters', + 'ms', 'millisecond', 'milliseconds', + 'us', 'microsecond', 'microseconds', + 'ns', 'nanosecond', 'nanoseconds', + 'ps', 'picosecond', 'picoseconds', + 'minute', 'minutes', + 'h', 'hour', 'hours', + 'day', 'days', + 'anomalistic_year', 'anomalistic_years', + 'sidereal_year', 'sidereal_years', + 'tropical_year', 'tropical_years', + 'common_year', 'common_years', + 'julian_year', 'julian_years', + 'draconic_year', 'draconic_years', + 'gaussian_year', 'gaussian_years', + 'full_moon_cycle', 'full_moon_cycles', + 'year', 'years', + 'G', 'gravitational_constant', + 'c', 'speed_of_light', + 'elementary_charge', + 'hbar', + 'planck', + 'eV', 'electronvolt', 'electronvolts', + 'avogadro_number', + 'avogadro', 'avogadro_constant', + 'boltzmann', 'boltzmann_constant', + 'stefan', 'stefan_boltzmann_constant', + 'R', 'molar_gas_constant', + 'faraday_constant', + 'josephson_constant', + 'von_klitzing_constant', + 'Da', 'dalton', 'amu', 'amus', 'atomic_mass_unit', 'atomic_mass_constant', + 'me', 'electron_rest_mass', + 'gee', 'gees', 'acceleration_due_to_gravity', + 'u0', 'magnetic_constant', 'vacuum_permeability', + 'e0', 'electric_constant', 'vacuum_permittivity', + 'Z0', 'vacuum_impedance', + 'coulomb_constant', 'coulombs_constant', 'electric_force_constant', + 'atmosphere', 'atmospheres', 'atm', + 'kPa', 'kilopascal', + 'bar', 'bars', + 'pound', 'pounds', + 'psi', + 'dHg0', + 'mmHg', 'torr', + 'mmu', 'mmus', 'milli_mass_unit', + 'quart', 'quarts', + 'angstrom', 'angstroms', + 'ly', 'lightyear', 'lightyears', + 'au', 'astronomical_unit', 'astronomical_units', + 'planck_mass', + 'planck_time', + 'planck_temperature', + 'planck_length', + 'planck_charge', + 'planck_area', + 'planck_volume', + 'planck_momentum', + 'planck_energy', + 'planck_force', + 'planck_power', + 'planck_density', + 'planck_energy_density', + 'planck_intensity', + 'planck_angular_frequency', + 'planck_pressure', + 'planck_current', + 'planck_voltage', + 'planck_impedance', + 'planck_acceleration', + 'bit', 'bits', + 'byte', + 'kibibyte', 'kibibytes', + 'mebibyte', 'mebibytes', + 'gibibyte', 'gibibytes', + 'tebibyte', 'tebibytes', + 'pebibyte', 'pebibytes', + 'exbibyte', 'exbibytes', + 'curie', 'rutherford', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b7d70a2ce4d9845050c6ef7b9005c2580f6d653 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__pycache__/dimension_definitions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__pycache__/dimension_definitions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6cfff883c616123dd49963e171215b9ead8bed6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__pycache__/dimension_definitions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__pycache__/unit_definitions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__pycache__/unit_definitions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0421ebbac0a1f7dd605981ec8e7c224b2a3239b4 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/__pycache__/unit_definitions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/dimension_definitions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/dimension_definitions.py new file mode 100644 index 0000000000000000000000000000000000000000..b2b5f1dee01f9107d966a99d1e616c79a070a5b8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/dimension_definitions.py @@ -0,0 +1,43 @@ +from sympy.physics.units import Dimension + + +angle: Dimension = Dimension(name="angle") + +# base dimensions (MKS) +length = Dimension(name="length", symbol="L") +mass = Dimension(name="mass", symbol="M") +time = Dimension(name="time", symbol="T") + +# base dimensions (MKSA not in MKS) +current: Dimension = Dimension(name='current', symbol='I') + +# other base dimensions: +temperature: Dimension = Dimension("temperature", "T") +amount_of_substance: Dimension = Dimension("amount_of_substance") +luminous_intensity: Dimension = Dimension("luminous_intensity") + +# derived dimensions (MKS) +velocity = Dimension(name="velocity") +acceleration = Dimension(name="acceleration") +momentum = Dimension(name="momentum") +force = Dimension(name="force", symbol="F") +energy = Dimension(name="energy", symbol="E") +power = Dimension(name="power") +pressure = Dimension(name="pressure") +frequency = Dimension(name="frequency", symbol="f") +action = Dimension(name="action", symbol="A") +area = Dimension("area") +volume = Dimension("volume") + +# derived dimensions (MKSA not in MKS) +voltage: Dimension = Dimension(name='voltage', symbol='U') +impedance: Dimension = Dimension(name='impedance', symbol='Z') +conductance: Dimension = Dimension(name='conductance', symbol='G') +capacitance: Dimension = Dimension(name='capacitance') +inductance: Dimension = Dimension(name='inductance') +charge: Dimension = Dimension(name='charge', symbol='Q') +magnetic_density: Dimension = Dimension(name='magnetic_density', symbol='B') +magnetic_flux: Dimension = Dimension(name='magnetic_flux') + +# Dimensions in information theory: +information: Dimension = Dimension(name='information') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/unit_definitions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/unit_definitions.py new file mode 100644 index 0000000000000000000000000000000000000000..c0a89802a444a40172a0dc70094321f07a7e396b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/definitions/unit_definitions.py @@ -0,0 +1,407 @@ +from sympy.physics.units.definitions.dimension_definitions import current, temperature, amount_of_substance, \ + luminous_intensity, angle, charge, voltage, impedance, conductance, capacitance, inductance, magnetic_density, \ + magnetic_flux, information + +from sympy.core.numbers import (Rational, pi) +from sympy.core.singleton import S as S_singleton +from sympy.physics.units.prefixes import kilo, mega, milli, micro, deci, centi, nano, pico, kibi, mebi, gibi, tebi, pebi, exbi +from sympy.physics.units.quantities import PhysicalConstant, Quantity + +One = S_singleton.One + +#### UNITS #### + +# Dimensionless: +percent = percents = Quantity("percent", latex_repr=r"\%") +percent.set_global_relative_scale_factor(Rational(1, 100), One) + +permille = Quantity("permille") +permille.set_global_relative_scale_factor(Rational(1, 1000), One) + + +# Angular units (dimensionless) +rad = radian = radians = Quantity("radian", abbrev="rad") +radian.set_global_dimension(angle) +deg = degree = degrees = Quantity("degree", abbrev="deg", latex_repr=r"^\circ") +degree.set_global_relative_scale_factor(pi/180, radian) +sr = steradian = steradians = Quantity("steradian", abbrev="sr") +mil = angular_mil = angular_mils = Quantity("angular_mil", abbrev="mil") + +# Base units: +m = meter = meters = Quantity("meter", abbrev="m") + +# gram; used to define its prefixed units +g = gram = grams = Quantity("gram", abbrev="g") + +# NOTE: the `kilogram` has scale factor 1000. In SI, kg is a base unit, but +# nonetheless we are trying to be compatible with the `kilo` prefix. In a +# similar manner, people using CGS or gaussian units could argue that the +# `centimeter` rather than `meter` is the fundamental unit for length, but the +# scale factor of `centimeter` will be kept as 1/100 to be compatible with the +# `centi` prefix. The current state of the code assumes SI unit dimensions, in +# the future this module will be modified in order to be unit system-neutral +# (that is, support all kinds of unit systems). +kg = kilogram = kilograms = Quantity("kilogram", abbrev="kg") +kg.set_global_relative_scale_factor(kilo, gram) + +s = second = seconds = Quantity("second", abbrev="s") +A = ampere = amperes = Quantity("ampere", abbrev='A') +ampere.set_global_dimension(current) +K = kelvin = kelvins = Quantity("kelvin", abbrev='K') +kelvin.set_global_dimension(temperature) +mol = mole = moles = Quantity("mole", abbrev="mol") +mole.set_global_dimension(amount_of_substance) +cd = candela = candelas = Quantity("candela", abbrev="cd") +candela.set_global_dimension(luminous_intensity) + +# derived units +newton = newtons = N = Quantity("newton", abbrev="N") + +kilonewton = kilonewtons = kN = Quantity("kilonewton", abbrev="kN") +kilonewton.set_global_relative_scale_factor(kilo, newton) + +meganewton = meganewtons = MN = Quantity("meganewton", abbrev="MN") +meganewton.set_global_relative_scale_factor(mega, newton) + +joule = joules = J = Quantity("joule", abbrev="J") +watt = watts = W = Quantity("watt", abbrev="W") +pascal = pascals = Pa = pa = Quantity("pascal", abbrev="Pa") +hertz = hz = Hz = Quantity("hertz", abbrev="Hz") + +# CGS derived units: +dyne = Quantity("dyne") +dyne.set_global_relative_scale_factor(One/10**5, newton) +erg = Quantity("erg") +erg.set_global_relative_scale_factor(One/10**7, joule) + +# MKSA extension to MKS: derived units +coulomb = coulombs = C = Quantity("coulomb", abbrev='C') +coulomb.set_global_dimension(charge) +volt = volts = v = V = Quantity("volt", abbrev='V') +volt.set_global_dimension(voltage) +ohm = ohms = Quantity("ohm", abbrev='ohm', latex_repr=r"\Omega") +ohm.set_global_dimension(impedance) +siemens = S = mho = mhos = Quantity("siemens", abbrev='S') +siemens.set_global_dimension(conductance) +farad = farads = F = Quantity("farad", abbrev='F') +farad.set_global_dimension(capacitance) +henry = henrys = H = Quantity("henry", abbrev='H') +henry.set_global_dimension(inductance) +tesla = teslas = T = Quantity("tesla", abbrev='T') +tesla.set_global_dimension(magnetic_density) +weber = webers = Wb = wb = Quantity("weber", abbrev='Wb') +weber.set_global_dimension(magnetic_flux) + +# CGS units for electromagnetic quantities: +statampere = Quantity("statampere") +statcoulomb = statC = franklin = Quantity("statcoulomb", abbrev="statC") +statvolt = Quantity("statvolt") +gauss = Quantity("gauss") +maxwell = Quantity("maxwell") +debye = Quantity("debye") +oersted = Quantity("oersted") + +# Other derived units: +optical_power = dioptre = diopter = D = Quantity("dioptre") +lux = lx = Quantity("lux", abbrev="lx") + +# katal is the SI unit of catalytic activity +katal = kat = Quantity("katal", abbrev="kat") + +# gray is the SI unit of absorbed dose +gray = Gy = Quantity("gray") + +# becquerel is the SI unit of radioactivity +becquerel = Bq = Quantity("becquerel", abbrev="Bq") + + +# Common mass units + +mg = milligram = milligrams = Quantity("milligram", abbrev="mg") +mg.set_global_relative_scale_factor(milli, gram) + +ug = microgram = micrograms = Quantity("microgram", abbrev="ug", latex_repr=r"\mu\text{g}") +ug.set_global_relative_scale_factor(micro, gram) + +# Atomic mass constant +Da = dalton = amu = amus = atomic_mass_unit = atomic_mass_constant = PhysicalConstant("atomic_mass_constant") + +t = metric_ton = tonne = Quantity("tonne", abbrev="t") +tonne.set_global_relative_scale_factor(mega, gram) + +# Electron rest mass +me = electron_rest_mass = Quantity("electron_rest_mass", abbrev="me") + + +# Common length units + +km = kilometer = kilometers = Quantity("kilometer", abbrev="km") +km.set_global_relative_scale_factor(kilo, meter) + +dm = decimeter = decimeters = Quantity("decimeter", abbrev="dm") +dm.set_global_relative_scale_factor(deci, meter) + +cm = centimeter = centimeters = Quantity("centimeter", abbrev="cm") +cm.set_global_relative_scale_factor(centi, meter) + +mm = millimeter = millimeters = Quantity("millimeter", abbrev="mm") +mm.set_global_relative_scale_factor(milli, meter) + +um = micrometer = micrometers = micron = microns = \ + Quantity("micrometer", abbrev="um", latex_repr=r'\mu\text{m}') +um.set_global_relative_scale_factor(micro, meter) + +nm = nanometer = nanometers = Quantity("nanometer", abbrev="nm") +nm.set_global_relative_scale_factor(nano, meter) + +pm = picometer = picometers = Quantity("picometer", abbrev="pm") +pm.set_global_relative_scale_factor(pico, meter) + +ft = foot = feet = Quantity("foot", abbrev="ft") +ft.set_global_relative_scale_factor(Rational(3048, 10000), meter) + +inch = inches = Quantity("inch") +inch.set_global_relative_scale_factor(Rational(1, 12), foot) + +yd = yard = yards = Quantity("yard", abbrev="yd") +yd.set_global_relative_scale_factor(3, feet) + +mi = mile = miles = Quantity("mile") +mi.set_global_relative_scale_factor(5280, feet) + +nmi = nautical_mile = nautical_miles = Quantity("nautical_mile") +nmi.set_global_relative_scale_factor(6076, feet) + +angstrom = angstroms = Quantity("angstrom", latex_repr=r'\r{A}') +angstrom.set_global_relative_scale_factor(Rational(1, 10**10), meter) + + +# Common volume and area units + +ha = hectare = Quantity("hectare", abbrev="ha") + +l = L = liter = liters = Quantity("liter", abbrev="l") + +dl = dL = deciliter = deciliters = Quantity("deciliter", abbrev="dl") +dl.set_global_relative_scale_factor(Rational(1, 10), liter) + +cl = cL = centiliter = centiliters = Quantity("centiliter", abbrev="cl") +cl.set_global_relative_scale_factor(Rational(1, 100), liter) + +ml = mL = milliliter = milliliters = Quantity("milliliter", abbrev="ml") +ml.set_global_relative_scale_factor(Rational(1, 1000), liter) + + +# Common time units + +ms = millisecond = milliseconds = Quantity("millisecond", abbrev="ms") +millisecond.set_global_relative_scale_factor(milli, second) + +us = microsecond = microseconds = Quantity("microsecond", abbrev="us", latex_repr=r'\mu\text{s}') +microsecond.set_global_relative_scale_factor(micro, second) + +ns = nanosecond = nanoseconds = Quantity("nanosecond", abbrev="ns") +nanosecond.set_global_relative_scale_factor(nano, second) + +ps = picosecond = picoseconds = Quantity("picosecond", abbrev="ps") +picosecond.set_global_relative_scale_factor(pico, second) + +minute = minutes = Quantity("minute") +minute.set_global_relative_scale_factor(60, second) + +h = hour = hours = Quantity("hour") +hour.set_global_relative_scale_factor(60, minute) + +day = days = Quantity("day") +day.set_global_relative_scale_factor(24, hour) + +anomalistic_year = anomalistic_years = Quantity("anomalistic_year") +anomalistic_year.set_global_relative_scale_factor(365.259636, day) + +sidereal_year = sidereal_years = Quantity("sidereal_year") +sidereal_year.set_global_relative_scale_factor(31558149.540, seconds) + +tropical_year = tropical_years = Quantity("tropical_year") +tropical_year.set_global_relative_scale_factor(365.24219, day) + +common_year = common_years = Quantity("common_year") +common_year.set_global_relative_scale_factor(365, day) + +julian_year = julian_years = Quantity("julian_year") +julian_year.set_global_relative_scale_factor((365 + One/4), day) + +draconic_year = draconic_years = Quantity("draconic_year") +draconic_year.set_global_relative_scale_factor(346.62, day) + +gaussian_year = gaussian_years = Quantity("gaussian_year") +gaussian_year.set_global_relative_scale_factor(365.2568983, day) + +full_moon_cycle = full_moon_cycles = Quantity("full_moon_cycle") +full_moon_cycle.set_global_relative_scale_factor(411.78443029, day) + +year = years = tropical_year + + +#### CONSTANTS #### + +# Newton constant +G = gravitational_constant = PhysicalConstant("gravitational_constant", abbrev="G") + +# speed of light +c = speed_of_light = PhysicalConstant("speed_of_light", abbrev="c") + +# elementary charge +elementary_charge = PhysicalConstant("elementary_charge", abbrev="e") + +# Planck constant +planck = PhysicalConstant("planck", abbrev="h") + +# Reduced Planck constant +hbar = PhysicalConstant("hbar", abbrev="hbar") + +# Electronvolt +eV = electronvolt = electronvolts = PhysicalConstant("electronvolt", abbrev="eV") + +# Avogadro number +avogadro_number = PhysicalConstant("avogadro_number") + +# Avogadro constant +avogadro = avogadro_constant = PhysicalConstant("avogadro_constant") + +# Boltzmann constant +boltzmann = boltzmann_constant = PhysicalConstant("boltzmann_constant") + +# Stefan-Boltzmann constant +stefan = stefan_boltzmann_constant = PhysicalConstant("stefan_boltzmann_constant") + +# Molar gas constant +R = molar_gas_constant = PhysicalConstant("molar_gas_constant", abbrev="R") + +# Faraday constant +faraday_constant = PhysicalConstant("faraday_constant") + +# Josephson constant +josephson_constant = PhysicalConstant("josephson_constant", abbrev="K_j") + +# Von Klitzing constant +von_klitzing_constant = PhysicalConstant("von_klitzing_constant", abbrev="R_k") + +# Acceleration due to gravity (on the Earth surface) +gee = gees = acceleration_due_to_gravity = PhysicalConstant("acceleration_due_to_gravity", abbrev="g") + +# magnetic constant: +u0 = magnetic_constant = vacuum_permeability = PhysicalConstant("magnetic_constant") + +# electric constat: +e0 = electric_constant = vacuum_permittivity = PhysicalConstant("vacuum_permittivity") + +# vacuum impedance: +Z0 = vacuum_impedance = PhysicalConstant("vacuum_impedance", abbrev='Z_0', latex_repr=r'Z_{0}') + +# Coulomb's constant: +coulomb_constant = coulombs_constant = electric_force_constant = \ + PhysicalConstant("coulomb_constant", abbrev="k_e") + + +atmosphere = atmospheres = atm = Quantity("atmosphere", abbrev="atm") + +kPa = kilopascal = Quantity("kilopascal", abbrev="kPa") +kilopascal.set_global_relative_scale_factor(kilo, Pa) + +bar = bars = Quantity("bar", abbrev="bar") + +pound = pounds = Quantity("pound") # exact + +psi = Quantity("psi") + +dHg0 = 13.5951 # approx value at 0 C +mmHg = torr = Quantity("mmHg") + +atmosphere.set_global_relative_scale_factor(101325, pascal) +bar.set_global_relative_scale_factor(100, kPa) +pound.set_global_relative_scale_factor(Rational(45359237, 100000000), kg) + +mmu = mmus = milli_mass_unit = Quantity("milli_mass_unit") + +quart = quarts = Quantity("quart") + + +# Other convenient units and magnitudes + +ly = lightyear = lightyears = Quantity("lightyear", abbrev="ly") + +au = astronomical_unit = astronomical_units = Quantity("astronomical_unit", abbrev="AU") + + +# Fundamental Planck units: +planck_mass = Quantity("planck_mass", abbrev="m_P", latex_repr=r'm_\text{P}') + +planck_time = Quantity("planck_time", abbrev="t_P", latex_repr=r't_\text{P}') + +planck_temperature = Quantity("planck_temperature", abbrev="T_P", + latex_repr=r'T_\text{P}') + +planck_length = Quantity("planck_length", abbrev="l_P", latex_repr=r'l_\text{P}') + +planck_charge = Quantity("planck_charge", abbrev="q_P", latex_repr=r'q_\text{P}') + + +# Derived Planck units: +planck_area = Quantity("planck_area") + +planck_volume = Quantity("planck_volume") + +planck_momentum = Quantity("planck_momentum") + +planck_energy = Quantity("planck_energy", abbrev="E_P", latex_repr=r'E_\text{P}') + +planck_force = Quantity("planck_force", abbrev="F_P", latex_repr=r'F_\text{P}') + +planck_power = Quantity("planck_power", abbrev="P_P", latex_repr=r'P_\text{P}') + +planck_density = Quantity("planck_density", abbrev="rho_P", latex_repr=r'\rho_\text{P}') + +planck_energy_density = Quantity("planck_energy_density", abbrev="rho^E_P") + +planck_intensity = Quantity("planck_intensity", abbrev="I_P", latex_repr=r'I_\text{P}') + +planck_angular_frequency = Quantity("planck_angular_frequency", abbrev="omega_P", + latex_repr=r'\omega_\text{P}') + +planck_pressure = Quantity("planck_pressure", abbrev="p_P", latex_repr=r'p_\text{P}') + +planck_current = Quantity("planck_current", abbrev="I_P", latex_repr=r'I_\text{P}') + +planck_voltage = Quantity("planck_voltage", abbrev="V_P", latex_repr=r'V_\text{P}') + +planck_impedance = Quantity("planck_impedance", abbrev="Z_P", latex_repr=r'Z_\text{P}') + +planck_acceleration = Quantity("planck_acceleration", abbrev="a_P", + latex_repr=r'a_\text{P}') + + +# Information theory units: +bit = bits = Quantity("bit") +bit.set_global_dimension(information) + +byte = bytes = Quantity("byte") + +kibibyte = kibibytes = Quantity("kibibyte") +mebibyte = mebibytes = Quantity("mebibyte") +gibibyte = gibibytes = Quantity("gibibyte") +tebibyte = tebibytes = Quantity("tebibyte") +pebibyte = pebibytes = Quantity("pebibyte") +exbibyte = exbibytes = Quantity("exbibyte") + +byte.set_global_relative_scale_factor(8, bit) +kibibyte.set_global_relative_scale_factor(kibi, byte) +mebibyte.set_global_relative_scale_factor(mebi, byte) +gibibyte.set_global_relative_scale_factor(gibi, byte) +tebibyte.set_global_relative_scale_factor(tebi, byte) +pebibyte.set_global_relative_scale_factor(pebi, byte) +exbibyte.set_global_relative_scale_factor(exbi, byte) + +# Older units for radioactivity +curie = Ci = Quantity("curie", abbrev="Ci") + +rutherford = Rd = Quantity("rutherford", abbrev="Rd") diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7c4f28d42eec86be8d679227f7b11ed7d48e61f1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__init__.py @@ -0,0 +1,6 @@ +from sympy.physics.units.systems.mks import MKS +from sympy.physics.units.systems.mksa import MKSA +from sympy.physics.units.systems.natural import natural +from sympy.physics.units.systems.si import SI + +__all__ = ['MKS', 'MKSA', 'natural', 'SI'] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..077c9ddf2ea4cad75509d1c1b59494a817a648f1 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/cgs.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/cgs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b4ab9fc3eb0cf359a59de0487595deed52d9c81 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/cgs.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/length_weight_time.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/length_weight_time.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69ad4715e899c6bf09049110c6d250faefe0d360 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/length_weight_time.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/mks.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/mks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9ade84c96e6c0b56a7ae2d5c73264d23294ba4b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/mks.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/mksa.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/mksa.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4bb2fa2c78b0fa490f886ef430aca8f8cd2f2ee3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/mksa.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/natural.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/natural.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..908adad98673116a68950d66c75d19ff8b5c9c67 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/natural.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/si.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/si.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..75e0f7e18249f9b9949974d7de06ebbe687e3632 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/__pycache__/si.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/cgs.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/cgs.py new file mode 100644 index 0000000000000000000000000000000000000000..1f5ee0b5454f1998672e1979ae4eaabe57a8edb4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/cgs.py @@ -0,0 +1,82 @@ +from sympy.core.singleton import S +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.physics.units import UnitSystem, centimeter, gram, second, coulomb, charge, speed_of_light, current, mass, \ + length, voltage, magnetic_density, magnetic_flux +from sympy.physics.units.definitions import coulombs_constant +from sympy.physics.units.definitions.unit_definitions import statcoulomb, statampere, statvolt, volt, tesla, gauss, \ + weber, maxwell, debye, oersted, ohm, farad, henry, erg, ampere, coulomb_constant +from sympy.physics.units.systems.mks import dimsys_length_weight_time + +One = S.One + +dimsys_cgs = dimsys_length_weight_time.extend( + [], + new_dim_deps={ + # Dimensional dependencies for derived dimensions + "impedance": {"time": 1, "length": -1}, + "conductance": {"time": -1, "length": 1}, + "capacitance": {"length": 1}, + "inductance": {"time": 2, "length": -1}, + "charge": {"mass": S.Half, "length": S(3)/2, "time": -1}, + "current": {"mass": One/2, "length": 3*One/2, "time": -2}, + "voltage": {"length": -One/2, "mass": One/2, "time": -1}, + "magnetic_density": {"length": -One/2, "mass": One/2, "time": -1}, + "magnetic_flux": {"length": 3*One/2, "mass": One/2, "time": -1}, + } +) + +cgs_gauss = UnitSystem( + base_units=[centimeter, gram, second], + units=[], + name="cgs_gauss", + dimension_system=dimsys_cgs) + + +cgs_gauss.set_quantity_scale_factor(coulombs_constant, 1) + +cgs_gauss.set_quantity_dimension(statcoulomb, charge) +cgs_gauss.set_quantity_scale_factor(statcoulomb, centimeter**(S(3)/2)*gram**(S.Half)/second) + +cgs_gauss.set_quantity_dimension(coulomb, charge) + +cgs_gauss.set_quantity_dimension(statampere, current) +cgs_gauss.set_quantity_scale_factor(statampere, statcoulomb/second) + +cgs_gauss.set_quantity_dimension(statvolt, voltage) +cgs_gauss.set_quantity_scale_factor(statvolt, erg/statcoulomb) + +cgs_gauss.set_quantity_dimension(volt, voltage) + +cgs_gauss.set_quantity_dimension(gauss, magnetic_density) +cgs_gauss.set_quantity_scale_factor(gauss, sqrt(gram/centimeter)/second) + +cgs_gauss.set_quantity_dimension(tesla, magnetic_density) + +cgs_gauss.set_quantity_dimension(maxwell, magnetic_flux) +cgs_gauss.set_quantity_scale_factor(maxwell, sqrt(centimeter**3*gram)/second) + +# SI units expressed in CGS-gaussian units: +cgs_gauss.set_quantity_scale_factor(coulomb, 10*speed_of_light*statcoulomb) +cgs_gauss.set_quantity_scale_factor(ampere, 10*speed_of_light*statcoulomb/second) +cgs_gauss.set_quantity_scale_factor(volt, 10**6/speed_of_light*statvolt) +cgs_gauss.set_quantity_scale_factor(weber, 10**8*maxwell) +cgs_gauss.set_quantity_scale_factor(tesla, 10**4*gauss) +cgs_gauss.set_quantity_scale_factor(debye, One/10**18*statcoulomb*centimeter) +cgs_gauss.set_quantity_scale_factor(oersted, sqrt(gram/centimeter)/second) +cgs_gauss.set_quantity_scale_factor(ohm, 10**5/speed_of_light**2*second/centimeter) +cgs_gauss.set_quantity_scale_factor(farad, One/10**5*speed_of_light**2*centimeter) +cgs_gauss.set_quantity_scale_factor(henry, 10**5/speed_of_light**2/centimeter*second**2) + +# Coulomb's constant: +cgs_gauss.set_quantity_dimension(coulomb_constant, 1) +cgs_gauss.set_quantity_scale_factor(coulomb_constant, 1) + +__all__ = [ + 'ohm', 'tesla', 'maxwell', 'speed_of_light', 'volt', 'second', 'voltage', + 'debye', 'dimsys_length_weight_time', 'centimeter', 'coulomb_constant', + 'farad', 'sqrt', 'UnitSystem', 'current', 'charge', 'weber', 'gram', + 'statcoulomb', 'gauss', 'S', 'statvolt', 'oersted', 'statampere', + 'dimsys_cgs', 'coulomb', 'magnetic_density', 'magnetic_flux', 'One', + 'length', 'erg', 'mass', 'coulombs_constant', 'henry', 'ampere', + 'cgs_gauss', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/length_weight_time.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/length_weight_time.py new file mode 100644 index 0000000000000000000000000000000000000000..dca4ded82afb8ff0e45f197e51c23850ca824737 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/length_weight_time.py @@ -0,0 +1,156 @@ +from sympy.core.singleton import S + +from sympy.core.numbers import pi + +from sympy.physics.units import DimensionSystem, hertz, kilogram +from sympy.physics.units.definitions import ( + G, Hz, J, N, Pa, W, c, g, kg, m, s, meter, gram, second, newton, + joule, watt, pascal) +from sympy.physics.units.definitions.dimension_definitions import ( + acceleration, action, energy, force, frequency, momentum, + power, pressure, velocity, length, mass, time) +from sympy.physics.units.prefixes import PREFIXES, prefix_unit +from sympy.physics.units.prefixes import ( + kibi, mebi, gibi, tebi, pebi, exbi +) +from sympy.physics.units.definitions import ( + cd, K, coulomb, volt, ohm, siemens, farad, henry, tesla, weber, dioptre, + lux, katal, gray, becquerel, inch, hectare, liter, julian_year, + gravitational_constant, speed_of_light, elementary_charge, planck, hbar, + electronvolt, avogadro_number, avogadro_constant, boltzmann_constant, + stefan_boltzmann_constant, atomic_mass_constant, molar_gas_constant, + faraday_constant, josephson_constant, von_klitzing_constant, + acceleration_due_to_gravity, magnetic_constant, vacuum_permittivity, + vacuum_impedance, coulomb_constant, atmosphere, bar, pound, psi, mmHg, + milli_mass_unit, quart, lightyear, astronomical_unit, planck_mass, + planck_time, planck_temperature, planck_length, planck_charge, + planck_area, planck_volume, planck_momentum, planck_energy, planck_force, + planck_power, planck_density, planck_energy_density, planck_intensity, + planck_angular_frequency, planck_pressure, planck_current, planck_voltage, + planck_impedance, planck_acceleration, bit, byte, kibibyte, mebibyte, + gibibyte, tebibyte, pebibyte, exbibyte, curie, rutherford, radian, degree, + steradian, angular_mil, atomic_mass_unit, gee, kPa, ampere, u0, kelvin, + mol, mole, candela, electric_constant, boltzmann, angstrom +) + + +dimsys_length_weight_time = DimensionSystem([ + # Dimensional dependencies for MKS base dimensions + length, + mass, + time, +], dimensional_dependencies={ + # Dimensional dependencies for derived dimensions + "velocity": {"length": 1, "time": -1}, + "acceleration": {"length": 1, "time": -2}, + "momentum": {"mass": 1, "length": 1, "time": -1}, + "force": {"mass": 1, "length": 1, "time": -2}, + "energy": {"mass": 1, "length": 2, "time": -2}, + "power": {"length": 2, "mass": 1, "time": -3}, + "pressure": {"mass": 1, "length": -1, "time": -2}, + "frequency": {"time": -1}, + "action": {"length": 2, "mass": 1, "time": -1}, + "area": {"length": 2}, + "volume": {"length": 3}, +}) + + +One = S.One + + +# Base units: +dimsys_length_weight_time.set_quantity_dimension(meter, length) +dimsys_length_weight_time.set_quantity_scale_factor(meter, One) + +# gram; used to define its prefixed units +dimsys_length_weight_time.set_quantity_dimension(gram, mass) +dimsys_length_weight_time.set_quantity_scale_factor(gram, One) + +dimsys_length_weight_time.set_quantity_dimension(second, time) +dimsys_length_weight_time.set_quantity_scale_factor(second, One) + +# derived units + +dimsys_length_weight_time.set_quantity_dimension(newton, force) +dimsys_length_weight_time.set_quantity_scale_factor(newton, kilogram*meter/second**2) + +dimsys_length_weight_time.set_quantity_dimension(joule, energy) +dimsys_length_weight_time.set_quantity_scale_factor(joule, newton*meter) + +dimsys_length_weight_time.set_quantity_dimension(watt, power) +dimsys_length_weight_time.set_quantity_scale_factor(watt, joule/second) + +dimsys_length_weight_time.set_quantity_dimension(pascal, pressure) +dimsys_length_weight_time.set_quantity_scale_factor(pascal, newton/meter**2) + +dimsys_length_weight_time.set_quantity_dimension(hertz, frequency) +dimsys_length_weight_time.set_quantity_scale_factor(hertz, One) + +# Other derived units: + +dimsys_length_weight_time.set_quantity_dimension(dioptre, 1 / length) +dimsys_length_weight_time.set_quantity_scale_factor(dioptre, 1/meter) + +# Common volume and area units + +dimsys_length_weight_time.set_quantity_dimension(hectare, length**2) +dimsys_length_weight_time.set_quantity_scale_factor(hectare, (meter**2)*(10000)) + +dimsys_length_weight_time.set_quantity_dimension(liter, length**3) +dimsys_length_weight_time.set_quantity_scale_factor(liter, meter**3/1000) + + +# Newton constant +# REF: NIST SP 959 (June 2019) + +dimsys_length_weight_time.set_quantity_dimension(gravitational_constant, length ** 3 * mass ** -1 * time ** -2) +dimsys_length_weight_time.set_quantity_scale_factor(gravitational_constant, 6.67430e-11*m**3/(kg*s**2)) + +# speed of light + +dimsys_length_weight_time.set_quantity_dimension(speed_of_light, velocity) +dimsys_length_weight_time.set_quantity_scale_factor(speed_of_light, 299792458*meter/second) + + +# Planck constant +# REF: NIST SP 959 (June 2019) + +dimsys_length_weight_time.set_quantity_dimension(planck, action) +dimsys_length_weight_time.set_quantity_scale_factor(planck, 6.62607015e-34*joule*second) + +# Reduced Planck constant +# REF: NIST SP 959 (June 2019) + +dimsys_length_weight_time.set_quantity_dimension(hbar, action) +dimsys_length_weight_time.set_quantity_scale_factor(hbar, planck / (2 * pi)) + + +__all__ = [ + 'mmHg', 'atmosphere', 'newton', 'meter', 'vacuum_permittivity', 'pascal', + 'magnetic_constant', 'angular_mil', 'julian_year', 'weber', 'exbibyte', + 'liter', 'molar_gas_constant', 'faraday_constant', 'avogadro_constant', + 'planck_momentum', 'planck_density', 'gee', 'mol', 'bit', 'gray', 'kibi', + 'bar', 'curie', 'prefix_unit', 'PREFIXES', 'planck_time', 'gram', + 'candela', 'force', 'planck_intensity', 'energy', 'becquerel', + 'planck_acceleration', 'speed_of_light', 'dioptre', 'second', 'frequency', + 'Hz', 'power', 'lux', 'planck_current', 'momentum', 'tebibyte', + 'planck_power', 'degree', 'mebi', 'K', 'planck_volume', + 'quart', 'pressure', 'W', 'joule', 'boltzmann_constant', 'c', 'g', + 'planck_force', 'exbi', 's', 'watt', 'action', 'hbar', 'gibibyte', + 'DimensionSystem', 'cd', 'volt', 'planck_charge', 'angstrom', + 'dimsys_length_weight_time', 'pebi', 'vacuum_impedance', 'planck', + 'farad', 'gravitational_constant', 'u0', 'hertz', 'tesla', 'steradian', + 'josephson_constant', 'planck_area', 'stefan_boltzmann_constant', + 'astronomical_unit', 'J', 'N', 'planck_voltage', 'planck_energy', + 'atomic_mass_constant', 'rutherford', 'elementary_charge', 'Pa', + 'planck_mass', 'henry', 'planck_angular_frequency', 'ohm', 'pound', + 'planck_pressure', 'G', 'avogadro_number', 'psi', 'von_klitzing_constant', + 'planck_length', 'radian', 'mole', 'acceleration', + 'planck_energy_density', 'mebibyte', 'length', + 'acceleration_due_to_gravity', 'planck_temperature', 'tebi', 'inch', + 'electronvolt', 'coulomb_constant', 'kelvin', 'kPa', 'boltzmann', + 'milli_mass_unit', 'gibi', 'planck_impedance', 'electric_constant', 'kg', + 'coulomb', 'siemens', 'byte', 'atomic_mass_unit', 'm', 'kibibyte', + 'kilogram', 'lightyear', 'mass', 'time', 'pebibyte', 'velocity', + 'ampere', 'katal', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/mks.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/mks.py new file mode 100644 index 0000000000000000000000000000000000000000..18cc4b1be5e2cbf5773845e48a0cb552fb750fae --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/mks.py @@ -0,0 +1,46 @@ +""" +MKS unit system. + +MKS stands for "meter, kilogram, second". +""" + +from sympy.physics.units import UnitSystem +from sympy.physics.units.definitions import gravitational_constant, hertz, joule, newton, pascal, watt, speed_of_light, gram, kilogram, meter, second +from sympy.physics.units.definitions.dimension_definitions import ( + acceleration, action, energy, force, frequency, momentum, + power, pressure, velocity, length, mass, time) +from sympy.physics.units.prefixes import PREFIXES, prefix_unit +from sympy.physics.units.systems.length_weight_time import dimsys_length_weight_time + +dims = (velocity, acceleration, momentum, force, energy, power, pressure, + frequency, action) + +units = [meter, gram, second, joule, newton, watt, pascal, hertz] +all_units = [] + +# Prefixes of units like gram, joule, newton etc get added using `prefix_unit` +# in the for loop, but the actual units have to be added manually. +all_units.extend([gram, joule, newton, watt, pascal, hertz]) + +for u in units: + all_units.extend(prefix_unit(u, PREFIXES)) +all_units.extend([gravitational_constant, speed_of_light]) + +# unit system +MKS = UnitSystem(base_units=(meter, kilogram, second), units=all_units, name="MKS", dimension_system=dimsys_length_weight_time, derived_units={ + power: watt, + time: second, + pressure: pascal, + length: meter, + frequency: hertz, + mass: kilogram, + force: newton, + energy: joule, + velocity: meter/second, + acceleration: meter/(second**2), +}) + + +__all__ = [ + 'MKS', 'units', 'all_units', 'dims', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/mksa.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/mksa.py new file mode 100644 index 0000000000000000000000000000000000000000..c18c0d6ae3801358d8828e2309d091cb9cb987d8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/mksa.py @@ -0,0 +1,54 @@ +""" +MKS unit system. + +MKS stands for "meter, kilogram, second, ampere". +""" + +from __future__ import annotations + +from sympy.physics.units.definitions import Z0, ampere, coulomb, farad, henry, siemens, tesla, volt, weber, ohm +from sympy.physics.units.definitions.dimension_definitions import ( + capacitance, charge, conductance, current, impedance, inductance, + magnetic_density, magnetic_flux, voltage) +from sympy.physics.units.prefixes import PREFIXES, prefix_unit +from sympy.physics.units.systems.mks import MKS, dimsys_length_weight_time +from sympy.physics.units.quantities import Quantity + +dims = (voltage, impedance, conductance, current, capacitance, inductance, charge, + magnetic_density, magnetic_flux) + +units = [ampere, volt, ohm, siemens, farad, henry, coulomb, tesla, weber] + +all_units: list[Quantity] = [] +for u in units: + all_units.extend(prefix_unit(u, PREFIXES)) +all_units.extend(units) + +all_units.append(Z0) + +dimsys_MKSA = dimsys_length_weight_time.extend([ + # Dimensional dependencies for base dimensions (MKSA not in MKS) + current, +], new_dim_deps={ + # Dimensional dependencies for derived dimensions + "voltage": {"mass": 1, "length": 2, "current": -1, "time": -3}, + "impedance": {"mass": 1, "length": 2, "current": -2, "time": -3}, + "conductance": {"mass": -1, "length": -2, "current": 2, "time": 3}, + "capacitance": {"mass": -1, "length": -2, "current": 2, "time": 4}, + "inductance": {"mass": 1, "length": 2, "current": -2, "time": -2}, + "charge": {"current": 1, "time": 1}, + "magnetic_density": {"mass": 1, "current": -1, "time": -2}, + "magnetic_flux": {"length": 2, "mass": 1, "current": -1, "time": -2}, +}) + +MKSA = MKS.extend(base=(ampere,), units=all_units, name='MKSA', dimension_system=dimsys_MKSA, derived_units={ + magnetic_flux: weber, + impedance: ohm, + current: ampere, + voltage: volt, + inductance: henry, + conductance: siemens, + magnetic_density: tesla, + charge: coulomb, + capacitance: farad, +}) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/natural.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/natural.py new file mode 100644 index 0000000000000000000000000000000000000000..13eb2c19e982438fab4b1422ddc5a25b16204be8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/natural.py @@ -0,0 +1,27 @@ +""" +Naturalunit system. + +The natural system comes from "setting c = 1, hbar = 1". From the computer +point of view it means that we use velocity and action instead of length and +time. Moreover instead of mass we use energy. +""" + +from sympy.physics.units import DimensionSystem +from sympy.physics.units.definitions import c, eV, hbar +from sympy.physics.units.definitions.dimension_definitions import ( + action, energy, force, frequency, length, mass, momentum, + power, time, velocity) +from sympy.physics.units.prefixes import PREFIXES, prefix_unit +from sympy.physics.units.unitsystem import UnitSystem + + +# dimension system +_natural_dim = DimensionSystem( + base_dims=(action, energy, velocity), + derived_dims=(length, mass, time, momentum, force, power, frequency) +) + +units = prefix_unit(eV, PREFIXES) + +# unit system +natural = UnitSystem(base_units=(hbar, eV, c), units=units, name="Natural system") diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/si.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/si.py new file mode 100644 index 0000000000000000000000000000000000000000..2bfa7805871b8663c70b8af7da9ca1dc9b4afab3 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/systems/si.py @@ -0,0 +1,377 @@ +""" +SI unit system. +Based on MKSA, which stands for "meter, kilogram, second, ampere". +Added kelvin, candela and mole. + +""" + +from __future__ import annotations + +from sympy.physics.units import DimensionSystem, Dimension, dHg0 + +from sympy.physics.units.quantities import Quantity + +from sympy.core.numbers import (Rational, pi) +from sympy.core.singleton import S +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.physics.units.definitions.dimension_definitions import ( + acceleration, action, current, impedance, length, mass, time, velocity, + amount_of_substance, temperature, information, frequency, force, pressure, + energy, power, charge, voltage, capacitance, conductance, magnetic_flux, + magnetic_density, inductance, luminous_intensity +) +from sympy.physics.units.definitions import ( + kilogram, newton, second, meter, gram, cd, K, joule, watt, pascal, hertz, + coulomb, volt, ohm, siemens, farad, henry, tesla, weber, dioptre, lux, + katal, gray, becquerel, inch, liter, julian_year, gravitational_constant, + speed_of_light, elementary_charge, planck, hbar, electronvolt, + avogadro_number, avogadro_constant, boltzmann_constant, electron_rest_mass, + stefan_boltzmann_constant, Da, atomic_mass_constant, molar_gas_constant, + faraday_constant, josephson_constant, von_klitzing_constant, + acceleration_due_to_gravity, magnetic_constant, vacuum_permittivity, + vacuum_impedance, coulomb_constant, atmosphere, bar, pound, psi, mmHg, + milli_mass_unit, quart, lightyear, astronomical_unit, planck_mass, + planck_time, planck_temperature, planck_length, planck_charge, planck_area, + planck_volume, planck_momentum, planck_energy, planck_force, planck_power, + planck_density, planck_energy_density, planck_intensity, + planck_angular_frequency, planck_pressure, planck_current, planck_voltage, + planck_impedance, planck_acceleration, bit, byte, kibibyte, mebibyte, + gibibyte, tebibyte, pebibyte, exbibyte, curie, rutherford, radian, degree, + steradian, angular_mil, atomic_mass_unit, gee, kPa, ampere, u0, c, kelvin, + mol, mole, candela, m, kg, s, electric_constant, G, boltzmann +) +from sympy.physics.units.prefixes import PREFIXES, prefix_unit +from sympy.physics.units.systems.mksa import MKSA, dimsys_MKSA + +derived_dims = (frequency, force, pressure, energy, power, charge, voltage, + capacitance, conductance, magnetic_flux, + magnetic_density, inductance, luminous_intensity) +base_dims = (amount_of_substance, luminous_intensity, temperature) + +units = [mol, cd, K, lux, hertz, newton, pascal, joule, watt, coulomb, volt, + farad, ohm, siemens, weber, tesla, henry, candela, lux, becquerel, + gray, katal] + +all_units: list[Quantity] = [] +for u in units: + all_units.extend(prefix_unit(u, PREFIXES)) + +all_units.extend(units) +all_units.extend([mol, cd, K, lux]) + + +dimsys_SI = dimsys_MKSA.extend( + [ + # Dimensional dependencies for other base dimensions: + temperature, + amount_of_substance, + luminous_intensity, + ]) + +dimsys_default = dimsys_SI.extend( + [information], +) + +SI = MKSA.extend(base=(mol, cd, K), units=all_units, name='SI', dimension_system=dimsys_SI, derived_units={ + power: watt, + magnetic_flux: weber, + time: second, + impedance: ohm, + pressure: pascal, + current: ampere, + voltage: volt, + length: meter, + frequency: hertz, + inductance: henry, + temperature: kelvin, + amount_of_substance: mole, + luminous_intensity: candela, + conductance: siemens, + mass: kilogram, + magnetic_density: tesla, + charge: coulomb, + force: newton, + capacitance: farad, + energy: joule, + velocity: meter/second, +}) + +One = S.One + +SI.set_quantity_dimension(radian, One) + +SI.set_quantity_scale_factor(ampere, One) + +SI.set_quantity_scale_factor(kelvin, One) + +SI.set_quantity_scale_factor(mole, One) + +SI.set_quantity_scale_factor(candela, One) + +# MKSA extension to MKS: derived units + +SI.set_quantity_scale_factor(coulomb, One) + +SI.set_quantity_scale_factor(volt, joule/coulomb) + +SI.set_quantity_scale_factor(ohm, volt/ampere) + +SI.set_quantity_scale_factor(siemens, ampere/volt) + +SI.set_quantity_scale_factor(farad, coulomb/volt) + +SI.set_quantity_scale_factor(henry, volt*second/ampere) + +SI.set_quantity_scale_factor(tesla, volt*second/meter**2) + +SI.set_quantity_scale_factor(weber, joule/ampere) + + +SI.set_quantity_dimension(lux, luminous_intensity / length ** 2) +SI.set_quantity_scale_factor(lux, steradian*candela/meter**2) + +# katal is the SI unit of catalytic activity + +SI.set_quantity_dimension(katal, amount_of_substance / time) +SI.set_quantity_scale_factor(katal, mol/second) + +# gray is the SI unit of absorbed dose + +SI.set_quantity_dimension(gray, energy / mass) +SI.set_quantity_scale_factor(gray, meter**2/second**2) + +# becquerel is the SI unit of radioactivity + +SI.set_quantity_dimension(becquerel, 1 / time) +SI.set_quantity_scale_factor(becquerel, 1/second) + +#### CONSTANTS #### + +# elementary charge +# REF: NIST SP 959 (June 2019) + +SI.set_quantity_dimension(elementary_charge, charge) +SI.set_quantity_scale_factor(elementary_charge, 1.602176634e-19*coulomb) + +# Electronvolt +# REF: NIST SP 959 (June 2019) + +SI.set_quantity_dimension(electronvolt, energy) +SI.set_quantity_scale_factor(electronvolt, 1.602176634e-19*joule) + +# Avogadro number +# REF: NIST SP 959 (June 2019) + +SI.set_quantity_dimension(avogadro_number, One) +SI.set_quantity_scale_factor(avogadro_number, 6.02214076e23) + +# Avogadro constant + +SI.set_quantity_dimension(avogadro_constant, amount_of_substance ** -1) +SI.set_quantity_scale_factor(avogadro_constant, avogadro_number / mol) + +# Boltzmann constant +# REF: NIST SP 959 (June 2019) + +SI.set_quantity_dimension(boltzmann_constant, energy / temperature) +SI.set_quantity_scale_factor(boltzmann_constant, 1.380649e-23*joule/kelvin) + +# Stefan-Boltzmann constant +# REF: NIST SP 959 (June 2019) + +SI.set_quantity_dimension(stefan_boltzmann_constant, energy * time ** -1 * length ** -2 * temperature ** -4) +SI.set_quantity_scale_factor(stefan_boltzmann_constant, pi**2 * boltzmann_constant**4 / (60 * hbar**3 * speed_of_light ** 2)) + +# Atomic mass +# REF: NIST SP 959 (June 2019) + +SI.set_quantity_dimension(atomic_mass_constant, mass) +SI.set_quantity_scale_factor(atomic_mass_constant, 1.66053906660e-24*gram) + +# Molar gas constant +# REF: NIST SP 959 (June 2019) + +SI.set_quantity_dimension(molar_gas_constant, energy / (temperature * amount_of_substance)) +SI.set_quantity_scale_factor(molar_gas_constant, boltzmann_constant * avogadro_constant) + +# Faraday constant + +SI.set_quantity_dimension(faraday_constant, charge / amount_of_substance) +SI.set_quantity_scale_factor(faraday_constant, elementary_charge * avogadro_constant) + +# Josephson constant + +SI.set_quantity_dimension(josephson_constant, frequency / voltage) +SI.set_quantity_scale_factor(josephson_constant, 0.5 * planck / elementary_charge) + +# Von Klitzing constant + +SI.set_quantity_dimension(von_klitzing_constant, voltage / current) +SI.set_quantity_scale_factor(von_klitzing_constant, hbar / elementary_charge ** 2) + +# Acceleration due to gravity (on the Earth surface) + +SI.set_quantity_dimension(acceleration_due_to_gravity, acceleration) +SI.set_quantity_scale_factor(acceleration_due_to_gravity, 9.80665*meter/second**2) + +# magnetic constant: + +SI.set_quantity_dimension(magnetic_constant, force / current ** 2) +SI.set_quantity_scale_factor(magnetic_constant, 4*pi/10**7 * newton/ampere**2) + +# electric constant: + +SI.set_quantity_dimension(vacuum_permittivity, capacitance / length) +SI.set_quantity_scale_factor(vacuum_permittivity, 1/(u0 * c**2)) + +# vacuum impedance: + +SI.set_quantity_dimension(vacuum_impedance, impedance) +SI.set_quantity_scale_factor(vacuum_impedance, u0 * c) + +# Electron rest mass +SI.set_quantity_dimension(electron_rest_mass, mass) +SI.set_quantity_scale_factor(electron_rest_mass, 9.1093837015e-31*kilogram) + +# Coulomb's constant: +SI.set_quantity_dimension(coulomb_constant, force * length ** 2 / charge ** 2) +SI.set_quantity_scale_factor(coulomb_constant, 1/(4*pi*vacuum_permittivity)) + +SI.set_quantity_dimension(psi, pressure) +SI.set_quantity_scale_factor(psi, pound * gee / inch ** 2) + +SI.set_quantity_dimension(mmHg, pressure) +SI.set_quantity_scale_factor(mmHg, dHg0 * acceleration_due_to_gravity * kilogram / meter**2) + +SI.set_quantity_dimension(milli_mass_unit, mass) +SI.set_quantity_scale_factor(milli_mass_unit, atomic_mass_unit/1000) + +SI.set_quantity_dimension(quart, length ** 3) +SI.set_quantity_scale_factor(quart, Rational(231, 4) * inch**3) + +# Other convenient units and magnitudes + +SI.set_quantity_dimension(lightyear, length) +SI.set_quantity_scale_factor(lightyear, speed_of_light*julian_year) + +SI.set_quantity_dimension(astronomical_unit, length) +SI.set_quantity_scale_factor(astronomical_unit, 149597870691*meter) + +# Fundamental Planck units: + +SI.set_quantity_dimension(planck_mass, mass) +SI.set_quantity_scale_factor(planck_mass, sqrt(hbar*speed_of_light/G)) + +SI.set_quantity_dimension(planck_time, time) +SI.set_quantity_scale_factor(planck_time, sqrt(hbar*G/speed_of_light**5)) + +SI.set_quantity_dimension(planck_temperature, temperature) +SI.set_quantity_scale_factor(planck_temperature, sqrt(hbar*speed_of_light**5/G/boltzmann**2)) + +SI.set_quantity_dimension(planck_length, length) +SI.set_quantity_scale_factor(planck_length, sqrt(hbar*G/speed_of_light**3)) + +SI.set_quantity_dimension(planck_charge, charge) +SI.set_quantity_scale_factor(planck_charge, sqrt(4*pi*electric_constant*hbar*speed_of_light)) + +# Derived Planck units: + +SI.set_quantity_dimension(planck_area, length ** 2) +SI.set_quantity_scale_factor(planck_area, planck_length**2) + +SI.set_quantity_dimension(planck_volume, length ** 3) +SI.set_quantity_scale_factor(planck_volume, planck_length**3) + +SI.set_quantity_dimension(planck_momentum, mass * velocity) +SI.set_quantity_scale_factor(planck_momentum, planck_mass * speed_of_light) + +SI.set_quantity_dimension(planck_energy, energy) +SI.set_quantity_scale_factor(planck_energy, planck_mass * speed_of_light**2) + +SI.set_quantity_dimension(planck_force, force) +SI.set_quantity_scale_factor(planck_force, planck_energy / planck_length) + +SI.set_quantity_dimension(planck_power, power) +SI.set_quantity_scale_factor(planck_power, planck_energy / planck_time) + +SI.set_quantity_dimension(planck_density, mass / length ** 3) +SI.set_quantity_scale_factor(planck_density, planck_mass / planck_length**3) + +SI.set_quantity_dimension(planck_energy_density, energy / length ** 3) +SI.set_quantity_scale_factor(planck_energy_density, planck_energy / planck_length**3) + +SI.set_quantity_dimension(planck_intensity, mass * time ** (-3)) +SI.set_quantity_scale_factor(planck_intensity, planck_energy_density * speed_of_light) + +SI.set_quantity_dimension(planck_angular_frequency, 1 / time) +SI.set_quantity_scale_factor(planck_angular_frequency, 1 / planck_time) + +SI.set_quantity_dimension(planck_pressure, pressure) +SI.set_quantity_scale_factor(planck_pressure, planck_force / planck_length**2) + +SI.set_quantity_dimension(planck_current, current) +SI.set_quantity_scale_factor(planck_current, planck_charge / planck_time) + +SI.set_quantity_dimension(planck_voltage, voltage) +SI.set_quantity_scale_factor(planck_voltage, planck_energy / planck_charge) + +SI.set_quantity_dimension(planck_impedance, impedance) +SI.set_quantity_scale_factor(planck_impedance, planck_voltage / planck_current) + +SI.set_quantity_dimension(planck_acceleration, acceleration) +SI.set_quantity_scale_factor(planck_acceleration, speed_of_light / planck_time) + +# Older units for radioactivity + +SI.set_quantity_dimension(curie, 1 / time) +SI.set_quantity_scale_factor(curie, 37000000000*becquerel) + +SI.set_quantity_dimension(rutherford, 1 / time) +SI.set_quantity_scale_factor(rutherford, 1000000*becquerel) + + +# check that scale factors are the right SI dimensions: +for _scale_factor, _dimension in zip( + SI._quantity_scale_factors.values(), + SI._quantity_dimension_map.values() +): + dimex = SI.get_dimensional_expr(_scale_factor) + if dimex != 1: + # XXX: equivalent_dims is an instance method taking two arguments in + # addition to self so this can not work: + if not DimensionSystem.equivalent_dims(_dimension, Dimension(dimex)): # type: ignore + raise ValueError("quantity value and dimension mismatch") +del _scale_factor, _dimension + +__all__ = [ + 'mmHg', 'atmosphere', 'inductance', 'newton', 'meter', + 'vacuum_permittivity', 'pascal', 'magnetic_constant', 'voltage', + 'angular_mil', 'luminous_intensity', 'all_units', + 'julian_year', 'weber', 'exbibyte', 'liter', + 'molar_gas_constant', 'faraday_constant', 'avogadro_constant', + 'lightyear', 'planck_density', 'gee', 'mol', 'bit', 'gray', + 'planck_momentum', 'bar', 'magnetic_density', 'prefix_unit', 'PREFIXES', + 'planck_time', 'dimex', 'gram', 'candela', 'force', 'planck_intensity', + 'energy', 'becquerel', 'planck_acceleration', 'speed_of_light', + 'conductance', 'frequency', 'coulomb_constant', 'degree', 'lux', 'planck', + 'current', 'planck_current', 'tebibyte', 'planck_power', 'MKSA', 'power', + 'K', 'planck_volume', 'quart', 'pressure', 'amount_of_substance', + 'joule', 'boltzmann_constant', 'Dimension', 'c', 'planck_force', 'length', + 'watt', 'action', 'hbar', 'gibibyte', 'DimensionSystem', 'cd', 'volt', + 'planck_charge', 'dioptre', 'vacuum_impedance', 'dimsys_default', 'farad', + 'charge', 'gravitational_constant', 'temperature', 'u0', 'hertz', + 'capacitance', 'tesla', 'steradian', 'planck_mass', 'josephson_constant', + 'planck_area', 'stefan_boltzmann_constant', 'base_dims', + 'astronomical_unit', 'radian', 'planck_voltage', 'impedance', + 'planck_energy', 'Da', 'atomic_mass_constant', 'rutherford', 'second', 'inch', + 'elementary_charge', 'SI', 'electronvolt', 'dimsys_SI', 'henry', + 'planck_angular_frequency', 'ohm', 'pound', 'planck_pressure', 'G', 'psi', + 'dHg0', 'von_klitzing_constant', 'planck_length', 'avogadro_number', + 'mole', 'acceleration', 'information', 'planck_energy_density', + 'mebibyte', 's', 'acceleration_due_to_gravity', 'electron_rest_mass', + 'planck_temperature', 'units', 'mass', 'dimsys_MKSA', 'kelvin', 'kPa', + 'boltzmann', 'milli_mass_unit', 'planck_impedance', 'electric_constant', + 'derived_dims', 'kg', 'coulomb', 'siemens', 'byte', 'magnetic_flux', + 'atomic_mass_unit', 'm', 'kibibyte', 'kilogram', 'One', 'curie', 'u', + 'time', 'pebibyte', 'velocity', 'ampere', 'katal', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..81deee77864529ea856b58b6731624f88e71e8bd Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_dimensions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_dimensions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b6800b7f51af08c9a07bf37722f200160ca8cb4b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_dimensions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_dimensionsystem.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_dimensionsystem.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2968d57b7773915dc97620676a5d355c3e4cc0d8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_dimensionsystem.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_prefixes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_prefixes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92055dd077f8546c63c4d136df784dbec958a556 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_prefixes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_quantities.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_quantities.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a96c43893b9bd391a9898e3ebbd9cf4db8f47d61 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_quantities.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_unit_system_cgs_gauss.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_unit_system_cgs_gauss.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..130a99354635632ecb0af46296106a6e39e08cea Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_unit_system_cgs_gauss.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_unitsystem.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_unitsystem.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a0315aa7bbbcad05fe00f1b930de4d79284b028d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_unitsystem.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_util.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_util.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..33bb38506b1507680ceb939f9e6f4f6e93e6fbb0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/__pycache__/test_util.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_dimensions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_dimensions.py new file mode 100644 index 0000000000000000000000000000000000000000..6455df41068a07c966c5f3e782e561fec4d16a97 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_dimensions.py @@ -0,0 +1,150 @@ +from sympy.physics.units.systems.si import dimsys_SI + +from sympy.core.numbers import pi +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (acos, atan2, cos) +from sympy.physics.units.dimensions import Dimension +from sympy.physics.units.definitions.dimension_definitions import ( + length, time, mass, force, pressure, angle +) +from sympy.physics.units import foot +from sympy.testing.pytest import raises + + +def test_Dimension_definition(): + assert dimsys_SI.get_dimensional_dependencies(length) == {length: 1} + assert length.name == Symbol("length") + assert length.symbol == Symbol("L") + + halflength = sqrt(length) + assert dimsys_SI.get_dimensional_dependencies(halflength) == {length: S.Half} + + +def test_Dimension_error_definition(): + # tuple with more or less than two entries + raises(TypeError, lambda: Dimension(("length", 1, 2))) + raises(TypeError, lambda: Dimension(["length"])) + + # non-number power + raises(TypeError, lambda: Dimension({"length": "a"})) + + # non-number with named argument + raises(TypeError, lambda: Dimension({"length": (1, 2)})) + + # symbol should by Symbol or str + raises(AssertionError, lambda: Dimension("length", symbol=1)) + + +def test_str(): + assert str(Dimension("length")) == "Dimension(length)" + assert str(Dimension("length", "L")) == "Dimension(length, L)" + + +def test_Dimension_properties(): + assert dimsys_SI.is_dimensionless(length) is False + assert dimsys_SI.is_dimensionless(length/length) is True + assert dimsys_SI.is_dimensionless(Dimension("undefined")) is False + + assert length.has_integer_powers(dimsys_SI) is True + assert (length**(-1)).has_integer_powers(dimsys_SI) is True + assert (length**1.5).has_integer_powers(dimsys_SI) is False + + +def test_Dimension_add_sub(): + assert length + length == length + assert length - length == length + assert -length == length + + raises(TypeError, lambda: length + foot) + raises(TypeError, lambda: foot + length) + raises(TypeError, lambda: length - foot) + raises(TypeError, lambda: foot - length) + + # issue 14547 - only raise error for dimensional args; allow + # others to pass + x = Symbol('x') + e = length + x + assert e == x + length and e.is_Add and set(e.args) == {length, x} + e = length + 1 + assert e == 1 + length == 1 - length and e.is_Add and set(e.args) == {length, 1} + + assert dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force) == \ + {length: 1, mass: 1, time: -2} + assert dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force - + pressure * length**2) == \ + {length: 1, mass: 1, time: -2} + + raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + pressure)) + +def test_Dimension_mul_div_exp(): + assert 2*length == length*2 == length/2 == length + assert 2/length == 1/length + x = Symbol('x') + m = x*length + assert m == length*x and m.is_Mul and set(m.args) == {x, length} + d = x/length + assert d == x*length**-1 and d.is_Mul and set(d.args) == {x, 1/length} + d = length/x + assert d == length*x**-1 and d.is_Mul and set(d.args) == {1/x, length} + + velo = length / time + + assert (length * length) == length ** 2 + + assert dimsys_SI.get_dimensional_dependencies(length * length) == {length: 2} + assert dimsys_SI.get_dimensional_dependencies(length ** 2) == {length: 2} + assert dimsys_SI.get_dimensional_dependencies(length * time) == {length: 1, time: 1} + assert dimsys_SI.get_dimensional_dependencies(velo) == {length: 1, time: -1} + assert dimsys_SI.get_dimensional_dependencies(velo ** 2) == {length: 2, time: -2} + + assert dimsys_SI.get_dimensional_dependencies(length / length) == {} + assert dimsys_SI.get_dimensional_dependencies(velo / length * time) == {} + assert dimsys_SI.get_dimensional_dependencies(length ** -1) == {length: -1} + assert dimsys_SI.get_dimensional_dependencies(velo ** -1.5) == {length: -1.5, time: 1.5} + + length_a = length**"a" + assert dimsys_SI.get_dimensional_dependencies(length_a) == {length: Symbol("a")} + + assert dimsys_SI.get_dimensional_dependencies(length**pi) == {length: pi} + assert dimsys_SI.get_dimensional_dependencies(length**(length/length)) == {length: Dimension(1)} + + raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(length**length)) + + assert length != 1 + assert length / length != 1 + + length_0 = length ** 0 + assert dimsys_SI.get_dimensional_dependencies(length_0) == {} + + # issue 18738 + a = Symbol('a') + b = Symbol('b') + c = sqrt(a**2 + b**2) + c_dim = c.subs({a: length, b: length}) + assert dimsys_SI.equivalent_dims(c_dim, length) + +def test_Dimension_functions(): + raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(cos(length))) + raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(acos(angle))) + raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(atan2(length, time))) + raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(length))) + raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(100, length))) + raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(length, 10))) + + assert dimsys_SI.get_dimensional_dependencies(pi) == {} + + assert dimsys_SI.get_dimensional_dependencies(cos(1)) == {} + assert dimsys_SI.get_dimensional_dependencies(cos(angle)) == {} + + assert dimsys_SI.get_dimensional_dependencies(atan2(length, length)) == {} + + assert dimsys_SI.get_dimensional_dependencies(log(length / length, length / length)) == {} + + assert dimsys_SI.get_dimensional_dependencies(Abs(length)) == {length: 1} + assert dimsys_SI.get_dimensional_dependencies(Abs(length / length)) == {} + + assert dimsys_SI.get_dimensional_dependencies(sqrt(-1)) == {} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_dimensionsystem.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_dimensionsystem.py new file mode 100644 index 0000000000000000000000000000000000000000..8a55ac398c38adf24d93bfa376c9cc51c1ec40fe --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_dimensionsystem.py @@ -0,0 +1,95 @@ +from sympy.core.symbol import symbols +from sympy.matrices.dense import (Matrix, eye) +from sympy.physics.units.definitions.dimension_definitions import ( + action, current, length, mass, time, + velocity) +from sympy.physics.units.dimensions import DimensionSystem + + +def test_extend(): + ms = DimensionSystem((length, time), (velocity,)) + + mks = ms.extend((mass,), (action,)) + + res = DimensionSystem((length, time, mass), (velocity, action)) + assert mks.base_dims == res.base_dims + assert mks.derived_dims == res.derived_dims + + +def test_list_dims(): + dimsys = DimensionSystem((length, time, mass)) + + assert dimsys.list_can_dims == (length, mass, time) + + +def test_dim_can_vector(): + dimsys = DimensionSystem( + [length, mass, time], + [velocity, action], + { + velocity: {length: 1, time: -1} + } + ) + + assert dimsys.dim_can_vector(length) == Matrix([1, 0, 0]) + assert dimsys.dim_can_vector(velocity) == Matrix([1, 0, -1]) + + dimsys = DimensionSystem( + (length, velocity, action), + (mass, time), + { + time: {length: 1, velocity: -1} + } + ) + + assert dimsys.dim_can_vector(length) == Matrix([0, 1, 0]) + assert dimsys.dim_can_vector(velocity) == Matrix([0, 0, 1]) + assert dimsys.dim_can_vector(time) == Matrix([0, 1, -1]) + + dimsys = DimensionSystem( + (length, mass, time), + (velocity, action), + {velocity: {length: 1, time: -1}, + action: {mass: 1, length: 2, time: -1}}) + + assert dimsys.dim_vector(length) == Matrix([1, 0, 0]) + assert dimsys.dim_vector(velocity) == Matrix([1, 0, -1]) + + +def test_inv_can_transf_matrix(): + dimsys = DimensionSystem((length, mass, time)) + assert dimsys.inv_can_transf_matrix == eye(3) + + +def test_can_transf_matrix(): + dimsys = DimensionSystem((length, mass, time)) + assert dimsys.can_transf_matrix == eye(3) + + dimsys = DimensionSystem((length, velocity, action)) + assert dimsys.can_transf_matrix == eye(3) + + dimsys = DimensionSystem((length, time), (velocity,), {velocity: {length: 1, time: -1}}) + assert dimsys.can_transf_matrix == eye(2) + + +def test_is_consistent(): + assert DimensionSystem((length, time)).is_consistent is True + + +def test_print_dim_base(): + mksa = DimensionSystem( + (length, time, mass, current), + (action,), + {action: {mass: 1, length: 2, time: -1}}) + L, M, T = symbols("L M T") + assert mksa.print_dim_base(action) == L**2*M/T + + +def test_dim(): + dimsys = DimensionSystem( + (length, mass, time), + (velocity, action), + {velocity: {length: 1, time: -1}, + action: {mass: 1, length: 2, time: -1}} + ) + assert dimsys.dim == 3 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_prefixes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_prefixes.py new file mode 100644 index 0000000000000000000000000000000000000000..7b180102ecd00abf3ff5f8cb4c24aa82ae76ef77 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_prefixes.py @@ -0,0 +1,86 @@ +from sympy.core.mul import Mul +from sympy.core.numbers import Rational +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.physics.units import Quantity, length, meter, W +from sympy.physics.units.prefixes import PREFIXES, Prefix, prefix_unit, kilo, \ + kibi +from sympy.physics.units.systems import SI + +x = Symbol('x') + + +def test_prefix_operations(): + m = PREFIXES['m'] + k = PREFIXES['k'] + M = PREFIXES['M'] + + dodeca = Prefix('dodeca', 'dd', 1, base=12) + + assert m * k is S.One + assert m * W == W / 1000 + assert k * k == M + assert 1 / m == k + assert k / m == M + + assert dodeca * dodeca == 144 + assert 1 / dodeca == S.One / 12 + assert k / dodeca == S(1000) / 12 + assert dodeca / dodeca is S.One + + m = Quantity("fake_meter") + SI.set_quantity_dimension(m, S.One) + SI.set_quantity_scale_factor(m, S.One) + + assert dodeca * m == 12 * m + assert dodeca / m == 12 / m + + expr1 = kilo * 3 + assert isinstance(expr1, Mul) + assert expr1.args == (3, kilo) + + expr2 = kilo * x + assert isinstance(expr2, Mul) + assert expr2.args == (x, kilo) + + expr3 = kilo / 3 + assert isinstance(expr3, Mul) + assert expr3.args == (Rational(1, 3), kilo) + assert expr3.args == (S.One/3, kilo) + + expr4 = kilo / x + assert isinstance(expr4, Mul) + assert expr4.args == (1/x, kilo) + + +def test_prefix_unit(): + m = Quantity("fake_meter", abbrev="m") + m.set_global_relative_scale_factor(1, meter) + + pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]} + + q1 = Quantity("millifake_meter", abbrev="mm") + q2 = Quantity("centifake_meter", abbrev="cm") + q3 = Quantity("decifake_meter", abbrev="dm") + + SI.set_quantity_dimension(q1, length) + + SI.set_quantity_scale_factor(q1, PREFIXES["m"]) + SI.set_quantity_scale_factor(q1, PREFIXES["c"]) + SI.set_quantity_scale_factor(q1, PREFIXES["d"]) + + res = [q1, q2, q3] + + prefs = prefix_unit(m, pref) + assert set(prefs) == set(res) + assert {v.abbrev for v in prefs} == set(symbols("mm,cm,dm")) + + +def test_bases(): + assert kilo.base == 10 + assert kibi.base == 2 + + +def test_repr(): + assert eval(repr(kilo)) == kilo + assert eval(repr(kibi)) == kibi diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_quantities.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_quantities.py new file mode 100644 index 0000000000000000000000000000000000000000..4e24ca48cc858bd8afd0b3c9762c4f8b6d0c5194 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_quantities.py @@ -0,0 +1,575 @@ +import warnings + +from sympy.core.add import Add +from sympy.core.function import (Function, diff) +from sympy.core.numbers import (Number, Rational) +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin +from sympy.integrals.integrals import integrate +from sympy.physics.units import (amount_of_substance, area, convert_to, find_unit, + volume, kilometer, joule, molar_gas_constant, + vacuum_permittivity, elementary_charge, volt, + ohm) +from sympy.physics.units.definitions import (amu, au, centimeter, coulomb, + day, foot, grams, hour, inch, kg, km, m, meter, millimeter, + minute, quart, s, second, speed_of_light, bit, + byte, kibibyte, mebibyte, gibibyte, tebibyte, pebibyte, exbibyte, + kilogram, gravitational_constant, electron_rest_mass) + +from sympy.physics.units.definitions.dimension_definitions import ( + Dimension, charge, length, time, temperature, pressure, + energy, mass +) +from sympy.physics.units.prefixes import PREFIXES, kilo +from sympy.physics.units.quantities import PhysicalConstant, Quantity +from sympy.physics.units.systems import SI +from sympy.testing.pytest import raises + +k = PREFIXES["k"] + + +def test_str_repr(): + assert str(kg) == "kilogram" + + +def test_eq(): + # simple test + assert 10*m == 10*m + assert 10*m != 10*s + + +def test_convert_to(): + q = Quantity("q1") + q.set_global_relative_scale_factor(S(5000), meter) + + assert q.convert_to(m) == 5000*m + + assert speed_of_light.convert_to(m / s) == 299792458 * m / s + assert day.convert_to(s) == 86400*s + + # Wrong dimension to convert: + assert q.convert_to(s) == q + assert speed_of_light.convert_to(m) == speed_of_light + + expr = joule*second + conv = convert_to(expr, joule) + assert conv == joule*second + + +def test_Quantity_definition(): + q = Quantity("s10", abbrev="sabbr") + q.set_global_relative_scale_factor(10, second) + u = Quantity("u", abbrev="dam") + u.set_global_relative_scale_factor(10, meter) + km = Quantity("km") + km.set_global_relative_scale_factor(kilo, meter) + v = Quantity("u") + v.set_global_relative_scale_factor(5*kilo, meter) + + assert q.scale_factor == 10 + assert q.dimension == time + assert q.abbrev == Symbol("sabbr") + + assert u.dimension == length + assert u.scale_factor == 10 + assert u.abbrev == Symbol("dam") + + assert km.scale_factor == 1000 + assert km.func(*km.args) == km + assert km.func(*km.args).args == km.args + + assert v.dimension == length + assert v.scale_factor == 5000 + + +def test_abbrev(): + u = Quantity("u") + u.set_global_relative_scale_factor(S.One, meter) + + assert u.name == Symbol("u") + assert u.abbrev == Symbol("u") + + u = Quantity("u", abbrev="om") + u.set_global_relative_scale_factor(S(2), meter) + + assert u.name == Symbol("u") + assert u.abbrev == Symbol("om") + assert u.scale_factor == 2 + assert isinstance(u.scale_factor, Number) + + u = Quantity("u", abbrev="ikm") + u.set_global_relative_scale_factor(3*kilo, meter) + + assert u.abbrev == Symbol("ikm") + assert u.scale_factor == 3000 + + +def test_print(): + u = Quantity("unitname", abbrev="dam") + assert repr(u) == "unitname" + assert str(u) == "unitname" + + +def test_Quantity_eq(): + u = Quantity("u", abbrev="dam") + v = Quantity("v1") + assert u != v + v = Quantity("v2", abbrev="ds") + assert u != v + v = Quantity("v3", abbrev="dm") + assert u != v + + +def test_add_sub(): + u = Quantity("u") + v = Quantity("v") + w = Quantity("w") + + u.set_global_relative_scale_factor(S(10), meter) + v.set_global_relative_scale_factor(S(5), meter) + w.set_global_relative_scale_factor(S(2), second) + + assert isinstance(u + v, Add) + assert (u + v.convert_to(u)) == (1 + S.Half)*u + assert isinstance(u - v, Add) + assert (u - v.convert_to(u)) == S.Half*u + + +def test_quantity_abs(): + v_w1 = Quantity('v_w1') + v_w2 = Quantity('v_w2') + v_w3 = Quantity('v_w3') + + v_w1.set_global_relative_scale_factor(1, meter/second) + v_w2.set_global_relative_scale_factor(1, meter/second) + v_w3.set_global_relative_scale_factor(1, meter/second) + + expr = v_w3 - Abs(v_w1 - v_w2) + + assert SI.get_dimensional_expr(v_w1) == (length/time).name + + Dq = Dimension(SI.get_dimensional_expr(expr)) + + assert SI.get_dimension_system().get_dimensional_dependencies(Dq) == { + length: 1, + time: -1, + } + assert meter == sqrt(meter**2) + + +def test_check_unit_consistency(): + u = Quantity("u") + v = Quantity("v") + w = Quantity("w") + + u.set_global_relative_scale_factor(S(10), meter) + v.set_global_relative_scale_factor(S(5), meter) + w.set_global_relative_scale_factor(S(2), second) + + def check_unit_consistency(expr): + SI._collect_factor_and_dimension(expr) + + raises(ValueError, lambda: check_unit_consistency(u + w)) + raises(ValueError, lambda: check_unit_consistency(u - w)) + raises(ValueError, lambda: check_unit_consistency(u + 1)) + raises(ValueError, lambda: check_unit_consistency(u - 1)) + raises(ValueError, lambda: check_unit_consistency(1 - exp(u / w))) + + +def test_mul_div(): + u = Quantity("u") + v = Quantity("v") + t = Quantity("t") + ut = Quantity("ut") + v2 = Quantity("v") + + u.set_global_relative_scale_factor(S(10), meter) + v.set_global_relative_scale_factor(S(5), meter) + t.set_global_relative_scale_factor(S(2), second) + ut.set_global_relative_scale_factor(S(20), meter*second) + v2.set_global_relative_scale_factor(S(5), meter/second) + + assert 1 / u == u**(-1) + assert u / 1 == u + + v1 = u / t + v2 = v + + # Pow only supports structural equality: + assert v1 != v2 + assert v1 == v2.convert_to(v1) + + # TODO: decide whether to allow such expression in the future + # (requires somehow manipulating the core). + # assert u / Quantity('l2', dimension=length, scale_factor=2) == 5 + + assert u * 1 == u + + ut1 = u * t + ut2 = ut + + # Mul only supports structural equality: + assert ut1 != ut2 + assert ut1 == ut2.convert_to(ut1) + + # Mul only supports structural equality: + lp1 = Quantity("lp1") + lp1.set_global_relative_scale_factor(S(2), 1/meter) + assert u * lp1 != 20 + + assert u**0 == 1 + assert u**1 == u + + # TODO: Pow only support structural equality: + u2 = Quantity("u2") + u3 = Quantity("u3") + u2.set_global_relative_scale_factor(S(100), meter**2) + u3.set_global_relative_scale_factor(Rational(1, 10), 1/meter) + + assert u ** 2 != u2 + assert u ** -1 != u3 + + assert u ** 2 == u2.convert_to(u) + assert u ** -1 == u3.convert_to(u) + + +def test_units(): + assert convert_to((5*m/s * day) / km, 1) == 432 + assert convert_to(foot / meter, meter) == Rational(3048, 10000) + # amu is a pure mass so mass/mass gives a number, not an amount (mol) + # TODO: need better simplification routine: + assert str(convert_to(grams/amu, grams).n(2)) == '6.0e+23' + + # Light from the sun needs about 8.3 minutes to reach earth + t = (1*au / speed_of_light) / minute + # TODO: need a better way to simplify expressions containing units: + t = convert_to(convert_to(t, meter / minute), meter) + assert t.simplify() == Rational(49865956897, 5995849160) + + # TODO: fix this, it should give `m` without `Abs` + assert sqrt(m**2) == m + assert (sqrt(m))**2 == m + + t = Symbol('t') + 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 convert_to(4 * quart / inch ** 3, meter) == 231 + assert convert_to(4 * quart / inch ** 3, millimeter) == 231 + +def test_electron_rest_mass(): + assert convert_to(electron_rest_mass, kilogram) == 9.1093837015e-31*kilogram + assert convert_to(electron_rest_mass, grams) == 9.1093837015e-28*grams + +def test_issue_5565(): + assert (m < s).is_Relational + + +def test_find_unit(): + assert find_unit('coulomb') == ['coulomb', 'coulombs', 'coulomb_constant'] + assert find_unit(coulomb) == ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge'] + assert find_unit(charge) == ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge'] + assert find_unit(inch) == [ + 'm', 'au', 'cm', 'dm', 'ft', 'km', 'ly', 'mi', 'mm', 'nm', 'pm', 'um', 'yd', + 'nmi', 'feet', 'foot', 'inch', 'mile', 'yard', 'meter', 'miles', 'yards', + 'inches', 'meters', 'micron', 'microns', 'angstrom', 'angstroms', 'decimeter', + 'kilometer', 'lightyear', 'nanometer', 'picometer', 'centimeter', 'decimeters', + 'kilometers', 'lightyears', 'micrometer', 'millimeter', 'nanometers', 'picometers', + 'centimeters', 'micrometers', 'millimeters', 'nautical_mile', 'planck_length', + 'nautical_miles', 'astronomical_unit', 'astronomical_units'] + assert find_unit(inch**-1) == ['D', 'dioptre', 'optical_power'] + assert find_unit(length**-1) == ['D', 'dioptre', 'optical_power'] + assert find_unit(inch ** 2) == ['ha', 'hectare', 'planck_area'] + assert find_unit(inch ** 3) == [ + 'L', 'l', 'cL', 'cl', 'dL', 'dl', 'mL', 'ml', 'liter', 'quart', 'liters', 'quarts', + 'deciliter', 'centiliter', 'deciliters', 'milliliter', + 'centiliters', 'milliliters', 'planck_volume'] + assert find_unit('voltage') == ['V', 'v', 'volt', 'volts', 'planck_voltage'] + assert find_unit(grams) == ['g', 't', 'Da', 'kg', 'me', 'mg', 'ug', 'amu', 'mmu', 'amus', + 'gram', 'mmus', 'grams', 'pound', 'tonne', 'dalton', 'pounds', + 'kilogram', 'kilograms', 'microgram', 'milligram', 'metric_ton', + 'micrograms', 'milligrams', 'planck_mass', 'milli_mass_unit', 'atomic_mass_unit', + 'electron_rest_mass', 'atomic_mass_constant'] + + +def test_Quantity_derivative(): + x = symbols("x") + assert diff(x*meter, x) == meter + assert diff(x**3*meter**2, x) == 3*x**2*meter**2 + assert diff(meter, meter) == 1 + assert diff(meter**2, meter) == 2*meter + + +def test_quantity_postprocessing(): + q1 = Quantity('q1') + q2 = Quantity('q2') + + SI.set_quantity_dimension(q1, length*pressure**2*temperature/time) + SI.set_quantity_dimension(q2, energy*pressure*temperature/(length**2*time)) + + assert q1 + q2 + q = q1 + q2 + Dq = Dimension(SI.get_dimensional_expr(q)) + assert SI.get_dimension_system().get_dimensional_dependencies(Dq) == { + length: -1, + mass: 2, + temperature: 1, + time: -5, + } + + +def test_factor_and_dimension(): + assert (3000, Dimension(1)) == SI._collect_factor_and_dimension(3000) + assert (1001, length) == SI._collect_factor_and_dimension(meter + km) + assert (2, length/time) == SI._collect_factor_and_dimension( + meter/second + 36*km/(10*hour)) + + x, y = symbols('x y') + assert (x + y/100, length) == SI._collect_factor_and_dimension( + x*m + y*centimeter) + + cH = Quantity('cH') + SI.set_quantity_dimension(cH, amount_of_substance/volume) + + pH = -log(cH) + + assert (1, volume/amount_of_substance) == SI._collect_factor_and_dimension( + exp(pH)) + + v_w1 = Quantity('v_w1') + v_w2 = Quantity('v_w2') + + v_w1.set_global_relative_scale_factor(Rational(3, 2), meter/second) + v_w2.set_global_relative_scale_factor(2, meter/second) + + expr = Abs(v_w1/2 - v_w2) + assert (Rational(5, 4), length/time) == \ + SI._collect_factor_and_dimension(expr) + + expr = Rational(5, 2)*second/meter*v_w1 - 3000 + assert (-(2996 + Rational(1, 4)), Dimension(1)) == \ + SI._collect_factor_and_dimension(expr) + + expr = v_w1**(v_w2/v_w1) + assert ((Rational(3, 2))**Rational(4, 3), (length/time)**Rational(4, 3)) == \ + SI._collect_factor_and_dimension(expr) + + +def test_dimensional_expr_of_derivative(): + l = Quantity('l') + t = Quantity('t') + t1 = Quantity('t1') + l.set_global_relative_scale_factor(36, km) + t.set_global_relative_scale_factor(1, hour) + t1.set_global_relative_scale_factor(1, second) + x = Symbol('x') + y = Symbol('y') + f = Function('f') + dfdx = f(x, y).diff(x, y) + dl_dt = dfdx.subs({f(x, y): l, x: t, y: t1}) + assert SI.get_dimensional_expr(dl_dt) ==\ + SI.get_dimensional_expr(l / t / t1) ==\ + Symbol("length")/Symbol("time")**2 + assert SI._collect_factor_and_dimension(dl_dt) ==\ + SI._collect_factor_and_dimension(l / t / t1) ==\ + (10, length/time**2) + + +def test_get_dimensional_expr_with_function(): + v_w1 = Quantity('v_w1') + v_w2 = Quantity('v_w2') + v_w1.set_global_relative_scale_factor(1, meter/second) + v_w2.set_global_relative_scale_factor(1, meter/second) + + assert SI.get_dimensional_expr(sin(v_w1)) == \ + sin(SI.get_dimensional_expr(v_w1)) + assert SI.get_dimensional_expr(sin(v_w1/v_w2)) == 1 + + +def test_binary_information(): + assert convert_to(kibibyte, byte) == 1024*byte + assert convert_to(mebibyte, byte) == 1024**2*byte + assert convert_to(gibibyte, byte) == 1024**3*byte + assert convert_to(tebibyte, byte) == 1024**4*byte + assert convert_to(pebibyte, byte) == 1024**5*byte + assert convert_to(exbibyte, byte) == 1024**6*byte + + assert kibibyte.convert_to(bit) == 8*1024*bit + assert byte.convert_to(bit) == 8*bit + + a = 10*kibibyte*hour + + assert convert_to(a, byte) == 10240*byte*hour + assert convert_to(a, minute) == 600*kibibyte*minute + assert convert_to(a, [byte, minute]) == 614400*byte*minute + + +def test_conversion_with_2_nonstandard_dimensions(): + good_grade = Quantity("good_grade") + kilo_good_grade = Quantity("kilo_good_grade") + centi_good_grade = Quantity("centi_good_grade") + + kilo_good_grade.set_global_relative_scale_factor(1000, good_grade) + centi_good_grade.set_global_relative_scale_factor(S.One/10**5, kilo_good_grade) + + charity_points = Quantity("charity_points") + milli_charity_points = Quantity("milli_charity_points") + missions = Quantity("missions") + + milli_charity_points.set_global_relative_scale_factor(S.One/1000, charity_points) + missions.set_global_relative_scale_factor(251, charity_points) + + assert convert_to( + kilo_good_grade*milli_charity_points*millimeter, + [centi_good_grade, missions, centimeter] + ) == S.One * 10**5 / (251*1000) / 10 * centi_good_grade*missions*centimeter + + +def test_eval_subs(): + energy, mass, force = symbols('energy mass force') + expr1 = energy/mass + units = {energy: kilogram*meter**2/second**2, mass: kilogram} + assert expr1.subs(units) == meter**2/second**2 + expr2 = force/mass + units = {force:gravitational_constant*kilogram**2/meter**2, mass:kilogram} + assert expr2.subs(units) == gravitational_constant*kilogram/meter**2 + + +def test_issue_14932(): + assert (log(inch) - log(2)).simplify() == log(inch/2) + assert (log(inch) - log(foot)).simplify() == -log(12) + p = symbols('p', positive=True) + assert (log(inch) - log(p)).simplify() == log(inch/p) + + +def test_issue_14547(): + # the root issue is that an argument with dimensions should + # not raise an error when the `arg - 1` calculation is + # performed in the assumptions system + from sympy.physics.units import foot, inch + from sympy.core.relational import Eq + assert log(foot).is_zero is None + assert log(foot).is_positive is None + assert log(foot).is_nonnegative is None + assert log(foot).is_negative is None + assert log(foot).is_algebraic is None + assert log(foot).is_rational is None + # doesn't raise error + assert Eq(log(foot), log(inch)) is not None # might be False or unevaluated + + x = Symbol('x') + e = foot + x + assert e.is_Add and set(e.args) == {foot, x} + e = foot + 1 + assert e.is_Add and set(e.args) == {foot, 1} + + +def test_issue_22164(): + warnings.simplefilter("error") + dm = Quantity("dm") + SI.set_quantity_dimension(dm, length) + SI.set_quantity_scale_factor(dm, 1) + + bad_exp = Quantity("bad_exp") + SI.set_quantity_dimension(bad_exp, length) + SI.set_quantity_scale_factor(bad_exp, 1) + + expr = dm ** bad_exp + + # deprecation warning is not expected here + SI._collect_factor_and_dimension(expr) + + +def test_issue_22819(): + from sympy.physics.units import tonne, gram, Da + from sympy.physics.units.systems.si import dimsys_SI + assert tonne.convert_to(gram) == 1000000*gram + assert dimsys_SI.get_dimensional_dependencies(area) == {length: 2} + assert Da.scale_factor == 1.66053906660000e-24 + + +def test_issue_20288(): + from sympy.core.numbers import E + from sympy.physics.units import energy + u = Quantity('u') + v = Quantity('v') + SI.set_quantity_dimension(u, energy) + SI.set_quantity_dimension(v, energy) + u.set_global_relative_scale_factor(1, joule) + v.set_global_relative_scale_factor(1, joule) + expr = 1 + exp(u**2/v**2) + assert SI._collect_factor_and_dimension(expr) == (1 + E, Dimension(1)) + + +def test_issue_24062(): + from sympy.core.numbers import E + from sympy.physics.units import impedance, capacitance, time, ohm, farad, second + + R = Quantity('R') + C = Quantity('C') + T = Quantity('T') + SI.set_quantity_dimension(R, impedance) + SI.set_quantity_dimension(C, capacitance) + SI.set_quantity_dimension(T, time) + R.set_global_relative_scale_factor(1, ohm) + C.set_global_relative_scale_factor(1, farad) + T.set_global_relative_scale_factor(1, second) + expr = T / (R * C) + dim = SI._collect_factor_and_dimension(expr)[1] + assert SI.get_dimension_system().is_dimensionless(dim) + + exp_expr = 1 + exp(expr) + assert SI._collect_factor_and_dimension(exp_expr) == (1 + E, Dimension(1)) + +def test_issue_24211(): + from sympy.physics.units import time, velocity, acceleration, second, meter + V1 = Quantity('V1') + SI.set_quantity_dimension(V1, velocity) + SI.set_quantity_scale_factor(V1, 1 * meter / second) + A1 = Quantity('A1') + SI.set_quantity_dimension(A1, acceleration) + SI.set_quantity_scale_factor(A1, 1 * meter / second**2) + T1 = Quantity('T1') + SI.set_quantity_dimension(T1, time) + SI.set_quantity_scale_factor(T1, 1 * second) + + expr = A1*T1 + V1 + # should not throw ValueError here + SI._collect_factor_and_dimension(expr) + + +def test_prefixed_property(): + assert not meter.is_prefixed + assert not joule.is_prefixed + assert not day.is_prefixed + assert not second.is_prefixed + assert not volt.is_prefixed + assert not ohm.is_prefixed + assert centimeter.is_prefixed + assert kilometer.is_prefixed + assert kilogram.is_prefixed + assert pebibyte.is_prefixed + +def test_physics_constant(): + from sympy.physics.units import definitions + + for name in dir(definitions): + quantity = getattr(definitions, name) + if not isinstance(quantity, Quantity): + continue + if name.endswith('_constant'): + assert isinstance(quantity, PhysicalConstant), f"{quantity} must be PhysicalConstant, but is {type(quantity)}" + assert quantity.is_physical_constant, f"{name} is not marked as physics constant when it should be" + + for const in [gravitational_constant, molar_gas_constant, vacuum_permittivity, speed_of_light, elementary_charge]: + assert isinstance(const, PhysicalConstant), f"{const} must be PhysicalConstant, but is {type(const)}" + assert const.is_physical_constant, f"{const} is not marked as physics constant when it should be" + + assert not meter.is_physical_constant + assert not joule.is_physical_constant diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_unit_system_cgs_gauss.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_unit_system_cgs_gauss.py new file mode 100644 index 0000000000000000000000000000000000000000..12629280785c94fa8be33bc97bdd714140a3e346 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_unit_system_cgs_gauss.py @@ -0,0 +1,55 @@ +from sympy.concrete.tests.test_sums_products import NS + +from sympy.core.singleton import S +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.physics.units import convert_to, coulomb_constant, elementary_charge, gravitational_constant, planck +from sympy.physics.units.definitions.unit_definitions import angstrom, statcoulomb, coulomb, second, gram, centimeter, erg, \ + newton, joule, dyne, speed_of_light, meter, farad, henry, statvolt, volt, ohm +from sympy.physics.units.systems import SI +from sympy.physics.units.systems.cgs import cgs_gauss + + +def test_conversion_to_from_si(): + assert convert_to(statcoulomb, coulomb, cgs_gauss) == coulomb/2997924580 + assert convert_to(coulomb, statcoulomb, cgs_gauss) == 2997924580*statcoulomb + assert convert_to(statcoulomb, sqrt(gram*centimeter**3)/second, cgs_gauss) == centimeter**(S(3)/2)*sqrt(gram)/second + assert convert_to(coulomb, sqrt(gram*centimeter**3)/second, cgs_gauss) == 2997924580*centimeter**(S(3)/2)*sqrt(gram)/second + + # SI units have an additional base unit, no conversion in case of electromagnetism: + assert convert_to(coulomb, statcoulomb, SI) == coulomb + assert convert_to(statcoulomb, coulomb, SI) == statcoulomb + + # SI without electromagnetism: + assert convert_to(erg, joule, SI) == joule/10**7 + assert convert_to(erg, joule, cgs_gauss) == joule/10**7 + assert convert_to(joule, erg, SI) == 10**7*erg + assert convert_to(joule, erg, cgs_gauss) == 10**7*erg + + + assert convert_to(dyne, newton, SI) == newton/10**5 + assert convert_to(dyne, newton, cgs_gauss) == newton/10**5 + assert convert_to(newton, dyne, SI) == 10**5*dyne + assert convert_to(newton, dyne, cgs_gauss) == 10**5*dyne + + +def test_cgs_gauss_convert_constants(): + + assert convert_to(speed_of_light, centimeter/second, cgs_gauss) == 29979245800*centimeter/second + + assert convert_to(coulomb_constant, 1, cgs_gauss) == 1 + assert convert_to(coulomb_constant, newton*meter**2/coulomb**2, cgs_gauss) == 22468879468420441*meter**2*newton/(2500000*coulomb**2) + assert convert_to(coulomb_constant, newton*meter**2/coulomb**2, SI) == 22468879468420441*meter**2*newton/(2500000*coulomb**2) + assert convert_to(coulomb_constant, dyne*centimeter**2/statcoulomb**2, cgs_gauss) == centimeter**2*dyne/statcoulomb**2 + assert convert_to(coulomb_constant, 1, SI) == coulomb_constant + assert NS(convert_to(coulomb_constant, newton*meter**2/coulomb**2, SI)) == '8987551787.36818*meter**2*newton/coulomb**2' + + assert convert_to(elementary_charge, statcoulomb, cgs_gauss) + assert convert_to(angstrom, centimeter, cgs_gauss) == 1*centimeter/10**8 + assert convert_to(gravitational_constant, dyne*centimeter**2/gram**2, cgs_gauss) + assert NS(convert_to(planck, erg*second, cgs_gauss)) == '6.62607015e-27*erg*second' + + spc = 25000*second/(22468879468420441*centimeter) + assert convert_to(ohm, second/centimeter, cgs_gauss) == spc + assert convert_to(henry, second**2/centimeter, cgs_gauss) == spc*second + assert convert_to(volt, statvolt, cgs_gauss) == 10**6*statvolt/299792458 + assert convert_to(farad, centimeter, cgs_gauss) == 299792458**2*centimeter/10**5 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_unitsystem.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_unitsystem.py new file mode 100644 index 0000000000000000000000000000000000000000..a04f3aabb6274bed4f1b82ac0719fa618b55eed7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_unitsystem.py @@ -0,0 +1,86 @@ +from sympy.physics.units import DimensionSystem, joule, second, ampere + +from sympy.core.numbers import Rational +from sympy.core.singleton import S +from sympy.physics.units.definitions import c, kg, m, s +from sympy.physics.units.definitions.dimension_definitions import length, time +from sympy.physics.units.quantities import Quantity +from sympy.physics.units.unitsystem import UnitSystem +from sympy.physics.units.util import convert_to + + +def test_definition(): + # want to test if the system can have several units of the same dimension + dm = Quantity("dm") + base = (m, s) + # base_dim = (m.dimension, s.dimension) + ms = UnitSystem(base, (c, dm), "MS", "MS system") + ms.set_quantity_dimension(dm, length) + ms.set_quantity_scale_factor(dm, Rational(1, 10)) + + assert set(ms._base_units) == set(base) + assert set(ms._units) == {m, s, c, dm} + # assert ms._units == DimensionSystem._sort_dims(base + (velocity,)) + assert ms.name == "MS" + assert ms.descr == "MS system" + + +def test_str_repr(): + assert str(UnitSystem((m, s), name="MS")) == "MS" + assert str(UnitSystem((m, s))) == "UnitSystem((meter, second))" + + assert repr(UnitSystem((m, s))) == "" % (m, s) + + +def test_convert_to(): + A = Quantity("A") + A.set_global_relative_scale_factor(S.One, ampere) + + Js = Quantity("Js") + Js.set_global_relative_scale_factor(S.One, joule*second) + + mksa = UnitSystem((m, kg, s, A), (Js,)) + assert convert_to(Js, mksa._base_units) == m**2*kg*s**-1/1000 + + +def test_extend(): + ms = UnitSystem((m, s), (c,)) + Js = Quantity("Js") + Js.set_global_relative_scale_factor(1, joule*second) + mks = ms.extend((kg,), (Js,)) + + res = UnitSystem((m, s, kg), (c, Js)) + assert set(mks._base_units) == set(res._base_units) + assert set(mks._units) == set(res._units) + + +def test_dim(): + dimsys = UnitSystem((m, kg, s), (c,)) + assert dimsys.dim == 3 + + +def test_is_consistent(): + dimension_system = DimensionSystem([length, time]) + us = UnitSystem([m, s], dimension_system=dimension_system) + assert us.is_consistent == True + + +def test_get_units_non_prefixed(): + from sympy.physics.units import volt, ohm + unit_system = UnitSystem.get_unit_system("SI") + units = unit_system.get_units_non_prefixed() + for prefix in ["giga", "tera", "peta", "exa", "zetta", "yotta", "kilo", "hecto", "deca", "deci", "centi", "milli", "micro", "nano", "pico", "femto", "atto", "zepto", "yocto"]: + for unit in units: + assert isinstance(unit, Quantity), f"{unit} must be a Quantity, not {type(unit)}" + assert not unit.is_prefixed, f"{unit} is marked as prefixed" + assert not unit.is_physical_constant, f"{unit} is marked as physics constant" + assert not unit.name.name.startswith(prefix), f"Unit {unit.name} has prefix {prefix}" + assert volt in units + assert ohm in units + +def test_derived_units_must_exist_in_unit_system(): + for unit_system in UnitSystem._unit_systems.values(): + for preferred_unit in unit_system.derived_units.values(): + units = preferred_unit.atoms(Quantity) + for unit in units: + assert unit in unit_system._units, f"Unit {unit} is not in unit system {unit_system}" diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_util.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_util.py new file mode 100644 index 0000000000000000000000000000000000000000..3522af675d33275f322e2b731309e19bffde1e1d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/units/tests/test_util.py @@ -0,0 +1,178 @@ +from sympy.core.containers import Tuple +from sympy.core.numbers import pi +from sympy.core.power import Pow +from sympy.core.symbol import symbols +from sympy.core.sympify import sympify +from sympy.printing.str import sstr +from sympy.physics.units import ( + G, centimeter, coulomb, day, degree, gram, hbar, hour, inch, joule, kelvin, + kilogram, kilometer, length, meter, mile, minute, newton, planck, + planck_length, planck_mass, planck_temperature, planck_time, radians, + second, speed_of_light, steradian, time, km) +from sympy.physics.units.util import convert_to, check_dimensions +from sympy.testing.pytest import raises +from sympy.functions.elementary.miscellaneous import sqrt + + +def NS(e, n=15, **options): + return sstr(sympify(e).evalf(n, **options), full_prec=True) + + +L = length +T = time + + +def test_dim_simplify_add(): + # assert Add(L, L) == L + assert L + L == L + + +def test_dim_simplify_mul(): + # assert Mul(L, T) == L*T + assert L*T == L*T + + +def test_dim_simplify_pow(): + assert Pow(L, 2) == L**2 + + +def test_dim_simplify_rec(): + # assert Mul(Add(L, L), T) == L*T + assert (L + L) * T == L*T + + +def test_convert_to_quantities(): + assert convert_to(3, meter) == 3 + + assert convert_to(mile, kilometer) == 25146*kilometer/15625 + assert convert_to(meter/second, speed_of_light) == speed_of_light/299792458 + assert convert_to(299792458*meter/second, speed_of_light) == speed_of_light + assert convert_to(2*299792458*meter/second, speed_of_light) == 2*speed_of_light + assert convert_to(speed_of_light, meter/second) == 299792458*meter/second + assert convert_to(2*speed_of_light, meter/second) == 599584916*meter/second + assert convert_to(day, second) == 86400*second + assert convert_to(2*hour, minute) == 120*minute + assert convert_to(mile, meter) == 201168*meter/125 + assert convert_to(mile/hour, kilometer/hour) == 25146*kilometer/(15625*hour) + assert convert_to(3*newton, meter/second) == 3*newton + assert convert_to(3*newton, kilogram*meter/second**2) == 3*meter*kilogram/second**2 + assert convert_to(kilometer + mile, meter) == 326168*meter/125 + assert convert_to(2*kilometer + 3*mile, meter) == 853504*meter/125 + assert convert_to(inch**2, meter**2) == 16129*meter**2/25000000 + assert convert_to(3*inch**2, meter) == 48387*meter**2/25000000 + assert convert_to(2*kilometer/hour + 3*mile/hour, meter/second) == 53344*meter/(28125*second) + assert convert_to(2*kilometer/hour + 3*mile/hour, centimeter/second) == 213376*centimeter/(1125*second) + assert convert_to(kilometer * (mile + kilometer), meter) == 2609344 * meter ** 2 + + assert convert_to(steradian, coulomb) == steradian + assert convert_to(radians, degree) == 180*degree/pi + assert convert_to(radians, [meter, degree]) == 180*degree/pi + assert convert_to(pi*radians, degree) == 180*degree + assert convert_to(pi, degree) == 180*degree + + # https://github.com/sympy/sympy/issues/26263 + assert convert_to(sqrt(meter**2 + meter**2.0), meter) == sqrt(meter**2 + meter**2.0) + assert convert_to((meter**2 + meter**2.0)**2, meter) == (meter**2 + meter**2.0)**2 + + +def test_convert_to_tuples_of_quantities(): + from sympy.core.symbol import symbols + + alpha, beta = symbols('alpha beta') + + assert convert_to(speed_of_light, [meter, second]) == 299792458 * meter / second + assert convert_to(speed_of_light, (meter, second)) == 299792458 * meter / second + assert convert_to(speed_of_light, Tuple(meter, second)) == 299792458 * meter / second + assert convert_to(joule, [meter, kilogram, second]) == kilogram*meter**2/second**2 + assert convert_to(joule, [centimeter, gram, second]) == 10000000*centimeter**2*gram/second**2 + assert convert_to(299792458*meter/second, [speed_of_light]) == speed_of_light + assert convert_to(speed_of_light / 2, [meter, second, kilogram]) == meter/second*299792458 / 2 + # This doesn't make physically sense, but let's keep it as a conversion test: + assert convert_to(2 * speed_of_light, [meter, second, kilogram]) == 2 * 299792458 * meter / second + assert convert_to(G, [G, speed_of_light, planck]) == 1.0*G + + assert NS(convert_to(meter, [G, speed_of_light, hbar]), n=7) == '6.187142e+34*gravitational_constant**0.5000000*hbar**0.5000000/speed_of_light**1.500000' + assert NS(convert_to(planck_mass, kilogram), n=7) == '2.176434e-8*kilogram' + assert NS(convert_to(planck_length, meter), n=7) == '1.616255e-35*meter' + assert NS(convert_to(planck_time, second), n=6) == '5.39125e-44*second' + assert NS(convert_to(planck_temperature, kelvin), n=7) == '1.416784e+32*kelvin' + assert NS(convert_to(convert_to(meter, [G, speed_of_light, planck]), meter), n=10) == '1.000000000*meter' + + # similar to https://github.com/sympy/sympy/issues/26263 + assert convert_to(sqrt(meter**2 + second**2.0), [meter, second]) == sqrt(meter**2 + second**2.0) + assert convert_to((meter**2 + second**2.0)**2, [meter, second]) == (meter**2 + second**2.0)**2 + + # similar to https://github.com/sympy/sympy/issues/21463 + assert convert_to(1/(beta*meter + meter), 1/meter) == 1/(beta*meter + meter) + assert convert_to(1/(beta*meter + alpha*meter), 1/kilometer) == (1/(kilometer*beta/1000 + alpha*kilometer/1000)) + +def test_eval_simplify(): + from sympy.physics.units import cm, mm, km, m, K, kilo + from sympy.core.symbol import symbols + + x, y = symbols('x y') + + assert (cm/mm).simplify() == 10 + assert (km/m).simplify() == 1000 + assert (km/cm).simplify() == 100000 + assert (10*x*K*km**2/m/cm).simplify() == 1000000000*x*kelvin + assert (cm/km/m).simplify() == 1/(10000000*centimeter) + + assert (3*kilo*meter).simplify() == 3000*meter + assert (4*kilo*meter/(2*kilometer)).simplify() == 2 + assert (4*kilometer**2/(kilo*meter)**2).simplify() == 4 + + +def test_quantity_simplify(): + from sympy.physics.units.util import quantity_simplify + from sympy.physics.units import kilo, foot + from sympy.core.symbol import symbols + + x, y = symbols('x y') + + assert quantity_simplify(x*(8*kilo*newton*meter + y)) == x*(8000*meter*newton + y) + assert quantity_simplify(foot*inch*(foot + inch)) == foot**2*(foot + foot/12)/12 + assert quantity_simplify(foot*inch*(foot*foot + inch*(foot + inch))) == foot**2*(foot**2 + foot/12*(foot + foot/12))/12 + assert quantity_simplify(2**(foot/inch*kilo/1000)*inch) == 4096*foot/12 + assert quantity_simplify(foot**2*inch + inch**2*foot) == 13*foot**3/144 + +def test_quantity_simplify_across_dimensions(): + from sympy.physics.units.util import quantity_simplify + from sympy.physics.units import ampere, ohm, volt, joule, pascal, farad, second, watt, siemens, henry, tesla, weber, hour, newton + + assert quantity_simplify(ampere*ohm, across_dimensions=True, unit_system="SI") == volt + assert quantity_simplify(6*ampere*ohm, across_dimensions=True, unit_system="SI") == 6*volt + assert quantity_simplify(volt/ampere, across_dimensions=True, unit_system="SI") == ohm + assert quantity_simplify(volt/ohm, across_dimensions=True, unit_system="SI") == ampere + assert quantity_simplify(joule/meter**3, across_dimensions=True, unit_system="SI") == pascal + assert quantity_simplify(farad*ohm, across_dimensions=True, unit_system="SI") == second + assert quantity_simplify(joule/second, across_dimensions=True, unit_system="SI") == watt + assert quantity_simplify(meter**3/second, across_dimensions=True, unit_system="SI") == meter**3/second + assert quantity_simplify(joule/second, across_dimensions=True, unit_system="SI") == watt + + assert quantity_simplify(joule/coulomb, across_dimensions=True, unit_system="SI") == volt + assert quantity_simplify(volt/ampere, across_dimensions=True, unit_system="SI") == ohm + assert quantity_simplify(ampere/volt, across_dimensions=True, unit_system="SI") == siemens + assert quantity_simplify(coulomb/volt, across_dimensions=True, unit_system="SI") == farad + assert quantity_simplify(volt*second/ampere, across_dimensions=True, unit_system="SI") == henry + assert quantity_simplify(volt*second/meter**2, across_dimensions=True, unit_system="SI") == tesla + assert quantity_simplify(joule/ampere, across_dimensions=True, unit_system="SI") == weber + + assert quantity_simplify(5*kilometer/hour, across_dimensions=True, unit_system="SI") == 25*meter/(18*second) + assert quantity_simplify(5*kilogram*meter/second**2, across_dimensions=True, unit_system="SI") == 5*newton + +def test_check_dimensions(): + x = symbols('x') + assert check_dimensions(inch + x) == inch + x + assert check_dimensions(length + x) == length + x + # after subs we get 2*length; check will clear the constant + assert check_dimensions((length + x).subs(x, length)) == length + assert check_dimensions(newton*meter + joule) == joule + meter*newton + raises(ValueError, lambda: check_dimensions(inch + 1)) + raises(ValueError, lambda: check_dimensions(length + 1)) + raises(ValueError, lambda: check_dimensions(length + time)) + raises(ValueError, lambda: check_dimensions(meter + second)) + raises(ValueError, lambda: check_dimensions(2 * meter + second)) + raises(ValueError, lambda: check_dimensions(2 * meter + 3 * second)) + raises(ValueError, lambda: check_dimensions(1 / second + 1 / meter)) + raises(ValueError, lambda: check_dimensions(2 * meter*(mile + centimeter) + km)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3dd469b1032d3befc3a6522c67b6b085aedc0b71 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/dyadic.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/dyadic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..089e45600aae21b5fdef048daec3c1f15929d629 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/dyadic.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/fieldfunctions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/fieldfunctions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19500fa6e36c4364d40965739a17f4416ab0db43 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/fieldfunctions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/frame.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/frame.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f6925af51131561b586dc7ea565863293af1c2e5 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/frame.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/functions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/functions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ee202f2dd17299a5e68f05b2cd1cc4ad6c896f9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/functions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/point.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/point.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff6da473572287750e27771e309ae00ccdb2cb9f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/point.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/printing.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/printing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e766bd77d86bab4e9808b1677d19ea9d04386f8 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/printing.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/vector.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/vector.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab3039f7ead1aec1aeb8a69f81803a307780df1c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/__pycache__/vector.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e16e31b2c6d10f5415d084a2ec07668440544548 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_dyadic.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_dyadic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6175b15a6e02da8bd2e56a05574081c6c7653afb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_dyadic.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_fieldfunctions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_fieldfunctions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3629462150802ec05255294fdd8ab4c3db46a565 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_fieldfunctions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_frame.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_frame.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b1e13d8b33a9fd176343124436ee09c8fb28705 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_frame.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_functions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_functions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fbd40166c110dcfadf7ac77f97d97eecf62635ac Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_functions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_output.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_output.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7a08c209c1a0e4476fa130cdc612a741a65df9d3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_output.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_point.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_point.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05d3c7f0a2a6d135b92bd0dd26ad50d87d533e97 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_point.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_printing.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_printing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b3e422e418e2fde5902bdcef203885e92c14eee Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_printing.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_vector.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_vector.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3dc2b36b34a2c4977e2b2b267dde16c2713617b3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/__pycache__/test_vector.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_dyadic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_dyadic.py new file mode 100644 index 0000000000000000000000000000000000000000..ab365b4687162ccbd3b21dd9709b84dbcdec8aa0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_dyadic.py @@ -0,0 +1,123 @@ +from sympy.core.numbers import (Float, pi) +from sympy.core.symbol import symbols +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix +from sympy.physics.vector import ReferenceFrame, dynamicsymbols, outer +from sympy.physics.vector.dyadic import _check_dyadic +from sympy.testing.pytest import raises + +A = ReferenceFrame('A') + + +def test_dyadic(): + d1 = A.x | A.x + d2 = A.y | A.y + d3 = A.x | A.y + assert d1 * 0 == 0 + assert d1 != 0 + assert d1 * 2 == 2 * A.x | A.x + assert d1 / 2. == 0.5 * d1 + assert d1 & (0 * d1) == 0 + assert d1 & d2 == 0 + assert d1 & A.x == A.x + assert d1 ^ A.x == 0 + assert d1 ^ A.y == A.x | A.z + assert d1 ^ A.z == - A.x | A.y + assert d2 ^ A.x == - A.y | A.z + assert A.x ^ d1 == 0 + assert A.y ^ d1 == - A.z | A.x + assert A.z ^ d1 == A.y | A.x + assert A.x & d1 == A.x + assert A.y & d1 == 0 + assert A.y & d2 == A.y + assert d1 & d3 == A.x | A.y + assert d3 & d1 == 0 + assert d1.dt(A) == 0 + q = dynamicsymbols('q') + qd = dynamicsymbols('q', 1) + B = A.orientnew('B', 'Axis', [q, A.z]) + assert d1.express(B) == d1.express(B, B) + assert d1.express(B) == ((cos(q)**2) * (B.x | B.x) + (-sin(q) * cos(q)) * + (B.x | B.y) + (-sin(q) * cos(q)) * (B.y | B.x) + (sin(q)**2) * + (B.y | B.y)) + assert d1.express(B, A) == (cos(q)) * (B.x | A.x) + (-sin(q)) * (B.y | A.x) + 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) + + assert d1.to_matrix(A) == Matrix([[1, 0, 0], [0, 0, 0], [0, 0, 0]]) + assert d1.to_matrix(A, B) == Matrix([[cos(q), -sin(q), 0], + [0, 0, 0], + [0, 0, 0]]) + assert d3.to_matrix(A) == Matrix([[0, 1, 0], [0, 0, 0], [0, 0, 0]]) + a, b, c, d, e, f = symbols('a, b, c, d, e, f') + v1 = a * A.x + b * A.y + c * A.z + v2 = d * A.x + e * A.y + f * A.z + d4 = v1.outer(v2) + assert d4.to_matrix(A) == Matrix([[a * d, a * e, a * f], + [b * d, b * e, b * f], + [c * d, c * e, c * f]]) + d5 = v1.outer(v1) + C = A.orientnew('C', 'Axis', [q, A.x]) + for expected, actual in zip(C.dcm(A) * d5.to_matrix(A) * C.dcm(A).T, + d5.to_matrix(C)): + assert (expected - actual).simplify() == 0 + + raises(TypeError, lambda: d1.applyfunc(0)) + + +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') + + dy = N.x | N.x + test1 = (1 / x + 1 / y) * dy + assert (N.x & test1 & N.x) != (x + y) / (x * y) + test1 = test1.simplify() + assert (N.x & test1 & N.x) == (x + y) / (x * y) + + test2 = (A**2 * s**4 / (4 * pi * k * m**3)) * dy + test2 = test2.simplify() + assert (N.x & test2 & N.x) == (A**2 * s**4 / (4 * pi * k * m**3)) + + test3 = ((4 + 4 * x - 2 * (2 + 2 * x)) / (2 + 2 * x)) * dy + test3 = test3.simplify() + assert (N.x & test3 & N.x) == 0 + + test4 = ((-4 * x * y**2 - 2 * y**3 - 2 * x**2 * y) / (x + y)**2) * dy + test4 = test4.simplify() + assert (N.x & test4 & N.x) == -2 * y + + +def test_dyadic_subs(): + N = ReferenceFrame('N') + s = symbols('s') + a = s*(N.x | N.x) + assert a.subs({s: 2}) == 2*(N.x | N.x) + + +def test_check_dyadic(): + raises(TypeError, lambda: _check_dyadic(0)) + + +def test_dyadic_evalf(): + N = ReferenceFrame('N') + a = pi * (N.x | N.x) + assert a.evalf(3) == Float('3.1416', 3) * (N.x | N.x) + s = symbols('s') + a = 5 * s * pi* (N.x | N.x) + assert a.evalf(2) == Float('5', 2) * Float('3.1416', 2) * s * (N.x | N.x) + assert a.evalf(9, subs={s: 5.124}) == Float('80.48760378', 9) * (N.x | N.x) + + +def test_dyadic_xreplace(): + x, y, z = symbols('x y z') + N = ReferenceFrame('N') + D = outer(N.x, N.x) + v = x*y * D + assert v.xreplace({x : cos(x)}) == cos(x)*y * D + assert v.xreplace({x*y : pi}) == pi * D + v = (x*y)**z * D + assert v.xreplace({(x*y)**z : 1}) == D + assert v.xreplace({x:1, z:0}) == D + raises(TypeError, lambda: v.xreplace()) + raises(TypeError, lambda: v.xreplace([x, y])) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_fieldfunctions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_fieldfunctions.py new file mode 100644 index 0000000000000000000000000000000000000000..4e5c67aad44ca972dac6e455c57b60a74bae207a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_fieldfunctions.py @@ -0,0 +1,133 @@ +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.physics.vector import ReferenceFrame, Vector, Point, \ + dynamicsymbols +from sympy.physics.vector.fieldfunctions import divergence, \ + gradient, curl, is_conservative, is_solenoidal, \ + scalar_potential, scalar_potential_difference +from sympy.testing.pytest import raises + +R = ReferenceFrame('R') +q = dynamicsymbols('q') +P = R.orientnew('P', 'Axis', [q, R.z]) + + +def test_curl(): + assert curl(Vector(0), R) == Vector(0) + assert curl(R.x, R) == Vector(0) + assert curl(2*R[1]**2*R.y, R) == Vector(0) + assert curl(R[0]*R[1]*R.z, R) == R[0]*R.x - R[1]*R.y + assert curl(R[0]*R[1]*R[2] * (R.x+R.y+R.z), R) == \ + (-R[0]*R[1] + R[0]*R[2])*R.x + (R[0]*R[1] - R[1]*R[2])*R.y + \ + (-R[0]*R[2] + R[1]*R[2])*R.z + assert curl(2*R[0]**2*R.y, R) == 4*R[0]*R.z + assert curl(P[0]**2*R.x + P.y, R) == \ + - 2*(R[0]*cos(q) + R[1]*sin(q))*sin(q)*R.z + assert curl(P[0]*R.y, P) == cos(q)*P.z + + +def test_divergence(): + assert divergence(Vector(0), R) is S.Zero + assert divergence(R.x, R) is S.Zero + assert divergence(R[0]**2*R.x, R) == 2*R[0] + assert divergence(R[0]*R[1]*R[2] * (R.x+R.y+R.z), R) == \ + R[0]*R[1] + R[0]*R[2] + R[1]*R[2] + assert divergence((1/(R[0]*R[1]*R[2])) * (R.x+R.y+R.z), R) == \ + -1/(R[0]*R[1]*R[2]**2) - 1/(R[0]*R[1]**2*R[2]) - \ + 1/(R[0]**2*R[1]*R[2]) + v = P[0]*P.x + P[1]*P.y + P[2]*P.z + assert divergence(v, P) == 3 + assert divergence(v, R).simplify() == 3 + assert divergence(P[0]*R.x + R[0]*P.x, R) == 2*cos(q) + + +def test_gradient(): + a = Symbol('a') + assert gradient(0, R) == Vector(0) + assert gradient(R[0], R) == R.x + assert gradient(R[0]*R[1]*R[2], R) == \ + R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z + assert gradient(2*R[0]**2, R) == 4*R[0]*R.x + assert gradient(a*sin(R[1])/R[0], R) == \ + - a*sin(R[1])/R[0]**2*R.x + a*cos(R[1])/R[0]*R.y + assert gradient(P[0]*P[1], R) == \ + ((-R[0]*sin(q) + R[1]*cos(q))*cos(q) - (R[0]*cos(q) + R[1]*sin(q))*sin(q))*R.x + \ + ((-R[0]*sin(q) + R[1]*cos(q))*sin(q) + (R[0]*cos(q) + R[1]*sin(q))*cos(q))*R.y + assert gradient(P[0]*R[2], P) == P[2]*P.x + P[0]*P.z + + +scalar_field = 2*R[0]**2*R[1]*R[2] +grad_field = gradient(scalar_field, R) +vector_field = R[1]**2*R.x + 3*R[0]*R.y + 5*R[1]*R[2]*R.z +curl_field = curl(vector_field, R) + + +def test_conservative(): + assert is_conservative(0) is True + assert is_conservative(R.x) is True + assert is_conservative(2 * R.x + 3 * R.y + 4 * R.z) is True + assert is_conservative(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z) is \ + True + assert is_conservative(R[0] * R.y) is False + assert is_conservative(grad_field) is True + assert is_conservative(curl_field) is False + assert is_conservative(4*R[0]*R[1]*R[2]*R.x + 2*R[0]**2*R[2]*R.y) is \ + False + assert is_conservative(R[2]*P.x + P[0]*R.z) is True + + +def test_solenoidal(): + assert is_solenoidal(0) is True + assert is_solenoidal(R.x) is True + assert is_solenoidal(2 * R.x + 3 * R.y + 4 * R.z) is True + assert is_solenoidal(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z) is \ + True + assert is_solenoidal(R[1] * R.y) is False + assert is_solenoidal(grad_field) is False + assert is_solenoidal(curl_field) is True + assert is_solenoidal((-2*R[1] + 3)*R.z) is True + assert is_solenoidal(cos(q)*R.x + sin(q)*R.y + cos(q)*P.z) is True + assert is_solenoidal(R[2]*P.x + P[0]*R.z) is True + + +def test_scalar_potential(): + assert scalar_potential(0, R) == 0 + assert scalar_potential(R.x, R) == R[0] + assert scalar_potential(R.y, R) == R[1] + assert scalar_potential(R.z, R) == R[2] + assert scalar_potential(R[1]*R[2]*R.x + R[0]*R[2]*R.y + \ + R[0]*R[1]*R.z, R) == R[0]*R[1]*R[2] + assert scalar_potential(grad_field, R) == scalar_field + assert scalar_potential(R[2]*P.x + P[0]*R.z, R) == \ + R[0]*R[2]*cos(q) + R[1]*R[2]*sin(q) + assert scalar_potential(R[2]*P.x + P[0]*R.z, P) == P[0]*P[2] + raises(ValueError, lambda: scalar_potential(R[0] * R.y, R)) + + +def test_scalar_potential_difference(): + origin = Point('O') + point1 = origin.locatenew('P1', 1*R.x + 2*R.y + 3*R.z) + point2 = origin.locatenew('P2', 4*R.x + 5*R.y + 6*R.z) + genericpointR = origin.locatenew('RP', R[0]*R.x + R[1]*R.y + R[2]*R.z) + genericpointP = origin.locatenew('PP', P[0]*P.x + P[1]*P.y + P[2]*P.z) + assert scalar_potential_difference(S.Zero, R, point1, point2, \ + origin) == 0 + assert scalar_potential_difference(scalar_field, R, origin, \ + genericpointR, origin) == \ + scalar_field + assert scalar_potential_difference(grad_field, R, origin, \ + genericpointR, origin) == \ + scalar_field + assert scalar_potential_difference(grad_field, R, point1, point2, + origin) == 948 + assert scalar_potential_difference(R[1]*R[2]*R.x + R[0]*R[2]*R.y + \ + R[0]*R[1]*R.z, R, point1, + genericpointR, origin) == \ + R[0]*R[1]*R[2] - 6 + potential_diff_P = 2*P[2]*(P[0]*sin(q) + P[1]*cos(q))*\ + (P[0]*cos(q) - P[1]*sin(q))**2 + assert scalar_potential_difference(grad_field, P, origin, \ + genericpointP, \ + origin).simplify() == \ + potential_diff_P diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_frame.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_frame.py new file mode 100644 index 0000000000000000000000000000000000000000..8e2d0234c7d2d9f91fdb5421c5a92f05495006c6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_frame.py @@ -0,0 +1,761 @@ +from sympy.core.numbers import pi +from sympy.core.symbol import symbols +from sympy.simplify import trigsimp +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.matrices.dense import (eye, zeros) +from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix +from sympy.simplify.simplify import simplify +from sympy.physics.vector import (ReferenceFrame, Vector, CoordinateSym, + dynamicsymbols, time_derivative, express, + dot) +from sympy.physics.vector.frame import _check_frame +from sympy.physics.vector.vector import VectorTypeError +from sympy.testing.pytest import raises +import warnings +import pickle + + +def test_dict_list(): + + A = ReferenceFrame('A') + B = ReferenceFrame('B') + C = ReferenceFrame('C') + D = ReferenceFrame('D') + E = ReferenceFrame('E') + F = ReferenceFrame('F') + + B.orient_axis(A, A.x, 1.0) + C.orient_axis(B, B.x, 1.0) + D.orient_axis(C, C.x, 1.0) + + assert D._dict_list(A, 0) == [D, C, B, A] + + E.orient_axis(D, D.x, 1.0) + + assert C._dict_list(A, 0) == [C, B, A] + assert C._dict_list(E, 0) == [C, D, E] + + # only 0, 1, 2 permitted for second argument + raises(ValueError, lambda: C._dict_list(E, 5)) + # no connecting path + raises(ValueError, lambda: F._dict_list(A, 0)) + + +def test_coordinate_vars(): + """Tests the coordinate variables functionality""" + A = ReferenceFrame('A') + assert CoordinateSym('Ax', A, 0) == A[0] + assert CoordinateSym('Ax', A, 1) == A[1] + assert CoordinateSym('Ax', A, 2) == A[2] + raises(ValueError, lambda: CoordinateSym('Ax', A, 3)) + q = dynamicsymbols('q') + qd = dynamicsymbols('q', 1) + assert isinstance(A[0], CoordinateSym) and \ + isinstance(A[0], CoordinateSym) and \ + isinstance(A[0], CoordinateSym) + assert A.variable_map(A) == {A[0]:A[0], A[1]:A[1], A[2]:A[2]} + assert A[0].frame == A + B = A.orientnew('B', 'Axis', [q, A.z]) + assert B.variable_map(A) == {B[2]: A[2], B[1]: -A[0]*sin(q) + A[1]*cos(q), + B[0]: A[0]*cos(q) + A[1]*sin(q)} + assert A.variable_map(B) == {A[0]: B[0]*cos(q) - B[1]*sin(q), + A[1]: B[0]*sin(q) + B[1]*cos(q), A[2]: B[2]} + assert time_derivative(B[0], A) == -A[0]*sin(q)*qd + A[1]*cos(q)*qd + assert time_derivative(B[1], A) == -A[0]*cos(q)*qd - A[1]*sin(q)*qd + assert time_derivative(B[2], A) == 0 + assert express(B[0], A, variables=True) == A[0]*cos(q) + A[1]*sin(q) + assert express(B[1], A, variables=True) == -A[0]*sin(q) + A[1]*cos(q) + assert express(B[2], A, variables=True) == A[2] + assert time_derivative(A[0]*A.x + A[1]*A.y + A[2]*A.z, B) == A[1]*qd*A.x - A[0]*qd*A.y + assert time_derivative(B[0]*B.x + B[1]*B.y + B[2]*B.z, A) == - B[1]*qd*B.x + B[0]*qd*B.y + assert express(B[0]*B[1]*B[2], A, variables=True) == \ + A[2]*(-A[0]*sin(q) + A[1]*cos(q))*(A[0]*cos(q) + A[1]*sin(q)) + assert (time_derivative(B[0]*B[1]*B[2], A) - + (A[2]*(-A[0]**2*cos(2*q) - + 2*A[0]*A[1]*sin(2*q) + + A[1]**2*cos(2*q))*qd)).trigsimp() == 0 + assert express(B[0]*B.x + B[1]*B.y + B[2]*B.z, A) == \ + (B[0]*cos(q) - B[1]*sin(q))*A.x + (B[0]*sin(q) + \ + B[1]*cos(q))*A.y + B[2]*A.z + assert express(B[0]*B.x + B[1]*B.y + B[2]*B.z, A, + variables=True).simplify() == A[0]*A.x + A[1]*A.y + A[2]*A.z + assert express(A[0]*A.x + A[1]*A.y + A[2]*A.z, B) == \ + (A[0]*cos(q) + A[1]*sin(q))*B.x + \ + (-A[0]*sin(q) + A[1]*cos(q))*B.y + A[2]*B.z + assert express(A[0]*A.x + A[1]*A.y + A[2]*A.z, B, + variables=True).simplify() == B[0]*B.x + B[1]*B.y + B[2]*B.z + N = B.orientnew('N', 'Axis', [-q, B.z]) + assert ({k: v.simplify() for k, v in N.variable_map(A).items()} == + {N[0]: A[0], N[2]: A[2], N[1]: A[1]}) + C = A.orientnew('C', 'Axis', [q, A.x + A.y + A.z]) + mapping = A.variable_map(C) + assert trigsimp(mapping[A[0]]) == (2*C[0]*cos(q)/3 + C[0]/3 - + 2*C[1]*sin(q + pi/6)/3 + + C[1]/3 - 2*C[2]*cos(q + pi/3)/3 + + C[2]/3) + assert trigsimp(mapping[A[1]]) == -2*C[0]*cos(q + pi/3)/3 + \ + C[0]/3 + 2*C[1]*cos(q)/3 + C[1]/3 - 2*C[2]*sin(q + pi/6)/3 + C[2]/3 + assert trigsimp(mapping[A[2]]) == -2*C[0]*sin(q + pi/6)/3 + C[0]/3 - \ + 2*C[1]*cos(q + pi/3)/3 + C[1]/3 + 2*C[2]*cos(q)/3 + C[2]/3 + + +def test_ang_vel(): + q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') + q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1) + N = ReferenceFrame('N') + A = N.orientnew('A', 'Axis', [q1, N.z]) + B = A.orientnew('B', 'Axis', [q2, A.x]) + C = B.orientnew('C', 'Axis', [q3, B.y]) + D = N.orientnew('D', 'Axis', [q4, N.y]) + u1, u2, u3 = dynamicsymbols('u1 u2 u3') + assert A.ang_vel_in(N) == (q1d)*A.z + assert B.ang_vel_in(N) == (q2d)*B.x + (q1d)*A.z + assert C.ang_vel_in(N) == (q3d)*C.y + (q2d)*B.x + (q1d)*A.z + + A2 = N.orientnew('A2', 'Axis', [q4, N.y]) + assert N.ang_vel_in(N) == 0 + assert N.ang_vel_in(A) == -q1d*N.z + assert N.ang_vel_in(B) == -q1d*A.z - q2d*B.x + assert N.ang_vel_in(C) == -q1d*A.z - q2d*B.x - q3d*B.y + assert N.ang_vel_in(A2) == -q4d*N.y + + assert A.ang_vel_in(N) == q1d*N.z + assert A.ang_vel_in(A) == 0 + assert A.ang_vel_in(B) == - q2d*B.x + assert A.ang_vel_in(C) == - q2d*B.x - q3d*B.y + assert A.ang_vel_in(A2) == q1d*N.z - q4d*N.y + + assert B.ang_vel_in(N) == q1d*A.z + q2d*A.x + assert B.ang_vel_in(A) == q2d*A.x + assert B.ang_vel_in(B) == 0 + assert B.ang_vel_in(C) == -q3d*B.y + assert B.ang_vel_in(A2) == q1d*A.z + q2d*A.x - q4d*N.y + + assert C.ang_vel_in(N) == q1d*A.z + q2d*A.x + q3d*B.y + assert C.ang_vel_in(A) == q2d*A.x + q3d*C.y + assert C.ang_vel_in(B) == q3d*B.y + assert C.ang_vel_in(C) == 0 + assert C.ang_vel_in(A2) == q1d*A.z + q2d*A.x + q3d*B.y - q4d*N.y + + assert A2.ang_vel_in(N) == q4d*A2.y + assert A2.ang_vel_in(A) == q4d*A2.y - q1d*N.z + assert A2.ang_vel_in(B) == q4d*N.y - q1d*A.z - q2d*A.x + assert A2.ang_vel_in(C) == q4d*N.y - q1d*A.z - q2d*A.x - q3d*B.y + assert A2.ang_vel_in(A2) == 0 + + C.set_ang_vel(N, u1*C.x + u2*C.y + u3*C.z) + assert C.ang_vel_in(N) == (u1)*C.x + (u2)*C.y + (u3)*C.z + assert N.ang_vel_in(C) == (-u1)*C.x + (-u2)*C.y + (-u3)*C.z + assert C.ang_vel_in(D) == (u1)*C.x + (u2)*C.y + (u3)*C.z + (-q4d)*D.y + assert D.ang_vel_in(C) == (-u1)*C.x + (-u2)*C.y + (-u3)*C.z + (q4d)*D.y + + q0 = dynamicsymbols('q0') + q0d = dynamicsymbols('q0', 1) + E = N.orientnew('E', 'Quaternion', (q0, q1, q2, q3)) + assert E.ang_vel_in(N) == ( + 2 * (q1d * q0 + q2d * q3 - q3d * q2 - q0d * q1) * E.x + + 2 * (q2d * q0 + q3d * q1 - q1d * q3 - q0d * q2) * E.y + + 2 * (q3d * q0 + q1d * q2 - q2d * q1 - q0d * q3) * E.z) + + F = N.orientnew('F', 'Body', (q1, q2, q3), 313) + assert F.ang_vel_in(N) == ((sin(q2)*sin(q3)*q1d + cos(q3)*q2d)*F.x + + (sin(q2)*cos(q3)*q1d - sin(q3)*q2d)*F.y + (cos(q2)*q1d + q3d)*F.z) + G = N.orientnew('G', 'Axis', (q1, N.x + N.y)) + 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') + A = N.orientnew('A', 'Axis', [q1, N.z]) + B = A.orientnew('B', 'Axis', [q2, A.x]) + C = B.orientnew('C', 'Axis', [q3, B.y]) + D = N.orientnew('D', 'Axis', [q4, N.y]) + E = N.orientnew('E', 'Space', [q1, q2, q3], '123') + assert N.dcm(C) == Matrix([ + [- 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), + cos(q2) * cos(q3)]]) + # This is a little touchy. Is it ok to use simplify in assert? + test_mat = 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) + 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(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))]]) + assert test_mat.expand() == zeros(3, 3) + 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)]]) + +def test_w_diff_dcm1(): + # Ref: + # Dynamics Theory and Applications, Kane 1985 + # Sec. 2.1 ANGULAR VELOCITY + A = ReferenceFrame('A') + B = ReferenceFrame('B') + + c11, c12, c13 = dynamicsymbols('C11 C12 C13') + c21, c22, c23 = dynamicsymbols('C21 C22 C23') + c31, c32, c33 = dynamicsymbols('C31 C32 C33') + + c11d, c12d, c13d = dynamicsymbols('C11 C12 C13', level=1) + c21d, c22d, c23d = dynamicsymbols('C21 C22 C23', level=1) + c31d, c32d, c33d = dynamicsymbols('C31 C32 C33', level=1) + + DCM = Matrix([ + [c11, c12, c13], + [c21, c22, c23], + [c31, c32, c33] + ]) + + B.orient(A, 'DCM', DCM) + b1a = (B.x).express(A) + b2a = (B.y).express(A) + b3a = (B.z).express(A) + + # Equation (2.1.1) + B.set_ang_vel(A, B.x*(dot((b3a).dt(A), B.y)) + + B.y*(dot((b1a).dt(A), B.z)) + + B.z*(dot((b2a).dt(A), B.x))) + + # Equation (2.1.21) + expr = ( (c12*c13d + c22*c23d + c32*c33d)*B.x + + (c13*c11d + c23*c21d + c33*c31d)*B.y + + (c11*c12d + c21*c22d + c31*c32d)*B.z) + assert B.ang_vel_in(A) - expr == 0 + +def test_w_diff_dcm2(): + q1, q2, q3 = dynamicsymbols('q1:4') + N = ReferenceFrame('N') + A = N.orientnew('A', 'axis', [q1, N.x]) + B = A.orientnew('B', 'axis', [q2, A.y]) + C = B.orientnew('C', 'axis', [q3, B.z]) + + DCM = C.dcm(N).T + D = N.orientnew('D', 'DCM', DCM) + + # Frames D and C are the same ReferenceFrame, + # since they have equal DCM respect to frame N. + # Therefore, D and C should have same angle velocity in N. + assert D.dcm(N) == C.dcm(N) == Matrix([ + [cos(q2)*cos(q3), sin(q1)*sin(q2)*cos(q3) + + sin(q3)*cos(q1), sin(q1)*sin(q3) - + sin(q2)*cos(q1)*cos(q3)], [-sin(q3)*cos(q2), + -sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), + sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1)], + [sin(q2), -sin(q1)*cos(q2), cos(q1)*cos(q2)]]) + assert (D.ang_vel_in(N) - C.ang_vel_in(N)).express(N).simplify() == 0 + +def test_orientnew_respects_parent_class(): + class MyReferenceFrame(ReferenceFrame): + pass + B = MyReferenceFrame('B') + C = B.orientnew('C', 'Axis', [0, B.x]) + assert isinstance(C, MyReferenceFrame) + + +def test_orientnew_respects_input_indices(): + N = ReferenceFrame('N') + q1 = dynamicsymbols('q1') + A = N.orientnew('a', 'Axis', [q1, N.z]) + #modify default indices: + minds = [x+'1' for x in N.indices] + B = N.orientnew('b', 'Axis', [q1, N.z], indices=minds) + + assert N.indices == A.indices + assert B.indices == minds + +def test_orientnew_respects_input_latexs(): + N = ReferenceFrame('N') + q1 = dynamicsymbols('q1') + A = N.orientnew('a', 'Axis', [q1, N.z]) + + #build default and alternate latex_vecs: + def_latex_vecs = [(r"\mathbf{\hat{%s}_%s}" % (A.name.lower(), + A.indices[0])), (r"\mathbf{\hat{%s}_%s}" % + (A.name.lower(), A.indices[1])), + (r"\mathbf{\hat{%s}_%s}" % (A.name.lower(), + A.indices[2]))] + + name = 'b' + indices = [x+'1' for x in N.indices] + new_latex_vecs = [(r"\mathbf{\hat{%s}_{%s}}" % (name.lower(), + indices[0])), (r"\mathbf{\hat{%s}_{%s}}" % + (name.lower(), indices[1])), + (r"\mathbf{\hat{%s}_{%s}}" % (name.lower(), + indices[2]))] + + B = N.orientnew(name, 'Axis', [q1, N.z], latexs=new_latex_vecs) + + assert A.latex_vecs == def_latex_vecs + assert B.latex_vecs == new_latex_vecs + assert B.indices != indices + +def test_orientnew_respects_input_variables(): + N = ReferenceFrame('N') + q1 = dynamicsymbols('q1') + A = N.orientnew('a', 'Axis', [q1, N.z]) + + #build non-standard variable names + name = 'b' + new_variables = ['notb_'+x+'1' for x in N.indices] + B = N.orientnew(name, 'Axis', [q1, N.z], variables=new_variables) + + for j,var in enumerate(A.varlist): + assert var.name == A.name + '_' + A.indices[j] + + for j,var in enumerate(B.varlist): + assert var.name == new_variables[j] + +def test_issue_10348(): + u = dynamicsymbols('u:3') + I = ReferenceFrame('I') + I.orientnew('A', 'space', u, 'XYZ') + + +def test_issue_11503(): + A = ReferenceFrame("A") + A.orientnew("B", "Axis", [35, A.y]) + C = ReferenceFrame("C") + A.orient(C, "Axis", [70, C.z]) + + +def test_partial_velocity(): + + N = ReferenceFrame('N') + A = ReferenceFrame('A') + + u1, u2 = dynamicsymbols('u1, u2') + + A.set_ang_vel(N, u1 * A.x + u2 * N.y) + + assert N.partial_velocity(A, u1) == -A.x + assert N.partial_velocity(A, u1, u2) == (-A.x, -N.y) + + assert A.partial_velocity(N, u1) == A.x + assert A.partial_velocity(N, u1, u2) == (A.x, N.y) + + assert N.partial_velocity(N, u1) == 0 + assert A.partial_velocity(A, u1) == 0 + + +def test_issue_11498(): + A = ReferenceFrame('A') + B = ReferenceFrame('B') + + # Identity transformation + A.orient(B, 'DCM', eye(3)) + assert A.dcm(B) == Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + assert B.dcm(A) == Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + + # x -> y + # y -> -z + # z -> -x + A.orient(B, 'DCM', Matrix([[0, 1, 0], [0, 0, -1], [-1, 0, 0]])) + assert B.dcm(A) == Matrix([[0, 1, 0], [0, 0, -1], [-1, 0, 0]]) + assert A.dcm(B) == Matrix([[0, 0, -1], [1, 0, 0], [0, -1, 0]]) + assert B.dcm(A).T == A.dcm(B) + + +def test_reference_frame(): + raises(TypeError, lambda: ReferenceFrame(0)) + raises(TypeError, lambda: ReferenceFrame('N', 0)) + raises(ValueError, lambda: ReferenceFrame('N', [0, 1])) + raises(TypeError, lambda: ReferenceFrame('N', [0, 1, 2])) + raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], 0)) + raises(ValueError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], [0, 1])) + raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], [0, 1, 2])) + raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], + ['a', 'b', 'c'], 0)) + raises(ValueError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], + ['a', 'b', 'c'], [0, 1])) + raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], + ['a', 'b', 'c'], [0, 1, 2])) + N = ReferenceFrame('N') + assert N[0] == CoordinateSym('N_x', N, 0) + assert N[1] == CoordinateSym('N_y', N, 1) + assert N[2] == CoordinateSym('N_z', N, 2) + raises(ValueError, lambda: N[3]) + N = ReferenceFrame('N', ['a', 'b', 'c']) + assert N['a'] == N.x + assert N['b'] == N.y + assert N['c'] == N.z + raises(ValueError, lambda: N['d']) + assert str(N) == 'N' + + A = ReferenceFrame('A') + B = ReferenceFrame('B') + q0, q1, q2, q3 = symbols('q0 q1 q2 q3') + raises(TypeError, lambda: A.orient(B, 'DCM', 0)) + raises(TypeError, lambda: B.orient(N, 'Space', [q1, q2, q3], '222')) + raises(TypeError, lambda: B.orient(N, 'Axis', [q1, N.x + 2 * N.y], '222')) + raises(TypeError, lambda: B.orient(N, 'Axis', q1)) + raises(IndexError, lambda: B.orient(N, 'Axis', [q1])) + raises(TypeError, lambda: B.orient(N, 'Quaternion', [q0, q1, q2, q3], '222')) + raises(TypeError, lambda: B.orient(N, 'Quaternion', q0)) + raises(TypeError, lambda: B.orient(N, 'Quaternion', [q0, q1, q2])) + raises(NotImplementedError, lambda: B.orient(N, 'Foo', [q0, q1, q2])) + raises(TypeError, lambda: B.orient(N, 'Body', [q1, q2], '232')) + raises(TypeError, lambda: B.orient(N, 'Space', [q1, q2], '232')) + + N.set_ang_acc(B, 0) + assert N.ang_acc_in(B) == Vector(0) + N.set_ang_vel(B, 0) + assert N.ang_vel_in(B) == Vector(0) + + +def test_check_frame(): + raises(VectorTypeError, lambda: _check_frame(0)) + + +def test_dcm_diff_16824(): + # NOTE : This is a regression test for the bug introduced in PR 14758, + # identified in 16824, and solved by PR 16828. + + # This is the solution to Problem 2.2 on page 264 in Kane & Lenvinson's + # 1985 book. + + q1, q2, q3 = dynamicsymbols('q1:4') + + s1 = sin(q1) + c1 = cos(q1) + s2 = sin(q2) + c2 = cos(q2) + s3 = sin(q3) + c3 = cos(q3) + + dcm = Matrix([[c2*c3, s1*s2*c3 - s3*c1, c1*s2*c3 + s3*s1], + [c2*s3, s1*s2*s3 + c3*c1, c1*s2*s3 - c3*s1], + [-s2, s1*c2, c1*c2]]) + + A = ReferenceFrame('A') + B = ReferenceFrame('B') + B.orient(A, 'DCM', dcm) + + AwB = B.ang_vel_in(A) + + alpha2 = s3*c2*q1.diff() + c3*q2.diff() + beta2 = s1*c2*q3.diff() + c1*q2.diff() + + assert simplify(AwB.dot(A.y) - alpha2) == 0 + assert simplify(AwB.dot(B.y) - beta2) == 0 + +def test_orient_explicit(): + cxx, cyy, czz = dynamicsymbols('c_{xx}, c_{yy}, c_{zz}') + cxy, cxz, cyx = dynamicsymbols('c_{xy}, c_{xz}, c_{yx}') + cyz, czx, czy = dynamicsymbols('c_{yz}, c_{zx}, c_{zy}') + dcxx, dcyy, dczz = dynamicsymbols('c_{xx}, c_{yy}, c_{zz}', 1) + dcxy, dcxz, dcyx = dynamicsymbols('c_{xy}, c_{xz}, c_{yx}', 1) + dcyz, dczx, dczy = dynamicsymbols('c_{yz}, c_{zx}, c_{zy}', 1) + A = ReferenceFrame('A') + B = ReferenceFrame('B') + B_C_A = Matrix([[cxx, cxy, cxz], + [cyx, cyy, cyz], + [czx, czy, czz]]) + B_w_A = ((cyx*dczx + cyy*dczy + cyz*dczz)*B.x + + (czx*dcxx + czy*dcxy + czz*dcxz)*B.y + + (cxx*dcyx + cxy*dcyy + cxz*dcyz)*B.z) + A.orient_explicit(B, B_C_A) + assert B.dcm(A) == B_C_A + assert A.ang_vel_in(B) == B_w_A + assert B.ang_vel_in(A) == -B_w_A + +def test_orient_dcm(): + cxx, cyy, czz = dynamicsymbols('c_{xx}, c_{yy}, c_{zz}') + cxy, cxz, cyx = dynamicsymbols('c_{xy}, c_{xz}, c_{yx}') + cyz, czx, czy = dynamicsymbols('c_{yz}, c_{zx}, c_{zy}') + B_C_A = Matrix([[cxx, cxy, cxz], + [cyx, cyy, cyz], + [czx, czy, czz]]) + A = ReferenceFrame('A') + B = ReferenceFrame('B') + B.orient_dcm(A, B_C_A) + assert B.dcm(A) == Matrix([[cxx, cxy, cxz], + [cyx, cyy, cyz], + [czx, czy, czz]]) + +def test_orient_axis(): + A = ReferenceFrame('A') + B = ReferenceFrame('B') + A.orient_axis(B,-B.x, 1) + A1 = A.dcm(B) + A.orient_axis(B, B.x, -1) + A2 = A.dcm(B) + A.orient_axis(B, 1, -B.x) + A3 = A.dcm(B) + assert A1 == A2 + assert A2 == A3 + raises(TypeError, lambda: A.orient_axis(B, 1, 1)) + +def test_orient_body(): + A = ReferenceFrame('A') + B = ReferenceFrame('B') + B.orient_body_fixed(A, (1,1,0), 'XYX') + assert B.dcm(A) == Matrix([[cos(1), sin(1)**2, -sin(1)*cos(1)], [0, cos(1), sin(1)], [sin(1), -sin(1)*cos(1), cos(1)**2]]) + + +def test_orient_body_advanced(): + q1, q2, q3 = dynamicsymbols('q1:4') + c1, c2, c3 = symbols('c1:4') + u1, u2, u3 = dynamicsymbols('q1:4', 1) + + # Test with everything as dynamicsymbols + A, B = ReferenceFrame('A'), ReferenceFrame('B') + B.orient_body_fixed(A, (q1, q2, q3), 'zxy') + assert A.dcm(B) == Matrix([ + [-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), cos(q2) * cos(q3)]]) + assert B.ang_vel_in(A).to_matrix(B) == Matrix([ + [-sin(q3) * cos(q2) * u1 + cos(q3) * u2], + [sin(q2) * u1 + u3], + [sin(q3) * u2 + cos(q2) * cos(q3) * u1]]) + + # Test with constant symbol + A, B = ReferenceFrame('A'), ReferenceFrame('B') + B.orient_body_fixed(A, (q1, c2, q3), 131) + assert A.dcm(B) == Matrix([ + [cos(c2), -sin(c2) * cos(q3), sin(c2) * sin(q3)], + [sin(c2) * cos(q1), -sin(q1) * sin(q3) + cos(c2) * cos(q1) * cos(q3), + -sin(q1) * cos(q3) - sin(q3) * cos(c2) * cos(q1)], + [sin(c2) * sin(q1), sin(q1) * cos(c2) * cos(q3) + sin(q3) * cos(q1), + -sin(q1) * sin(q3) * cos(c2) + cos(q1) * cos(q3)]]) + assert B.ang_vel_in(A).to_matrix(B) == Matrix([ + [cos(c2) * u1 + u3], + [-sin(c2) * cos(q3) * u1], + [sin(c2) * sin(q3) * u1]]) + + # Test all symbols not time dependent + A, B = ReferenceFrame('A'), ReferenceFrame('B') + B.orient_body_fixed(A, (c1, c2, c3), 123) + assert B.ang_vel_in(A) == Vector(0) + + +def test_orient_space_advanced(): + # space fixed is in the end like body fixed only in opposite order + q1, q2, q3 = dynamicsymbols('q1:4') + c1, c2, c3 = symbols('c1:4') + u1, u2, u3 = dynamicsymbols('q1:4', 1) + + # Test with everything as dynamicsymbols + A, B = ReferenceFrame('A'), ReferenceFrame('B') + B.orient_space_fixed(A, (q3, q2, q1), 'yxz') + assert A.dcm(B) == Matrix([ + [-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), cos(q2) * cos(q3)]]) + assert B.ang_vel_in(A).to_matrix(B) == Matrix([ + [-sin(q3) * cos(q2) * u1 + cos(q3) * u2], + [sin(q2) * u1 + u3], + [sin(q3) * u2 + cos(q2) * cos(q3) * u1]]) + + # Test with constant symbol + A, B = ReferenceFrame('A'), ReferenceFrame('B') + B.orient_space_fixed(A, (q3, c2, q1), 131) + assert A.dcm(B) == Matrix([ + [cos(c2), -sin(c2) * cos(q3), sin(c2) * sin(q3)], + [sin(c2) * cos(q1), -sin(q1) * sin(q3) + cos(c2) * cos(q1) * cos(q3), + -sin(q1) * cos(q3) - sin(q3) * cos(c2) * cos(q1)], + [sin(c2) * sin(q1), sin(q1) * cos(c2) * cos(q3) + sin(q3) * cos(q1), + -sin(q1) * sin(q3) * cos(c2) + cos(q1) * cos(q3)]]) + assert B.ang_vel_in(A).to_matrix(B) == Matrix([ + [cos(c2) * u1 + u3], + [-sin(c2) * cos(q3) * u1], + [sin(c2) * sin(q3) * u1]]) + + # Test all symbols not time dependent + A, B = ReferenceFrame('A'), ReferenceFrame('B') + B.orient_space_fixed(A, (c1, c2, c3), 123) + assert B.ang_vel_in(A) == Vector(0) + + +def test_orient_body_simple_ang_vel(): + """This test ensures that the simplest form of that linear system solution + is returned, thus the == for the expression comparison.""" + + psi, theta, phi = dynamicsymbols('psi, theta, varphi') + t = dynamicsymbols._t + A = ReferenceFrame('A') + B = ReferenceFrame('B') + B.orient_body_fixed(A, (psi, theta, phi), 'ZXZ') + A_w_B = B.ang_vel_in(A) + assert A_w_B.args[0][1] == B + assert A_w_B.args[0][0][0] == (sin(theta)*sin(phi)*psi.diff(t) + + cos(phi)*theta.diff(t)) + assert A_w_B.args[0][0][1] == (sin(theta)*cos(phi)*psi.diff(t) - + sin(phi)*theta.diff(t)) + assert A_w_B.args[0][0][2] == cos(theta)*psi.diff(t) + phi.diff(t) + + +def test_orient_space(): + A = ReferenceFrame('A') + B = ReferenceFrame('B') + B.orient_space_fixed(A, (0,0,0), '123') + assert B.dcm(A) == Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + +def test_orient_quaternion(): + A = ReferenceFrame('A') + B = ReferenceFrame('B') + B.orient_quaternion(A, (0,0,0,0)) + assert B.dcm(A) == Matrix([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) + +def test_looped_frame_warning(): + A = ReferenceFrame('A') + B = ReferenceFrame('B') + C = ReferenceFrame('C') + + a, b, c = symbols('a b c') + B.orient_axis(A, A.x, a) + C.orient_axis(B, B.x, b) + + with warnings.catch_warnings(record = True) as w: + warnings.simplefilter("always") + A.orient_axis(C, C.x, c) + assert issubclass(w[-1].category, UserWarning) + assert 'Loops are defined among the orientation of frames. ' + \ + 'This is likely not desired and may cause errors in your calculations.' in str(w[-1].message) + +def test_frame_dict(): + A = ReferenceFrame('A') + B = ReferenceFrame('B') + C = ReferenceFrame('C') + + a, b, c = symbols('a b c') + + B.orient_axis(A, A.x, a) + assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(a), -sin(a)],[0, sin(a), cos(a)]])} + assert B._dcm_dict == {A: Matrix([[1, 0, 0],[0, cos(a), sin(a)],[0, -sin(a), cos(a)]])} + assert C._dcm_dict == {} + + B.orient_axis(C, C.x, b) + # Previous relation is not wiped + assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(a), -sin(a)],[0, sin(a), cos(a)]])} + assert B._dcm_dict == {A: Matrix([[1, 0, 0],[0, cos(a), sin(a)],[0, -sin(a), cos(a)]]), \ + C: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]])} + assert C._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])} + + A.orient_axis(B, B.x, c) + # Previous relation is updated + assert B._dcm_dict == {C: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]]),\ + A: Matrix([[1, 0, 0],[0, cos(c), -sin(c)],[0, sin(c), cos(c)]])} + assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(c), sin(c)],[0, -sin(c), cos(c)]])} + assert C._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])} + +def test_dcm_cache_dict(): + A = ReferenceFrame('A') + B = ReferenceFrame('B') + C = ReferenceFrame('C') + D = ReferenceFrame('D') + + a, b, c = symbols('a b c') + + B.orient_axis(A, A.x, a) + C.orient_axis(B, B.x, b) + D.orient_axis(C, C.x, c) + + assert D._dcm_dict == {C: Matrix([[1, 0, 0],[0, cos(c), sin(c)],[0, -sin(c), cos(c)]])} + assert C._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]]), \ + D: Matrix([[1, 0, 0],[0, cos(c), -sin(c)],[0, sin(c), cos(c)]])} + assert B._dcm_dict == {A: Matrix([[1, 0, 0],[0, cos(a), sin(a)],[0, -sin(a), cos(a)]]), \ + C: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])} + assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(a), -sin(a)],[0, sin(a), cos(a)]])} + + assert D._dcm_dict == D._dcm_cache + + D.dcm(A) # Check calculated dcm relation is stored in _dcm_cache and not in _dcm_dict + assert list(A._dcm_cache.keys()) == [A, B, D] + assert list(D._dcm_cache.keys()) == [C, A] + assert list(A._dcm_dict.keys()) == [B] + assert list(D._dcm_dict.keys()) == [C] + assert A._dcm_dict != A._dcm_cache + + A.orient_axis(B, B.x, b) # _dcm_cache of A is wiped out and new relation is stored. + assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]])} + assert A._dcm_dict == A._dcm_cache + assert B._dcm_dict == {C: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]]), \ + A: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])} + +def test_xx_dyad(): + N = ReferenceFrame('N') + F = ReferenceFrame('F', indices=['1', '2', '3']) + assert N.xx == Vector.outer(N.x, N.x) + assert F.xx == Vector.outer(F.x, F.x) + +def test_xy_dyad(): + N = ReferenceFrame('N') + F = ReferenceFrame('F', indices=['1', '2', '3']) + assert N.xy == Vector.outer(N.x, N.y) + assert F.xy == Vector.outer(F.x, F.y) + +def test_xz_dyad(): + N = ReferenceFrame('N') + F = ReferenceFrame('F', indices=['1', '2', '3']) + assert N.xz == Vector.outer(N.x, N.z) + assert F.xz == Vector.outer(F.x, F.z) + +def test_yx_dyad(): + N = ReferenceFrame('N') + F = ReferenceFrame('F', indices=['1', '2', '3']) + assert N.yx == Vector.outer(N.y, N.x) + assert F.yx == Vector.outer(F.y, F.x) + +def test_yy_dyad(): + N = ReferenceFrame('N') + F = ReferenceFrame('F', indices=['1', '2', '3']) + assert N.yy == Vector.outer(N.y, N.y) + assert F.yy == Vector.outer(F.y, F.y) + +def test_yz_dyad(): + N = ReferenceFrame('N') + F = ReferenceFrame('F', indices=['1', '2', '3']) + assert N.yz == Vector.outer(N.y, N.z) + assert F.yz == Vector.outer(F.y, F.z) + +def test_zx_dyad(): + N = ReferenceFrame('N') + F = ReferenceFrame('F', indices=['1', '2', '3']) + assert N.zx == Vector.outer(N.z, N.x) + assert F.zx == Vector.outer(F.z, F.x) + +def test_zy_dyad(): + N = ReferenceFrame('N') + F = ReferenceFrame('F', indices=['1', '2', '3']) + assert N.zy == Vector.outer(N.z, N.y) + assert F.zy == Vector.outer(F.z, F.y) + +def test_zz_dyad(): + N = ReferenceFrame('N') + F = ReferenceFrame('F', indices=['1', '2', '3']) + assert N.zz == Vector.outer(N.z, N.z) + assert F.zz == Vector.outer(F.z, F.z) + +def test_unit_dyadic(): + N = ReferenceFrame('N') + F = ReferenceFrame('F', indices=['1', '2', '3']) + assert N.u == N.xx + N.yy + N.zz + assert F.u == F.xx + F.yy + F.zz + + +def test_pickle_frame(): + N = ReferenceFrame('N') + A = ReferenceFrame('A') + A.orient_axis(N, N.x, 1) + A_C_N = A.dcm(N) + N1 = pickle.loads(pickle.dumps(N)) + A1 = tuple(N1._dcm_dict.keys())[0] + assert A1.dcm(N1) == A_C_N diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_functions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_functions.py new file mode 100644 index 0000000000000000000000000000000000000000..ff938da980c4bbd51d378b30fd5310a88e528e97 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_functions.py @@ -0,0 +1,509 @@ +from sympy.core.numbers import pi +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.integrals.integrals import Integral +from sympy.physics.vector import Dyadic, Point, ReferenceFrame, Vector +from sympy.physics.vector.functions import (cross, dot, express, + time_derivative, + kinematic_equations, outer, + partial_velocity, + get_motion_params, dynamicsymbols) +from sympy.simplify import trigsimp +from sympy.testing.pytest import raises + +q1, q2, q3, q4, q5 = symbols('q1 q2 q3 q4 q5') +N = ReferenceFrame('N') +A = N.orientnew('A', 'Axis', [q1, N.z]) +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 + assert dot(A.x, A.z) == 0 + + assert dot(A.y, A.x) == 0 + assert dot(A.y, A.y) == 1 + assert dot(A.y, A.z) == 0 + + assert dot(A.z, A.x) == 0 + assert dot(A.z, A.y) == 0 + assert dot(A.z, A.z) == 1 + + +def test_dot_different_frames(): + assert dot(N.x, A.x) == cos(q1) + assert dot(N.x, A.y) == -sin(q1) + assert dot(N.x, A.z) == 0 + assert dot(N.y, A.x) == sin(q1) + assert dot(N.y, A.y) == cos(q1) + assert dot(N.y, A.z) == 0 + assert dot(N.z, A.x) == 0 + assert dot(N.z, A.y) == 0 + assert dot(N.z, A.z) == 1 + + assert trigsimp(dot(N.x, A.x + A.y)) == sqrt(2)*cos(q1 + pi/4) + assert trigsimp(dot(N.x, A.x + A.y)) == trigsimp(dot(A.x + A.y, N.x)) + + assert dot(A.x, C.x) == cos(q3) + assert dot(A.x, C.y) == 0 + assert dot(A.x, C.z) == sin(q3) + assert dot(A.y, C.x) == sin(q2)*sin(q3) + assert dot(A.y, C.y) == cos(q2) + assert dot(A.y, C.z) == -sin(q2)*cos(q3) + assert dot(A.z, C.x) == -cos(q2)*sin(q3) + assert dot(A.z, C.y) == sin(q2) + assert dot(A.z, C.z) == cos(q2)*cos(q3) + + +def test_cross(): + assert cross(A.x, A.x) == 0 + assert cross(A.x, A.y) == A.z + assert cross(A.x, A.z) == -A.y + + assert cross(A.y, A.x) == -A.z + assert cross(A.y, A.y) == 0 + assert cross(A.y, A.z) == A.x + + assert cross(A.z, A.x) == A.y + 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.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.z, A.x) == A.y + assert cross(N.z, A.y) == -A.x + assert cross(N.z, A.z) == 0 + + 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.x + A.y) == sin(q1)*A.z + cos(q1)*A.z + assert cross(A.x + A.y, N.x) == -sin(q1)*A.z - cos(q1)*A.z + + assert cross(A.x, C.x) == sin(q3)*C.y + assert cross(A.x, C.y) == -sin(q3)*C.x + cos(q3)*C.z + assert cross(A.x, C.z) == -cos(q3)*C.y + assert cross(C.x, A.x) == -sin(q3)*C.y + assert cross(C.y, A.x).express(C).simplify() == sin(q3)*C.x - cos(q3)*C.z + assert cross(C.z, A.x) == cos(q3)*C.y + +def test_operator_match(): + """Test that the output of dot, cross, outer functions match + operator behavior. + """ + A = ReferenceFrame('A') + v = A.x + A.y + d = v | v + zerov = Vector(0) + zerod = Dyadic(0) + + # dot products + assert d & d == dot(d, d) + assert d & zerod == dot(d, zerod) + assert zerod & d == dot(zerod, d) + assert d & v == dot(d, v) + assert v & d == dot(v, d) + assert d & zerov == dot(d, zerov) + assert zerov & d == dot(zerov, d) + raises(TypeError, lambda: dot(d, S.Zero)) + raises(TypeError, lambda: dot(S.Zero, d)) + raises(TypeError, lambda: dot(d, 0)) + raises(TypeError, lambda: dot(0, d)) + assert v & v == dot(v, v) + assert v & zerov == dot(v, zerov) + assert zerov & v == dot(zerov, v) + raises(TypeError, lambda: dot(v, S.Zero)) + raises(TypeError, lambda: dot(S.Zero, v)) + raises(TypeError, lambda: dot(v, 0)) + raises(TypeError, lambda: dot(0, v)) + + # cross products + raises(TypeError, lambda: cross(d, d)) + raises(TypeError, lambda: cross(d, zerod)) + raises(TypeError, lambda: cross(zerod, d)) + assert d ^ v == cross(d, v) + assert v ^ d == cross(v, d) + assert d ^ zerov == cross(d, zerov) + assert zerov ^ d == cross(zerov, d) + assert zerov ^ d == cross(zerov, d) + raises(TypeError, lambda: cross(d, S.Zero)) + raises(TypeError, lambda: cross(S.Zero, d)) + raises(TypeError, lambda: cross(d, 0)) + raises(TypeError, lambda: cross(0, d)) + assert v ^ v == cross(v, v) + assert v ^ zerov == cross(v, zerov) + assert zerov ^ v == cross(zerov, v) + raises(TypeError, lambda: cross(v, S.Zero)) + raises(TypeError, lambda: cross(S.Zero, v)) + raises(TypeError, lambda: cross(v, 0)) + raises(TypeError, lambda: cross(0, v)) + + # outer products + raises(TypeError, lambda: outer(d, d)) + raises(TypeError, lambda: outer(d, zerod)) + raises(TypeError, lambda: outer(zerod, d)) + raises(TypeError, lambda: outer(d, v)) + raises(TypeError, lambda: outer(v, d)) + raises(TypeError, lambda: outer(d, zerov)) + raises(TypeError, lambda: outer(zerov, d)) + raises(TypeError, lambda: outer(zerov, d)) + raises(TypeError, lambda: outer(d, S.Zero)) + raises(TypeError, lambda: outer(S.Zero, d)) + raises(TypeError, lambda: outer(d, 0)) + raises(TypeError, lambda: outer(0, d)) + assert v | v == outer(v, v) + assert v | zerov == outer(v, zerov) + assert zerov | v == outer(zerov, v) + raises(TypeError, lambda: outer(v, S.Zero)) + raises(TypeError, lambda: outer(S.Zero, v)) + raises(TypeError, lambda: outer(v, 0)) + raises(TypeError, lambda: outer(0, v)) + + +def test_express(): + assert express(Vector(0), N) == Vector(0) + assert express(S.Zero, N) is S.Zero + 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 + assert express(A.z, C) == -sin(q3)*cos(q2)*C.x + sin(q2)*C.y + \ + 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 + assert express(A.x, A) == A.x + assert express(A.y, A) == A.y + assert express(A.z, A) == A.z + assert express(A.x, B) == B.x + assert express(A.y, B) == cos(q2)*B.y - sin(q2)*B.z + 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 + assert express(A.z, C) == -sin(q3)*cos(q2)*C.x + sin(q2)*C.y + \ + 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 + assert express(N.z, N) == N.z + 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 + + sin(q1)*sin(q2)*B.z) + 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) + 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) + assert express(N.z, C) == (-sin(q3)*cos(q2)*C.x + sin(q2)*C.y + + 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 + assert express(A.x, A) == A.x + assert express(A.y, A) == A.y + assert express(A.z, A) == A.z + assert express(A.x, B) == B.x + assert express(A.y, B) == (cos(q2)*B.y - sin(q2)*B.z) + 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) + assert express(A.z, C) == (-sin(q3)*cos(q2)*C.x + sin(q2)*C.y + + cos(q2)*cos(q3)*C.z) + + assert express(B.x, N) == (cos(q1)*N.x + sin(q1)*N.y) + assert express(B.y, N) == (-sin(q1)*cos(q2)*N.x + + cos(q1)*cos(q2)*N.y + sin(q2)*N.z) + assert express(B.z, N) == (sin(q1)*sin(q2)*N.x - + sin(q2)*cos(q1)*N.y + cos(q2)*N.z) + assert express(B.x, A) == A.x + assert express(B.y, A) == (cos(q2)*A.y + sin(q2)*A.z) + assert express(B.z, A) == (-sin(q2)*A.y + cos(q2)*A.z) + assert express(B.x, B) == B.x + assert express(B.y, B) == B.y + assert express(B.z, B) == B.z + assert express(B.x, C) == (cos(q3)*C.x + sin(q3)*C.z) + assert express(B.y, C) == C.y + 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) + assert express(C.y, N) == ( + -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) + 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) + assert express(C.z, A) == (sin(q3)*A.x - sin(q2)*cos(q3)*A.y + + cos(q2)*cos(q3)*A.z) + assert express(C.x, B) == (cos(q3)*B.x - sin(q3)*B.z) + assert express(C.y, B) == B.y + assert express(C.z, B) == (sin(q3)*B.x + cos(q3)*B.z) + assert express(C.x, C) == C.x + assert express(C.y, C) == C.y + assert express(C.z, C) == C.z == (C.z) + + # Check to make sure Vectors get converted back to UnitVectors + assert N.x == express((cos(q1)*A.x - sin(q1)*A.y), N).simplify() + assert N.y == express((sin(q1)*A.x + cos(q1)*A.y), N).simplify() + assert N.x == express((cos(q1)*B.x - sin(q1)*cos(q2)*B.y + + sin(q1)*sin(q2)*B.z), N).simplify() + assert N.y == express((sin(q1)*B.x + cos(q1)*cos(q2)*B.y - + sin(q2)*cos(q1)*B.z), N).simplify() + assert N.z == express((sin(q2)*B.y + cos(q2)*B.z), N).simplify() + + """ + These don't really test our code, they instead test the auto simplification + (or lack thereof) of SymPy. + assert N.x == express(( + (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), N) + assert N.y == express(( + (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), N) + assert N.z == express((-sin(q3)*cos(q2)*C.x + sin(q2)*C.y + + cos(q2)*cos(q3)*C.z), N) + """ + + assert A.x == express((cos(q1)*N.x + sin(q1)*N.y), A).simplify() + assert A.y == express((-sin(q1)*N.x + cos(q1)*N.y), A).simplify() + + assert A.y == express((cos(q2)*B.y - sin(q2)*B.z), A).simplify() + assert A.z == express((sin(q2)*B.y + cos(q2)*B.z), A).simplify() + + assert A.x == express((cos(q3)*C.x + sin(q3)*C.z), A).simplify() + + # Tripsimp messes up here too. + #print express((sin(q2)*sin(q3)*C.x + cos(q2)*C.y - + # sin(q2)*cos(q3)*C.z), A) + assert A.y == express((sin(q2)*sin(q3)*C.x + cos(q2)*C.y - + sin(q2)*cos(q3)*C.z), A).simplify() + + assert A.z == express((-sin(q3)*cos(q2)*C.x + sin(q2)*C.y + + cos(q2)*cos(q3)*C.z), A).simplify() + assert B.x == express((cos(q1)*N.x + sin(q1)*N.y), B).simplify() + assert B.y == express((-sin(q1)*cos(q2)*N.x + + cos(q1)*cos(q2)*N.y + sin(q2)*N.z), B).simplify() + + assert B.z == express((sin(q1)*sin(q2)*N.x - + sin(q2)*cos(q1)*N.y + cos(q2)*N.z), B).simplify() + + assert B.y == express((cos(q2)*A.y + sin(q2)*A.z), B).simplify() + assert B.z == express((-sin(q2)*A.y + cos(q2)*A.z), B).simplify() + assert B.x == express((cos(q3)*C.x + sin(q3)*C.z), B).simplify() + assert B.z == express((-sin(q3)*C.x + cos(q3)*C.z), B).simplify() + + """ + assert C.x == express(( + (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), C) + assert C.y == express(( + -sin(q1)*cos(q2)*N.x + cos(q1)*cos(q2)*N.y + sin(q2)*N.z), C) + assert C.z == express(( + (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), C) + """ + assert C.x == express((cos(q3)*A.x + sin(q2)*sin(q3)*A.y - + sin(q3)*cos(q2)*A.z), C).simplify() + assert C.y == express((cos(q2)*A.y + sin(q2)*A.z), C).simplify() + assert C.z == express((sin(q3)*A.x - sin(q2)*cos(q3)*A.y + + cos(q2)*cos(q3)*A.z), C).simplify() + assert C.x == express((cos(q3)*B.x - sin(q3)*B.z), C).simplify() + assert C.z == express((sin(q3)*B.x + cos(q3)*B.z), C).simplify() + + +def test_time_derivative(): + #The use of time_derivative for calculations pertaining to scalar + #fields has been tested in test_coordinate_vars in test_essential.py + A = ReferenceFrame('A') + q = dynamicsymbols('q') + qd = dynamicsymbols('q', 1) + B = A.orientnew('B', 'Axis', [q, A.z]) + d = A.x | A.x + assert time_derivative(d, B) == (-qd) * (A.y | A.x) + \ + (-qd) * (A.x | A.y) + d1 = A.x | B.y + assert time_derivative(d1, A) == - qd*(A.x|B.x) + assert time_derivative(d1, B) == - qd*(A.y|B.y) + d2 = A.x | B.x + assert time_derivative(d2, A) == qd*(A.x|B.y) + assert time_derivative(d2, B) == - qd*(A.y|B.x) + d3 = A.x | B.z + assert time_derivative(d3, A) == 0 + assert time_derivative(d3, B) == - qd*(A.y|B.z) + q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') + q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1) + q1dd, q2dd, q3dd, q4dd = dynamicsymbols('q1 q2 q3 q4', 2) + C = B.orientnew('C', 'Axis', [q4, B.x]) + v1 = q1 * A.z + v2 = q2*A.x + q3*B.y + v3 = q1*A.x + q2*A.y + q3*A.z + assert time_derivative(B.x, C) == 0 + assert time_derivative(B.y, C) == - q4d*B.z + assert time_derivative(B.z, C) == q4d*B.y + assert time_derivative(v1, B) == q1d*A.z + assert time_derivative(v1, C) == - q1*sin(q)*q4d*A.x + \ + q1*cos(q)*q4d*A.y + q1d*A.z + assert time_derivative(v2, A) == q2d*A.x - q3*qd*B.x + q3d*B.y + assert time_derivative(v2, C) == q2d*A.x - q2*qd*A.y + \ + q2*sin(q)*q4d*A.z + q3d*B.y - q3*q4d*B.z + assert time_derivative(v3, B) == (q2*qd + q1d)*A.x + \ + (-q1*qd + q2d)*A.y + q3d*A.z + assert time_derivative(d, C) == - qd*(A.y|A.x) + \ + sin(q)*q4d*(A.z|A.x) - qd*(A.x|A.y) + sin(q)*q4d*(A.x|A.z) + raises(ValueError, lambda: time_derivative(B.x, C, order=0.5)) + raises(ValueError, lambda: time_derivative(B.x, C, order=-1)) + + +def test_get_motion_methods(): + #Initialization + t = dynamicsymbols._t + s1, s2, s3 = symbols('s1 s2 s3') + S1, S2, S3 = symbols('S1 S2 S3') + S4, S5, S6 = symbols('S4 S5 S6') + t1, t2 = symbols('t1 t2') + a, b, c = dynamicsymbols('a b c') + ad, bd, cd = dynamicsymbols('a b c', 1) + a2d, b2d, c2d = dynamicsymbols('a b c', 2) + v0 = S1*N.x + S2*N.y + S3*N.z + v01 = S4*N.x + S5*N.y + S6*N.z + v1 = s1*N.x + s2*N.y + s3*N.z + v2 = a*N.x + b*N.y + c*N.z + v2d = ad*N.x + bd*N.y + cd*N.z + v2dd = a2d*N.x + b2d*N.y + c2d*N.z + #Test position parameter + assert get_motion_params(frame = N) == (0, 0, 0) + assert get_motion_params(N, position=v1) == (0, 0, v1) + assert get_motion_params(N, position=v2) == (v2dd, v2d, v2) + #Test velocity parameter + assert get_motion_params(N, velocity=v1) == (0, v1, v1 * t) + assert get_motion_params(N, velocity=v1, position=v0, timevalue1=t1) == \ + (0, v1, v0 + v1*(t - t1)) + answer = get_motion_params(N, velocity=v1, position=v2, timevalue1=t1) + answer_expected = (0, v1, v1*t - v1*t1 + v2.subs(t, t1)) + assert answer == answer_expected + + answer = get_motion_params(N, velocity=v2, position=v0, timevalue1=t1) + integral_vector = Integral(a, (t, t1, t))*N.x + Integral(b, (t, t1, t))*N.y \ + + Integral(c, (t, t1, t))*N.z + answer_expected = (v2d, v2, v0 + integral_vector) + assert answer == answer_expected + + #Test acceleration parameter + assert get_motion_params(N, acceleration=v1) == \ + (v1, v1 * t, v1 * t**2/2) + assert get_motion_params(N, acceleration=v1, velocity=v0, + position=v2, timevalue1=t1, timevalue2=t2) == \ + (v1, (v0 + v1*t - v1*t2), + -v0*t1 + v1*t**2/2 + v1*t2*t1 - \ + v1*t1**2/2 + t*(v0 - v1*t2) + \ + v2.subs(t, t1)) + assert get_motion_params(N, acceleration=v1, velocity=v0, + position=v01, timevalue1=t1, timevalue2=t2) == \ + (v1, v0 + v1*t - v1*t2, + -v0*t1 + v01 + v1*t**2/2 + \ + v1*t2*t1 - v1*t1**2/2 + \ + t*(v0 - v1*t2)) + answer = get_motion_params(N, acceleration=a*N.x, velocity=S1*N.x, + position=S2*N.x, timevalue1=t1, timevalue2=t2) + i1 = Integral(a, (t, t2, t)) + answer_expected = (a*N.x, (S1 + i1)*N.x, \ + (S2 + Integral(S1 + i1, (t, t1, t)))*N.x) + assert answer == answer_expected + + +def test_kin_eqs(): + q0, q1, q2, q3 = dynamicsymbols('q0 q1 q2 q3') + q0d, q1d, q2d, q3d = dynamicsymbols('q0 q1 q2 q3', 1) + u1, u2, u3 = dynamicsymbols('u1 u2 u3') + ke = kinematic_equations([u1,u2,u3], [q1,q2,q3], 'body', 313) + assert ke == kinematic_equations([u1,u2,u3], [q1,q2,q3], 'body', '313') + kds = kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'quaternion') + assert kds == [-0.5 * q0 * u1 - 0.5 * q2 * u3 + 0.5 * q3 * u2 + q1d, + -0.5 * q0 * u2 + 0.5 * q1 * u3 - 0.5 * q3 * u1 + q2d, + -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] + raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2], 'quaternion')) + raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'quaternion', '123')) + raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'foo')) + raises(TypeError, lambda: kinematic_equations(u1, [q0, q1, q2, q3], 'quaternion')) + raises(TypeError, lambda: kinematic_equations([u1], [q0, q1, q2, q3], 'quaternion')) + raises(TypeError, lambda: kinematic_equations([u1, u2, u3], q0, 'quaternion')) + raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'body')) + raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'space')) + raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2], 'body', '222')) + assert kinematic_equations([0, 0, 0], [q0, q1, q2], 'space') == [S.Zero, S.Zero, S.Zero] + + +def test_partial_velocity(): + q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') + u4, u5 = dynamicsymbols('u4, u5') + r = symbols('r') + + 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) + + C = Point('C') + C.set_vel(N, u4 * L.x + u5 * (Y.z ^ L.x)) + Dmc = C.locatenew('Dmc', r * L.z) + Dmc.v2pt_theory(C, N, R) + + vel_list = [Dmc.vel(N), C.vel(N), R.ang_vel_in(N)] + u_list = [u1, u2, u3, u4, u5] + assert (partial_velocity(vel_list, u_list, N) == + [[- r*L.y, r*L.x, 0, L.x, cos(q2)*L.y - sin(q2)*L.z], + [0, 0, 0, L.x, cos(q2)*L.y - sin(q2)*L.z], + [L.x, L.y, L.z, 0, 0]]) + + # Make sure that partial velocities can be computed regardless if the + # orientation between frames is defined or not. + A = ReferenceFrame('A') + B = ReferenceFrame('B') + v = u4 * A.x + u5 * B.y + assert partial_velocity((v, ), (u4, u5), A) == [[A.x, B.y]] + + raises(TypeError, lambda: partial_velocity(Dmc.vel(N), u_list, N)) + raises(TypeError, lambda: partial_velocity(vel_list, u1, N)) + +def test_dynamicsymbols(): + #Tests to check the assumptions applied to dynamicsymbols + f1 = dynamicsymbols('f1') + f2 = dynamicsymbols('f2', real=True) + f3 = dynamicsymbols('f3', positive=True) + f4, f5 = dynamicsymbols('f4,f5', commutative=False) + f6 = dynamicsymbols('f6', integer=True) + assert f1.is_real is None + assert f2.is_real + assert f3.is_positive + assert f4*f5 != f5*f4 + assert f6.is_integer diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_output.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_output.py new file mode 100644 index 0000000000000000000000000000000000000000..e02f3e5962bc23bbb62929e343a5afac574a2570 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_output.py @@ -0,0 +1,75 @@ +from sympy.core.singleton import S +from sympy.physics.vector import Vector, ReferenceFrame, Dyadic +from sympy.testing.pytest import raises + +A = ReferenceFrame('A') + + +def test_output_type(): + A = ReferenceFrame('A') + v = A.x + A.y + d = v | v + zerov = Vector(0) + zerod = Dyadic(0) + + # dot products + assert isinstance(d & d, Dyadic) + assert isinstance(d & zerod, Dyadic) + assert isinstance(zerod & d, Dyadic) + assert isinstance(d & v, Vector) + assert isinstance(v & d, Vector) + assert isinstance(d & zerov, Vector) + assert isinstance(zerov & d, Vector) + raises(TypeError, lambda: d & S.Zero) + raises(TypeError, lambda: S.Zero & d) + raises(TypeError, lambda: d & 0) + raises(TypeError, lambda: 0 & d) + assert not isinstance(v & v, (Vector, Dyadic)) + assert not isinstance(v & zerov, (Vector, Dyadic)) + assert not isinstance(zerov & v, (Vector, Dyadic)) + raises(TypeError, lambda: v & S.Zero) + raises(TypeError, lambda: S.Zero & v) + raises(TypeError, lambda: v & 0) + raises(TypeError, lambda: 0 & v) + + # cross products + raises(TypeError, lambda: d ^ d) + raises(TypeError, lambda: d ^ zerod) + raises(TypeError, lambda: zerod ^ d) + assert isinstance(d ^ v, Dyadic) + assert isinstance(v ^ d, Dyadic) + assert isinstance(d ^ zerov, Dyadic) + assert isinstance(zerov ^ d, Dyadic) + assert isinstance(zerov ^ d, Dyadic) + raises(TypeError, lambda: d ^ S.Zero) + raises(TypeError, lambda: S.Zero ^ d) + raises(TypeError, lambda: d ^ 0) + raises(TypeError, lambda: 0 ^ d) + assert isinstance(v ^ v, Vector) + assert isinstance(v ^ zerov, Vector) + assert isinstance(zerov ^ v, Vector) + raises(TypeError, lambda: v ^ S.Zero) + raises(TypeError, lambda: S.Zero ^ v) + raises(TypeError, lambda: v ^ 0) + raises(TypeError, lambda: 0 ^ v) + + # outer products + raises(TypeError, lambda: d | d) + raises(TypeError, lambda: d | zerod) + raises(TypeError, lambda: zerod | d) + raises(TypeError, lambda: d | v) + raises(TypeError, lambda: v | d) + raises(TypeError, lambda: d | zerov) + raises(TypeError, lambda: zerov | d) + raises(TypeError, lambda: zerov | d) + raises(TypeError, lambda: d | S.Zero) + raises(TypeError, lambda: S.Zero | d) + raises(TypeError, lambda: d | 0) + raises(TypeError, lambda: 0 | d) + assert isinstance(v | v, Dyadic) + assert isinstance(v | zerov, Dyadic) + assert isinstance(zerov | v, Dyadic) + raises(TypeError, lambda: v | S.Zero) + raises(TypeError, lambda: S.Zero | v) + raises(TypeError, lambda: v | 0) + raises(TypeError, lambda: 0 | v) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_point.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_point.py new file mode 100644 index 0000000000000000000000000000000000000000..0e0c8b092ef61c590d3c713cef25feb3e64051c6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_point.py @@ -0,0 +1,382 @@ +from sympy.physics.vector import dynamicsymbols, Point, ReferenceFrame +from sympy.testing.pytest import raises, ignore_warnings +import warnings + +def test_point_v1pt_theorys(): + q, q2 = dynamicsymbols('q q2') + qd, q2d = dynamicsymbols('q q2', 1) + qdd, q2dd = dynamicsymbols('q q2', 2) + N = ReferenceFrame('N') + B = ReferenceFrame('B') + B.set_ang_vel(N, qd * B.z) + O = Point('O') + P = O.locatenew('P', B.x) + P.set_vel(B, 0) + O.set_vel(N, 0) + assert P.v1pt_theory(O, N, B) == qd * B.y + O.set_vel(N, N.x) + assert P.v1pt_theory(O, N, B) == N.x + qd * B.y + 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) + qdd, q2dd = dynamicsymbols('q q2', 2) + N = ReferenceFrame('N') + B = ReferenceFrame('B') + B.set_ang_vel(N, qd * B.z) + O = Point('O') + 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 + 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) + N = ReferenceFrame('N') + B = N.orientnew('B', 'Axis', [q, N.z]) + O = Point('O') + P = O.locatenew('P', 0) + O.set_vel(N, 0) + assert P.v2pt_theory(O, N, B) == 0 + P = O.locatenew('P', B.x) + assert P.v2pt_theory(O, N, B) == (qd * B.z ^ B.x) + 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) + qdd = dynamicsymbols('q', 2) + N = ReferenceFrame('N') + B = N.orientnew('B', 'Axis', [q, N.z]) + O = Point('O') + P = O.locatenew('P', 0) + O.set_vel(N, 0) + assert P.a2pt_theory(O, N, B) == 0 + 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) + qdd, q2dd = dynamicsymbols('q q2', 2) + N = ReferenceFrame('N') + B = ReferenceFrame('B') + B.set_ang_vel(N, 5 * B.y) + O = Point('O') + P = O.locatenew('P', q * B.x + q2 * B.y) + assert P.pos_from(O) == q * B.x + q2 * B.y + P.set_vel(B, qd * B.x + q2d * B.y) + assert P.vel(B) == qd * B.x + q2d * B.y + O.set_vel(N, 0) + assert O.vel(N) == 0 + assert P.a1pt_theory(O, N, B) == ((-25 * q + qdd) * B.x + (q2dd) * B.y + + (-10 * qd) * B.z) + + B = N.orientnew('B', 'Axis', [q, N.z]) + O = Point('O') + P = O.locatenew('P', 10 * B.x) + O.set_vel(N, 5 * N.x) + assert O.vel(N) == 5 * N.x + assert P.a2pt_theory(O, N, B) == (-10 * qd**2) * B.x + (10 * qdd) * B.y + + B.set_ang_vel(N, 5 * B.y) + O = Point('O') + P = O.locatenew('P', q * B.x + q2 * B.y) + P.set_vel(B, qd * B.x + q2d * B.y) + 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') + B = N.orientnew('B', 'Axis', [q, N.z]) + O = Point('O') + P = O.locatenew('P', 10 * N.x + 5 * B.x) + assert P.pos_from(O) == 10 * N.x + 5 * B.x + Q = P.locatenew('Q', 10 * N.y + 5 * B.y) + assert Q.pos_from(P) == 10 * N.y + 5 * B.y + assert Q.pos_from(O) == 10 * N.x + 10 * N.y + 5 * B.x + 5 * B.y + assert O.pos_from(Q) == -10 * N.x - 10 * N.y - 5 * B.x - 5 * B.y + +def test_point_partial_velocity(): + + N = ReferenceFrame('N') + A = ReferenceFrame('A') + + p = Point('p') + + u1, u2 = dynamicsymbols('u1, u2') + + p.set_vel(N, u1 * A.x + u2 * N.y) + + assert p.partial_velocity(N, u1) == A.x + assert p.partial_velocity(N, u1, u2) == (A.x, N.y) + raises(ValueError, lambda: p.partial_velocity(A, u1)) + +def test_point_vel(): #Basic functionality + q1, q2 = dynamicsymbols('q1 q2') + N = ReferenceFrame('N') + B = ReferenceFrame('B') + Q = Point('Q') + O = Point('O') + Q.set_pos(O, q1 * N.x) + raises(ValueError , lambda: Q.vel(N)) # Velocity of O in N is not defined + O.set_vel(N, q2 * N.y) + assert O.vel(N) == q2 * N.y + raises(ValueError , lambda : O.vel(B)) #Velocity of O is not defined in B + +def test_auto_point_vel(): + t = dynamicsymbols._t + q1, q2 = dynamicsymbols('q1 q2') + N = ReferenceFrame('N') + B = ReferenceFrame('B') + O = Point('O') + Q = Point('Q') + Q.set_pos(O, q1 * N.x) + O.set_vel(N, q2 * N.y) + assert Q.vel(N) == q1.diff(t) * N.x + q2 * N.y # Velocity of Q using O + P1 = Point('P1') + P1.set_pos(O, q1 * B.x) + P2 = Point('P2') + P2.set_pos(P1, q2 * B.z) + raises(ValueError, lambda : P2.vel(B)) # O's velocity is defined in different frame, and no + #point in between has its velocity defined + raises(ValueError, lambda: P2.vel(N)) # Velocity of O not defined in N + +def test_auto_point_vel_multiple_point_path(): + t = dynamicsymbols._t + q1, q2 = dynamicsymbols('q1 q2') + B = ReferenceFrame('B') + P = Point('P') + P.set_vel(B, q1 * B.x) + P1 = Point('P1') + P1.set_pos(P, q2 * B.y) + P1.set_vel(B, q1 * B.z) + P2 = Point('P2') + P2.set_pos(P1, q1 * B.z) + P3 = Point('P3') + P3.set_pos(P2, 10 * q1 * B.y) + assert P3.vel(B) == 10 * q1.diff(t) * B.y + (q1 + q1.diff(t)) * B.z + +def test_auto_vel_dont_overwrite(): + t = dynamicsymbols._t + q1, q2, u1 = dynamicsymbols('q1, q2, u1') + N = ReferenceFrame('N') + P = Point('P1') + P.set_vel(N, u1 * N.x) + P1 = Point('P1') + P1.set_pos(P, q2 * N.y) + assert P1.vel(N) == q2.diff(t) * N.y + u1 * N.x + assert P.vel(N) == u1 * N.x + P1.set_vel(N, u1 * N.z) + assert P1.vel(N) == u1 * N.z + +def test_auto_point_vel_if_tree_has_vel_but_inappropriate_pos_vector(): + q1, q2 = dynamicsymbols('q1 q2') + B = ReferenceFrame('B') + S = ReferenceFrame('S') + P = Point('P') + P.set_vel(B, q1 * B.x) + P1 = Point('P1') + P1.set_pos(P, S.y) + raises(ValueError, lambda : P1.vel(B)) # P1.pos_from(P) can't be expressed in B + raises(ValueError, lambda : P1.vel(S)) # P.vel(S) not defined + +def test_auto_point_vel_shortest_path(): + t = dynamicsymbols._t + q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2') + B = ReferenceFrame('B') + P = Point('P') + P.set_vel(B, u1 * B.x) + P1 = Point('P1') + P1.set_pos(P, q2 * B.y) + P1.set_vel(B, q1 * B.z) + P2 = Point('P2') + P2.set_pos(P1, q1 * B.z) + P3 = Point('P3') + P3.set_pos(P2, 10 * q1 * B.y) + P4 = Point('P4') + P4.set_pos(P3, q1 * B.x) + O = Point('O') + O.set_vel(B, u2 * B.y) + O1 = Point('O1') + O1.set_pos(O, q2 * B.z) + P4.set_pos(O1, q1 * B.x + q2 * B.z) + with warnings.catch_warnings(): #There are two possible paths in this point tree, thus a warning is raised + warnings.simplefilter('error') + with ignore_warnings(UserWarning): + assert P4.vel(B) == q1.diff(t) * B.x + u2 * B.y + 2 * q2.diff(t) * B.z + +def test_auto_point_vel_connected_frames(): + t = dynamicsymbols._t + q, q1, q2, u = dynamicsymbols('q q1 q2 u') + N = ReferenceFrame('N') + B = ReferenceFrame('B') + O = Point('O') + O.set_vel(N, u * N.x) + P = Point('P') + P.set_pos(O, q1 * N.x + q2 * B.y) + raises(ValueError, lambda: P.vel(N)) + N.orient(B, 'Axis', (q, B.x)) + assert P.vel(N) == (u + q1.diff(t)) * N.x + q2.diff(t) * B.y - q2 * q.diff(t) * B.z + +def test_auto_point_vel_multiple_paths_warning_arises(): + q, u = dynamicsymbols('q u') + N = ReferenceFrame('N') + O = Point('O') + P = Point('P') + Q = Point('Q') + R = Point('R') + P.set_vel(N, u * N.x) + Q.set_vel(N, u *N.y) + R.set_vel(N, u * N.z) + O.set_pos(P, q * N.z) + O.set_pos(Q, q * N.y) + O.set_pos(R, q * N.x) + with warnings.catch_warnings(): #There are two possible paths in this point tree, thus a warning is raised + warnings.simplefilter("error") + raises(UserWarning ,lambda: O.vel(N)) + +def test_auto_vel_cyclic_warning_arises(): + P = Point('P') + P1 = Point('P1') + P2 = Point('P2') + P3 = Point('P3') + N = ReferenceFrame('N') + P.set_vel(N, N.x) + P1.set_pos(P, N.x) + P2.set_pos(P1, N.y) + P3.set_pos(P2, N.z) + P1.set_pos(P3, N.x + N.y) + with warnings.catch_warnings(): #The path is cyclic at P1, thus a warning is raised + warnings.simplefilter("error") + raises(UserWarning ,lambda: P2.vel(N)) + +def test_auto_vel_cyclic_warning_msg(): + P = Point('P') + P1 = Point('P1') + P2 = Point('P2') + P3 = Point('P3') + N = ReferenceFrame('N') + P.set_vel(N, N.x) + P1.set_pos(P, N.x) + P2.set_pos(P1, N.y) + P3.set_pos(P2, N.z) + P1.set_pos(P3, N.x + N.y) + with warnings.catch_warnings(record = True) as w: #The path is cyclic at P1, thus a warning is raised + warnings.simplefilter("always") + P2.vel(N) + msg = str(w[-1].message).replace("\n", " ") + assert issubclass(w[-1].category, UserWarning) + assert 'Kinematic loops are defined among the positions of points. This is likely not desired and may cause errors in your calculations.' in msg + +def test_auto_vel_multiple_path_warning_msg(): + N = ReferenceFrame('N') + O = Point('O') + P = Point('P') + Q = Point('Q') + P.set_vel(N, N.x) + Q.set_vel(N, N.y) + O.set_pos(P, N.z) + O.set_pos(Q, N.y) + with warnings.catch_warnings(record = True) as w: #There are two possible paths in this point tree, thus a warning is raised + warnings.simplefilter("always") + O.vel(N) + msg = str(w[-1].message).replace("\n", " ") + assert issubclass(w[-1].category, UserWarning) + assert 'Velocity' in msg + assert 'automatically calculated based on point' in msg + assert 'Velocities from these points are not necessarily the same. This may cause errors in your calculations.' in msg + +def test_auto_vel_derivative(): + q1, q2 = dynamicsymbols('q1:3') + u1, u2 = dynamicsymbols('u1:3', 1) + A = ReferenceFrame('A') + B = ReferenceFrame('B') + C = ReferenceFrame('C') + B.orient_axis(A, A.z, q1) + B.set_ang_vel(A, u1 * A.z) + C.orient_axis(B, B.z, q2) + C.set_ang_vel(B, u2 * B.z) + + Am = Point('Am') + Am.set_vel(A, 0) + Bm = Point('Bm') + Bm.set_pos(Am, B.x) + Bm.set_vel(B, 0) + Bm.set_vel(C, 0) + Cm = Point('Cm') + Cm.set_pos(Bm, C.x) + Cm.set_vel(C, 0) + temp = Cm._vel_dict.copy() + assert Cm.vel(A) == (u1 * B.y + (u1 + u2) * C.y) + Cm._vel_dict = temp + Cm.v2pt_theory(Bm, B, C) + assert Cm.vel(A) == (u1 * B.y + (u1 + u2) * C.y) + +def test_auto_point_acc_zero_vel(): + N = ReferenceFrame('N') + O = Point('O') + O.set_vel(N, 0) + assert O.acc(N) == 0 * N.x + +def test_auto_point_acc_compute_vel(): + t = dynamicsymbols._t + q1 = dynamicsymbols('q1') + N = ReferenceFrame('N') + A = ReferenceFrame('A') + A.orient_axis(N, N.z, q1) + + O = Point('O') + O.set_vel(N, 0) + P = Point('P') + P.set_pos(O, A.x) + assert P.acc(N) == -q1.diff(t) ** 2 * A.x + q1.diff(t, 2) * A.y + +def test_auto_acc_derivative(): + # Tests whether the Point.acc method gives the correct acceleration of the + # end point of two linkages in series, while getting minimal information. + q1, q2 = dynamicsymbols('q1:3') + u1, u2 = dynamicsymbols('q1:3', 1) + v1, v2 = dynamicsymbols('q1:3', 2) + A = ReferenceFrame('A') + B = ReferenceFrame('B') + C = ReferenceFrame('C') + B.orient_axis(A, A.z, q1) + C.orient_axis(B, B.z, q2) + + Am = Point('Am') + Am.set_vel(A, 0) + Bm = Point('Bm') + Bm.set_pos(Am, B.x) + Bm.set_vel(B, 0) + Bm.set_vel(C, 0) + Cm = Point('Cm') + Cm.set_pos(Bm, C.x) + Cm.set_vel(C, 0) + + # Copy dictionaries to later check the calculation using the 2pt_theories + Bm_vel_dict, Cm_vel_dict = Bm._vel_dict.copy(), Cm._vel_dict.copy() + Bm_acc_dict, Cm_acc_dict = Bm._acc_dict.copy(), Cm._acc_dict.copy() + check = -u1 ** 2 * B.x + v1 * B.y - (u1 + u2) ** 2 * C.x + (v1 + v2) * C.y + assert Cm.acc(A) == check + Bm._vel_dict, Cm._vel_dict = Bm_vel_dict, Cm_vel_dict + Bm._acc_dict, Cm._acc_dict = Bm_acc_dict, Cm_acc_dict + Bm.v2pt_theory(Am, A, B) + Cm.v2pt_theory(Bm, A, C) + Bm.a2pt_theory(Am, A, B) + assert Cm.a2pt_theory(Bm, A, C) == check diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_printing.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_printing.py new file mode 100644 index 0000000000000000000000000000000000000000..0930fe9d0bc6e2fcc60b34f37215fdb19e32fdc4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_printing.py @@ -0,0 +1,353 @@ +# -*- coding: utf-8 -*- + +from sympy.core.function import Function +from sympy.core.symbol import symbols +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (asin, cos, sin) +from sympy.physics.vector import ReferenceFrame, dynamicsymbols, Dyadic +from sympy.physics.vector.printing import (VectorLatexPrinter, vpprint, + vsprint, vsstrrepr, vlatex) + + +a, b, c = symbols('a, b, c') +alpha, omega, beta = dynamicsymbols('alpha, omega, beta') + +A = ReferenceFrame('A') +N = ReferenceFrame('N') + +v = a ** 2 * N.x + b * N.y + c * sin(alpha) * N.z +w = alpha * N.x + sin(omega) * N.y + alpha * beta * N.z +ww = alpha * N.x + asin(omega) * N.y - alpha.diff() * beta * N.z +o = a/b * N.x + (c+b)/a * N.y + c**2/b * N.z + +y = a ** 2 * (N.x | N.y) + b * (N.y | N.y) + c * sin(alpha) * (N.z | N.y) +x = alpha * (N.x | N.x) + sin(omega) * (N.y | N.z) + alpha * beta * (N.z | N.x) +xx = N.x | (-N.y - N.z) +xx2 = N.x | (N.y + N.z) + +def ascii_vpretty(expr): + return vpprint(expr, use_unicode=False, wrap_line=False) + + +def unicode_vpretty(expr): + return vpprint(expr, use_unicode=True, wrap_line=False) + + +def test_latex_printer(): + r = Function('r')('t') + assert VectorLatexPrinter().doprint(r ** 2) == "r^{2}" + r2 = Function('r^2')('t') + assert VectorLatexPrinter().doprint(r2.diff()) == r'\dot{r^{2}}' + ra = Function('r__a')('t') + assert VectorLatexPrinter().doprint(ra.diff().diff()) == r'\ddot{r^{a}}' + + +def test_vector_pretty_print(): + + # TODO : The unit vectors should print with subscripts but they just + # print as `n_x` instead of making `x` a subscript with unicode. + + # TODO : The pretty print division does not print correctly here: + # w = alpha * N.x + sin(omega) * N.y + alpha / beta * N.z + + expected = """\ + 2 \n\ +a n_x + b n_y + c*sin(alpha) n_z\ +""" + uexpected = """\ + 2 \n\ +a n_x + b n_y + c⋅sin(α) n_z\ +""" + + assert ascii_vpretty(v) == expected + assert unicode_vpretty(v) == uexpected + + expected = 'alpha n_x + sin(omega) n_y + alpha*beta n_z' + uexpected = 'α n_x + sin(ω) n_y + α⋅β n_z' + + assert ascii_vpretty(w) == expected + assert unicode_vpretty(w) == uexpected + + expected = """\ + 2 \n\ +a b + c c \n\ +- n_x + ----- n_y + -- n_z\n\ +b a b \ +""" + uexpected = """\ + 2 \n\ +a b + c c \n\ +─ n_x + ───── n_y + ── n_z\n\ +b a b \ +""" + + assert ascii_vpretty(o) == expected + assert unicode_vpretty(o) == uexpected + + # https://github.com/sympy/sympy/issues/26731 + assert ascii_vpretty(-A.x) == '-a_x' + assert unicode_vpretty(-A.x) == '-a_x' + + # https://github.com/sympy/sympy/issues/26799 + assert ascii_vpretty(0*A.x) == '0' + assert unicode_vpretty(0*A.x) == '0' + + +def test_vector_latex(): + + a, b, c, d, omega = symbols('a, b, c, d, omega') + + v = (a ** 2 + b / c) * A.x + sqrt(d) * A.y + cos(omega) * A.z + + assert vlatex(v) == (r'(a^{2} + \frac{b}{c})\mathbf{\hat{a}_x} + ' + r'\sqrt{d}\mathbf{\hat{a}_y} + ' + r'\cos{\left(\omega \right)}' + r'\mathbf{\hat{a}_z}') + + theta, omega, alpha, q = dynamicsymbols('theta, omega, alpha, q') + + v = theta * A.x + omega * omega * A.y + (q * alpha) * A.z + + assert vlatex(v) == (r'\theta\mathbf{\hat{a}_x} + ' + r'\omega^{2}\mathbf{\hat{a}_y} + ' + r'\alpha q\mathbf{\hat{a}_z}') + + phi1, phi2, phi3 = dynamicsymbols('phi1, phi2, phi3') + theta1, theta2, theta3 = symbols('theta1, theta2, theta3') + + v = (sin(theta1) * A.x + + cos(phi1) * cos(phi2) * A.y + + cos(theta1 + phi3) * A.z) + + assert vlatex(v) == (r'\sin{\left(\theta_{1} \right)}' + r'\mathbf{\hat{a}_x} + \cos{' + r'\left(\phi_{1} \right)} \cos{' + r'\left(\phi_{2} \right)}\mathbf{\hat{a}_y} + ' + r'\cos{\left(\theta_{1} + ' + r'\phi_{3} \right)}\mathbf{\hat{a}_z}') + + N = ReferenceFrame('N') + + a, b, c, d, omega = symbols('a, b, c, d, omega') + + v = (a ** 2 + b / c) * N.x + sqrt(d) * N.y + cos(omega) * N.z + + expected = (r'(a^{2} + \frac{b}{c})\mathbf{\hat{n}_x} + ' + r'\sqrt{d}\mathbf{\hat{n}_y} + ' + r'\cos{\left(\omega \right)}' + r'\mathbf{\hat{n}_z}') + + assert vlatex(v) == expected + + # Try custom unit vectors. + + N = ReferenceFrame('N', latexs=(r'\hat{i}', r'\hat{j}', r'\hat{k}')) + + v = (a ** 2 + b / c) * N.x + sqrt(d) * N.y + cos(omega) * N.z + + expected = (r'(a^{2} + \frac{b}{c})\hat{i} + ' + r'\sqrt{d}\hat{j} + ' + r'\cos{\left(\omega \right)}\hat{k}') + assert vlatex(v) == expected + + expected = r'\alpha\mathbf{\hat{n}_x} + \operatorname{asin}{\left(\omega ' \ + r'\right)}\mathbf{\hat{n}_y} - \beta \dot{\alpha}\mathbf{\hat{n}_z}' + assert vlatex(ww) == expected + + expected = r'- \mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_y} - ' \ + r'\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_z}' + assert vlatex(xx) == expected + + expected = r'\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_y} + ' \ + r'\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_z}' + assert vlatex(xx2) == expected + + +def test_vector_latex_arguments(): + assert vlatex(N.x * 3.0, full_prec=False) == r'3.0\mathbf{\hat{n}_x}' + assert vlatex(N.x * 3.0, full_prec=True) == r'3.00000000000000\mathbf{\hat{n}_x}' + + +def test_vector_latex_with_functions(): + + N = ReferenceFrame('N') + + omega, alpha = dynamicsymbols('omega, alpha') + + v = omega.diff() * N.x + + assert vlatex(v) == r'\dot{\omega}\mathbf{\hat{n}_x}' + + v = omega.diff() ** alpha * N.x + + assert vlatex(v) == (r'\dot{\omega}^{\alpha}' + r'\mathbf{\hat{n}_x}') + + +def test_dyadic_pretty_print(): + + expected = """\ + 2 +a n_x|n_y + b n_y|n_y + c*sin(alpha) n_z|n_y\ +""" + + uexpected = """\ + 2 +a n_x⊗n_y + b n_y⊗n_y + c⋅sin(α) n_z⊗n_y\ +""" + assert ascii_vpretty(y) == expected + assert unicode_vpretty(y) == uexpected + + expected = 'alpha n_x|n_x + sin(omega) n_y|n_z + alpha*beta n_z|n_x' + uexpected = 'α n_x⊗n_x + sin(ω) n_y⊗n_z + α⋅β n_z⊗n_x' + assert ascii_vpretty(x) == expected + assert unicode_vpretty(x) == uexpected + + assert ascii_vpretty(Dyadic([])) == '0' + assert unicode_vpretty(Dyadic([])) == '0' + + assert ascii_vpretty(xx) == '- n_x|n_y - n_x|n_z' + assert unicode_vpretty(xx) == '- n_x⊗n_y - n_x⊗n_z' + + assert ascii_vpretty(xx2) == 'n_x|n_y + n_x|n_z' + assert unicode_vpretty(xx2) == 'n_x⊗n_y + n_x⊗n_z' + + +def test_dyadic_latex(): + + expected = (r'a^{2}\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_y} + ' + r'b\mathbf{\hat{n}_y}\otimes \mathbf{\hat{n}_y} + ' + r'c \sin{\left(\alpha \right)}' + r'\mathbf{\hat{n}_z}\otimes \mathbf{\hat{n}_y}') + + assert vlatex(y) == expected + + expected = (r'\alpha\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_x} + ' + r'\sin{\left(\omega \right)}\mathbf{\hat{n}_y}' + r'\otimes \mathbf{\hat{n}_z} + ' + r'\alpha \beta\mathbf{\hat{n}_z}\otimes \mathbf{\hat{n}_x}') + + assert vlatex(x) == expected + + assert vlatex(Dyadic([])) == '0' + + +def test_dyadic_str(): + assert vsprint(Dyadic([])) == '0' + assert vsprint(y) == 'a**2*(N.x|N.y) + b*(N.y|N.y) + c*sin(alpha)*(N.z|N.y)' + assert vsprint(x) == 'alpha*(N.x|N.x) + sin(omega)*(N.y|N.z) + alpha*beta*(N.z|N.x)' + assert vsprint(ww) == "alpha*N.x + asin(omega)*N.y - beta*alpha'*N.z" + assert vsprint(xx) == '- (N.x|N.y) - (N.x|N.z)' + assert vsprint(xx2) == '(N.x|N.y) + (N.x|N.z)' + + +def test_vlatex(): # vlatex is broken #12078 + from sympy.physics.vector import vlatex + + x = symbols('x') + J = symbols('J') + + f = Function('f') + g = Function('g') + h = Function('h') + + expected = r'J \left(\frac{d}{d x} g{\left(x \right)} - \frac{d}{d x} h{\left(x \right)}\right)' + + expr = J*f(x).diff(x).subs(f(x), g(x)-h(x)) + + assert vlatex(expr) == expected + + +def test_issue_13354(): + """ + Test for proper pretty printing of physics vectors with ADD + instances in arguments. + + Test is exactly the one suggested in the original bug report by + @moorepants. + """ + + a, b, c = symbols('a, b, c') + A = ReferenceFrame('A') + v = a * A.x + b * A.y + c * A.z + w = b * A.x + c * A.y + a * A.z + z = w + v + + expected = """(a + b) a_x + (b + c) a_y + (a + c) a_z""" + + assert ascii_vpretty(z) == expected + + +def test_vector_derivative_printing(): + # First order + v = omega.diff() * N.x + assert unicode_vpretty(v) == 'ω̇ n_x' + assert ascii_vpretty(v) == "omega'(t) n_x" + + # Second order + v = omega.diff().diff() * N.x + + assert vlatex(v) == r'\ddot{\omega}\mathbf{\hat{n}_x}' + assert unicode_vpretty(v) == 'ω̈ n_x' + assert ascii_vpretty(v) == "omega''(t) n_x" + + # Third order + v = omega.diff().diff().diff() * N.x + + assert vlatex(v) == r'\dddot{\omega}\mathbf{\hat{n}_x}' + assert unicode_vpretty(v) == 'ω⃛ n_x' + assert ascii_vpretty(v) == "omega'''(t) n_x" + + # Fourth order + v = omega.diff().diff().diff().diff() * N.x + + assert vlatex(v) == r'\ddddot{\omega}\mathbf{\hat{n}_x}' + assert unicode_vpretty(v) == 'ω⃜ n_x' + assert ascii_vpretty(v) == "omega''''(t) n_x" + + # Fifth order + v = omega.diff().diff().diff().diff().diff() * N.x + + assert vlatex(v) == r'\frac{d^{5}}{d t^{5}} \omega\mathbf{\hat{n}_x}' + expected = '''\ + 5 \n\ +d \n\ +---(omega) n_x\n\ + 5 \n\ +dt \ +''' + uexpected = '''\ + 5 \n\ +d \n\ +───(ω) n_x\n\ + 5 \n\ +dt \ +''' + assert unicode_vpretty(v) == uexpected + assert ascii_vpretty(v) == expected + + +def test_vector_str_printing(): + assert vsprint(w) == 'alpha*N.x + sin(omega)*N.y + alpha*beta*N.z' + assert vsprint(omega.diff() * N.x) == "omega'*N.x" + assert vsstrrepr(w) == 'alpha*N.x + sin(omega)*N.y + alpha*beta*N.z' + + +def test_vector_str_arguments(): + assert vsprint(N.x * 3.0, full_prec=False) == '3.0*N.x' + assert vsprint(N.x * 3.0, full_prec=True) == '3.00000000000000*N.x' + + +def test_issue_14041(): + import sympy.physics.mechanics as me + + A_frame = me.ReferenceFrame('A') + thetad, phid = me.dynamicsymbols('theta, phi', 1) + L = symbols('L') + + assert vlatex(L*(phid + thetad)**2*A_frame.x) == \ + r"L \left(\dot{\phi} + \dot{\theta}\right)^{2}\mathbf{\hat{a}_x}" + assert vlatex((phid + thetad)**2*A_frame.x) == \ + r"\left(\dot{\phi} + \dot{\theta}\right)^{2}\mathbf{\hat{a}_x}" + assert vlatex((phid*thetad)**a*A_frame.x) == \ + r"\left(\dot{\phi} \dot{\theta}\right)^{a}\mathbf{\hat{a}_x}" diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_vector.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_vector.py new file mode 100644 index 0000000000000000000000000000000000000000..2b9c154e60be553228d37eec609dfc23120935ff --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/physics/vector/tests/test_vector.py @@ -0,0 +1,274 @@ +from sympy.core.numbers import (Float, pi) +from sympy.core.symbol import symbols +from sympy.core.sorting import ordered +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix +from sympy.physics.vector import ReferenceFrame, Vector, dynamicsymbols, dot +from sympy.physics.vector.vector import VectorTypeError +from sympy.abc import x, y, z +from sympy.testing.pytest import raises + +A = ReferenceFrame('A') + + +def test_free_dynamicsymbols(): + A, B, C, D = symbols('A, B, C, D', cls=ReferenceFrame) + a, b, c, d, e, f = dynamicsymbols('a, b, c, d, e, f') + B.orient_axis(A, a, A.x) + C.orient_axis(B, b, B.y) + D.orient_axis(C, c, C.x) + + v = d*D.x + e*D.y + f*D.z + + assert set(ordered(v.free_dynamicsymbols(A))) == {a, b, c, d, e, f} + assert set(ordered(v.free_dynamicsymbols(B))) == {b, c, d, e, f} + assert set(ordered(v.free_dynamicsymbols(C))) == {c, d, e, f} + assert set(ordered(v.free_dynamicsymbols(D))) == {d, e, f} + + +def test_Vector(): + assert A.x != A.y + assert A.y != A.z + assert A.z != A.x + + assert A.x + 0 == A.x + + v1 = x*A.x + y*A.y + z*A.z + v2 = x**2*A.x + y**2*A.y + z**2*A.z + v3 = v1 + v2 + v4 = v1 - v2 + + assert isinstance(v1, Vector) + assert dot(v1, A.x) == x + assert dot(v1, A.y) == y + assert dot(v1, A.z) == z + + assert isinstance(v2, Vector) + assert dot(v2, A.x) == x**2 + assert dot(v2, A.y) == y**2 + assert dot(v2, A.z) == z**2 + + assert isinstance(v3, Vector) + # We probably shouldn't be using simplify in dot... + 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... + assert dot(v4, A.x) == x - x**2 + assert dot(v4, A.y) == y - y**2 + assert dot(v4, A.z) == z - z**2 + + assert v1.to_matrix(A) == Matrix([[x], [y], [z]]) + q = symbols('q') + B = A.orientnew('B', 'Axis', (q, A.x)) + assert v1.to_matrix(B) == Matrix([[x], + [ y * cos(q) + z * sin(q)], + [-y * sin(q) + z * cos(q)]]) + + #Test the separate method + B = ReferenceFrame('B') + v5 = x*A.x + y*A.y + z*B.z + assert Vector(0).separate() == {} + assert v1.separate() == {A: v1} + assert v5.separate() == {A: x*A.x + y*A.y, B: z*B.z} + + #Test the free_symbols property + v6 = x*A.x + y*A.y + z*A.z + assert v6.free_symbols(A) == {x,y,z} + + raises(TypeError, lambda: v3.applyfunc(v1)) + + +def test_Vector_diffs(): + q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') + q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1) + q1dd, q2dd, q3dd, q4dd = dynamicsymbols('q1 q2 q3 q4', 2) + N = ReferenceFrame('N') + A = N.orientnew('A', 'Axis', [q3, N.z]) + B = A.orientnew('B', 'Axis', [q2, A.x]) + v1 = q2 * A.x + q3 * N.y + v2 = q3 * B.x + v1 + v3 = v1.dt(B) + v4 = v2.dt(B) + v5 = q1*A.x + q2*A.y + q3*A.z + + assert v1.dt(N) == q2d * A.x + q2 * q3d * A.y + q3d * N.y + assert v1.dt(A) == q2d * A.x + q3 * q3d * N.x + q3d * N.y + assert v1.dt(B) == (q2d * A.x + q3 * q3d * N.x + q3d * + N.y - q3 * cos(q3) * q2d * N.z) + assert v2.dt(N) == (q2d * A.x + (q2 + q3) * q3d * A.y + q3d * B.x + q3d * + N.y) + assert v2.dt(A) == q2d * A.x + q3d * B.x + q3 * q3d * N.x + q3d * N.y + assert v2.dt(B) == (q2d * A.x + q3d * B.x + q3 * q3d * N.x + q3d * N.y - + q3 * cos(q3) * q2d * N.z) + assert v3.dt(N) == (q2dd * A.x + q2d * q3d * A.y + (q3d**2 + q3 * q3dd) * + N.x + q3dd * N.y + (q3 * sin(q3) * q2d * q3d - + cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z) + assert v3.dt(A) == (q2dd * A.x + (2 * q3d**2 + q3 * q3dd) * N.x + (q3dd - + q3 * q3d**2) * N.y + (q3 * sin(q3) * q2d * q3d - + cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z) + assert (v3.dt(B) - (q2dd*A.x - q3*cos(q3)*q2d**2*A.y + (2*q3d**2 + + q3*q3dd)*N.x + (q3dd - q3*q3d**2)*N.y + (2*q3*sin(q3)*q2d*q3d - + 2*cos(q3)*q2d*q3d - q3*cos(q3)*q2dd)*N.z)).express(B).simplify() == 0 + assert v4.dt(N) == (q2dd * A.x + q3d * (q2d + q3d) * A.y + q3dd * B.x + + (q3d**2 + q3 * q3dd) * N.x + q3dd * N.y + (q3 * + sin(q3) * q2d * q3d - cos(q3) * q2d * q3d - q3 * + cos(q3) * q2dd) * N.z) + assert v4.dt(A) == (q2dd * A.x + q3dd * B.x + (2 * q3d**2 + q3 * q3dd) * + N.x + (q3dd - q3 * q3d**2) * N.y + (q3 * sin(q3) * + q2d * q3d - cos(q3) * q2d * q3d - q3 * cos(q3) * + q2dd) * N.z) + assert (v4.dt(B) - (q2dd*A.x - q3*cos(q3)*q2d**2*A.y + q3dd*B.x + + (2*q3d**2 + q3*q3dd)*N.x + (q3dd - q3*q3d**2)*N.y + + (2*q3*sin(q3)*q2d*q3d - 2*cos(q3)*q2d*q3d - + q3*cos(q3)*q2dd)*N.z)).express(B).simplify() == 0 + assert v5.dt(B) == q1d*A.x + (q3*q2d + q2d)*A.y + (-q2*q2d + q3d)*A.z + assert v5.dt(A) == q1d*A.x + q2d*A.y + q3d*A.z + assert v5.dt(N) == (-q2*q3d + q1d)*A.x + (q1*q3d + q2d)*A.y + q3d*A.z + assert v3.diff(q1d, N) == 0 + assert v3.diff(q2d, N) == A.x - q3 * cos(q3) * N.z + assert v3.diff(q3d, N) == q3 * N.x + N.y + assert v3.diff(q1d, A) == 0 + assert v3.diff(q2d, A) == A.x - q3 * cos(q3) * N.z + assert v3.diff(q3d, A) == q3 * N.x + N.y + assert v3.diff(q1d, B) == 0 + assert v3.diff(q2d, B) == A.x - q3 * cos(q3) * N.z + assert v3.diff(q3d, B) == q3 * N.x + N.y + assert v4.diff(q1d, N) == 0 + assert v4.diff(q2d, N) == A.x - q3 * cos(q3) * N.z + assert v4.diff(q3d, N) == B.x + q3 * N.x + N.y + assert v4.diff(q1d, A) == 0 + assert v4.diff(q2d, A) == A.x - q3 * cos(q3) * N.z + assert v4.diff(q3d, A) == B.x + q3 * N.x + N.y + assert v4.diff(q1d, B) == 0 + assert v4.diff(q2d, B) == A.x - q3 * cos(q3) * N.z + assert v4.diff(q3d, B) == B.x + q3 * N.x + N.y + + # diff() should only express vector components in the derivative frame if + # the orientation of the component's frame depends on the variable + v6 = q2**2*N.y + q2**2*A.y + q2**2*B.y + # already expressed in N + n_measy = 2*q2 + # A_C_N does not depend on q2, so don't express in N + a_measy = 2*q2 + # B_C_N depends on q2, so express in N + b_measx = (q2**2*B.y).dot(N.x).diff(q2) + b_measy = (q2**2*B.y).dot(N.y).diff(q2) + b_measz = (q2**2*B.y).dot(N.z).diff(q2) + n_comp, a_comp = v6.diff(q2, N).args + assert len(v6.diff(q2, N).args) == 2 # only N and A parts + assert n_comp[1] == N + assert a_comp[1] == A + assert n_comp[0] == Matrix([b_measx, b_measy + n_measy, b_measz]) + assert a_comp[0] == Matrix([0, a_measy, 0]) + + +def test_vector_var_in_dcm(): + + N = ReferenceFrame('N') + A = ReferenceFrame('A') + B = ReferenceFrame('B') + u1, u2, u3, u4 = dynamicsymbols('u1 u2 u3 u4') + + v = u1 * u2 * A.x + u3 * N.y + u4**2 * N.z + + assert v.diff(u1, N, var_in_dcm=False) == u2 * A.x + assert v.diff(u1, A, var_in_dcm=False) == u2 * A.x + assert v.diff(u3, N, var_in_dcm=False) == N.y + assert v.diff(u3, A, var_in_dcm=False) == N.y + assert v.diff(u3, B, var_in_dcm=False) == N.y + assert v.diff(u4, N, var_in_dcm=False) == 2 * u4 * N.z + + raises(ValueError, lambda: v.diff(u1, N)) + + +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') + + test1 = (1 / x + 1 / y) * N.x + assert (test1 & N.x) != (x + y) / (x * y) + test1 = test1.simplify() + assert (test1 & N.x) == (x + y) / (x * y) + + test2 = (A**2 * s**4 / (4 * pi * k * m**3)) * N.x + test2 = test2.simplify() + assert (test2 & N.x) == (A**2 * s**4 / (4 * pi * k * m**3)) + + test3 = ((4 + 4 * x - 2 * (2 + 2 * x)) / (2 + 2 * x)) * N.x + test3 = test3.simplify() + assert (test3 & N.x) == 0 + + test4 = ((-4 * x * y**2 - 2 * y**3 - 2 * x**2 * y) / (x + y)**2) * N.x + test4 = test4.simplify() + assert (test4 & N.x) == -2 * y + + +def test_vector_evalf(): + a, b = symbols('a b') + v = pi * A.x + assert v.evalf(2) == Float('3.1416', 2) * A.x + v = pi * A.x + 5 * a * A.y - b * A.z + assert v.evalf(3) == Float('3.1416', 3) * A.x + Float('5', 3) * a * A.y - b * A.z + assert v.evalf(5, subs={a: 1.234, b:5.8973}) == Float('3.1415926536', 5) * A.x + Float('6.17', 5) * A.y - Float('5.8973', 5) * A.z + + +def test_vector_angle(): + A = ReferenceFrame('A') + v1 = A.x + A.y + v2 = A.z + assert v1.angle_between(v2) == pi/2 + B = ReferenceFrame('B') + B.orient_axis(A, A.x, pi) + v3 = A.x + v4 = B.x + assert v3.angle_between(v4) == 0 + + +def test_vector_xreplace(): + x, y, z = symbols('x y z') + v = x**2 * A.x + x*y * A.y + x*y*z * A.z + assert v.xreplace({x : cos(x)}) == cos(x)**2 * A.x + y*cos(x) * A.y + y*z*cos(x) * A.z + assert v.xreplace({x*y : pi}) == x**2 * A.x + pi * A.y + x*y*z * A.z + assert v.xreplace({x*y*z : 1}) == x**2*A.x + x*y*A.y + A.z + assert v.xreplace({x:1, z:0}) == A.x + y * A.y + raises(TypeError, lambda: v.xreplace()) + raises(TypeError, lambda: v.xreplace([x, y])) + +def test_issue_23366(): + u1 = dynamicsymbols('u1') + N = ReferenceFrame('N') + N_v_A = u1*N.x + raises(VectorTypeError, lambda: N_v_A.diff(N, u1)) + + +def test_vector_outer(): + a, b, c, d, e, f = symbols('a, b, c, d, e, f') + N = ReferenceFrame('N') + v1 = a*N.x + b*N.y + c*N.z + v2 = d*N.x + e*N.y + f*N.z + v1v2 = Matrix([[a*d, a*e, a*f], + [b*d, b*e, b*f], + [c*d, c*e, c*f]]) + assert v1.outer(v2).to_matrix(N) == v1v2 + assert (v1 | v2).to_matrix(N) == v1v2 + v2v1 = Matrix([[d*a, d*b, d*c], + [e*a, e*b, e*c], + [f*a, f*b, f*c]]) + assert v2.outer(v1).to_matrix(N) == v2v1 + assert (v2 | v1).to_matrix(N) == v2v1 + + +def test_overloaded_operators(): + a, b, c, d, e, f = symbols('a, b, c, d, e, f') + N = ReferenceFrame('N') + v1 = a*N.x + b*N.y + c*N.z + v2 = d*N.x + e*N.y + f*N.z + + assert v1 + v2 == v2 + v1 + assert v1 - v2 == -v2 + v1 + assert v1 & v2 == v2 & v1 + assert v1 ^ v2 == v1.cross(v2) + assert v2 ^ v1 == v2.cross(v1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3e5f03c1ff2bb90a3487ed5c2c05b2a7fa3bece Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/appellseqs.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/appellseqs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ff29f13ad7b0a534bb900e860bc913b18443bcb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/appellseqs.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/constructor.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/constructor.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e08fde6b0d90fd4f5f825bd7d5adf746dcb34a9f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/constructor.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/densearith.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/densearith.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba84e251add18a8c91a13fafe18a4bf2164d7519 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/densearith.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/densebasic.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/densebasic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ce1a6eb258201b2ae3da6f9ac7dc3357018625ce Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/densebasic.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/densetools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/densetools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..149eca2e49ad08b8630313bbcdd41e1f02ab6e8b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/densetools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/dispersion.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/dispersion.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d59a2d28b6505f0a331454f7cce7eef23b087152 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/dispersion.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/distributedmodules.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/distributedmodules.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b4eb6c2cd32f91f4d49da685e44231ae76c93c7b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/distributedmodules.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/domainmatrix.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/domainmatrix.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f7e43e4ebb898f54c21c6a09da4fd7f604720a0e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/domainmatrix.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/euclidtools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/euclidtools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b86219d73df4334fa795eaefa83aa7df6074ac02 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/euclidtools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/factortools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/factortools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..faa6d43f47cd61a5f66fd210bc90786bff57fdde Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/factortools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/fglmtools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/fglmtools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bcfc9df7ca0a80a3b0d99c855bfe05c30c207fe0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/fglmtools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/fields.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/fields.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5166fa41663d64459b2816e0531fd14f073ee9af Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/fields.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/galoistools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/galoistools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d27d944cb798dd1c36819cd4702ecdc30bcf8ac6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/galoistools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/groebnertools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/groebnertools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a04da8e69c596082bd6ad6cd52ba688b67b11b81 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/groebnertools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/heuristicgcd.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/heuristicgcd.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7231b2d6d3ee28681a024024579e19390fe603a9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/heuristicgcd.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/modulargcd.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/modulargcd.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b5cccc006fd49c137a4e12913f9aa5e45de5554 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/modulargcd.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/monomials.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/monomials.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd8705d6e76e403b365bfa0442af1e22dc5770c6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/monomials.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/multivariate_resultants.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/multivariate_resultants.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ac3f1c3a72a15343ab0bf12987a8debbe011f07 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/multivariate_resultants.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/orderings.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/orderings.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fef3897a35388d7da0ac320399b24a06b87c1b29 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/orderings.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/orthopolys.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/orthopolys.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d74f3d79c78621db8e34f287bf8980e3d13570b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/orthopolys.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/partfrac.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/partfrac.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..89ac7aff8c795a86d8d79d0257667e2499c1401d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/partfrac.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyconfig.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyconfig.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..86f583198a58e783cc0a9a31c8f6952a85fc030c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyconfig.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyerrors.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyerrors.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99f77dd98456149fceddafd2d63bfd48959b007e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyerrors.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyfuncs.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyfuncs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0cb261b333332bb7d616a852ad1c8cf714e642c9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyfuncs.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polymatrix.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polymatrix.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0da877f1ea22d92f5b2c69d11a54a52e0efae5ae Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polymatrix.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyoptions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyoptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..190d9d7c4b82f71f7dc4620466f5078c569e6b96 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyoptions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyroots.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyroots.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..41a362a1d1e6bdb528d83d8938373dfa9f55d7eb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyroots.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyutils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyutils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b07d882b9a986a373e49c8b9e90b74fb02ca44af Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/polyutils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/puiseux.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/puiseux.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c378bd202d8b45bc258cfefe66a88166b5c4b77 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/puiseux.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/rationaltools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/rationaltools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc3b74476e980880babd31a77da8fabc7c82a866 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/rationaltools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/ring_series.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/ring_series.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a972fe2046a638eb4b919af82960f0f7dd662815 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/ring_series.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/rootisolation.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/rootisolation.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b30b98deb1cbe62fb83c3e8df55761ea8d617f9e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/rootisolation.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/rootoftools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/rootoftools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e773c77b14238db786ebcf9d60c93c92ae4bd21 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/rootoftools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/solvers.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/solvers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6150cabb0f800e6fd6e4e334b1b1a7870deac92 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/solvers.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/specialpolys.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/specialpolys.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d0967fd68cf758c042c9eaeab9e49772dc97d8cd Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/specialpolys.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/sqfreetools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/sqfreetools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25207478e601553c6779c1f550084ef00608b47a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/sqfreetools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/subresultants_qq_zz.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/subresultants_qq_zz.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..81d8c680fa6e84ed70ad77ba5dcc387dee757b58 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/__pycache__/subresultants_qq_zz.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..43486eec86f7453ec470a22b8f8decaa316cbe70 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/__init__.py @@ -0,0 +1,5 @@ +"""Module for algebraic geometry and commutative algebra.""" + +from .homomorphisms import homomorphism + +__all__ = ['homomorphism'] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/extensions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/extensions.py new file mode 100644 index 0000000000000000000000000000000000000000..2668f792b5721db877f275e57ed54961b2e4df93 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/extensions.py @@ -0,0 +1,356 @@ +"""Finite extensions of ring domains.""" + +from sympy.polys.domains.domain import Domain +from sympy.polys.domains.domainelement import DomainElement +from sympy.polys.polyerrors import (CoercionFailed, NotInvertible, + GeneratorsError) +from sympy.polys.polytools import Poly +from sympy.printing.defaults import DefaultPrinting + + +class ExtensionElement(DomainElement, DefaultPrinting): + """ + Element of a finite extension. + + A class of univariate polynomials modulo the ``modulus`` + of the extension ``ext``. It is represented by the + unique polynomial ``rep`` of lowest degree. Both + ``rep`` and the representation ``mod`` of ``modulus`` + are of class DMP. + + """ + __slots__ = ('rep', 'ext') + + def __init__(self, rep, ext): + self.rep = rep + self.ext = ext + + def parent(f): + return f.ext + + def as_expr(f): + return f.ext.to_sympy(f) + + def __bool__(f): + return bool(f.rep) + + def __pos__(f): + return f + + def __neg__(f): + return ExtElem(-f.rep, f.ext) + + def _get_rep(f, g): + if isinstance(g, ExtElem): + if g.ext == f.ext: + return g.rep + else: + return None + else: + try: + g = f.ext.convert(g) + return g.rep + except CoercionFailed: + return None + + def __add__(f, g): + rep = f._get_rep(g) + if rep is not None: + return ExtElem(f.rep + rep, f.ext) + else: + return NotImplemented + + __radd__ = __add__ + + def __sub__(f, g): + rep = f._get_rep(g) + if rep is not None: + return ExtElem(f.rep - rep, f.ext) + else: + return NotImplemented + + def __rsub__(f, g): + rep = f._get_rep(g) + if rep is not None: + return ExtElem(rep - f.rep, f.ext) + else: + return NotImplemented + + def __mul__(f, g): + rep = f._get_rep(g) + if rep is not None: + return ExtElem((f.rep * rep) % f.ext.mod, f.ext) + else: + return NotImplemented + + __rmul__ = __mul__ + + def _divcheck(f): + """Raise if division is not implemented for this divisor""" + if not f: + raise NotInvertible('Zero divisor') + elif f.ext.is_Field: + return True + elif f.rep.is_ground and f.ext.domain.is_unit(f.rep.LC()): + return True + else: + # Some cases like (2*x + 2)/2 over ZZ will fail here. It is + # unclear how to implement division in general if the ground + # domain is not a field so for now it was decided to restrict the + # implementation to division by invertible constants. + msg = (f"Can not invert {f} in {f.ext}. " + "Only division by invertible constants is implemented.") + raise NotImplementedError(msg) + + def inverse(f): + """Multiplicative inverse. + + Raises + ====== + + NotInvertible + If the element is a zero divisor. + + """ + f._divcheck() + + if f.ext.is_Field: + invrep = f.rep.invert(f.ext.mod) + else: + R = f.ext.ring + invrep = R.exquo(R.one, f.rep) + + return ExtElem(invrep, f.ext) + + def __truediv__(f, g): + rep = f._get_rep(g) + if rep is None: + return NotImplemented + g = ExtElem(rep, f.ext) + + try: + ginv = g.inverse() + except NotInvertible: + raise ZeroDivisionError(f"{f} / {g}") + + return f * ginv + + __floordiv__ = __truediv__ + + def __rtruediv__(f, g): + try: + g = f.ext.convert(g) + except CoercionFailed: + return NotImplemented + return g / f + + __rfloordiv__ = __rtruediv__ + + def __mod__(f, g): + rep = f._get_rep(g) + if rep is None: + return NotImplemented + g = ExtElem(rep, f.ext) + + try: + g._divcheck() + except NotInvertible: + raise ZeroDivisionError(f"{f} % {g}") + + # Division where defined is always exact so there is no remainder + return f.ext.zero + + def __rmod__(f, g): + try: + g = f.ext.convert(g) + except CoercionFailed: + return NotImplemented + return g % f + + def __pow__(f, n): + if not isinstance(n, int): + raise TypeError("exponent of type 'int' expected") + if n < 0: + try: + f, n = f.inverse(), -n + except NotImplementedError: + raise ValueError("negative powers are not defined") + + b = f.rep + m = f.ext.mod + r = f.ext.one.rep + while n > 0: + if n % 2: + r = (r*b) % m + b = (b*b) % m + n //= 2 + + return ExtElem(r, f.ext) + + def __eq__(f, g): + if isinstance(g, ExtElem): + return f.rep == g.rep and f.ext == g.ext + else: + return NotImplemented + + def __ne__(f, g): + return not f == g + + def __hash__(f): + return hash((f.rep, f.ext)) + + def __str__(f): + from sympy.printing.str import sstr + return sstr(f.as_expr()) + + __repr__ = __str__ + + @property + def is_ground(f): + return f.rep.is_ground + + def to_ground(f): + [c] = f.rep.to_list() + return c + +ExtElem = ExtensionElement + + +class MonogenicFiniteExtension(Domain): + r""" + Finite extension generated by an integral element. + + The generator is defined by a monic univariate + polynomial derived from the argument ``mod``. + + A shorter alias is ``FiniteExtension``. + + Examples + ======== + + Quadratic integer ring $\mathbb{Z}[\sqrt2]$: + + >>> from sympy import Symbol, Poly + >>> from sympy.polys.agca.extensions import FiniteExtension + >>> x = Symbol('x') + >>> R = FiniteExtension(Poly(x**2 - 2)); R + ZZ[x]/(x**2 - 2) + >>> R.rank + 2 + >>> R(1 + x)*(3 - 2*x) + x - 1 + + Finite field $GF(5^3)$ defined by the primitive + polynomial $x^3 + x^2 + 2$ (over $\mathbb{Z}_5$). + + >>> F = FiniteExtension(Poly(x**3 + x**2 + 2, modulus=5)); F + GF(5)[x]/(x**3 + x**2 + 2) + >>> F.basis + (1, x, x**2) + >>> F(x + 3)/(x**2 + 2) + -2*x**2 + x + 2 + + Function field of an elliptic curve: + + >>> t = Symbol('t') + >>> FiniteExtension(Poly(t**2 - x**3 - x + 1, t, field=True)) + ZZ(x)[t]/(t**2 - x**3 - x + 1) + + """ + is_FiniteExtension = True + + dtype = ExtensionElement + + def __init__(self, mod): + if not (isinstance(mod, Poly) and mod.is_univariate): + raise TypeError("modulus must be a univariate Poly") + + # Using auto=True (default) potentially changes the ground domain to a + # field whereas auto=False raises if division is not exact. We'll let + # the caller decide whether or not they want to put the ground domain + # over a field. In most uses mod is already monic. + mod = mod.monic(auto=False) + + self.rank = mod.degree() + self.modulus = mod + self.mod = mod.rep # DMP representation + + self.domain = dom = mod.domain + self.ring = dom.old_poly_ring(*mod.gens) + + self.zero = self.convert(self.ring.zero) + self.one = self.convert(self.ring.one) + + gen = self.ring.gens[0] + self.symbol = self.ring.symbols[0] + self.generator = self.convert(gen) + self.basis = tuple(self.convert(gen**i) for i in range(self.rank)) + + # XXX: It might be necessary to check mod.is_irreducible here + self.is_Field = self.domain.is_Field + + def new(self, arg): + rep = self.ring.convert(arg) + return ExtElem(rep % self.mod, self) + + def __eq__(self, other): + if not isinstance(other, FiniteExtension): + return False + return self.modulus == other.modulus + + def __hash__(self): + return hash((self.__class__.__name__, self.modulus)) + + def __str__(self): + return "%s/(%s)" % (self.ring, self.modulus.as_expr()) + + __repr__ = __str__ + + @property + def has_CharacteristicZero(self): + return self.domain.has_CharacteristicZero + + def characteristic(self): + return self.domain.characteristic() + + def convert(self, f, base=None): + rep = self.ring.convert(f, base) + return ExtElem(rep % self.mod, self) + + def convert_from(self, f, base): + rep = self.ring.convert(f, base) + return ExtElem(rep % self.mod, self) + + def to_sympy(self, f): + return self.ring.to_sympy(f.rep) + + def from_sympy(self, f): + return self.convert(f) + + def set_domain(self, K): + mod = self.modulus.set_domain(K) + return self.__class__(mod) + + def drop(self, *symbols): + if self.symbol in symbols: + raise GeneratorsError('Can not drop generator from FiniteExtension') + K = self.domain.drop(*symbols) + return self.set_domain(K) + + def quo(self, f, g): + return self.exquo(f, g) + + def exquo(self, f, g): + rep = self.ring.exquo(f.rep, g.rep) + return ExtElem(rep % self.mod, self) + + def is_negative(self, a): + return False + + def is_unit(self, a): + if self.is_Field: + return bool(a) + elif a.is_ground: + return self.domain.is_unit(a.to_ground()) + +FiniteExtension = MonogenicFiniteExtension diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/homomorphisms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/homomorphisms.py new file mode 100644 index 0000000000000000000000000000000000000000..45e9549980a8848eee944000d321922576961a00 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/homomorphisms.py @@ -0,0 +1,691 @@ +""" +Computations with homomorphisms of modules and rings. + +This module implements classes for representing homomorphisms of rings and +their modules. Instead of instantiating the classes directly, you should use +the function ``homomorphism(from, to, matrix)`` to create homomorphism objects. +""" + + +from sympy.polys.agca.modules import (Module, FreeModule, QuotientModule, + SubModule, SubQuotientModule) +from sympy.polys.polyerrors import CoercionFailed + +# The main computational task for module homomorphisms is kernels. +# For this reason, the concrete classes are organised by domain module type. + + +class ModuleHomomorphism: + """ + Abstract base class for module homomoprhisms. Do not instantiate. + + Instead, use the ``homomorphism`` function: + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> homomorphism(F, F, [[1, 0], [0, 1]]) + Matrix([ + [1, 0], : QQ[x]**2 -> QQ[x]**2 + [0, 1]]) + + Attributes: + + - ring - the ring over which we are considering modules + - domain - the domain module + - codomain - the codomain module + - _ker - cached kernel + - _img - cached image + + Non-implemented methods: + + - _kernel + - _image + - _restrict_domain + - _restrict_codomain + - _quotient_domain + - _quotient_codomain + - _apply + - _mul_scalar + - _compose + - _add + """ + + def __init__(self, domain, codomain): + if not isinstance(domain, Module): + raise TypeError('Source must be a module, got %s' % domain) + if not isinstance(codomain, Module): + raise TypeError('Target must be a module, got %s' % codomain) + if domain.ring != codomain.ring: + raise ValueError('Source and codomain must be over same ring, ' + 'got %s != %s' % (domain, codomain)) + self.domain = domain + self.codomain = codomain + self.ring = domain.ring + self._ker = None + self._img = None + + def kernel(self): + r""" + Compute the kernel of ``self``. + + That is, if ``self`` is the homomorphism `\phi: M \to N`, then compute + `ker(\phi) = \{x \in M | \phi(x) = 0\}`. This is a submodule of `M`. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> homomorphism(F, F, [[1, 0], [x, 0]]).kernel() + <[x, -1]> + """ + if self._ker is None: + self._ker = self._kernel() + return self._ker + + def image(self): + r""" + Compute the image of ``self``. + + That is, if ``self`` is the homomorphism `\phi: M \to N`, then compute + `im(\phi) = \{\phi(x) | x \in M \}`. This is a submodule of `N`. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> homomorphism(F, F, [[1, 0], [x, 0]]).image() == F.submodule([1, 0]) + True + """ + if self._img is None: + self._img = self._image() + return self._img + + def _kernel(self): + """Compute the kernel of ``self``.""" + raise NotImplementedError + + def _image(self): + """Compute the image of ``self``.""" + raise NotImplementedError + + def _restrict_domain(self, sm): + """Implementation of domain restriction.""" + raise NotImplementedError + + def _restrict_codomain(self, sm): + """Implementation of codomain restriction.""" + raise NotImplementedError + + def _quotient_domain(self, sm): + """Implementation of domain quotient.""" + raise NotImplementedError + + def _quotient_codomain(self, sm): + """Implementation of codomain quotient.""" + raise NotImplementedError + + def restrict_domain(self, sm): + """ + Return ``self``, with the domain restricted to ``sm``. + + Here ``sm`` has to be a submodule of ``self.domain``. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) + >>> h + Matrix([ + [1, x], : QQ[x]**2 -> QQ[x]**2 + [0, 0]]) + >>> h.restrict_domain(F.submodule([1, 0])) + 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() + 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' + % (self.domain, sm)) + if sm == self.domain: + return self + return self._restrict_domain(sm) + + def restrict_codomain(self, sm): + """ + Return ``self``, with codomain restricted to to ``sm``. + + Here ``sm`` has to be a submodule of ``self.codomain`` containing the + image. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) + >>> h + Matrix([ + [1, x], : QQ[x]**2 -> QQ[x]**2 + [0, 0]]) + >>> h.restrict_codomain(F.submodule([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' + % (self.image(), sm)) + if sm == self.codomain: + return self + return self._restrict_codomain(sm) + + def quotient_domain(self, sm): + """ + Return ``self`` with domain replaced by ``domain/sm``. + + Here ``sm`` must be a submodule of ``self.kernel()``. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) + >>> h + Matrix([ + [1, x], : QQ[x]**2 -> QQ[x]**2 + [0, 0]]) + >>> h.quotient_domain(F.submodule([-x, 1])) + 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' % + (self.kernel(), sm)) + if sm.is_zero(): + return self + return self._quotient_domain(sm) + + def quotient_codomain(self, sm): + """ + Return ``self`` with codomain replaced by ``codomain/sm``. + + Here ``sm`` must be a submodule of ``self.codomain``. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) + >>> h + Matrix([ + [1, x], : QQ[x]**2 -> QQ[x]**2 + [0, 0]]) + >>> h.quotient_codomain(F.submodule([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 + 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' + % (self.codomain, sm)) + if sm.is_zero(): + return self + return self._quotient_codomain(sm) + + def _apply(self, elem): + """Apply ``self`` to ``elem``.""" + raise NotImplementedError + + def __call__(self, elem): + return self.codomain.convert(self._apply(self.domain.convert(elem))) + + def _compose(self, oth): + """ + Compose ``self`` with ``oth``, that is, return the homomorphism + obtained by first applying then ``self``, then ``oth``. + + (This method is private since in this syntax, it is non-obvious which + homomorphism is executed first.) + """ + raise NotImplementedError + + def _mul_scalar(self, c): + """Scalar multiplication. ``c`` is guaranteed in self.ring.""" + raise NotImplementedError + + def _add(self, oth): + """ + Homomorphism addition. + ``oth`` is guaranteed to be a homomorphism with same domain/codomain. + """ + raise NotImplementedError + + def _check_hom(self, oth): + """Helper to check that oth is a homomorphism with same domain/codomain.""" + if not isinstance(oth, ModuleHomomorphism): + return False + return oth.domain == self.domain and oth.codomain == self.codomain + + def __mul__(self, oth): + if isinstance(oth, ModuleHomomorphism) and self.domain == oth.codomain: + return oth._compose(self) + try: + return self._mul_scalar(self.ring.convert(oth)) + except CoercionFailed: + return NotImplemented + + # NOTE: _compose will never be called from rmul + __rmul__ = __mul__ + + def __truediv__(self, oth): + try: + return self._mul_scalar(1/self.ring.convert(oth)) + except CoercionFailed: + return NotImplemented + + def __add__(self, oth): + if self._check_hom(oth): + return self._add(oth) + return NotImplemented + + def __sub__(self, oth): + if self._check_hom(oth): + return self._add(oth._mul_scalar(self.ring.convert(-1))) + return NotImplemented + + def is_injective(self): + """ + Return True if ``self`` is injective. + + That is, check if the elements of the domain are mapped to the same + codomain element. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) + >>> h.is_injective() + False + >>> h.quotient_domain(h.kernel()).is_injective() + True + """ + return self.kernel().is_zero() + + def is_surjective(self): + """ + Return True if ``self`` is surjective. + + That is, check if every element of the codomain has at least one + preimage. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) + >>> h.is_surjective() + False + >>> h.restrict_codomain(h.image()).is_surjective() + True + """ + return self.image() == self.codomain + + def is_isomorphism(self): + """ + Return True if ``self`` is an isomorphism. + + That is, check if every element of the codomain has precisely one + preimage. Equivalently, ``self`` is both injective and surjective. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) + >>> h = h.restrict_codomain(h.image()) + >>> h.is_isomorphism() + False + >>> h.quotient_domain(h.kernel()).is_isomorphism() + True + """ + return self.is_injective() and self.is_surjective() + + def is_zero(self): + """ + Return True if ``self`` is a zero morphism. + + That is, check if every element of the domain is mapped to zero + under self. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) + >>> h.is_zero() + False + >>> h.restrict_domain(F.submodule()).is_zero() + True + >>> h.quotient_codomain(h.image()).is_zero() + True + """ + return self.image().is_zero() + + def __eq__(self, oth): + try: + return (self - oth).is_zero() + except TypeError: + return False + + def __ne__(self, oth): + return not (self == oth) + + +class MatrixHomomorphism(ModuleHomomorphism): + r""" + Helper class for all homomoprhisms which are expressed via a matrix. + + That is, for such homomorphisms ``domain`` is contained in a module + generated by finitely many elements `e_1, \ldots, e_n`, so that the + homomorphism is determined uniquely by its action on the `e_i`. It + can thus be represented as a vector of elements of the codomain module, + or potentially a supermodule of the codomain module + (and hence conventionally as a matrix, if there is a similar interpretation + for elements of the codomain module). + + Note that this class does *not* assume that the `e_i` freely generate a + submodule, nor that ``domain`` is even all of this submodule. It exists + only to unify the interface. + + Do not instantiate. + + Attributes: + + - matrix - the list of images determining the homomorphism. + NOTE: the elements of matrix belong to either self.codomain or + self.codomain.container + + Still non-implemented methods: + + - kernel + - _apply + """ + + def __init__(self, domain, codomain, matrix): + ModuleHomomorphism.__init__(self, domain, codomain) + if len(matrix) != domain.rank: + raise ValueError('Need to provide %s elements, got %s' + % (domain.rank, len(matrix))) + + converter = self.codomain.convert + if isinstance(self.codomain, (SubModule, SubQuotientModule)): + converter = self.codomain.container.convert + self.matrix = tuple(converter(x) for x in matrix) + + def _sympy_matrix(self): + """Helper function which returns a SymPy matrix ``self.matrix``.""" + from sympy.matrices import Matrix + c = lambda x: x + if isinstance(self.codomain, (QuotientModule, SubQuotientModule)): + c = lambda x: x.data + 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) + + def _restrict_domain(self, sm): + """Implementation of domain restriction.""" + return SubModuleHomomorphism(sm, self.codomain, self.matrix) + + def _restrict_codomain(self, sm): + """Implementation of codomain restriction.""" + return self.__class__(self.domain, sm, self.matrix) + + def _quotient_domain(self, sm): + """Implementation of domain quotient.""" + return self.__class__(self.domain/sm, self.codomain, self.matrix) + + def _quotient_codomain(self, sm): + """Implementation of codomain quotient.""" + Q = self.codomain/sm + converter = Q.convert + if isinstance(self.codomain, SubModule): + converter = Q.container.convert + return self.__class__(self.domain, self.codomain/sm, + [converter(x) for x in self.matrix]) + + def _add(self, oth): + return self.__class__(self.domain, self.codomain, + [x + y for x, y in zip(self.matrix, oth.matrix)]) + + def _mul_scalar(self, c): + return self.__class__(self.domain, self.codomain, [c*x for x in self.matrix]) + + 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 + thereof. + + Do not instantiate; the constructor does not check that your data is well + defined. Use the ``homomorphism`` function instead: + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> homomorphism(F, F, [[1, 0], [0, 1]]) + Matrix([ + [1, 0], : QQ[x]**2 -> QQ[x]**2 + [0, 1]]) + """ + + def _apply(self, elem): + if isinstance(self.domain, QuotientModule): + elem = elem.data + return sum(x * e for x, e in zip(elem, self.matrix)) + + def _image(self): + return self.codomain.submodule(*self.matrix) + + def _kernel(self): + # The domain is either a free module or a quotient thereof. + # It does not matter if it is a quotient, because that won't increase + # the kernel. + # Our generators {e_i} are sent to the matrix entries {b_i}. + # The kernel is essentially the syzygy module of these {b_i}. + 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 + or a quotient thereof. + + Do not instantiate; the constructor does not check that your data is well + defined. Use the ``homomorphism`` function instead: + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> M = QQ.old_poly_ring(x).free_module(2)*x + >>> homomorphism(M, M, [[1, 0], [0, 1]]) + Matrix([ + [1, 0], : <[x, 0], [0, x]> -> <[x, 0], [0, x]> + [0, 1]]) + """ + + def _apply(self, elem): + if isinstance(self.domain, SubQuotientModule): + elem = elem.data + return sum(x * e for x, e in zip(elem, self.matrix)) + + def _image(self): + return self.codomain.submodule(*[self(x) for x in self.domain.gens]) + + def _kernel(self): + syz = self.image().syzygy_module() + return self.domain.submodule( + *[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. + + This function tries to build a homomorphism from ``domain`` to ``codomain`` + via the matrix ``matrix``. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> from sympy.polys.agca import homomorphism + + >>> R = QQ.old_poly_ring(x) + >>> T = R.free_module(2) + + If ``domain`` is a free module generated by `e_1, \ldots, e_n`, then + ``matrix`` should be an n-element iterable `(b_1, \ldots, b_n)` where + the `b_i` are elements of ``codomain``. The constructed homomorphism is the + unique homomorphism sending `e_i` to `b_i`. + + >>> F = R.free_module(2) + >>> h = homomorphism(F, T, [[1, x], [x**2, 0]]) + >>> h + Matrix([ + [1, x**2], : QQ[x]**2 -> QQ[x]**2 + [x, 0]]) + >>> h([1, 0]) + [1, x] + >>> h([0, 1]) + [x**2, 0] + >>> h([1, 1]) + [x**2 + 1, x] + + If ``domain`` is a submodule of a free module, them ``matrix`` determines + a homomoprhism from the containing free module to ``codomain``, and the + homomorphism returned is obtained by restriction to ``domain``. + + >>> S = F.submodule([1, 0], [0, x]) + >>> homomorphism(S, T, [[1, x], [x**2, 0]]) + 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 + homomorphism descends to ``domain`` and is returned; otherwise an exception + is raised. + + >>> homomorphism(S/[(1, 0)], T, [0, [x**2, 0]]) + 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): + ... + ValueError: kernel <[1, 0], [0, 0]> must contain sm, got <[0,x]> + + """ + def freepres(module): + """ + Return a tuple ``(F, S, Q, c)`` where ``F`` is a free module, ``S`` is a + submodule of ``F``, and ``Q`` a submodule of ``S``, such that + ``module = S/Q``, and ``c`` is a conversion function. + """ + if isinstance(module, FreeModule): + return module, module, module.submodule(), lambda x: module.convert(x) + if isinstance(module, QuotientModule): + return (module.base, module.base, module.killed_module, + lambda x: module.convert(x).data) + if isinstance(module, SubQuotientModule): + return (module.base.container, module.base, module.killed_module, + lambda x: module.container.convert(x).data) + # an ordinary submodule + return (module.container, module, module.submodule(), + lambda x: module.container.convert(x)) + + SF, SS, SQ, _ = freepres(domain) + TF, TS, TQ, c = freepres(codomain) + # NOTE this is probably a bit inefficient (redundant checks) + return FreeModuleHomomorphism(SF, TF, [c(x) for x in matrix] + ).restrict_domain(SS).restrict_codomain(TS + ).quotient_codomain(TQ).quotient_domain(SQ) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/ideals.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/ideals.py new file mode 100644 index 0000000000000000000000000000000000000000..1969554a1d674bc36ded1a3e312d587c66104086 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/ideals.py @@ -0,0 +1,395 @@ +"""Computations with ideals of polynomial rings.""" + +from sympy.polys.polyerrors import CoercionFailed +from sympy.polys.polyutils import IntegerPowerable + + +class Ideal(IntegerPowerable): + """ + Abstract base class for ideals. + + Do not instantiate - use explicit constructors in the ring class instead: + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> QQ.old_poly_ring(x).ideal(x+1) + + + Attributes + + - ring - the ring this ideal belongs to + + Non-implemented methods: + + - _contains_elem + - _contains_ideal + - _quotient + - _intersect + - _union + - _product + - is_whole_ring + - is_zero + - is_prime, is_maximal, is_primary, is_radical + - is_principal + - height, depth + - radical + + Methods that likely should be overridden in subclasses: + + - reduce_element + """ + + def _contains_elem(self, x): + """Implementation of element containment.""" + raise NotImplementedError + + def _contains_ideal(self, I): + """Implementation of ideal containment.""" + raise NotImplementedError + + def _quotient(self, J): + """Implementation of ideal quotient.""" + raise NotImplementedError + + def _intersect(self, J): + """Implementation of ideal intersection.""" + raise NotImplementedError + + def is_whole_ring(self): + """Return True if ``self`` is the whole ring.""" + raise NotImplementedError + + def is_zero(self): + """Return True if ``self`` is the zero ideal.""" + raise NotImplementedError + + def _equals(self, J): + """Implementation of ideal equality.""" + return self._contains_ideal(J) and J._contains_ideal(self) + + def is_prime(self): + """Return True if ``self`` is a prime ideal.""" + raise NotImplementedError + + def is_maximal(self): + """Return True if ``self`` is a maximal ideal.""" + raise NotImplementedError + + def is_radical(self): + """Return True if ``self`` is a radical ideal.""" + raise NotImplementedError + + def is_primary(self): + """Return True if ``self`` is a primary ideal.""" + raise NotImplementedError + + def is_principal(self): + """Return True if ``self`` is a principal ideal.""" + raise NotImplementedError + + def radical(self): + """Compute the radical of ``self``.""" + raise NotImplementedError + + def depth(self): + """Compute the depth of ``self``.""" + raise NotImplementedError + + def height(self): + """Compute the height of ``self``.""" + raise NotImplementedError + + # TODO more + + # non-implemented methods end here + + def __init__(self, ring): + self.ring = ring + + 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)) + + def contains(self, elem): + """ + Return True if ``elem`` is an element of this ideal. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).ideal(x+1, x-1).contains(3) + True + >>> QQ.old_poly_ring(x).ideal(x**2, x**3).contains(x) + False + """ + return self._contains_elem(self.ring.convert(elem)) + + def subset(self, other): + """ + Returns True if ``other`` is is a subset of ``self``. + + Here ``other`` may be an ideal. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> I = QQ.old_poly_ring(x).ideal(x+1) + >>> I.subset([x**2 - 1, x**2 + 2*x + 1]) + True + >>> I.subset([x**2 + 1, x + 1]) + False + >>> I.subset(QQ.old_poly_ring(x).ideal(x**2 - 1)) + True + """ + if isinstance(other, Ideal): + return self._contains_ideal(other) + return all(self._contains_elem(x) for x in other) + + def quotient(self, J, **opts): + r""" + Compute the ideal quotient of ``self`` by ``J``. + + That is, if ``self`` is the ideal `I`, compute the set + `I : J = \{x \in R | xJ \subset I \}`. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import QQ + >>> R = QQ.old_poly_ring(x, y) + >>> R.ideal(x*y).quotient(R.ideal(x)) + + """ + self._check_ideal(J) + return self._quotient(J, **opts) + + def intersect(self, J): + """ + Compute the intersection of self with ideal J. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import QQ + >>> R = QQ.old_poly_ring(x, y) + >>> R.ideal(x).intersect(R.ideal(y)) + + """ + self._check_ideal(J) + return self._intersect(J) + + def saturate(self, J): + r""" + Compute the ideal saturation of ``self`` by ``J``. + + That is, if ``self`` is the ideal `I`, compute the set + `I : J^\infty = \{x \in R | xJ^n \subset I \text{ for some } n\}`. + """ + raise NotImplementedError + # Note this can be implemented using repeated quotient + + def union(self, J): + """ + Compute the ideal generated by the union of ``self`` and ``J``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).ideal(x**2 - 1).union(QQ.old_poly_ring(x).ideal((x+1)**2)) == QQ.old_poly_ring(x).ideal(x+1) + True + """ + self._check_ideal(J) + return self._union(J) + + def product(self, J): + r""" + Compute the ideal product of ``self`` and ``J``. + + That is, compute the ideal generated by products `xy`, for `x` an element + of ``self`` and `y \in J`. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import QQ + >>> QQ.old_poly_ring(x, y).ideal(x).product(QQ.old_poly_ring(x, y).ideal(y)) + + """ + self._check_ideal(J) + return self._product(J) + + def reduce_element(self, x): + """ + Reduce the element ``x`` of our ring modulo the ideal ``self``. + + Here "reduce" has no specific meaning: it could return a unique normal + form, simplify the expression a bit, or just do nothing. + """ + return x + + def __add__(self, e): + if not isinstance(e, Ideal): + R = self.ring.quotient_ring(self) + if isinstance(e, R.dtype): + return e + if isinstance(e, R.ring.dtype): + return R(e) + return R.convert(e) + self._check_ideal(e) + return self.union(e) + + __radd__ = __add__ + + def __mul__(self, e): + if not isinstance(e, Ideal): + try: + e = self.ring.ideal(e) + except CoercionFailed: + return NotImplemented + self._check_ideal(e) + return self.product(e) + + __rmul__ = __mul__ + + def _zeroth_power(self): + return self.ring.ideal(1) + + def _first_power(self): + # Raising to any power but 1 returns a new instance. So we mult by 1 + # here so that the first power is no exception. + return self * 1 + + def __eq__(self, e): + if not isinstance(e, Ideal) or e.ring != self.ring: + return False + return self._equals(e) + + def __ne__(self, e): + return not (self == e) + + +class ModuleImplementedIdeal(Ideal): + """ + Ideal implementation relying on the modules code. + + Attributes: + + - _module - the underlying module + """ + + def __init__(self, ring, module): + Ideal.__init__(self, ring) + self._module = module + + def _contains_elem(self, x): + return self._module.contains([x]) + + def _contains_ideal(self, J): + if not isinstance(J, ModuleImplementedIdeal): + raise NotImplementedError + return self._module.is_submodule(J._module) + + def _intersect(self, J): + if not isinstance(J, ModuleImplementedIdeal): + raise NotImplementedError + return self.__class__(self.ring, self._module.intersect(J._module)) + + def _quotient(self, J, **opts): + if not isinstance(J, ModuleImplementedIdeal): + raise NotImplementedError + return self._module.module_quotient(J._module, **opts) + + def _union(self, J): + if not isinstance(J, ModuleImplementedIdeal): + raise NotImplementedError + return self.__class__(self.ring, self._module.union(J._module)) + + @property + def gens(self): + """ + Return generators for ``self``. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x, y + >>> list(QQ.old_poly_ring(x, y).ideal(x, y, x**2 + y).gens) + [DMP_Python([[1], []], QQ), DMP_Python([[1, 0]], QQ), DMP_Python([[1], [], [1, 0]], QQ)] + """ + return (x[0] for x in self._module.gens) + + def is_zero(self): + """ + Return True if ``self`` is the zero ideal. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).ideal(x).is_zero() + False + >>> QQ.old_poly_ring(x).ideal().is_zero() + True + """ + return self._module.is_zero() + + def is_whole_ring(self): + """ + Return True if ``self`` is the whole ring, i.e. one generator is a unit. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ, ilex + >>> QQ.old_poly_ring(x).ideal(x).is_whole_ring() + False + >>> QQ.old_poly_ring(x).ideal(3).is_whole_ring() + True + >>> QQ.old_poly_ring(x, order=ilex).ideal(2 + x).is_whole_ring() + True + """ + return self._module.is_full_module() + + def __repr__(self): + from sympy.printing.str import sstr + gens = [self.ring.to_sympy(x) for [x] in self._module.gens] + return '<' + ','.join(sstr(g) for g in gens) + '>' + + # NOTE this is the only method using the fact that the module is a SubModule + def _product(self, J): + 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])) + + def in_terms_of_generators(self, e): + """ + Express ``e`` in terms of the generators of ``self``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> I = QQ.old_poly_ring(x).ideal(x**2 + 1, x) + >>> I.in_terms_of_generators(1) # doctest: +SKIP + [DMP_Python([1], QQ), DMP_Python([-1, 0], QQ)] + """ + return self._module.in_terms_of_generators([e]) + + def reduce_element(self, x, **options): + return self._module.reduce_element([x], **options)[0] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/modules.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/modules.py new file mode 100644 index 0000000000000000000000000000000000000000..0a2e2ed814f4143b4b49f8b1f10c2a07cb32d06a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/agca/modules.py @@ -0,0 +1,1488 @@ +""" +Computations with modules over polynomial rings. + +This module implements various classes that encapsulate groebner basis +computations for modules. Most of them should not be instantiated by hand. +Instead, use the constructing routines on objects you already have. + +For example, to construct a free module over ``QQ[x, y]``, call +``QQ[x, y].free_module(rank)`` instead of the ``FreeModule`` constructor. +In fact ``FreeModule`` is an abstract base class that should not be +instantiated, the ``free_module`` method instead returns the implementing class +``FreeModulePolyRing``. + +In general, the abstract base classes implement most functionality in terms of +a few non-implemented methods. The concrete base classes supply only these +non-implemented methods. They may also supply new implementations of the +convenience methods, for example if there are faster algorithms available. +""" + + +from copy import copy +from functools import reduce + +from sympy.polys.agca.ideals import Ideal +from sympy.polys.domains.field import Field +from sympy.polys.orderings import ProductOrder, monomial_key +from sympy.polys.polyclasses import DMP +from sympy.polys.polyerrors import CoercionFailed +from sympy.core.basic import _aresame +from sympy.utilities.iterables import iterable + +# TODO +# - module saturation +# - module quotient/intersection for quotient rings +# - free resoltutions / syzygies +# - finding small/minimal generating sets +# - ... + +########################################################################## +## Abstract base classes ################################################# +########################################################################## + + +class Module: + """ + Abstract base class for modules. + + Do not instantiate - use ring explicit constructors instead: + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> QQ.old_poly_ring(x).free_module(2) + QQ[x]**2 + + Attributes: + + - dtype - type of elements + - ring - containing ring + + Non-implemented methods: + + - submodule + - quotient_module + - is_zero + - is_submodule + - multiply_ideal + + The method convert likely needs to be changed in subclasses. + """ + + def __init__(self, ring): + self.ring = ring + + def convert(self, elem, M=None): + """ + Convert ``elem`` into internal representation of this module. + + If ``M`` is not None, it should be a module containing it. + """ + if not isinstance(elem, self.dtype): + raise CoercionFailed + return elem + + def submodule(self, *gens): + """Generate a submodule.""" + raise NotImplementedError + + def quotient_module(self, other): + """Generate a quotient module.""" + raise NotImplementedError + + def __truediv__(self, e): + if not isinstance(e, Module): + e = self.submodule(*e) + return self.quotient_module(e) + + def contains(self, elem): + """Return True if ``elem`` is an element of this module.""" + try: + self.convert(elem) + return True + except CoercionFailed: + return False + + def __contains__(self, elem): + return self.contains(elem) + + def subset(self, other): + """ + Returns True if ``other`` is is a subset of ``self``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> F.subset([(1, x), (x, 2)]) + True + >>> F.subset([(1/x, x), (x, 2)]) + False + """ + return all(self.contains(x) for x in other) + + def __eq__(self, other): + return self.is_submodule(other) and other.is_submodule(self) + + def __ne__(self, other): + return not (self == other) + + def is_zero(self): + """Returns True if ``self`` is a zero module.""" + raise NotImplementedError + + def is_submodule(self, other): + """Returns True if ``other`` is a submodule of ``self``.""" + raise NotImplementedError + + def multiply_ideal(self, other): + """ + Multiply ``self`` by the ideal ``other``. + """ + raise NotImplementedError + + def __mul__(self, e): + if not isinstance(e, Ideal): + try: + e = self.ring.ideal(e) + except (CoercionFailed, NotImplementedError): + return NotImplemented + return self.multiply_ideal(e) + + __rmul__ = __mul__ + + def identity_hom(self): + """Return the identity homomorphism on ``self``.""" + raise NotImplementedError + + +class ModuleElement: + """ + Base class for module element wrappers. + + Use this class to wrap primitive data types as module elements. It stores + a reference to the containing module, and implements all the arithmetic + operators. + + Attributes: + + - module - containing module + - data - internal data + + Methods that likely need change in subclasses: + + - add + - mul + - div + - eq + """ + + def __init__(self, module, data): + self.module = module + self.data = data + + def add(self, d1, d2): + """Add data ``d1`` and ``d2``.""" + return d1 + d2 + + def mul(self, m, d): + """Multiply module data ``m`` by coefficient d.""" + return m * d + + def div(self, m, d): + """Divide module data ``m`` by coefficient d.""" + return m / d + + def eq(self, d1, d2): + """Return true if d1 and d2 represent the same element.""" + return d1 == d2 + + def __add__(self, om): + if not isinstance(om, self.__class__) or om.module != self.module: + try: + om = self.module.convert(om) + except CoercionFailed: + return NotImplemented + return self.__class__(self.module, self.add(self.data, om.data)) + + __radd__ = __add__ + + def __neg__(self): + return self.__class__(self.module, self.mul(self.data, + self.module.ring.convert(-1))) + + def __sub__(self, om): + if not isinstance(om, self.__class__) or om.module != self.module: + try: + om = self.module.convert(om) + except CoercionFailed: + return NotImplemented + return self.__add__(-om) + + def __rsub__(self, om): + return (-self).__add__(om) + + def __mul__(self, o): + if not isinstance(o, self.module.ring.dtype): + try: + o = self.module.ring.convert(o) + except CoercionFailed: + return NotImplemented + return self.__class__(self.module, self.mul(self.data, o)) + + __rmul__ = __mul__ + + def __truediv__(self, o): + if not isinstance(o, self.module.ring.dtype): + try: + o = self.module.ring.convert(o) + except CoercionFailed: + return NotImplemented + return self.__class__(self.module, self.div(self.data, o)) + + def __eq__(self, om): + if not isinstance(om, self.__class__) or om.module != self.module: + try: + om = self.module.convert(om) + except CoercionFailed: + return False + return self.eq(self.data, om.data) + + def __ne__(self, om): + return not self == om + +########################################################################## +## Free Modules ########################################################## +########################################################################## + + +class FreeModuleElement(ModuleElement): + """Element of a free module. Data stored as a tuple.""" + + def add(self, d1, d2): + return tuple(x + y for x, y in zip(d1, d2)) + + def mul(self, d, p): + return tuple(x * p for x in d) + + def div(self, d, p): + return tuple(x / p for x in d) + + def __repr__(self): + from sympy.printing.str import sstr + data = self.data + if any(isinstance(x, DMP) for x in data): + data = [self.module.ring.to_sympy(x) for x in data] + return '[' + ', '.join(sstr(x) for x in data) + ']' + + def __iter__(self): + return self.data.__iter__() + + def __getitem__(self, idx): + return self.data[idx] + + +class FreeModule(Module): + """ + Abstract base class for free modules. + + Additional attributes: + + - rank - rank of the free module + + Non-implemented methods: + + - submodule + """ + + dtype = FreeModuleElement + + def __init__(self, ring, rank): + Module.__init__(self, ring) + self.rank = rank + + def __repr__(self): + return repr(self.ring) + "**" + repr(self.rank) + + def is_submodule(self, other): + """ + Returns True if ``other`` is a submodule of ``self``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> M = F.submodule([2, x]) + >>> F.is_submodule(F) + True + >>> F.is_submodule(M) + True + >>> M.is_submodule(F) + False + """ + if isinstance(other, SubModule): + return other.container == self + if isinstance(other, FreeModule): + return other.ring == self.ring and other.rank == self.rank + return False + + def convert(self, elem, M=None): + """ + Convert ``elem`` into the internal representation. + + This method is called implicitly whenever computations involve elements + not in the internal representation. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> F.convert([1, 0]) + [1, 0] + """ + if isinstance(elem, FreeModuleElement): + if elem.module is self: + return elem + if elem.module.rank != self.rank: + raise CoercionFailed + return FreeModuleElement(self, + tuple(self.ring.convert(x, elem.module.ring) for x in elem.data)) + elif iterable(elem): + tpl = tuple(self.ring.convert(x) for x in elem) + if len(tpl) != self.rank: + raise CoercionFailed + return FreeModuleElement(self, tpl) + elif _aresame(elem, 0): + return FreeModuleElement(self, (self.ring.convert(0),)*self.rank) + else: + raise CoercionFailed + + def is_zero(self): + """ + Returns True if ``self`` is a zero module. + + (If, as this implementation assumes, the coefficient ring is not the + zero ring, then this is equivalent to the rank being zero.) + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).free_module(0).is_zero() + True + >>> QQ.old_poly_ring(x).free_module(1).is_zero() + False + """ + return self.rank == 0 + + def basis(self): + """ + Return a set of basis elements. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).free_module(3).basis() + ([1, 0, 0], [0, 1, 0], [0, 0, 1]) + """ + from sympy.matrices import eye + M = eye(self.rank) + return tuple(self.convert(M.row(i)) for i in range(self.rank)) + + def quotient_module(self, submodule): + """ + Return a quotient module. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> M = QQ.old_poly_ring(x).free_module(2) + >>> M.quotient_module(M.submodule([1, x], [x, 2])) + QQ[x]**2/<[1, x], [x, 2]> + + Or more conicisely, using the overloaded division operator: + + >>> QQ.old_poly_ring(x).free_module(2) / [[1, x], [x, 2]] + QQ[x]**2/<[1, x], [x, 2]> + """ + return QuotientModule(self.ring, self, submodule) + + def multiply_ideal(self, other): + """ + Multiply ``self`` by the ideal ``other``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> I = QQ.old_poly_ring(x).ideal(x) + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> F.multiply_ideal(I) + <[x, 0], [0, x]> + """ + return self.submodule(*self.basis()).multiply_ideal(other) + + def identity_hom(self): + """ + Return the identity homomorphism on ``self``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).free_module(2).identity_hom() + 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. + + Do not instantiate this, use the constructor method of the ring instead: + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(3) + >>> F + QQ[x]**3 + >>> F.contains([x, 1, 0]) + True + >>> F.contains([1/x, 0, 1]) + False + """ + + def __init__(self, ring, rank): + 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 ' + + 'polynomial rings, got %s' % ring) + if not isinstance(ring.dom, Field): + raise NotImplementedError('Ground domain must be a field, ' + + 'got %s' % ring.dom) + + def submodule(self, *gens, **opts): + """ + Generate a submodule. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import QQ + >>> M = QQ.old_poly_ring(x, y).free_module(2).submodule([x, x + y]) + >>> M + <[x, x + y]> + >>> M.contains([2*x, 2*x + 2*y]) + True + >>> M.contains([x, y]) + False + """ + return SubModulePolyRing(gens, self, **opts) + + +class FreeModuleQuotientRing(FreeModule): + """ + Free module over a quotient ring. + + Do not instantiate this, use the constructor method of the ring instead: + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = (QQ.old_poly_ring(x)/[x**2 + 1]).free_module(3) + >>> F + (QQ[x]/)**3 + + Attributes + + - quot - the quotient module `R^n / IR^n`, where `R/I` is our ring + """ + + def __init__(self, ring, rank): + from sympy.polys.domains.quotientring import QuotientRing + FreeModule.__init__(self, ring, rank) + if not isinstance(ring, QuotientRing): + raise NotImplementedError('This implementation only works over ' + + 'quotient rings, got %s' % ring) + F = self.ring.ring.free_module(self.rank) + self.quot = F / (self.ring.base_ideal*F) + + def __repr__(self): + return "(" + repr(self.ring) + ")" + "**" + repr(self.rank) + + def submodule(self, *gens, **opts): + """ + Generate a submodule. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import QQ + >>> M = (QQ.old_poly_ring(x, y)/[x**2 - y**2]).free_module(2).submodule([x, x + y]) + >>> M + <[x + , x + y + ]> + >>> M.contains([y**2, x**2 + x*y]) + True + >>> M.contains([x, y]) + False + """ + return SubModuleQuotientRing(gens, self, **opts) + + def lift(self, elem): + """ + Lift the element ``elem`` of self to the module self.quot. + + Note that self.quot is the same set as self, just as an R-module + and not as an R/I-module, so this makes sense. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = (QQ.old_poly_ring(x)/[x**2 + 1]).free_module(2) + >>> e = F.convert([1, 0]) + >>> e + [1 + , 0 + ] + >>> L = F.quot + >>> l = F.lift(e) + >>> l + [1, 0] + <[x**2 + 1, 0], [0, x**2 + 1]> + >>> L.contains(l) + True + """ + return self.quot.convert([x.data for x in elem]) + + def unlift(self, elem): + """ + Push down an element of self.quot to self. + + This undoes ``lift``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = (QQ.old_poly_ring(x)/[x**2 + 1]).free_module(2) + >>> e = F.convert([1, 0]) + >>> l = F.lift(e) + >>> e == l + False + >>> e == F.unlift(l) + True + """ + return self.convert(elem.data) + +########################################################################## +## Submodules and subquotients ########################################### +########################################################################## + + +class SubModule(Module): + """ + Base class for submodules. + + Attributes: + + - container - containing module + - gens - generators (subset of containing module) + - rank - rank of containing module + + Non-implemented methods: + + - _contains + - _syzygies + - _in_terms_of_generators + - _intersect + - _module_quotient + + Methods that likely need change in subclasses: + + - reduce_element + """ + + def __init__(self, gens, container): + Module.__init__(self, container.ring) + self.gens = tuple(container.convert(x) for x in gens) + self.container = container + self.rank = container.rank + self.ring = container.ring + self.dtype = container.dtype + + def __repr__(self): + return "<" + ", ".join(repr(x) for x in self.gens) + ">" + + def _contains(self, other): + """Implementation of containment. + Other is guaranteed to be FreeModuleElement.""" + raise NotImplementedError + + def _syzygies(self): + """Implementation of syzygy computation wrt self generators.""" + raise NotImplementedError + + def _in_terms_of_generators(self, e): + """Implementation of expression in terms of generators.""" + raise NotImplementedError + + def convert(self, elem, M=None): + """ + Convert ``elem`` into the internal represantition. + + Mostly called implicitly. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> M = QQ.old_poly_ring(x).free_module(2).submodule([1, x]) + >>> M.convert([2, 2*x]) + [2, 2*x] + """ + if isinstance(elem, self.container.dtype) and elem.module is self: + return elem + r = copy(self.container.convert(elem, M)) + r.module = self + if not self._contains(r): + raise CoercionFailed + return r + + def _intersect(self, other): + """Implementation of intersection. + Other is guaranteed to be a submodule of same free module.""" + raise NotImplementedError + + def _module_quotient(self, other): + """Implementation of quotient. + Other is guaranteed to be a submodule of same free module.""" + raise NotImplementedError + + def intersect(self, other, **options): + """ + Returns the intersection of ``self`` with submodule ``other``. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x, y).free_module(2) + >>> F.submodule([x, x]).intersect(F.submodule([y, y])) + <[x*y, x*y]> + + Some implementation allow further options to be passed. Currently, to + only one implemented is ``relations=True``, in which case the function + will return a triple ``(res, rela, relb)``, where ``res`` is the + intersection module, and ``rela`` and ``relb`` are lists of coefficient + vectors, expressing the generators of ``res`` in terms of the + generators of ``self`` (``rela``) and ``other`` (``relb``). + + >>> F.submodule([x, x]).intersect(F.submodule([y, y]), relations=True) + (<[x*y, x*y]>, [(DMP_Python([[1, 0]], QQ),)], [(DMP_Python([[1], []], QQ),)]) + + The above result says: the intersection module is generated by the + single element `(-xy, -xy) = -y (x, x) = -x (y, y)`, where + `(x, x)` and `(y, y)` respectively are the unique generators of + the two modules being intersected. + """ + 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) + return self._intersect(other, **options) + + def module_quotient(self, other, **options): + r""" + Returns the module quotient of ``self`` by submodule ``other``. + + That is, if ``self`` is the module `M` and ``other`` is `N`, then + return the ideal `\{f \in R | fN \subset M\}`. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.abc import x, y + >>> F = QQ.old_poly_ring(x, y).free_module(2) + >>> S = F.submodule([x*y, x*y]) + >>> T = F.submodule([x, x]) + >>> S.module_quotient(T) + + + Some implementations allow further options to be passed. Currently, the + only one implemented is ``relations=True``, which may only be passed + if ``other`` is principal. In this case the function + will return a pair ``(res, rel)`` where ``res`` is the ideal, and + ``rel`` is a list of coefficient vectors, expressing the generators of + the ideal, multiplied by the generator of ``other`` in terms of + generators of ``self``. + + >>> S.module_quotient(T, relations=True) + (, [[DMP_Python([[1]], QQ)]]) + + This means that the quotient ideal is generated by the single element + `y`, and that `y (x, x) = 1 (xy, xy)`, `(x, x)` and `(xy, xy)` being + the generators of `T` and `S`, respectively. + """ + 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) + return self._module_quotient(other, **options) + + def union(self, other): + """ + Returns the module generated by the union of ``self`` and ``other``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(1) + >>> M = F.submodule([x**2 + x]) # + >>> N = F.submodule([x**2 - 1]) # <(x-1)(x+1)> + >>> M.union(N) == F.submodule([x+1]) + True + """ + 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) + return self.__class__(self.gens + other.gens, self.container) + + def is_zero(self): + """ + Return True if ``self`` is a zero module. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> F.submodule([x, 1]).is_zero() + False + >>> F.submodule([0, 0]).is_zero() + True + """ + return all(x == 0 for x in self.gens) + + def submodule(self, *gens): + """ + Generate a submodule. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> M = QQ.old_poly_ring(x).free_module(2).submodule([x, 1]) + >>> M.submodule([x**2, x]) + <[x**2, x]> + """ + if not self.subset(gens): + raise ValueError('%s not a subset of %s' % (gens, self)) + return self.__class__(gens, self.container) + + def is_full_module(self): + """ + Return True if ``self`` is the entire free module. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> F.submodule([x, 1]).is_full_module() + False + >>> F.submodule([1, 1], [1, 2]).is_full_module() + True + """ + return all(self.contains(x) for x in self.container.basis()) + + def is_submodule(self, other): + """ + Returns True if ``other`` is a submodule of ``self``. + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> M = F.submodule([2, x]) + >>> N = M.submodule([2*x, x**2]) + >>> M.is_submodule(M) + True + >>> M.is_submodule(N) + True + >>> N.is_submodule(M) + False + """ + if isinstance(other, SubModule): + return self.container == other.container and \ + 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 + + def syzygy_module(self, **opts): + r""" + Compute the syzygy module of the generators of ``self``. + + Suppose `M` is generated by `f_1, \ldots, f_n` over the ring + `R`. Consider the homomorphism `\phi: R^n \to M`, given by + sending `(r_1, \ldots, r_n) \to r_1 f_1 + \cdots + r_n f_n`. + The syzygy module is defined to be the kernel of `\phi`. + + Examples + ======== + + The syzygy module is zero iff the generators generate freely a free + submodule: + + >>> from sympy.abc import x, y + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).free_module(2).submodule([1, 0], [1, 1]).syzygy_module().is_zero() + True + + A slightly more interesting example: + + >>> M = QQ.old_poly_ring(x, y).free_module(2).submodule([x, 2*x], [y, 2*y]) + >>> S = QQ.old_poly_ring(x, y).free_module(2).submodule([y, -x]) + >>> M.syzygy_module() == S + True + """ + F = self.ring.free_module(len(self.gens)) + # NOTE we filter out zero syzygies. This is for convenience of the + # _syzygies function and not meant to replace any real "generating set + # reduction" algorithm + return F.submodule(*[x for x in self._syzygies() if F.convert(x) != 0], + **opts) + + def in_terms_of_generators(self, e): + """ + Express element ``e`` of ``self`` in terms of the generators. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> M = F.submodule([1, 0], [1, 1]) + >>> M.in_terms_of_generators([x, x**2]) # doctest: +SKIP + [DMP_Python([-1, 1, 0], QQ), DMP_Python([1, 0, 0], QQ)] + """ + try: + e = self.convert(e) + except CoercionFailed: + raise ValueError('%s is not an element of %s' % (e, self)) + return self._in_terms_of_generators(e) + + def reduce_element(self, x): + """ + Reduce the element ``x`` of our ring modulo the ideal ``self``. + + Here "reduce" has no specific meaning, it could return a unique normal + form, simplify the expression a bit, or just do nothing. + """ + return x + + def quotient_module(self, other, **opts): + """ + Return a quotient module. + + This is the same as taking a submodule of a quotient of the containing + module. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> S1 = F.submodule([x, 1]) + >>> S2 = F.submodule([x**2, x]) + >>> S1.quotient_module(S2) + <[x, 1] + <[x**2, x]>> + + Or more coincisely, using the overloaded division operator: + + >>> F.submodule([x, 1]) / [(x**2, x)] + <[x, 1] + <[x**2, x]>> + """ + if not self.is_submodule(other): + raise ValueError('%s not a submodule of %s' % (other, self)) + return SubQuotientModule(self.gens, + self.container.quotient_module(other), **opts) + + def __add__(self, oth): + return self.container.quotient_module(self).convert(oth) + + __radd__ = __add__ + + def multiply_ideal(self, I): + """ + Multiply ``self`` by the ideal ``I``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> I = QQ.old_poly_ring(x).ideal(x**2) + >>> M = QQ.old_poly_ring(x).free_module(2).submodule([1, 1]) + >>> I*M + <[x**2, x**2]> + """ + return self.submodule(*[x*g for [x] in I._module.gens for g in self.gens]) + + def inclusion_hom(self): + """ + Return a homomorphism representing the inclusion map of ``self``. + + That is, the natural map from ``self`` to ``self.container``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).free_module(2).submodule([x, x]).inclusion_hom() + Matrix([ + [1, 0], : <[x, x]> -> QQ[x]**2 + [0, 1]]) + """ + return self.container.identity_hom().restrict_domain(self) + + def identity_hom(self): + """ + Return the identity homomorphism on ``self``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).free_module(2).submodule([x, x]).identity_hom() + 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. + + Equivalently, quotient module of a submodule. + + Do not instantiate this, instead use the submodule or quotient_module + constructing methods: + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> S = F.submodule([1, 0], [1, x]) + >>> Q = F/[(1, 0)] + >>> S/[(1, 0)] == Q.submodule([5, x]) + True + + Attributes: + + - base - base module we are quotient of + - killed_module - submodule used to form the quotient + """ + def __init__(self, gens, container, **opts): + SubModule.__init__(self, gens, container) + self.killed_module = self.container.killed_module + # 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) + + def _contains(self, elem): + return self.base.contains(elem.data) + + def _syzygies(self): + # let N = self.killed_module be generated by e_1, ..., e_r + # let F = self.base be generated by f_1, ..., f_s and e_1, ..., e_r + # Then self = F/N. + # Let phi: R**s --> self be the evident surjection. + # Similarly psi: R**(s + r) --> F. + # We need to find generators for ker(phi). Let chi: R**s --> F be the + # evident lift of phi. For X in R**s, phi(X) = 0 iff chi(X) is + # contained in N, iff there exists Y in R**r such that + # psi(X, Y) = 0. + # Hence if alpha: R**(s + r) --> R**s is the projection map, then + # ker(phi) = alpha ker(psi). + return [X[:len(self.gens)] for X in self.base._syzygies()] + + def _in_terms_of_generators(self, e): + return self.base._in_terms_of_generators(e.data)[:len(self.gens)] + + def is_full_module(self): + """ + Return True if ``self`` is the entire free module. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> F.submodule([x, 1]).is_full_module() + False + >>> F.submodule([1, 1], [1, 2]).is_full_module() + True + """ + return self.base.is_full_module() + + def quotient_hom(self): + """ + Return the quotient homomorphism to self. + + That is, return the natural map from ``self.base`` to ``self``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> M = (QQ.old_poly_ring(x).free_module(2) / [(1, x)]).submodule([1, 0]) + >>> M.quotient_hom() + 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.""" + + def __init__(self, o1, o2, TOP): + if TOP: + ProductOrder.__init__(self, (o2, _subs1), (o1, _subs0)) + else: + ProductOrder.__init__(self, (o1, _subs0), (o2, _subs1)) + + +class SubModulePolyRing(SubModule): + """ + Submodule of a free module over a generalized polynomial ring. + + Do not instantiate this, use the constructor method of FreeModule instead: + + >>> from sympy.abc import x, y + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x, y).free_module(2) + >>> F.submodule([x, y], [1, 0]) + <[x, y], [1, 0]> + + Attributes: + + - order - monomial order used + """ + + #self._gb - cached groebner basis + #self._gbe - cached groebner basis relations + + def __init__(self, gens, container, order="lex", TOP=True): + SubModule.__init__(self, gens, container) + if not isinstance(container, FreeModulePolyRing): + raise NotImplementedError('This implementation is for submodules of ' + + 'FreeModulePolyRing, got %s' % container) + self.order = ModuleOrder(monomial_key(order), self.ring.order, TOP) + self._gb = None + self._gbe = None + + def __eq__(self, other): + if isinstance(other, SubModulePolyRing) and self.order != other.order: + return False + return SubModule.__eq__(self, other) + + def _groebner(self, extended=False): + """Returns a standard basis in sdm form.""" + 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._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], + sdm_nf_mora, self.order, self.ring.dom)) + if extended: + return self._gb, self._gbe + else: + return self._gb + + def _groebner_vec(self, extended=False): + """Returns a standard basis in element form.""" + if not extended: + return [FreeModuleElement(self, + tuple(self.ring._sdm_to_vector(x, self.rank))) + for x in self._groebner()] + gb, gbe = self._groebner(extended=True) + return ([self.convert(self.ring._sdm_to_vector(x, self.rank)) + 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() + + def _syzygies(self): + """Compute syzygies. See [SCA, algorithm 2.5.4].""" + # NOTE if self.gens is a standard basis, this can be done more + # efficiently using Schreyer's theorem + + # First bullet point + k = len(self.gens) + r = self.rank + zero = self.ring.convert(0) + one = self.ring.convert(1) + Rkr = self.ring.free_module(r + k) + newgens = [] + for j, f in enumerate(self.gens): + m = [0]*(r + k) + for i, v in enumerate(f): + m[i] = v + for i in range(k): + m[r + i] = one if j == i else zero + m = FreeModuleElement(Rkr, tuple(m)) + newgens.append(m) + # Note: we need *descending* order on module index, and TOP=False to + # get an elimination order + F = Rkr.submodule(*newgens, order='ilex', TOP=False) + + # Second bullet point: standard basis of F + G = F._groebner_vec() + + # Third bullet point: G0 = G intersect the new k components + G0 = [x[r:] for x in G if all(y == zero for y in x[:r])] + + # Fourth and fifth bullet points: we are done + return G0 + + def _in_terms_of_generators(self, e): + """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! + G = S._groebner_vec() + # This list cannot not be empty since e is an element + e = [x for x in G if self.ring.is_unit(x[0])][0] + return [-x/e[0] for x in e[1:]] + + def reduce_element(self, x, NF=None): + """ + Reduce the element ``x`` of our container modulo ``self``. + + This applies the normal form ``NF`` to ``x``. If ``NF`` is passed + as none, the default Mora normal form is used (which is not unique!). + """ + from sympy.polys.distributedmodules import sdm_nf_mora + 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)) + + def _intersect(self, other, relations=False): + # See: [SCA, section 2.8.2] + fi = self.gens + hi = other.gens + r = self.rank + ci = [[0]*(2*r) for _ in range(r)] + for k in range(r): + ci[k][k] = 1 + ci[k][r + k] = 1 + di = [list(f) + [0]*r for f in fi] + ei = [[0]*r + list(h) for h in hi] + 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] + if relations: + return res, reln1, reln2 + return res + + def _module_quotient(self, other, relations=False): + # See: [SCA, section 2.8.4] + if relations and len(other.gens) != 1: + raise NotImplementedError + if len(other.gens) == 0: + return self.ring.ideal(1) + elif len(other.gens) == 1: + # We do some trickery. Let f be the (vector!) generating ``other`` + # and f1, .., fn be the (vectors) generating self. + # Consider the submodule of R^{r+1} generated by (f, 1) and + # {(fi, 0) | i}. Then the intersection with the last module + # component yields the quotient. + g1 = list(other.gens[0]) + [1] + gi = [list(x) + [0] for x in self.gens] + # NOTE: We *need* to use an elimination order + M = self.ring.free_module(self.rank + 1).submodule(*([g1] + gi), + order='ilex', TOP=False) + if not relations: + return self.ring.ideal(*[x[-1] for x in M._groebner_vec() if + all(y == self.ring.zero for y in x[:-1])]) + else: + G, R = M._groebner_vec(extended=True) + indices = [i for i, x in enumerate(G) if + all(y == self.ring.zero for y in x[:-1])] + return (self.ring.ideal(*[G[i][-1] for i in indices]), + [[-x for x in R[i][1:]] for i in indices]) + # For more generators, we use I : = intersection of + # {I : | i} + # TODO this can be done more efficiently + 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. + + Do not instantiate this. Instead use the submodule methods. + + >>> from sympy.abc import x, y + >>> from sympy import QQ + >>> M = (QQ.old_poly_ring(x, y)/[x**2 - y**2]).free_module(2).submodule([x, x + y]) + >>> M + <[x + , x + y + ]> + >>> M.contains([y**2, x**2 + x*y]) + True + >>> M.contains([x, y]) + False + + Attributes: + + - quot - the subquotient of `R^n/IR^n` generated by lifts of our generators + """ + + def __init__(self, gens, container): + SubModule.__init__(self, gens, container) + self.quot = self.container.quot.submodule( + *[self.container.lift(x) for x in self.gens]) + + def _contains(self, elem): + return self.quot._contains(self.container.lift(elem)) + + def _syzygies(self): + return [tuple(self.ring.convert(y, self.quot.ring) for y in x) + for x in self.quot._syzygies()] + + def _in_terms_of_generators(self, elem): + 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.""" + + def eq(self, d1, d2): + """Equality comparison.""" + return self.module.killed_module.contains(d1 - d2) + + def __repr__(self): + return repr(self.data) + " + " + repr(self.module.killed_module) + + +class QuotientModule(Module): + """ + Class for quotient modules. + + Do not instantiate this directly. For subquotients, see the + SubQuotientModule class. + + Attributes: + + - base - the base module we are a quotient of + - killed_module - the submodule used to form the quotient + - rank of the base + """ + + dtype = QuotientModuleElement + + def __init__(self, ring, base, submodule): + Module.__init__(self, ring) + if not base.is_submodule(submodule): + raise ValueError('%s is not a submodule of %s' % (submodule, base)) + self.base = base + self.killed_module = submodule + self.rank = base.rank + + def __repr__(self): + return repr(self.base) + "/" + repr(self.killed_module) + + def is_zero(self): + """ + Return True if ``self`` is a zero module. + + This happens if and only if the base module is the same as the + submodule being killed. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) + >>> (F/[(1, 0)]).is_zero() + False + >>> (F/[(1, 0), (0, 1)]).is_zero() + True + """ + return self.base == self.killed_module + + def is_submodule(self, other): + """ + Return True if ``other`` is a submodule of ``self``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> Q = QQ.old_poly_ring(x).free_module(2) / [(x, x)] + >>> S = Q.submodule([1, 0]) + >>> Q.is_submodule(S) + True + >>> S.is_submodule(Q) + False + """ + if isinstance(other, QuotientModule): + return self.killed_module == other.killed_module and \ + self.base.is_submodule(other.base) + if isinstance(other, SubQuotientModule): + return other.container == self + return False + + def submodule(self, *gens, **opts): + """ + Generate a submodule. + + This is the same as taking a quotient of a submodule of the base + module. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> Q = QQ.old_poly_ring(x).free_module(2) / [(x, x)] + >>> Q.submodule([x, 0]) + <[x, 0] + <[x, x]>> + """ + return SubQuotientModule(gens, self, **opts) + + def convert(self, elem, M=None): + """ + Convert ``elem`` into the internal representation. + + This method is called implicitly whenever computations involve elements + not in the internal representation. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> F = QQ.old_poly_ring(x).free_module(2) / [(1, 2), (1, x)] + >>> F.convert([1, 0]) + [1, 0] + <[1, 2], [1, x]> + """ + if isinstance(elem, QuotientModuleElement): + if elem.module is self: + return elem + if self.killed_module.is_submodule(elem.module.killed_module): + return QuotientModuleElement(self, self.base.convert(elem.data)) + raise CoercionFailed + return QuotientModuleElement(self, self.base.convert(elem)) + + def identity_hom(self): + """ + Return the identity homomorphism on ``self``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> M = QQ.old_poly_ring(x).free_module(2) / [(1, 2), (1, x)] + >>> M.identity_hom() + 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) + + def quotient_hom(self): + """ + Return the quotient homomorphism to ``self``. + + That is, return a homomorphism representing the natural map from + ``self.base`` to ``self``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> M = QQ.old_poly_ring(x).free_module(2) / [(1, 2), (1, x)] + >>> M.quotient_hom() + 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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/benchmarks/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/benchmarks/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/benchmarks/bench_galoispolys.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/benchmarks/bench_galoispolys.py new file mode 100644 index 0000000000000000000000000000000000000000..8b2a0329a0cf96be2e8359a3741d8e2de13fa37a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/benchmarks/bench_galoispolys.py @@ -0,0 +1,66 @@ +"""Benchmarks for polynomials over Galois fields. """ + + +from sympy.polys.galoistools import gf_from_dict, gf_factor_sqf +from sympy.polys.domains import ZZ +from sympy.core.numbers import pi +from sympy.ntheory.generate import nextprime + + +def gathen_poly(n, p, K): + return gf_from_dict({n: K.one, 1: K.one, 0: K.one}, p, K) + + +def shoup_poly(n, p, K): + f = [K.one] * (n + 1) + for i in range(1, n + 1): + f[i] = (f[i - 1]**2 + K.one) % p + return f + + +def genprime(n, K): + return K(nextprime(int((2**n * pi).evalf()))) + +p_10 = genprime(10, ZZ) +f_10 = gathen_poly(10, p_10, ZZ) + +p_20 = genprime(20, ZZ) +f_20 = gathen_poly(20, p_20, ZZ) + + +def timeit_gathen_poly_f10_zassenhaus(): + gf_factor_sqf(f_10, p_10, ZZ, method='zassenhaus') + + +def timeit_gathen_poly_f10_shoup(): + gf_factor_sqf(f_10, p_10, ZZ, method='shoup') + + +def timeit_gathen_poly_f20_zassenhaus(): + gf_factor_sqf(f_20, p_20, ZZ, method='zassenhaus') + + +def timeit_gathen_poly_f20_shoup(): + gf_factor_sqf(f_20, p_20, ZZ, method='shoup') + +P_08 = genprime(8, ZZ) +F_10 = shoup_poly(10, P_08, ZZ) + +P_18 = genprime(18, ZZ) +F_20 = shoup_poly(20, P_18, ZZ) + + +def timeit_shoup_poly_F10_zassenhaus(): + gf_factor_sqf(F_10, P_08, ZZ, method='zassenhaus') + + +def timeit_shoup_poly_F10_shoup(): + gf_factor_sqf(F_10, P_08, ZZ, method='shoup') + + +def timeit_shoup_poly_F20_zassenhaus(): + gf_factor_sqf(F_20, P_18, ZZ, method='zassenhaus') + + +def timeit_shoup_poly_F20_shoup(): + gf_factor_sqf(F_20, P_18, ZZ, method='shoup') diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/benchmarks/bench_groebnertools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/benchmarks/bench_groebnertools.py new file mode 100644 index 0000000000000000000000000000000000000000..e709f4f6d2cb42c0980d2e49725e01a7a2aa2b87 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/benchmarks/bench_groebnertools.py @@ -0,0 +1,25 @@ +"""Benchmark of the Groebner bases algorithms. """ + + +from sympy.polys.rings import ring +from sympy.polys.domains import QQ +from sympy.polys.groebnertools import groebner + +R, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12 = ring("x1:13", QQ) + +V = R.gens +E = [(x1, x2), (x2, x3), (x1, x4), (x1, x6), (x1, x12), (x2, x5), (x2, x7), (x3, x8), + (x3, x10), (x4, x11), (x4, x9), (x5, x6), (x6, x7), (x7, x8), (x8, x9), (x9, x10), + (x10, x11), (x11, x12), (x5, x12), (x5, x9), (x6, x10), (x7, x11), (x8, x12)] + +F3 = [ x**3 - 1 for x in V ] +Fg = [ x**2 + x*y + y**2 for x, y in E ] + +F_1 = F3 + Fg +F_2 = F3 + Fg + [x3**2 + x3*x4 + x4**2] + +def time_vertex_color_12_vertices_23_edges(): + assert groebner(F_1, R) != [1] + +def time_vertex_color_12_vertices_24_edges(): + assert groebner(F_2, R) == [1] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/benchmarks/bench_solvers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/benchmarks/bench_solvers.py new file mode 100644 index 0000000000000000000000000000000000000000..ed3ce5e246db2f5589e6a5dba9f18b7388c179c4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/benchmarks/bench_solvers.py @@ -0,0 +1,543 @@ +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 + +# Expected times on 3.4 GHz i7: + +# In [1]: %timeit time_solve_lin_sys_189x49() +# 1 loops, best of 3: 864 ms per loop +# In [2]: %timeit time_solve_lin_sys_165x165() +# 1 loops, best of 3: 1.83 s per loop +# In [3]: %timeit time_solve_lin_sys_10x8() +# 1 loops, best of 3: 2.31 s per loop + +# Benchmark R_165: shows how fast are arithmetics in QQ. + +R_165, uk_0, uk_1, uk_2, uk_3, uk_4, uk_5, uk_6, uk_7, uk_8, uk_9, uk_10, uk_11, uk_12, uk_13, uk_14, uk_15, uk_16, uk_17, uk_18, uk_19, uk_20, uk_21, uk_22, uk_23, uk_24, uk_25, uk_26, uk_27, uk_28, uk_29, uk_30, uk_31, uk_32, uk_33, uk_34, uk_35, uk_36, uk_37, uk_38, uk_39, uk_40, uk_41, uk_42, uk_43, uk_44, uk_45, uk_46, uk_47, uk_48, uk_49, uk_50, uk_51, uk_52, uk_53, uk_54, uk_55, uk_56, uk_57, uk_58, uk_59, uk_60, uk_61, uk_62, uk_63, uk_64, uk_65, uk_66, uk_67, uk_68, uk_69, uk_70, uk_71, uk_72, uk_73, uk_74, uk_75, uk_76, uk_77, uk_78, uk_79, uk_80, uk_81, uk_82, uk_83, uk_84, uk_85, uk_86, uk_87, uk_88, uk_89, uk_90, uk_91, uk_92, uk_93, uk_94, uk_95, uk_96, uk_97, uk_98, uk_99, uk_100, uk_101, uk_102, uk_103, uk_104, uk_105, uk_106, uk_107, uk_108, uk_109, uk_110, uk_111, uk_112, uk_113, uk_114, uk_115, uk_116, uk_117, uk_118, uk_119, uk_120, uk_121, uk_122, uk_123, uk_124, uk_125, uk_126, uk_127, uk_128, uk_129, uk_130, uk_131, uk_132, uk_133, uk_134, uk_135, uk_136, uk_137, uk_138, uk_139, uk_140, uk_141, uk_142, uk_143, uk_144, uk_145, uk_146, uk_147, uk_148, uk_149, uk_150, uk_151, uk_152, uk_153, uk_154, uk_155, uk_156, uk_157, uk_158, uk_159, uk_160, uk_161, uk_162, uk_163, uk_164 = ring("uk_:165", QQ) + +def eqs_165x165(): + return [ + uk_0 + 50719*uk_1 + 2789545*uk_10 + 411400*uk_100 + 1683000*uk_101 + 166375*uk_103 + 680625*uk_104 + 2784375*uk_106 + 729*uk_109 + 456471*uk_11 + 4131*uk_110 + 11016*uk_111 + 4455*uk_112 + 18225*uk_113 + 23409*uk_115 + 62424*uk_116 + 25245*uk_117 + 103275*uk_118 + 2586669*uk_12 + 166464*uk_120 + 67320*uk_121 + 275400*uk_122 + 27225*uk_124 + 111375*uk_125 + 455625*uk_127 + 6897784*uk_13 + 132651*uk_130 + 353736*uk_131 + 143055*uk_132 + 585225*uk_133 + 943296*uk_135 + 381480*uk_136 + 1560600*uk_137 + 154275*uk_139 + 2789545*uk_14 + 631125*uk_140 + 2581875*uk_142 + 2515456*uk_145 + 1017280*uk_146 + 4161600*uk_147 + 411400*uk_149 + 11411775*uk_15 + 1683000*uk_150 + 6885000*uk_152 + 166375*uk_155 + 680625*uk_156 + 2784375*uk_158 + 11390625*uk_161 + 3025*uk_17 + 495*uk_18 + 2805*uk_19 + 55*uk_2 + 7480*uk_20 + 3025*uk_21 + 12375*uk_22 + 81*uk_24 + 459*uk_25 + 1224*uk_26 + 495*uk_27 + 2025*uk_28 + 9*uk_3 + 2601*uk_30 + 6936*uk_31 + 2805*uk_32 + 11475*uk_33 + 18496*uk_35 + 7480*uk_36 + 30600*uk_37 + 3025*uk_39 + 51*uk_4 + 12375*uk_40 + 50625*uk_42 + 130470415844959*uk_45 + 141482932855*uk_46 + 23151752649*uk_47 + 131193265011*uk_48 + 349848706696*uk_49 + 136*uk_5 + 141482932855*uk_50 + 578793816225*uk_51 + 153424975*uk_53 + 25105905*uk_54 + 142266795*uk_55 + 379378120*uk_56 + 153424975*uk_57 + 627647625*uk_58 + 55*uk_6 + 4108239*uk_60 + 23280021*uk_61 + 62080056*uk_62 + 25105905*uk_63 + 102705975*uk_64 + 131920119*uk_66 + 351786984*uk_67 + 142266795*uk_68 + 582000525*uk_69 + 225*uk_7 + 938098624*uk_71 + 379378120*uk_72 + 1552001400*uk_73 + 153424975*uk_75 + 627647625*uk_76 + 2567649375*uk_78 + 166375*uk_81 + 27225*uk_82 + 154275*uk_83 + 411400*uk_84 + 166375*uk_85 + 680625*uk_86 + 4455*uk_88 + 25245*uk_89 + 2572416961*uk_9 + 67320*uk_90 + 27225*uk_91 + 111375*uk_92 + 143055*uk_94 + 381480*uk_95 + 154275*uk_96 + 631125*uk_97 + 1017280*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 413820*uk_100 + 1633500*uk_101 + 65340*uk_102 + 178695*uk_103 + 705375*uk_104 + 28215*uk_105 + 2784375*uk_106 + 111375*uk_107 + 4455*uk_108 + 97336*uk_109 + 2333074*uk_11 + 19044*uk_110 + 279312*uk_111 + 120612*uk_112 + 476100*uk_113 + 19044*uk_114 + 3726*uk_115 + 54648*uk_116 + 23598*uk_117 + 93150*uk_118 + 3726*uk_119 + 456471*uk_12 + 801504*uk_120 + 346104*uk_121 + 1366200*uk_122 + 54648*uk_123 + 149454*uk_124 + 589950*uk_125 + 23598*uk_126 + 2328750*uk_127 + 93150*uk_128 + 3726*uk_129 + 6694908*uk_13 + 729*uk_130 + 10692*uk_131 + 4617*uk_132 + 18225*uk_133 + 729*uk_134 + 156816*uk_135 + 67716*uk_136 + 267300*uk_137 + 10692*uk_138 + 29241*uk_139 + 2890983*uk_14 + 115425*uk_140 + 4617*uk_141 + 455625*uk_142 + 18225*uk_143 + 729*uk_144 + 2299968*uk_145 + 993168*uk_146 + 3920400*uk_147 + 156816*uk_148 + 428868*uk_149 + 11411775*uk_15 + 1692900*uk_150 + 67716*uk_151 + 6682500*uk_152 + 267300*uk_153 + 10692*uk_154 + 185193*uk_155 + 731025*uk_156 + 29241*uk_157 + 2885625*uk_158 + 115425*uk_159 + 456471*uk_16 + 4617*uk_160 + 11390625*uk_161 + 455625*uk_162 + 18225*uk_163 + 729*uk_164 + 3025*uk_17 + 2530*uk_18 + 495*uk_19 + 55*uk_2 + 7260*uk_20 + 3135*uk_21 + 12375*uk_22 + 495*uk_23 + 2116*uk_24 + 414*uk_25 + 6072*uk_26 + 2622*uk_27 + 10350*uk_28 + 414*uk_29 + 46*uk_3 + 81*uk_30 + 1188*uk_31 + 513*uk_32 + 2025*uk_33 + 81*uk_34 + 17424*uk_35 + 7524*uk_36 + 29700*uk_37 + 1188*uk_38 + 3249*uk_39 + 9*uk_4 + 12825*uk_40 + 513*uk_41 + 50625*uk_42 + 2025*uk_43 + 81*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 118331180206*uk_47 + 23151752649*uk_48 + 339559038852*uk_49 + 132*uk_5 + 146627766777*uk_50 + 578793816225*uk_51 + 23151752649*uk_52 + 153424975*uk_53 + 128319070*uk_54 + 25105905*uk_55 + 368219940*uk_56 + 159004065*uk_57 + 627647625*uk_58 + 25105905*uk_59 + 57*uk_6 + 107321404*uk_60 + 20997666*uk_61 + 307965768*uk_62 + 132985218*uk_63 + 524941650*uk_64 + 20997666*uk_65 + 4108239*uk_66 + 60254172*uk_67 + 26018847*uk_68 + 102705975*uk_69 + 225*uk_7 + 4108239*uk_70 + 883727856*uk_71 + 381609756*uk_72 + 1506354300*uk_73 + 60254172*uk_74 + 164786031*uk_75 + 650471175*uk_76 + 26018847*uk_77 + 2567649375*uk_78 + 102705975*uk_79 + 9*uk_8 + 4108239*uk_80 + 166375*uk_81 + 139150*uk_82 + 27225*uk_83 + 399300*uk_84 + 172425*uk_85 + 680625*uk_86 + 27225*uk_87 + 116380*uk_88 + 22770*uk_89 + 2572416961*uk_9 + 333960*uk_90 + 144210*uk_91 + 569250*uk_92 + 22770*uk_93 + 4455*uk_94 + 65340*uk_95 + 28215*uk_96 + 111375*uk_97 + 4455*uk_98 + 958320*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 402380*uk_100 + 1534500*uk_101 + 313720*uk_102 + 191455*uk_103 + 730125*uk_104 + 149270*uk_105 + 2784375*uk_106 + 569250*uk_107 + 116380*uk_108 + 912673*uk_109 + 4919743*uk_11 + 432814*uk_110 + 1166716*uk_111 + 555131*uk_112 + 2117025*uk_113 + 432814*uk_114 + 205252*uk_115 + 553288*uk_116 + 263258*uk_117 + 1003950*uk_118 + 205252*uk_119 + 2333074*uk_12 + 1491472*uk_120 + 709652*uk_121 + 2706300*uk_122 + 553288*uk_123 + 337657*uk_124 + 1287675*uk_125 + 263258*uk_126 + 4910625*uk_127 + 1003950*uk_128 + 205252*uk_129 + 6289156*uk_13 + 97336*uk_130 + 262384*uk_131 + 124844*uk_132 + 476100*uk_133 + 97336*uk_134 + 707296*uk_135 + 336536*uk_136 + 1283400*uk_137 + 262384*uk_138 + 160126*uk_139 + 2992421*uk_14 + 610650*uk_140 + 124844*uk_141 + 2328750*uk_142 + 476100*uk_143 + 97336*uk_144 + 1906624*uk_145 + 907184*uk_146 + 3459600*uk_147 + 707296*uk_148 + 431644*uk_149 + 11411775*uk_15 + 1646100*uk_150 + 336536*uk_151 + 6277500*uk_152 + 1283400*uk_153 + 262384*uk_154 + 205379*uk_155 + 783225*uk_156 + 160126*uk_157 + 2986875*uk_158 + 610650*uk_159 + 2333074*uk_16 + 124844*uk_160 + 11390625*uk_161 + 2328750*uk_162 + 476100*uk_163 + 97336*uk_164 + 3025*uk_17 + 5335*uk_18 + 2530*uk_19 + 55*uk_2 + 6820*uk_20 + 3245*uk_21 + 12375*uk_22 + 2530*uk_23 + 9409*uk_24 + 4462*uk_25 + 12028*uk_26 + 5723*uk_27 + 21825*uk_28 + 4462*uk_29 + 97*uk_3 + 2116*uk_30 + 5704*uk_31 + 2714*uk_32 + 10350*uk_33 + 2116*uk_34 + 15376*uk_35 + 7316*uk_36 + 27900*uk_37 + 5704*uk_38 + 3481*uk_39 + 46*uk_4 + 13275*uk_40 + 2714*uk_41 + 50625*uk_42 + 10350*uk_43 + 2116*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 249524445217*uk_47 + 118331180206*uk_48 + 318979703164*uk_49 + 124*uk_5 + 151772600699*uk_50 + 578793816225*uk_51 + 118331180206*uk_52 + 153424975*uk_53 + 270585865*uk_54 + 128319070*uk_55 + 345903580*uk_56 + 164583155*uk_57 + 627647625*uk_58 + 128319070*uk_59 + 59*uk_6 + 477215071*uk_60 + 226308178*uk_61 + 610048132*uk_62 + 290264837*uk_63 + 1106942175*uk_64 + 226308178*uk_65 + 107321404*uk_66 + 289301176*uk_67 + 137651366*uk_68 + 524941650*uk_69 + 225*uk_7 + 107321404*uk_70 + 779855344*uk_71 + 371060204*uk_72 + 1415060100*uk_73 + 289301176*uk_74 + 176552839*uk_75 + 673294725*uk_76 + 137651366*uk_77 + 2567649375*uk_78 + 524941650*uk_79 + 46*uk_8 + 107321404*uk_80 + 166375*uk_81 + 293425*uk_82 + 139150*uk_83 + 375100*uk_84 + 178475*uk_85 + 680625*uk_86 + 139150*uk_87 + 517495*uk_88 + 245410*uk_89 + 2572416961*uk_9 + 661540*uk_90 + 314765*uk_91 + 1200375*uk_92 + 245410*uk_93 + 116380*uk_94 + 313720*uk_95 + 149270*uk_96 + 569250*uk_97 + 116380*uk_98 + 845680*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 389180*uk_100 + 1435500*uk_101 + 618860*uk_102 + 204655*uk_103 + 754875*uk_104 + 325435*uk_105 + 2784375*uk_106 + 1200375*uk_107 + 517495*uk_108 + 3375000*uk_109 + 7607850*uk_11 + 2182500*uk_110 + 2610000*uk_111 + 1372500*uk_112 + 5062500*uk_113 + 2182500*uk_114 + 1411350*uk_115 + 1687800*uk_116 + 887550*uk_117 + 3273750*uk_118 + 1411350*uk_119 + 4919743*uk_12 + 2018400*uk_120 + 1061400*uk_121 + 3915000*uk_122 + 1687800*uk_123 + 558150*uk_124 + 2058750*uk_125 + 887550*uk_126 + 7593750*uk_127 + 3273750*uk_128 + 1411350*uk_129 + 5883404*uk_13 + 912673*uk_130 + 1091444*uk_131 + 573949*uk_132 + 2117025*uk_133 + 912673*uk_134 + 1305232*uk_135 + 686372*uk_136 + 2531700*uk_137 + 1091444*uk_138 + 360937*uk_139 + 3093859*uk_14 + 1331325*uk_140 + 573949*uk_141 + 4910625*uk_142 + 2117025*uk_143 + 912673*uk_144 + 1560896*uk_145 + 820816*uk_146 + 3027600*uk_147 + 1305232*uk_148 + 431636*uk_149 + 11411775*uk_15 + 1592100*uk_150 + 686372*uk_151 + 5872500*uk_152 + 2531700*uk_153 + 1091444*uk_154 + 226981*uk_155 + 837225*uk_156 + 360937*uk_157 + 3088125*uk_158 + 1331325*uk_159 + 4919743*uk_16 + 573949*uk_160 + 11390625*uk_161 + 4910625*uk_162 + 2117025*uk_163 + 912673*uk_164 + 3025*uk_17 + 8250*uk_18 + 5335*uk_19 + 55*uk_2 + 6380*uk_20 + 3355*uk_21 + 12375*uk_22 + 5335*uk_23 + 22500*uk_24 + 14550*uk_25 + 17400*uk_26 + 9150*uk_27 + 33750*uk_28 + 14550*uk_29 + 150*uk_3 + 9409*uk_30 + 11252*uk_31 + 5917*uk_32 + 21825*uk_33 + 9409*uk_34 + 13456*uk_35 + 7076*uk_36 + 26100*uk_37 + 11252*uk_38 + 3721*uk_39 + 97*uk_4 + 13725*uk_40 + 5917*uk_41 + 50625*uk_42 + 21825*uk_43 + 9409*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 385862544150*uk_47 + 249524445217*uk_48 + 298400367476*uk_49 + 116*uk_5 + 156917434621*uk_50 + 578793816225*uk_51 + 249524445217*uk_52 + 153424975*uk_53 + 418431750*uk_54 + 270585865*uk_55 + 323587220*uk_56 + 170162245*uk_57 + 627647625*uk_58 + 270585865*uk_59 + 61*uk_6 + 1141177500*uk_60 + 737961450*uk_61 + 882510600*uk_62 + 464078850*uk_63 + 1711766250*uk_64 + 737961450*uk_65 + 477215071*uk_66 + 570690188*uk_67 + 300104323*uk_68 + 1106942175*uk_69 + 225*uk_7 + 477215071*uk_70 + 682474864*uk_71 + 358887644*uk_72 + 1323765900*uk_73 + 570690188*uk_74 + 188725399*uk_75 + 696118275*uk_76 + 300104323*uk_77 + 2567649375*uk_78 + 1106942175*uk_79 + 97*uk_8 + 477215071*uk_80 + 166375*uk_81 + 453750*uk_82 + 293425*uk_83 + 350900*uk_84 + 184525*uk_85 + 680625*uk_86 + 293425*uk_87 + 1237500*uk_88 + 800250*uk_89 + 2572416961*uk_9 + 957000*uk_90 + 503250*uk_91 + 1856250*uk_92 + 800250*uk_93 + 517495*uk_94 + 618860*uk_95 + 325435*uk_96 + 1200375*uk_97 + 517495*uk_98 + 740080*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 374220*uk_100 + 1336500*uk_101 + 891000*uk_102 + 218295*uk_103 + 779625*uk_104 + 519750*uk_105 + 2784375*uk_106 + 1856250*uk_107 + 1237500*uk_108 + 7189057*uk_109 + 9788767*uk_11 + 5587350*uk_110 + 4022892*uk_111 + 2346687*uk_112 + 8381025*uk_113 + 5587350*uk_114 + 4342500*uk_115 + 3126600*uk_116 + 1823850*uk_117 + 6513750*uk_118 + 4342500*uk_119 + 7607850*uk_12 + 2251152*uk_120 + 1313172*uk_121 + 4689900*uk_122 + 3126600*uk_123 + 766017*uk_124 + 2735775*uk_125 + 1823850*uk_126 + 9770625*uk_127 + 6513750*uk_128 + 4342500*uk_129 + 5477652*uk_13 + 3375000*uk_130 + 2430000*uk_131 + 1417500*uk_132 + 5062500*uk_133 + 3375000*uk_134 + 1749600*uk_135 + 1020600*uk_136 + 3645000*uk_137 + 2430000*uk_138 + 595350*uk_139 + 3195297*uk_14 + 2126250*uk_140 + 1417500*uk_141 + 7593750*uk_142 + 5062500*uk_143 + 3375000*uk_144 + 1259712*uk_145 + 734832*uk_146 + 2624400*uk_147 + 1749600*uk_148 + 428652*uk_149 + 11411775*uk_15 + 1530900*uk_150 + 1020600*uk_151 + 5467500*uk_152 + 3645000*uk_153 + 2430000*uk_154 + 250047*uk_155 + 893025*uk_156 + 595350*uk_157 + 3189375*uk_158 + 2126250*uk_159 + 7607850*uk_16 + 1417500*uk_160 + 11390625*uk_161 + 7593750*uk_162 + 5062500*uk_163 + 3375000*uk_164 + 3025*uk_17 + 10615*uk_18 + 8250*uk_19 + 55*uk_2 + 5940*uk_20 + 3465*uk_21 + 12375*uk_22 + 8250*uk_23 + 37249*uk_24 + 28950*uk_25 + 20844*uk_26 + 12159*uk_27 + 43425*uk_28 + 28950*uk_29 + 193*uk_3 + 22500*uk_30 + 16200*uk_31 + 9450*uk_32 + 33750*uk_33 + 22500*uk_34 + 11664*uk_35 + 6804*uk_36 + 24300*uk_37 + 16200*uk_38 + 3969*uk_39 + 150*uk_4 + 14175*uk_40 + 9450*uk_41 + 50625*uk_42 + 33750*uk_43 + 22500*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 496476473473*uk_47 + 385862544150*uk_48 + 277821031788*uk_49 + 108*uk_5 + 162062268543*uk_50 + 578793816225*uk_51 + 385862544150*uk_52 + 153424975*uk_53 + 538382185*uk_54 + 418431750*uk_55 + 301270860*uk_56 + 175741335*uk_57 + 627647625*uk_58 + 418431750*uk_59 + 63*uk_6 + 1889232031*uk_60 + 1468315050*uk_61 + 1057186836*uk_62 + 616692321*uk_63 + 2202472575*uk_64 + 1468315050*uk_65 + 1141177500*uk_66 + 821647800*uk_67 + 479294550*uk_68 + 1711766250*uk_69 + 225*uk_7 + 1141177500*uk_70 + 591586416*uk_71 + 345092076*uk_72 + 1232471700*uk_73 + 821647800*uk_74 + 201303711*uk_75 + 718941825*uk_76 + 479294550*uk_77 + 2567649375*uk_78 + 1711766250*uk_79 + 150*uk_8 + 1141177500*uk_80 + 166375*uk_81 + 583825*uk_82 + 453750*uk_83 + 326700*uk_84 + 190575*uk_85 + 680625*uk_86 + 453750*uk_87 + 2048695*uk_88 + 1592250*uk_89 + 2572416961*uk_9 + 1146420*uk_90 + 668745*uk_91 + 2388375*uk_92 + 1592250*uk_93 + 1237500*uk_94 + 891000*uk_95 + 519750*uk_96 + 1856250*uk_97 + 1237500*uk_98 + 641520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 357500*uk_100 + 1237500*uk_101 + 1061500*uk_102 + 232375*uk_103 + 804375*uk_104 + 689975*uk_105 + 2784375*uk_106 + 2388375*uk_107 + 2048695*uk_108 + 9800344*uk_109 + 10853866*uk_11 + 8838628*uk_110 + 4579600*uk_111 + 2976740*uk_112 + 10304100*uk_113 + 8838628*uk_114 + 7971286*uk_115 + 4130200*uk_116 + 2684630*uk_117 + 9292950*uk_118 + 7971286*uk_119 + 9788767*uk_12 + 2140000*uk_120 + 1391000*uk_121 + 4815000*uk_122 + 4130200*uk_123 + 904150*uk_124 + 3129750*uk_125 + 2684630*uk_126 + 10833750*uk_127 + 9292950*uk_128 + 7971286*uk_129 + 5071900*uk_13 + 7189057*uk_130 + 3724900*uk_131 + 2421185*uk_132 + 8381025*uk_133 + 7189057*uk_134 + 1930000*uk_135 + 1254500*uk_136 + 4342500*uk_137 + 3724900*uk_138 + 815425*uk_139 + 3296735*uk_14 + 2822625*uk_140 + 2421185*uk_141 + 9770625*uk_142 + 8381025*uk_143 + 7189057*uk_144 + 1000000*uk_145 + 650000*uk_146 + 2250000*uk_147 + 1930000*uk_148 + 422500*uk_149 + 11411775*uk_15 + 1462500*uk_150 + 1254500*uk_151 + 5062500*uk_152 + 4342500*uk_153 + 3724900*uk_154 + 274625*uk_155 + 950625*uk_156 + 815425*uk_157 + 3290625*uk_158 + 2822625*uk_159 + 9788767*uk_16 + 2421185*uk_160 + 11390625*uk_161 + 9770625*uk_162 + 8381025*uk_163 + 7189057*uk_164 + 3025*uk_17 + 11770*uk_18 + 10615*uk_19 + 55*uk_2 + 5500*uk_20 + 3575*uk_21 + 12375*uk_22 + 10615*uk_23 + 45796*uk_24 + 41302*uk_25 + 21400*uk_26 + 13910*uk_27 + 48150*uk_28 + 41302*uk_29 + 214*uk_3 + 37249*uk_30 + 19300*uk_31 + 12545*uk_32 + 43425*uk_33 + 37249*uk_34 + 10000*uk_35 + 6500*uk_36 + 22500*uk_37 + 19300*uk_38 + 4225*uk_39 + 193*uk_4 + 14625*uk_40 + 12545*uk_41 + 50625*uk_42 + 43425*uk_43 + 37249*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 550497229654*uk_47 + 496476473473*uk_48 + 257241696100*uk_49 + 100*uk_5 + 167207102465*uk_50 + 578793816225*uk_51 + 496476473473*uk_52 + 153424975*uk_53 + 596962630*uk_54 + 538382185*uk_55 + 278954500*uk_56 + 181320425*uk_57 + 627647625*uk_58 + 538382185*uk_59 + 65*uk_6 + 2322727324*uk_60 + 2094796138*uk_61 + 1085386600*uk_62 + 705501290*uk_63 + 2442119850*uk_64 + 2094796138*uk_65 + 1889232031*uk_66 + 978876700*uk_67 + 636269855*uk_68 + 2202472575*uk_69 + 225*uk_7 + 1889232031*uk_70 + 507190000*uk_71 + 329673500*uk_72 + 1141177500*uk_73 + 978876700*uk_74 + 214287775*uk_75 + 741765375*uk_76 + 636269855*uk_77 + 2567649375*uk_78 + 2202472575*uk_79 + 193*uk_8 + 1889232031*uk_80 + 166375*uk_81 + 647350*uk_82 + 583825*uk_83 + 302500*uk_84 + 196625*uk_85 + 680625*uk_86 + 583825*uk_87 + 2518780*uk_88 + 2271610*uk_89 + 2572416961*uk_9 + 1177000*uk_90 + 765050*uk_91 + 2648250*uk_92 + 2271610*uk_93 + 2048695*uk_94 + 1061500*uk_95 + 689975*uk_96 + 2388375*uk_97 + 2048695*uk_98 + 550000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 339020*uk_100 + 1138500*uk_101 + 1082840*uk_102 + 246895*uk_103 + 829125*uk_104 + 788590*uk_105 + 2784375*uk_106 + 2648250*uk_107 + 2518780*uk_108 + 8120601*uk_109 + 10194519*uk_11 + 8645814*uk_110 + 3716892*uk_111 + 2706867*uk_112 + 9090225*uk_113 + 8645814*uk_114 + 9204996*uk_115 + 3957288*uk_116 + 2881938*uk_117 + 9678150*uk_118 + 9204996*uk_119 + 10853866*uk_12 + 1701264*uk_120 + 1238964*uk_121 + 4160700*uk_122 + 3957288*uk_123 + 902289*uk_124 + 3030075*uk_125 + 2881938*uk_126 + 10175625*uk_127 + 9678150*uk_128 + 9204996*uk_129 + 4666148*uk_13 + 9800344*uk_130 + 4213232*uk_131 + 3068332*uk_132 + 10304100*uk_133 + 9800344*uk_134 + 1811296*uk_135 + 1319096*uk_136 + 4429800*uk_137 + 4213232*uk_138 + 960646*uk_139 + 3398173*uk_14 + 3226050*uk_140 + 3068332*uk_141 + 10833750*uk_142 + 10304100*uk_143 + 9800344*uk_144 + 778688*uk_145 + 567088*uk_146 + 1904400*uk_147 + 1811296*uk_148 + 412988*uk_149 + 11411775*uk_15 + 1386900*uk_150 + 1319096*uk_151 + 4657500*uk_152 + 4429800*uk_153 + 4213232*uk_154 + 300763*uk_155 + 1010025*uk_156 + 960646*uk_157 + 3391875*uk_158 + 3226050*uk_159 + 10853866*uk_16 + 3068332*uk_160 + 11390625*uk_161 + 10833750*uk_162 + 10304100*uk_163 + 9800344*uk_164 + 3025*uk_17 + 11055*uk_18 + 11770*uk_19 + 55*uk_2 + 5060*uk_20 + 3685*uk_21 + 12375*uk_22 + 11770*uk_23 + 40401*uk_24 + 43014*uk_25 + 18492*uk_26 + 13467*uk_27 + 45225*uk_28 + 43014*uk_29 + 201*uk_3 + 45796*uk_30 + 19688*uk_31 + 14338*uk_32 + 48150*uk_33 + 45796*uk_34 + 8464*uk_35 + 6164*uk_36 + 20700*uk_37 + 19688*uk_38 + 4489*uk_39 + 214*uk_4 + 15075*uk_40 + 14338*uk_41 + 50625*uk_42 + 48150*uk_43 + 45796*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 517055809161*uk_47 + 550497229654*uk_48 + 236662360412*uk_49 + 92*uk_5 + 172351936387*uk_50 + 578793816225*uk_51 + 550497229654*uk_52 + 153424975*uk_53 + 560698545*uk_54 + 596962630*uk_55 + 256638140*uk_56 + 186899515*uk_57 + 627647625*uk_58 + 596962630*uk_59 + 67*uk_6 + 2049098319*uk_60 + 2181627066*uk_61 + 937895748*uk_62 + 683032773*uk_63 + 2293766775*uk_64 + 2181627066*uk_65 + 2322727324*uk_66 + 998555672*uk_67 + 727209022*uk_68 + 2442119850*uk_69 + 225*uk_7 + 2322727324*uk_70 + 429285616*uk_71 + 312631916*uk_72 + 1049883300*uk_73 + 998555672*uk_74 + 227677591*uk_75 + 764588925*uk_76 + 727209022*uk_77 + 2567649375*uk_78 + 2442119850*uk_79 + 214*uk_8 + 2322727324*uk_80 + 166375*uk_81 + 608025*uk_82 + 647350*uk_83 + 278300*uk_84 + 202675*uk_85 + 680625*uk_86 + 647350*uk_87 + 2222055*uk_88 + 2365770*uk_89 + 2572416961*uk_9 + 1017060*uk_90 + 740685*uk_91 + 2487375*uk_92 + 2365770*uk_93 + 2518780*uk_94 + 1082840*uk_95 + 788590*uk_96 + 2648250*uk_97 + 2518780*uk_98 + 465520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 318780*uk_100 + 1039500*uk_101 + 928620*uk_102 + 261855*uk_103 + 853875*uk_104 + 762795*uk_105 + 2784375*uk_106 + 2487375*uk_107 + 2222055*uk_108 + 2863288*uk_109 + 7202098*uk_11 + 4052964*uk_110 + 1693776*uk_111 + 1391316*uk_112 + 4536900*uk_113 + 4052964*uk_114 + 5736942*uk_115 + 2397528*uk_116 + 1969398*uk_117 + 6421950*uk_118 + 5736942*uk_119 + 10194519*uk_12 + 1001952*uk_120 + 823032*uk_121 + 2683800*uk_122 + 2397528*uk_123 + 676062*uk_124 + 2204550*uk_125 + 1969398*uk_126 + 7188750*uk_127 + 6421950*uk_128 + 5736942*uk_129 + 4260396*uk_13 + 8120601*uk_130 + 3393684*uk_131 + 2787669*uk_132 + 9090225*uk_133 + 8120601*uk_134 + 1418256*uk_135 + 1164996*uk_136 + 3798900*uk_137 + 3393684*uk_138 + 956961*uk_139 + 3499611*uk_14 + 3120525*uk_140 + 2787669*uk_141 + 10175625*uk_142 + 9090225*uk_143 + 8120601*uk_144 + 592704*uk_145 + 486864*uk_146 + 1587600*uk_147 + 1418256*uk_148 + 399924*uk_149 + 11411775*uk_15 + 1304100*uk_150 + 1164996*uk_151 + 4252500*uk_152 + 3798900*uk_153 + 3393684*uk_154 + 328509*uk_155 + 1071225*uk_156 + 956961*uk_157 + 3493125*uk_158 + 3120525*uk_159 + 10194519*uk_16 + 2787669*uk_160 + 11390625*uk_161 + 10175625*uk_162 + 9090225*uk_163 + 8120601*uk_164 + 3025*uk_17 + 7810*uk_18 + 11055*uk_19 + 55*uk_2 + 4620*uk_20 + 3795*uk_21 + 12375*uk_22 + 11055*uk_23 + 20164*uk_24 + 28542*uk_25 + 11928*uk_26 + 9798*uk_27 + 31950*uk_28 + 28542*uk_29 + 142*uk_3 + 40401*uk_30 + 16884*uk_31 + 13869*uk_32 + 45225*uk_33 + 40401*uk_34 + 7056*uk_35 + 5796*uk_36 + 18900*uk_37 + 16884*uk_38 + 4761*uk_39 + 201*uk_4 + 15525*uk_40 + 13869*uk_41 + 50625*uk_42 + 45225*uk_43 + 40401*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 365283208462*uk_47 + 517055809161*uk_48 + 216083024724*uk_49 + 84*uk_5 + 177496770309*uk_50 + 578793816225*uk_51 + 517055809161*uk_52 + 153424975*uk_53 + 396115390*uk_54 + 560698545*uk_55 + 234321780*uk_56 + 192478605*uk_57 + 627647625*uk_58 + 560698545*uk_59 + 69*uk_6 + 1022697916*uk_60 + 1447621698*uk_61 + 604976232*uk_62 + 496944762*uk_63 + 1620472050*uk_64 + 1447621698*uk_65 + 2049098319*uk_66 + 856339596*uk_67 + 703421811*uk_68 + 2293766775*uk_69 + 225*uk_7 + 2049098319*uk_70 + 357873264*uk_71 + 293967324*uk_72 + 958589100*uk_73 + 856339596*uk_74 + 241473159*uk_75 + 787412475*uk_76 + 703421811*uk_77 + 2567649375*uk_78 + 2293766775*uk_79 + 201*uk_8 + 2049098319*uk_80 + 166375*uk_81 + 429550*uk_82 + 608025*uk_83 + 254100*uk_84 + 208725*uk_85 + 680625*uk_86 + 608025*uk_87 + 1109020*uk_88 + 1569810*uk_89 + 2572416961*uk_9 + 656040*uk_90 + 538890*uk_91 + 1757250*uk_92 + 1569810*uk_93 + 2222055*uk_94 + 928620*uk_95 + 762795*uk_96 + 2487375*uk_97 + 2222055*uk_98 + 388080*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 296780*uk_100 + 940500*uk_101 + 593560*uk_102 + 277255*uk_103 + 878625*uk_104 + 554510*uk_105 + 2784375*uk_106 + 1757250*uk_107 + 1109020*uk_108 + 15625*uk_109 + 1267975*uk_11 + 88750*uk_110 + 47500*uk_111 + 44375*uk_112 + 140625*uk_113 + 88750*uk_114 + 504100*uk_115 + 269800*uk_116 + 252050*uk_117 + 798750*uk_118 + 504100*uk_119 + 7202098*uk_12 + 144400*uk_120 + 134900*uk_121 + 427500*uk_122 + 269800*uk_123 + 126025*uk_124 + 399375*uk_125 + 252050*uk_126 + 1265625*uk_127 + 798750*uk_128 + 504100*uk_129 + 3854644*uk_13 + 2863288*uk_130 + 1532464*uk_131 + 1431644*uk_132 + 4536900*uk_133 + 2863288*uk_134 + 820192*uk_135 + 766232*uk_136 + 2428200*uk_137 + 1532464*uk_138 + 715822*uk_139 + 3601049*uk_14 + 2268450*uk_140 + 1431644*uk_141 + 7188750*uk_142 + 4536900*uk_143 + 2863288*uk_144 + 438976*uk_145 + 410096*uk_146 + 1299600*uk_147 + 820192*uk_148 + 383116*uk_149 + 11411775*uk_15 + 1214100*uk_150 + 766232*uk_151 + 3847500*uk_152 + 2428200*uk_153 + 1532464*uk_154 + 357911*uk_155 + 1134225*uk_156 + 715822*uk_157 + 3594375*uk_158 + 2268450*uk_159 + 7202098*uk_16 + 1431644*uk_160 + 11390625*uk_161 + 7188750*uk_162 + 4536900*uk_163 + 2863288*uk_164 + 3025*uk_17 + 1375*uk_18 + 7810*uk_19 + 55*uk_2 + 4180*uk_20 + 3905*uk_21 + 12375*uk_22 + 7810*uk_23 + 625*uk_24 + 3550*uk_25 + 1900*uk_26 + 1775*uk_27 + 5625*uk_28 + 3550*uk_29 + 25*uk_3 + 20164*uk_30 + 10792*uk_31 + 10082*uk_32 + 31950*uk_33 + 20164*uk_34 + 5776*uk_35 + 5396*uk_36 + 17100*uk_37 + 10792*uk_38 + 5041*uk_39 + 142*uk_4 + 15975*uk_40 + 10082*uk_41 + 50625*uk_42 + 31950*uk_43 + 20164*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 64310424025*uk_47 + 365283208462*uk_48 + 195503689036*uk_49 + 76*uk_5 + 182641604231*uk_50 + 578793816225*uk_51 + 365283208462*uk_52 + 153424975*uk_53 + 69738625*uk_54 + 396115390*uk_55 + 212005420*uk_56 + 198057695*uk_57 + 627647625*uk_58 + 396115390*uk_59 + 71*uk_6 + 31699375*uk_60 + 180052450*uk_61 + 96366100*uk_62 + 90026225*uk_63 + 285294375*uk_64 + 180052450*uk_65 + 1022697916*uk_66 + 547359448*uk_67 + 511348958*uk_68 + 1620472050*uk_69 + 225*uk_7 + 1022697916*uk_70 + 292952944*uk_71 + 273679724*uk_72 + 867294900*uk_73 + 547359448*uk_74 + 255674479*uk_75 + 810236025*uk_76 + 511348958*uk_77 + 2567649375*uk_78 + 1620472050*uk_79 + 142*uk_8 + 1022697916*uk_80 + 166375*uk_81 + 75625*uk_82 + 429550*uk_83 + 229900*uk_84 + 214775*uk_85 + 680625*uk_86 + 429550*uk_87 + 34375*uk_88 + 195250*uk_89 + 2572416961*uk_9 + 104500*uk_90 + 97625*uk_91 + 309375*uk_92 + 195250*uk_93 + 1109020*uk_94 + 593560*uk_95 + 554510*uk_96 + 1757250*uk_97 + 1109020*uk_98 + 317680*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 321200*uk_100 + 990000*uk_101 + 110000*uk_102 + 293095*uk_103 + 903375*uk_104 + 100375*uk_105 + 2784375*uk_106 + 309375*uk_107 + 34375*uk_108 + 185193*uk_109 + 2890983*uk_11 + 81225*uk_110 + 259920*uk_111 + 237177*uk_112 + 731025*uk_113 + 81225*uk_114 + 35625*uk_115 + 114000*uk_116 + 104025*uk_117 + 320625*uk_118 + 35625*uk_119 + 1267975*uk_12 + 364800*uk_120 + 332880*uk_121 + 1026000*uk_122 + 114000*uk_123 + 303753*uk_124 + 936225*uk_125 + 104025*uk_126 + 2885625*uk_127 + 320625*uk_128 + 35625*uk_129 + 4057520*uk_13 + 15625*uk_130 + 50000*uk_131 + 45625*uk_132 + 140625*uk_133 + 15625*uk_134 + 160000*uk_135 + 146000*uk_136 + 450000*uk_137 + 50000*uk_138 + 133225*uk_139 + 3702487*uk_14 + 410625*uk_140 + 45625*uk_141 + 1265625*uk_142 + 140625*uk_143 + 15625*uk_144 + 512000*uk_145 + 467200*uk_146 + 1440000*uk_147 + 160000*uk_148 + 426320*uk_149 + 11411775*uk_15 + 1314000*uk_150 + 146000*uk_151 + 4050000*uk_152 + 450000*uk_153 + 50000*uk_154 + 389017*uk_155 + 1199025*uk_156 + 133225*uk_157 + 3695625*uk_158 + 410625*uk_159 + 1267975*uk_16 + 45625*uk_160 + 11390625*uk_161 + 1265625*uk_162 + 140625*uk_163 + 15625*uk_164 + 3025*uk_17 + 3135*uk_18 + 1375*uk_19 + 55*uk_2 + 4400*uk_20 + 4015*uk_21 + 12375*uk_22 + 1375*uk_23 + 3249*uk_24 + 1425*uk_25 + 4560*uk_26 + 4161*uk_27 + 12825*uk_28 + 1425*uk_29 + 57*uk_3 + 625*uk_30 + 2000*uk_31 + 1825*uk_32 + 5625*uk_33 + 625*uk_34 + 6400*uk_35 + 5840*uk_36 + 18000*uk_37 + 2000*uk_38 + 5329*uk_39 + 25*uk_4 + 16425*uk_40 + 1825*uk_41 + 50625*uk_42 + 5625*uk_43 + 625*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 146627766777*uk_47 + 64310424025*uk_48 + 205793356880*uk_49 + 80*uk_5 + 187786438153*uk_50 + 578793816225*uk_51 + 64310424025*uk_52 + 153424975*uk_53 + 159004065*uk_54 + 69738625*uk_55 + 223163600*uk_56 + 203636785*uk_57 + 627647625*uk_58 + 69738625*uk_59 + 73*uk_6 + 164786031*uk_60 + 72274575*uk_61 + 231278640*uk_62 + 211041759*uk_63 + 650471175*uk_64 + 72274575*uk_65 + 31699375*uk_66 + 101438000*uk_67 + 92562175*uk_68 + 285294375*uk_69 + 225*uk_7 + 31699375*uk_70 + 324601600*uk_71 + 296198960*uk_72 + 912942000*uk_73 + 101438000*uk_74 + 270281551*uk_75 + 833059575*uk_76 + 92562175*uk_77 + 2567649375*uk_78 + 285294375*uk_79 + 25*uk_8 + 31699375*uk_80 + 166375*uk_81 + 172425*uk_82 + 75625*uk_83 + 242000*uk_84 + 220825*uk_85 + 680625*uk_86 + 75625*uk_87 + 178695*uk_88 + 78375*uk_89 + 2572416961*uk_9 + 250800*uk_90 + 228855*uk_91 + 705375*uk_92 + 78375*uk_93 + 34375*uk_94 + 110000*uk_95 + 100375*uk_96 + 309375*uk_97 + 34375*uk_98 + 352000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 297000*uk_100 + 891000*uk_101 + 225720*uk_102 + 309375*uk_103 + 928125*uk_104 + 235125*uk_105 + 2784375*uk_106 + 705375*uk_107 + 178695*uk_108 + 6859*uk_109 + 963661*uk_11 + 20577*uk_110 + 25992*uk_111 + 27075*uk_112 + 81225*uk_113 + 20577*uk_114 + 61731*uk_115 + 77976*uk_116 + 81225*uk_117 + 243675*uk_118 + 61731*uk_119 + 2890983*uk_12 + 98496*uk_120 + 102600*uk_121 + 307800*uk_122 + 77976*uk_123 + 106875*uk_124 + 320625*uk_125 + 81225*uk_126 + 961875*uk_127 + 243675*uk_128 + 61731*uk_129 + 3651768*uk_13 + 185193*uk_130 + 233928*uk_131 + 243675*uk_132 + 731025*uk_133 + 185193*uk_134 + 295488*uk_135 + 307800*uk_136 + 923400*uk_137 + 233928*uk_138 + 320625*uk_139 + 3803925*uk_14 + 961875*uk_140 + 243675*uk_141 + 2885625*uk_142 + 731025*uk_143 + 185193*uk_144 + 373248*uk_145 + 388800*uk_146 + 1166400*uk_147 + 295488*uk_148 + 405000*uk_149 + 11411775*uk_15 + 1215000*uk_150 + 307800*uk_151 + 3645000*uk_152 + 923400*uk_153 + 233928*uk_154 + 421875*uk_155 + 1265625*uk_156 + 320625*uk_157 + 3796875*uk_158 + 961875*uk_159 + 2890983*uk_16 + 243675*uk_160 + 11390625*uk_161 + 2885625*uk_162 + 731025*uk_163 + 185193*uk_164 + 3025*uk_17 + 1045*uk_18 + 3135*uk_19 + 55*uk_2 + 3960*uk_20 + 4125*uk_21 + 12375*uk_22 + 3135*uk_23 + 361*uk_24 + 1083*uk_25 + 1368*uk_26 + 1425*uk_27 + 4275*uk_28 + 1083*uk_29 + 19*uk_3 + 3249*uk_30 + 4104*uk_31 + 4275*uk_32 + 12825*uk_33 + 3249*uk_34 + 5184*uk_35 + 5400*uk_36 + 16200*uk_37 + 4104*uk_38 + 5625*uk_39 + 57*uk_4 + 16875*uk_40 + 4275*uk_41 + 50625*uk_42 + 12825*uk_43 + 3249*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 48875922259*uk_47 + 146627766777*uk_48 + 185214021192*uk_49 + 72*uk_5 + 192931272075*uk_50 + 578793816225*uk_51 + 146627766777*uk_52 + 153424975*uk_53 + 53001355*uk_54 + 159004065*uk_55 + 200847240*uk_56 + 209215875*uk_57 + 627647625*uk_58 + 159004065*uk_59 + 75*uk_6 + 18309559*uk_60 + 54928677*uk_61 + 69383592*uk_62 + 72274575*uk_63 + 216823725*uk_64 + 54928677*uk_65 + 164786031*uk_66 + 208150776*uk_67 + 216823725*uk_68 + 650471175*uk_69 + 225*uk_7 + 164786031*uk_70 + 262927296*uk_71 + 273882600*uk_72 + 821647800*uk_73 + 208150776*uk_74 + 285294375*uk_75 + 855883125*uk_76 + 216823725*uk_77 + 2567649375*uk_78 + 650471175*uk_79 + 57*uk_8 + 164786031*uk_80 + 166375*uk_81 + 57475*uk_82 + 172425*uk_83 + 217800*uk_84 + 226875*uk_85 + 680625*uk_86 + 172425*uk_87 + 19855*uk_88 + 59565*uk_89 + 2572416961*uk_9 + 75240*uk_90 + 78375*uk_91 + 235125*uk_92 + 59565*uk_93 + 178695*uk_94 + 225720*uk_95 + 235125*uk_96 + 705375*uk_97 + 178695*uk_98 + 285120*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 304920*uk_100 + 891000*uk_101 + 75240*uk_102 + 326095*uk_103 + 952875*uk_104 + 80465*uk_105 + 2784375*uk_106 + 235125*uk_107 + 19855*uk_108 + 148877*uk_109 + 2688107*uk_11 + 53371*uk_110 + 202248*uk_111 + 216293*uk_112 + 632025*uk_113 + 53371*uk_114 + 19133*uk_115 + 72504*uk_116 + 77539*uk_117 + 226575*uk_118 + 19133*uk_119 + 963661*uk_12 + 274752*uk_120 + 293832*uk_121 + 858600*uk_122 + 72504*uk_123 + 314237*uk_124 + 918225*uk_125 + 77539*uk_126 + 2683125*uk_127 + 226575*uk_128 + 19133*uk_129 + 3651768*uk_13 + 6859*uk_130 + 25992*uk_131 + 27797*uk_132 + 81225*uk_133 + 6859*uk_134 + 98496*uk_135 + 105336*uk_136 + 307800*uk_137 + 25992*uk_138 + 112651*uk_139 + 3905363*uk_14 + 329175*uk_140 + 27797*uk_141 + 961875*uk_142 + 81225*uk_143 + 6859*uk_144 + 373248*uk_145 + 399168*uk_146 + 1166400*uk_147 + 98496*uk_148 + 426888*uk_149 + 11411775*uk_15 + 1247400*uk_150 + 105336*uk_151 + 3645000*uk_152 + 307800*uk_153 + 25992*uk_154 + 456533*uk_155 + 1334025*uk_156 + 112651*uk_157 + 3898125*uk_158 + 329175*uk_159 + 963661*uk_16 + 27797*uk_160 + 11390625*uk_161 + 961875*uk_162 + 81225*uk_163 + 6859*uk_164 + 3025*uk_17 + 2915*uk_18 + 1045*uk_19 + 55*uk_2 + 3960*uk_20 + 4235*uk_21 + 12375*uk_22 + 1045*uk_23 + 2809*uk_24 + 1007*uk_25 + 3816*uk_26 + 4081*uk_27 + 11925*uk_28 + 1007*uk_29 + 53*uk_3 + 361*uk_30 + 1368*uk_31 + 1463*uk_32 + 4275*uk_33 + 361*uk_34 + 5184*uk_35 + 5544*uk_36 + 16200*uk_37 + 1368*uk_38 + 5929*uk_39 + 19*uk_4 + 17325*uk_40 + 1463*uk_41 + 50625*uk_42 + 4275*uk_43 + 361*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 136338098933*uk_47 + 48875922259*uk_48 + 185214021192*uk_49 + 72*uk_5 + 198076105997*uk_50 + 578793816225*uk_51 + 48875922259*uk_52 + 153424975*uk_53 + 147845885*uk_54 + 53001355*uk_55 + 200847240*uk_56 + 214794965*uk_57 + 627647625*uk_58 + 53001355*uk_59 + 77*uk_6 + 142469671*uk_60 + 51074033*uk_61 + 193543704*uk_62 + 206984239*uk_63 + 604824075*uk_64 + 51074033*uk_65 + 18309559*uk_66 + 69383592*uk_67 + 74201897*uk_68 + 216823725*uk_69 + 225*uk_7 + 18309559*uk_70 + 262927296*uk_71 + 281186136*uk_72 + 821647800*uk_73 + 69383592*uk_74 + 300712951*uk_75 + 878706675*uk_76 + 74201897*uk_77 + 2567649375*uk_78 + 216823725*uk_79 + 19*uk_8 + 18309559*uk_80 + 166375*uk_81 + 160325*uk_82 + 57475*uk_83 + 217800*uk_84 + 232925*uk_85 + 680625*uk_86 + 57475*uk_87 + 154495*uk_88 + 55385*uk_89 + 2572416961*uk_9 + 209880*uk_90 + 224455*uk_91 + 655875*uk_92 + 55385*uk_93 + 19855*uk_94 + 75240*uk_95 + 80465*uk_96 + 235125*uk_97 + 19855*uk_98 + 285120*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 278080*uk_100 + 792000*uk_101 + 186560*uk_102 + 343255*uk_103 + 977625*uk_104 + 230285*uk_105 + 2784375*uk_106 + 655875*uk_107 + 154495*uk_108 + uk_109 + 50719*uk_11 + 53*uk_110 + 64*uk_111 + 79*uk_112 + 225*uk_113 + 53*uk_114 + 2809*uk_115 + 3392*uk_116 + 4187*uk_117 + 11925*uk_118 + 2809*uk_119 + 2688107*uk_12 + 4096*uk_120 + 5056*uk_121 + 14400*uk_122 + 3392*uk_123 + 6241*uk_124 + 17775*uk_125 + 4187*uk_126 + 50625*uk_127 + 11925*uk_128 + 2809*uk_129 + 3246016*uk_13 + 148877*uk_130 + 179776*uk_131 + 221911*uk_132 + 632025*uk_133 + 148877*uk_134 + 217088*uk_135 + 267968*uk_136 + 763200*uk_137 + 179776*uk_138 + 330773*uk_139 + 4006801*uk_14 + 942075*uk_140 + 221911*uk_141 + 2683125*uk_142 + 632025*uk_143 + 148877*uk_144 + 262144*uk_145 + 323584*uk_146 + 921600*uk_147 + 217088*uk_148 + 399424*uk_149 + 11411775*uk_15 + 1137600*uk_150 + 267968*uk_151 + 3240000*uk_152 + 763200*uk_153 + 179776*uk_154 + 493039*uk_155 + 1404225*uk_156 + 330773*uk_157 + 3999375*uk_158 + 942075*uk_159 + 2688107*uk_16 + 221911*uk_160 + 11390625*uk_161 + 2683125*uk_162 + 632025*uk_163 + 148877*uk_164 + 3025*uk_17 + 55*uk_18 + 2915*uk_19 + 55*uk_2 + 3520*uk_20 + 4345*uk_21 + 12375*uk_22 + 2915*uk_23 + uk_24 + 53*uk_25 + 64*uk_26 + 79*uk_27 + 225*uk_28 + 53*uk_29 + uk_3 + 2809*uk_30 + 3392*uk_31 + 4187*uk_32 + 11925*uk_33 + 2809*uk_34 + 4096*uk_35 + 5056*uk_36 + 14400*uk_37 + 3392*uk_38 + 6241*uk_39 + 53*uk_4 + 17775*uk_40 + 4187*uk_41 + 50625*uk_42 + 11925*uk_43 + 2809*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 2572416961*uk_47 + 136338098933*uk_48 + 164634685504*uk_49 + 64*uk_5 + 203220939919*uk_50 + 578793816225*uk_51 + 136338098933*uk_52 + 153424975*uk_53 + 2789545*uk_54 + 147845885*uk_55 + 178530880*uk_56 + 220374055*uk_57 + 627647625*uk_58 + 147845885*uk_59 + 79*uk_6 + 50719*uk_60 + 2688107*uk_61 + 3246016*uk_62 + 4006801*uk_63 + 11411775*uk_64 + 2688107*uk_65 + 142469671*uk_66 + 172038848*uk_67 + 212360453*uk_68 + 604824075*uk_69 + 225*uk_7 + 142469671*uk_70 + 207745024*uk_71 + 256435264*uk_72 + 730353600*uk_73 + 172038848*uk_74 + 316537279*uk_75 + 901530225*uk_76 + 212360453*uk_77 + 2567649375*uk_78 + 604824075*uk_79 + 53*uk_8 + 142469671*uk_80 + 166375*uk_81 + 3025*uk_82 + 160325*uk_83 + 193600*uk_84 + 238975*uk_85 + 680625*uk_86 + 160325*uk_87 + 55*uk_88 + 2915*uk_89 + 2572416961*uk_9 + 3520*uk_90 + 4345*uk_91 + 12375*uk_92 + 2915*uk_93 + 154495*uk_94 + 186560*uk_95 + 230285*uk_96 + 655875*uk_97 + 154495*uk_98 + 225280*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 285120*uk_100 + 792000*uk_101 + 3520*uk_102 + 360855*uk_103 + 1002375*uk_104 + 4455*uk_105 + 2784375*uk_106 + 12375*uk_107 + 55*uk_108 + 2197*uk_109 + 659347*uk_11 + 169*uk_110 + 10816*uk_111 + 13689*uk_112 + 38025*uk_113 + 169*uk_114 + 13*uk_115 + 832*uk_116 + 1053*uk_117 + 2925*uk_118 + 13*uk_119 + 50719*uk_12 + 53248*uk_120 + 67392*uk_121 + 187200*uk_122 + 832*uk_123 + 85293*uk_124 + 236925*uk_125 + 1053*uk_126 + 658125*uk_127 + 2925*uk_128 + 13*uk_129 + 3246016*uk_13 + uk_130 + 64*uk_131 + 81*uk_132 + 225*uk_133 + uk_134 + 4096*uk_135 + 5184*uk_136 + 14400*uk_137 + 64*uk_138 + 6561*uk_139 + 4108239*uk_14 + 18225*uk_140 + 81*uk_141 + 50625*uk_142 + 225*uk_143 + uk_144 + 262144*uk_145 + 331776*uk_146 + 921600*uk_147 + 4096*uk_148 + 419904*uk_149 + 11411775*uk_15 + 1166400*uk_150 + 5184*uk_151 + 3240000*uk_152 + 14400*uk_153 + 64*uk_154 + 531441*uk_155 + 1476225*uk_156 + 6561*uk_157 + 4100625*uk_158 + 18225*uk_159 + 50719*uk_16 + 81*uk_160 + 11390625*uk_161 + 50625*uk_162 + 225*uk_163 + uk_164 + 3025*uk_17 + 715*uk_18 + 55*uk_19 + 55*uk_2 + 3520*uk_20 + 4455*uk_21 + 12375*uk_22 + 55*uk_23 + 169*uk_24 + 13*uk_25 + 832*uk_26 + 1053*uk_27 + 2925*uk_28 + 13*uk_29 + 13*uk_3 + uk_30 + 64*uk_31 + 81*uk_32 + 225*uk_33 + uk_34 + 4096*uk_35 + 5184*uk_36 + 14400*uk_37 + 64*uk_38 + 6561*uk_39 + uk_4 + 18225*uk_40 + 81*uk_41 + 50625*uk_42 + 225*uk_43 + uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 33441420493*uk_47 + 2572416961*uk_48 + 164634685504*uk_49 + 64*uk_5 + 208365773841*uk_50 + 578793816225*uk_51 + 2572416961*uk_52 + 153424975*uk_53 + 36264085*uk_54 + 2789545*uk_55 + 178530880*uk_56 + 225953145*uk_57 + 627647625*uk_58 + 2789545*uk_59 + 81*uk_6 + 8571511*uk_60 + 659347*uk_61 + 42198208*uk_62 + 53407107*uk_63 + 148353075*uk_64 + 659347*uk_65 + 50719*uk_66 + 3246016*uk_67 + 4108239*uk_68 + 11411775*uk_69 + 225*uk_7 + 50719*uk_70 + 207745024*uk_71 + 262927296*uk_72 + 730353600*uk_73 + 3246016*uk_74 + 332767359*uk_75 + 924353775*uk_76 + 4108239*uk_77 + 2567649375*uk_78 + 11411775*uk_79 + uk_8 + 50719*uk_80 + 166375*uk_81 + 39325*uk_82 + 3025*uk_83 + 193600*uk_84 + 245025*uk_85 + 680625*uk_86 + 3025*uk_87 + 9295*uk_88 + 715*uk_89 + 2572416961*uk_9 + 45760*uk_90 + 57915*uk_91 + 160875*uk_92 + 715*uk_93 + 55*uk_94 + 3520*uk_95 + 4455*uk_96 + 12375*uk_97 + 55*uk_98 + 225280*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 273900*uk_100 + 742500*uk_101 + 42900*uk_102 + 378895*uk_103 + 1027125*uk_104 + 59345*uk_105 + 2784375*uk_106 + 160875*uk_107 + 9295*uk_108 + 216*uk_109 + 304314*uk_11 + 468*uk_110 + 2160*uk_111 + 2988*uk_112 + 8100*uk_113 + 468*uk_114 + 1014*uk_115 + 4680*uk_116 + 6474*uk_117 + 17550*uk_118 + 1014*uk_119 + 659347*uk_12 + 21600*uk_120 + 29880*uk_121 + 81000*uk_122 + 4680*uk_123 + 41334*uk_124 + 112050*uk_125 + 6474*uk_126 + 303750*uk_127 + 17550*uk_128 + 1014*uk_129 + 3043140*uk_13 + 2197*uk_130 + 10140*uk_131 + 14027*uk_132 + 38025*uk_133 + 2197*uk_134 + 46800*uk_135 + 64740*uk_136 + 175500*uk_137 + 10140*uk_138 + 89557*uk_139 + 4209677*uk_14 + 242775*uk_140 + 14027*uk_141 + 658125*uk_142 + 38025*uk_143 + 2197*uk_144 + 216000*uk_145 + 298800*uk_146 + 810000*uk_147 + 46800*uk_148 + 413340*uk_149 + 11411775*uk_15 + 1120500*uk_150 + 64740*uk_151 + 3037500*uk_152 + 175500*uk_153 + 10140*uk_154 + 571787*uk_155 + 1550025*uk_156 + 89557*uk_157 + 4201875*uk_158 + 242775*uk_159 + 659347*uk_16 + 14027*uk_160 + 11390625*uk_161 + 658125*uk_162 + 38025*uk_163 + 2197*uk_164 + 3025*uk_17 + 330*uk_18 + 715*uk_19 + 55*uk_2 + 3300*uk_20 + 4565*uk_21 + 12375*uk_22 + 715*uk_23 + 36*uk_24 + 78*uk_25 + 360*uk_26 + 498*uk_27 + 1350*uk_28 + 78*uk_29 + 6*uk_3 + 169*uk_30 + 780*uk_31 + 1079*uk_32 + 2925*uk_33 + 169*uk_34 + 3600*uk_35 + 4980*uk_36 + 13500*uk_37 + 780*uk_38 + 6889*uk_39 + 13*uk_4 + 18675*uk_40 + 1079*uk_41 + 50625*uk_42 + 2925*uk_43 + 169*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 15434501766*uk_47 + 33441420493*uk_48 + 154345017660*uk_49 + 60*uk_5 + 213510607763*uk_50 + 578793816225*uk_51 + 33441420493*uk_52 + 153424975*uk_53 + 16737270*uk_54 + 36264085*uk_55 + 167372700*uk_56 + 231532235*uk_57 + 627647625*uk_58 + 36264085*uk_59 + 83*uk_6 + 1825884*uk_60 + 3956082*uk_61 + 18258840*uk_62 + 25258062*uk_63 + 68470650*uk_64 + 3956082*uk_65 + 8571511*uk_66 + 39560820*uk_67 + 54725801*uk_68 + 148353075*uk_69 + 225*uk_7 + 8571511*uk_70 + 182588400*uk_71 + 252580620*uk_72 + 684706500*uk_73 + 39560820*uk_74 + 349403191*uk_75 + 947177325*uk_76 + 54725801*uk_77 + 2567649375*uk_78 + 148353075*uk_79 + 13*uk_8 + 8571511*uk_80 + 166375*uk_81 + 18150*uk_82 + 39325*uk_83 + 181500*uk_84 + 251075*uk_85 + 680625*uk_86 + 39325*uk_87 + 1980*uk_88 + 4290*uk_89 + 2572416961*uk_9 + 19800*uk_90 + 27390*uk_91 + 74250*uk_92 + 4290*uk_93 + 9295*uk_94 + 42900*uk_95 + 59345*uk_96 + 160875*uk_97 + 9295*uk_98 + 198000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 280500*uk_100 + 742500*uk_101 + 19800*uk_102 + 397375*uk_103 + 1051875*uk_104 + 28050*uk_105 + 2784375*uk_106 + 74250*uk_107 + 1980*uk_108 + 205379*uk_109 + 2992421*uk_11 + 20886*uk_110 + 208860*uk_111 + 295885*uk_112 + 783225*uk_113 + 20886*uk_114 + 2124*uk_115 + 21240*uk_116 + 30090*uk_117 + 79650*uk_118 + 2124*uk_119 + 304314*uk_12 + 212400*uk_120 + 300900*uk_121 + 796500*uk_122 + 21240*uk_123 + 426275*uk_124 + 1128375*uk_125 + 30090*uk_126 + 2986875*uk_127 + 79650*uk_128 + 2124*uk_129 + 3043140*uk_13 + 216*uk_130 + 2160*uk_131 + 3060*uk_132 + 8100*uk_133 + 216*uk_134 + 21600*uk_135 + 30600*uk_136 + 81000*uk_137 + 2160*uk_138 + 43350*uk_139 + 4311115*uk_14 + 114750*uk_140 + 3060*uk_141 + 303750*uk_142 + 8100*uk_143 + 216*uk_144 + 216000*uk_145 + 306000*uk_146 + 810000*uk_147 + 21600*uk_148 + 433500*uk_149 + 11411775*uk_15 + 1147500*uk_150 + 30600*uk_151 + 3037500*uk_152 + 81000*uk_153 + 2160*uk_154 + 614125*uk_155 + 1625625*uk_156 + 43350*uk_157 + 4303125*uk_158 + 114750*uk_159 + 304314*uk_16 + 3060*uk_160 + 11390625*uk_161 + 303750*uk_162 + 8100*uk_163 + 216*uk_164 + 3025*uk_17 + 3245*uk_18 + 330*uk_19 + 55*uk_2 + 3300*uk_20 + 4675*uk_21 + 12375*uk_22 + 330*uk_23 + 3481*uk_24 + 354*uk_25 + 3540*uk_26 + 5015*uk_27 + 13275*uk_28 + 354*uk_29 + 59*uk_3 + 36*uk_30 + 360*uk_31 + 510*uk_32 + 1350*uk_33 + 36*uk_34 + 3600*uk_35 + 5100*uk_36 + 13500*uk_37 + 360*uk_38 + 7225*uk_39 + 6*uk_4 + 19125*uk_40 + 510*uk_41 + 50625*uk_42 + 1350*uk_43 + 36*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 151772600699*uk_47 + 15434501766*uk_48 + 154345017660*uk_49 + 60*uk_5 + 218655441685*uk_50 + 578793816225*uk_51 + 15434501766*uk_52 + 153424975*uk_53 + 164583155*uk_54 + 16737270*uk_55 + 167372700*uk_56 + 237111325*uk_57 + 627647625*uk_58 + 16737270*uk_59 + 85*uk_6 + 176552839*uk_60 + 17954526*uk_61 + 179545260*uk_62 + 254355785*uk_63 + 673294725*uk_64 + 17954526*uk_65 + 1825884*uk_66 + 18258840*uk_67 + 25866690*uk_68 + 68470650*uk_69 + 225*uk_7 + 1825884*uk_70 + 182588400*uk_71 + 258666900*uk_72 + 684706500*uk_73 + 18258840*uk_74 + 366444775*uk_75 + 970000875*uk_76 + 25866690*uk_77 + 2567649375*uk_78 + 68470650*uk_79 + 6*uk_8 + 1825884*uk_80 + 166375*uk_81 + 178475*uk_82 + 18150*uk_83 + 181500*uk_84 + 257125*uk_85 + 680625*uk_86 + 18150*uk_87 + 191455*uk_88 + 19470*uk_89 + 2572416961*uk_9 + 194700*uk_90 + 275825*uk_91 + 730125*uk_92 + 19470*uk_93 + 1980*uk_94 + 19800*uk_95 + 28050*uk_96 + 74250*uk_97 + 1980*uk_98 + 198000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 267960*uk_100 + 693000*uk_101 + 181720*uk_102 + 416295*uk_103 + 1076625*uk_104 + 282315*uk_105 + 2784375*uk_106 + 730125*uk_107 + 191455*uk_108 + 614125*uk_109 + 4311115*uk_11 + 426275*uk_110 + 404600*uk_111 + 628575*uk_112 + 1625625*uk_113 + 426275*uk_114 + 295885*uk_115 + 280840*uk_116 + 436305*uk_117 + 1128375*uk_118 + 295885*uk_119 + 2992421*uk_12 + 266560*uk_120 + 414120*uk_121 + 1071000*uk_122 + 280840*uk_123 + 643365*uk_124 + 1663875*uk_125 + 436305*uk_126 + 4303125*uk_127 + 1128375*uk_128 + 295885*uk_129 + 2840264*uk_13 + 205379*uk_130 + 194936*uk_131 + 302847*uk_132 + 783225*uk_133 + 205379*uk_134 + 185024*uk_135 + 287448*uk_136 + 743400*uk_137 + 194936*uk_138 + 446571*uk_139 + 4412553*uk_14 + 1154925*uk_140 + 302847*uk_141 + 2986875*uk_142 + 783225*uk_143 + 205379*uk_144 + 175616*uk_145 + 272832*uk_146 + 705600*uk_147 + 185024*uk_148 + 423864*uk_149 + 11411775*uk_15 + 1096200*uk_150 + 287448*uk_151 + 2835000*uk_152 + 743400*uk_153 + 194936*uk_154 + 658503*uk_155 + 1703025*uk_156 + 446571*uk_157 + 4404375*uk_158 + 1154925*uk_159 + 2992421*uk_16 + 302847*uk_160 + 11390625*uk_161 + 2986875*uk_162 + 783225*uk_163 + 205379*uk_164 + 3025*uk_17 + 4675*uk_18 + 3245*uk_19 + 55*uk_2 + 3080*uk_20 + 4785*uk_21 + 12375*uk_22 + 3245*uk_23 + 7225*uk_24 + 5015*uk_25 + 4760*uk_26 + 7395*uk_27 + 19125*uk_28 + 5015*uk_29 + 85*uk_3 + 3481*uk_30 + 3304*uk_31 + 5133*uk_32 + 13275*uk_33 + 3481*uk_34 + 3136*uk_35 + 4872*uk_36 + 12600*uk_37 + 3304*uk_38 + 7569*uk_39 + 59*uk_4 + 19575*uk_40 + 5133*uk_41 + 50625*uk_42 + 13275*uk_43 + 3481*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 218655441685*uk_47 + 151772600699*uk_48 + 144055349816*uk_49 + 56*uk_5 + 223800275607*uk_50 + 578793816225*uk_51 + 151772600699*uk_52 + 153424975*uk_53 + 237111325*uk_54 + 164583155*uk_55 + 156214520*uk_56 + 242690415*uk_57 + 627647625*uk_58 + 164583155*uk_59 + 87*uk_6 + 366444775*uk_60 + 254355785*uk_61 + 241422440*uk_62 + 375067005*uk_63 + 970000875*uk_64 + 254355785*uk_65 + 176552839*uk_66 + 167575576*uk_67 + 260340627*uk_68 + 673294725*uk_69 + 225*uk_7 + 176552839*uk_70 + 159054784*uk_71 + 247102968*uk_72 + 639059400*uk_73 + 167575576*uk_74 + 383892111*uk_75 + 992824425*uk_76 + 260340627*uk_77 + 2567649375*uk_78 + 673294725*uk_79 + 59*uk_8 + 176552839*uk_80 + 166375*uk_81 + 257125*uk_82 + 178475*uk_83 + 169400*uk_84 + 263175*uk_85 + 680625*uk_86 + 178475*uk_87 + 397375*uk_88 + 275825*uk_89 + 2572416961*uk_9 + 261800*uk_90 + 406725*uk_91 + 1051875*uk_92 + 275825*uk_93 + 191455*uk_94 + 181720*uk_95 + 282315*uk_96 + 730125*uk_97 + 191455*uk_98 + 172480*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 254540*uk_100 + 643500*uk_101 + 243100*uk_102 + 435655*uk_103 + 1101375*uk_104 + 416075*uk_105 + 2784375*uk_106 + 1051875*uk_107 + 397375*uk_108 + 474552*uk_109 + 3956082*uk_11 + 517140*uk_110 + 316368*uk_111 + 541476*uk_112 + 1368900*uk_113 + 517140*uk_114 + 563550*uk_115 + 344760*uk_116 + 590070*uk_117 + 1491750*uk_118 + 563550*uk_119 + 4311115*uk_12 + 210912*uk_120 + 360984*uk_121 + 912600*uk_122 + 344760*uk_123 + 617838*uk_124 + 1561950*uk_125 + 590070*uk_126 + 3948750*uk_127 + 1491750*uk_128 + 563550*uk_129 + 2637388*uk_13 + 614125*uk_130 + 375700*uk_131 + 643025*uk_132 + 1625625*uk_133 + 614125*uk_134 + 229840*uk_135 + 393380*uk_136 + 994500*uk_137 + 375700*uk_138 + 673285*uk_139 + 4513991*uk_14 + 1702125*uk_140 + 643025*uk_141 + 4303125*uk_142 + 1625625*uk_143 + 614125*uk_144 + 140608*uk_145 + 240656*uk_146 + 608400*uk_147 + 229840*uk_148 + 411892*uk_149 + 11411775*uk_15 + 1041300*uk_150 + 393380*uk_151 + 2632500*uk_152 + 994500*uk_153 + 375700*uk_154 + 704969*uk_155 + 1782225*uk_156 + 673285*uk_157 + 4505625*uk_158 + 1702125*uk_159 + 4311115*uk_16 + 643025*uk_160 + 11390625*uk_161 + 4303125*uk_162 + 1625625*uk_163 + 614125*uk_164 + 3025*uk_17 + 4290*uk_18 + 4675*uk_19 + 55*uk_2 + 2860*uk_20 + 4895*uk_21 + 12375*uk_22 + 4675*uk_23 + 6084*uk_24 + 6630*uk_25 + 4056*uk_26 + 6942*uk_27 + 17550*uk_28 + 6630*uk_29 + 78*uk_3 + 7225*uk_30 + 4420*uk_31 + 7565*uk_32 + 19125*uk_33 + 7225*uk_34 + 2704*uk_35 + 4628*uk_36 + 11700*uk_37 + 4420*uk_38 + 7921*uk_39 + 85*uk_4 + 20025*uk_40 + 7565*uk_41 + 50625*uk_42 + 19125*uk_43 + 7225*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 200648522958*uk_47 + 218655441685*uk_48 + 133765681972*uk_49 + 52*uk_5 + 228945109529*uk_50 + 578793816225*uk_51 + 218655441685*uk_52 + 153424975*uk_53 + 217584510*uk_54 + 237111325*uk_55 + 145056340*uk_56 + 248269505*uk_57 + 627647625*uk_58 + 237111325*uk_59 + 89*uk_6 + 308574396*uk_60 + 336266970*uk_61 + 205716264*uk_62 + 352091298*uk_63 + 890118450*uk_64 + 336266970*uk_65 + 366444775*uk_66 + 224177980*uk_67 + 383689235*uk_68 + 970000875*uk_69 + 225*uk_7 + 366444775*uk_70 + 137144176*uk_71 + 234727532*uk_72 + 593412300*uk_73 + 224177980*uk_74 + 401745199*uk_75 + 1015647975*uk_76 + 383689235*uk_77 + 2567649375*uk_78 + 970000875*uk_79 + 85*uk_8 + 366444775*uk_80 + 166375*uk_81 + 235950*uk_82 + 257125*uk_83 + 157300*uk_84 + 269225*uk_85 + 680625*uk_86 + 257125*uk_87 + 334620*uk_88 + 364650*uk_89 + 2572416961*uk_9 + 223080*uk_90 + 381810*uk_91 + 965250*uk_92 + 364650*uk_93 + 397375*uk_94 + 243100*uk_95 + 416075*uk_96 + 1051875*uk_97 + 397375*uk_98 + 148720*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 240240*uk_100 + 594000*uk_101 + 205920*uk_102 + 455455*uk_103 + 1126125*uk_104 + 390390*uk_105 + 2784375*uk_106 + 965250*uk_107 + 334620*uk_108 + 32768*uk_109 + 1623008*uk_11 + 79872*uk_110 + 49152*uk_111 + 93184*uk_112 + 230400*uk_113 + 79872*uk_114 + 194688*uk_115 + 119808*uk_116 + 227136*uk_117 + 561600*uk_118 + 194688*uk_119 + 3956082*uk_12 + 73728*uk_120 + 139776*uk_121 + 345600*uk_122 + 119808*uk_123 + 264992*uk_124 + 655200*uk_125 + 227136*uk_126 + 1620000*uk_127 + 561600*uk_128 + 194688*uk_129 + 2434512*uk_13 + 474552*uk_130 + 292032*uk_131 + 553644*uk_132 + 1368900*uk_133 + 474552*uk_134 + 179712*uk_135 + 340704*uk_136 + 842400*uk_137 + 292032*uk_138 + 645918*uk_139 + 4615429*uk_14 + 1597050*uk_140 + 553644*uk_141 + 3948750*uk_142 + 1368900*uk_143 + 474552*uk_144 + 110592*uk_145 + 209664*uk_146 + 518400*uk_147 + 179712*uk_148 + 397488*uk_149 + 11411775*uk_15 + 982800*uk_150 + 340704*uk_151 + 2430000*uk_152 + 842400*uk_153 + 292032*uk_154 + 753571*uk_155 + 1863225*uk_156 + 645918*uk_157 + 4606875*uk_158 + 1597050*uk_159 + 3956082*uk_16 + 553644*uk_160 + 11390625*uk_161 + 3948750*uk_162 + 1368900*uk_163 + 474552*uk_164 + 3025*uk_17 + 1760*uk_18 + 4290*uk_19 + 55*uk_2 + 2640*uk_20 + 5005*uk_21 + 12375*uk_22 + 4290*uk_23 + 1024*uk_24 + 2496*uk_25 + 1536*uk_26 + 2912*uk_27 + 7200*uk_28 + 2496*uk_29 + 32*uk_3 + 6084*uk_30 + 3744*uk_31 + 7098*uk_32 + 17550*uk_33 + 6084*uk_34 + 2304*uk_35 + 4368*uk_36 + 10800*uk_37 + 3744*uk_38 + 8281*uk_39 + 78*uk_4 + 20475*uk_40 + 7098*uk_41 + 50625*uk_42 + 17550*uk_43 + 6084*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 82317342752*uk_47 + 200648522958*uk_48 + 123476014128*uk_49 + 48*uk_5 + 234089943451*uk_50 + 578793816225*uk_51 + 200648522958*uk_52 + 153424975*uk_53 + 89265440*uk_54 + 217584510*uk_55 + 133898160*uk_56 + 253848595*uk_57 + 627647625*uk_58 + 217584510*uk_59 + 91*uk_6 + 51936256*uk_60 + 126594624*uk_61 + 77904384*uk_62 + 147693728*uk_63 + 365176800*uk_64 + 126594624*uk_65 + 308574396*uk_66 + 189891936*uk_67 + 360003462*uk_68 + 890118450*uk_69 + 225*uk_7 + 308574396*uk_70 + 116856576*uk_71 + 221540592*uk_72 + 547765200*uk_73 + 189891936*uk_74 + 420004039*uk_75 + 1038471525*uk_76 + 360003462*uk_77 + 2567649375*uk_78 + 890118450*uk_79 + 78*uk_8 + 308574396*uk_80 + 166375*uk_81 + 96800*uk_82 + 235950*uk_83 + 145200*uk_84 + 275275*uk_85 + 680625*uk_86 + 235950*uk_87 + 56320*uk_88 + 137280*uk_89 + 2572416961*uk_9 + 84480*uk_90 + 160160*uk_91 + 396000*uk_92 + 137280*uk_93 + 334620*uk_94 + 205920*uk_95 + 390390*uk_96 + 965250*uk_97 + 334620*uk_98 + 126720*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 245520*uk_100 + 594000*uk_101 + 84480*uk_102 + 475695*uk_103 + 1150875*uk_104 + 163680*uk_105 + 2784375*uk_106 + 396000*uk_107 + 56320*uk_108 + 39304*uk_109 + 1724446*uk_11 + 36992*uk_110 + 55488*uk_111 + 107508*uk_112 + 260100*uk_113 + 36992*uk_114 + 34816*uk_115 + 52224*uk_116 + 101184*uk_117 + 244800*uk_118 + 34816*uk_119 + 1623008*uk_12 + 78336*uk_120 + 151776*uk_121 + 367200*uk_122 + 52224*uk_123 + 294066*uk_124 + 711450*uk_125 + 101184*uk_126 + 1721250*uk_127 + 244800*uk_128 + 34816*uk_129 + 2434512*uk_13 + 32768*uk_130 + 49152*uk_131 + 95232*uk_132 + 230400*uk_133 + 32768*uk_134 + 73728*uk_135 + 142848*uk_136 + 345600*uk_137 + 49152*uk_138 + 276768*uk_139 + 4716867*uk_14 + 669600*uk_140 + 95232*uk_141 + 1620000*uk_142 + 230400*uk_143 + 32768*uk_144 + 110592*uk_145 + 214272*uk_146 + 518400*uk_147 + 73728*uk_148 + 415152*uk_149 + 11411775*uk_15 + 1004400*uk_150 + 142848*uk_151 + 2430000*uk_152 + 345600*uk_153 + 49152*uk_154 + 804357*uk_155 + 1946025*uk_156 + 276768*uk_157 + 4708125*uk_158 + 669600*uk_159 + 1623008*uk_16 + 95232*uk_160 + 11390625*uk_161 + 1620000*uk_162 + 230400*uk_163 + 32768*uk_164 + 3025*uk_17 + 1870*uk_18 + 1760*uk_19 + 55*uk_2 + 2640*uk_20 + 5115*uk_21 + 12375*uk_22 + 1760*uk_23 + 1156*uk_24 + 1088*uk_25 + 1632*uk_26 + 3162*uk_27 + 7650*uk_28 + 1088*uk_29 + 34*uk_3 + 1024*uk_30 + 1536*uk_31 + 2976*uk_32 + 7200*uk_33 + 1024*uk_34 + 2304*uk_35 + 4464*uk_36 + 10800*uk_37 + 1536*uk_38 + 8649*uk_39 + 32*uk_4 + 20925*uk_40 + 2976*uk_41 + 50625*uk_42 + 7200*uk_43 + 1024*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 87462176674*uk_47 + 82317342752*uk_48 + 123476014128*uk_49 + 48*uk_5 + 239234777373*uk_50 + 578793816225*uk_51 + 82317342752*uk_52 + 153424975*uk_53 + 94844530*uk_54 + 89265440*uk_55 + 133898160*uk_56 + 259427685*uk_57 + 627647625*uk_58 + 89265440*uk_59 + 93*uk_6 + 58631164*uk_60 + 55182272*uk_61 + 82773408*uk_62 + 160373478*uk_63 + 388000350*uk_64 + 55182272*uk_65 + 51936256*uk_66 + 77904384*uk_67 + 150939744*uk_68 + 365176800*uk_69 + 225*uk_7 + 51936256*uk_70 + 116856576*uk_71 + 226409616*uk_72 + 547765200*uk_73 + 77904384*uk_74 + 438668631*uk_75 + 1061295075*uk_76 + 150939744*uk_77 + 2567649375*uk_78 + 365176800*uk_79 + 32*uk_8 + 51936256*uk_80 + 166375*uk_81 + 102850*uk_82 + 96800*uk_83 + 145200*uk_84 + 281325*uk_85 + 680625*uk_86 + 96800*uk_87 + 63580*uk_88 + 59840*uk_89 + 2572416961*uk_9 + 89760*uk_90 + 173910*uk_91 + 420750*uk_92 + 59840*uk_93 + 56320*uk_94 + 84480*uk_95 + 163680*uk_96 + 396000*uk_97 + 56320*uk_98 + 126720*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 250800*uk_100 + 594000*uk_101 + 89760*uk_102 + 496375*uk_103 + 1175625*uk_104 + 177650*uk_105 + 2784375*uk_106 + 420750*uk_107 + 63580*uk_108 + 592704*uk_109 + 4260396*uk_11 + 239904*uk_110 + 338688*uk_111 + 670320*uk_112 + 1587600*uk_113 + 239904*uk_114 + 97104*uk_115 + 137088*uk_116 + 271320*uk_117 + 642600*uk_118 + 97104*uk_119 + 1724446*uk_12 + 193536*uk_120 + 383040*uk_121 + 907200*uk_122 + 137088*uk_123 + 758100*uk_124 + 1795500*uk_125 + 271320*uk_126 + 4252500*uk_127 + 642600*uk_128 + 97104*uk_129 + 2434512*uk_13 + 39304*uk_130 + 55488*uk_131 + 109820*uk_132 + 260100*uk_133 + 39304*uk_134 + 78336*uk_135 + 155040*uk_136 + 367200*uk_137 + 55488*uk_138 + 306850*uk_139 + 4818305*uk_14 + 726750*uk_140 + 109820*uk_141 + 1721250*uk_142 + 260100*uk_143 + 39304*uk_144 + 110592*uk_145 + 218880*uk_146 + 518400*uk_147 + 78336*uk_148 + 433200*uk_149 + 11411775*uk_15 + 1026000*uk_150 + 155040*uk_151 + 2430000*uk_152 + 367200*uk_153 + 55488*uk_154 + 857375*uk_155 + 2030625*uk_156 + 306850*uk_157 + 4809375*uk_158 + 726750*uk_159 + 1724446*uk_16 + 109820*uk_160 + 11390625*uk_161 + 1721250*uk_162 + 260100*uk_163 + 39304*uk_164 + 3025*uk_17 + 4620*uk_18 + 1870*uk_19 + 55*uk_2 + 2640*uk_20 + 5225*uk_21 + 12375*uk_22 + 1870*uk_23 + 7056*uk_24 + 2856*uk_25 + 4032*uk_26 + 7980*uk_27 + 18900*uk_28 + 2856*uk_29 + 84*uk_3 + 1156*uk_30 + 1632*uk_31 + 3230*uk_32 + 7650*uk_33 + 1156*uk_34 + 2304*uk_35 + 4560*uk_36 + 10800*uk_37 + 1632*uk_38 + 9025*uk_39 + 34*uk_4 + 21375*uk_40 + 3230*uk_41 + 50625*uk_42 + 7650*uk_43 + 1156*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 216083024724*uk_47 + 87462176674*uk_48 + 123476014128*uk_49 + 48*uk_5 + 244379611295*uk_50 + 578793816225*uk_51 + 87462176674*uk_52 + 153424975*uk_53 + 234321780*uk_54 + 94844530*uk_55 + 133898160*uk_56 + 265006775*uk_57 + 627647625*uk_58 + 94844530*uk_59 + 95*uk_6 + 357873264*uk_60 + 144853464*uk_61 + 204499008*uk_62 + 404737620*uk_63 + 958589100*uk_64 + 144853464*uk_65 + 58631164*uk_66 + 82773408*uk_67 + 163822370*uk_68 + 388000350*uk_69 + 225*uk_7 + 58631164*uk_70 + 116856576*uk_71 + 231278640*uk_72 + 547765200*uk_73 + 82773408*uk_74 + 457738975*uk_75 + 1084118625*uk_76 + 163822370*uk_77 + 2567649375*uk_78 + 388000350*uk_79 + 34*uk_8 + 58631164*uk_80 + 166375*uk_81 + 254100*uk_82 + 102850*uk_83 + 145200*uk_84 + 287375*uk_85 + 680625*uk_86 + 102850*uk_87 + 388080*uk_88 + 157080*uk_89 + 2572416961*uk_9 + 221760*uk_90 + 438900*uk_91 + 1039500*uk_92 + 157080*uk_93 + 63580*uk_94 + 89760*uk_95 + 177650*uk_96 + 420750*uk_97 + 63580*uk_98 + 126720*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 234740*uk_100 + 544500*uk_101 + 203280*uk_102 + 517495*uk_103 + 1200375*uk_104 + 448140*uk_105 + 2784375*uk_106 + 1039500*uk_107 + 388080*uk_108 + 614125*uk_109 + 4311115*uk_11 + 606900*uk_110 + 317900*uk_111 + 700825*uk_112 + 1625625*uk_113 + 606900*uk_114 + 599760*uk_115 + 314160*uk_116 + 692580*uk_117 + 1606500*uk_118 + 599760*uk_119 + 4260396*uk_12 + 164560*uk_120 + 362780*uk_121 + 841500*uk_122 + 314160*uk_123 + 799765*uk_124 + 1855125*uk_125 + 692580*uk_126 + 4303125*uk_127 + 1606500*uk_128 + 599760*uk_129 + 2231636*uk_13 + 592704*uk_130 + 310464*uk_131 + 684432*uk_132 + 1587600*uk_133 + 592704*uk_134 + 162624*uk_135 + 358512*uk_136 + 831600*uk_137 + 310464*uk_138 + 790356*uk_139 + 4919743*uk_14 + 1833300*uk_140 + 684432*uk_141 + 4252500*uk_142 + 1587600*uk_143 + 592704*uk_144 + 85184*uk_145 + 187792*uk_146 + 435600*uk_147 + 162624*uk_148 + 413996*uk_149 + 11411775*uk_15 + 960300*uk_150 + 358512*uk_151 + 2227500*uk_152 + 831600*uk_153 + 310464*uk_154 + 912673*uk_155 + 2117025*uk_156 + 790356*uk_157 + 4910625*uk_158 + 1833300*uk_159 + 4260396*uk_16 + 684432*uk_160 + 11390625*uk_161 + 4252500*uk_162 + 1587600*uk_163 + 592704*uk_164 + 3025*uk_17 + 4675*uk_18 + 4620*uk_19 + 55*uk_2 + 2420*uk_20 + 5335*uk_21 + 12375*uk_22 + 4620*uk_23 + 7225*uk_24 + 7140*uk_25 + 3740*uk_26 + 8245*uk_27 + 19125*uk_28 + 7140*uk_29 + 85*uk_3 + 7056*uk_30 + 3696*uk_31 + 8148*uk_32 + 18900*uk_33 + 7056*uk_34 + 1936*uk_35 + 4268*uk_36 + 9900*uk_37 + 3696*uk_38 + 9409*uk_39 + 84*uk_4 + 21825*uk_40 + 8148*uk_41 + 50625*uk_42 + 18900*uk_43 + 7056*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 218655441685*uk_47 + 216083024724*uk_48 + 113186346284*uk_49 + 44*uk_5 + 249524445217*uk_50 + 578793816225*uk_51 + 216083024724*uk_52 + 153424975*uk_53 + 237111325*uk_54 + 234321780*uk_55 + 122739980*uk_56 + 270585865*uk_57 + 627647625*uk_58 + 234321780*uk_59 + 97*uk_6 + 366444775*uk_60 + 362133660*uk_61 + 189689060*uk_62 + 418178155*uk_63 + 970000875*uk_64 + 362133660*uk_65 + 357873264*uk_66 + 187457424*uk_67 + 413258412*uk_68 + 958589100*uk_69 + 225*uk_7 + 357873264*uk_70 + 98191984*uk_71 + 216468692*uk_72 + 502118100*uk_73 + 187457424*uk_74 + 477215071*uk_75 + 1106942175*uk_76 + 413258412*uk_77 + 2567649375*uk_78 + 958589100*uk_79 + 84*uk_8 + 357873264*uk_80 + 166375*uk_81 + 257125*uk_82 + 254100*uk_83 + 133100*uk_84 + 293425*uk_85 + 680625*uk_86 + 254100*uk_87 + 397375*uk_88 + 392700*uk_89 + 2572416961*uk_9 + 205700*uk_90 + 453475*uk_91 + 1051875*uk_92 + 392700*uk_93 + 388080*uk_94 + 203280*uk_95 + 448140*uk_96 + 1039500*uk_97 + 388080*uk_98 + 106480*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 217800*uk_100 + 495000*uk_101 + 187000*uk_102 + 539055*uk_103 + 1225125*uk_104 + 462825*uk_105 + 2784375*uk_106 + 1051875*uk_107 + 397375*uk_108 + 29791*uk_109 + 1572289*uk_11 + 81685*uk_110 + 38440*uk_111 + 95139*uk_112 + 216225*uk_113 + 81685*uk_114 + 223975*uk_115 + 105400*uk_116 + 260865*uk_117 + 592875*uk_118 + 223975*uk_119 + 4311115*uk_12 + 49600*uk_120 + 122760*uk_121 + 279000*uk_122 + 105400*uk_123 + 303831*uk_124 + 690525*uk_125 + 260865*uk_126 + 1569375*uk_127 + 592875*uk_128 + 223975*uk_129 + 2028760*uk_13 + 614125*uk_130 + 289000*uk_131 + 715275*uk_132 + 1625625*uk_133 + 614125*uk_134 + 136000*uk_135 + 336600*uk_136 + 765000*uk_137 + 289000*uk_138 + 833085*uk_139 + 5021181*uk_14 + 1893375*uk_140 + 715275*uk_141 + 4303125*uk_142 + 1625625*uk_143 + 614125*uk_144 + 64000*uk_145 + 158400*uk_146 + 360000*uk_147 + 136000*uk_148 + 392040*uk_149 + 11411775*uk_15 + 891000*uk_150 + 336600*uk_151 + 2025000*uk_152 + 765000*uk_153 + 289000*uk_154 + 970299*uk_155 + 2205225*uk_156 + 833085*uk_157 + 5011875*uk_158 + 1893375*uk_159 + 4311115*uk_16 + 715275*uk_160 + 11390625*uk_161 + 4303125*uk_162 + 1625625*uk_163 + 614125*uk_164 + 3025*uk_17 + 1705*uk_18 + 4675*uk_19 + 55*uk_2 + 2200*uk_20 + 5445*uk_21 + 12375*uk_22 + 4675*uk_23 + 961*uk_24 + 2635*uk_25 + 1240*uk_26 + 3069*uk_27 + 6975*uk_28 + 2635*uk_29 + 31*uk_3 + 7225*uk_30 + 3400*uk_31 + 8415*uk_32 + 19125*uk_33 + 7225*uk_34 + 1600*uk_35 + 3960*uk_36 + 9000*uk_37 + 3400*uk_38 + 9801*uk_39 + 85*uk_4 + 22275*uk_40 + 8415*uk_41 + 50625*uk_42 + 19125*uk_43 + 7225*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 79744925791*uk_47 + 218655441685*uk_48 + 102896678440*uk_49 + 40*uk_5 + 254669279139*uk_50 + 578793816225*uk_51 + 218655441685*uk_52 + 153424975*uk_53 + 86475895*uk_54 + 237111325*uk_55 + 111581800*uk_56 + 276164955*uk_57 + 627647625*uk_58 + 237111325*uk_59 + 99*uk_6 + 48740959*uk_60 + 133644565*uk_61 + 62891560*uk_62 + 155656611*uk_63 + 353765025*uk_64 + 133644565*uk_65 + 366444775*uk_66 + 172444600*uk_67 + 426800385*uk_68 + 970000875*uk_69 + 225*uk_7 + 366444775*uk_70 + 81150400*uk_71 + 200847240*uk_72 + 456471000*uk_73 + 172444600*uk_74 + 497096919*uk_75 + 1129765725*uk_76 + 426800385*uk_77 + 2567649375*uk_78 + 970000875*uk_79 + 85*uk_8 + 366444775*uk_80 + 166375*uk_81 + 93775*uk_82 + 257125*uk_83 + 121000*uk_84 + 299475*uk_85 + 680625*uk_86 + 257125*uk_87 + 52855*uk_88 + 144925*uk_89 + 2572416961*uk_9 + 68200*uk_90 + 168795*uk_91 + 383625*uk_92 + 144925*uk_93 + 397375*uk_94 + 187000*uk_95 + 462825*uk_96 + 1051875*uk_97 + 397375*uk_98 + 88000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 222200*uk_100 + 495000*uk_101 + 68200*uk_102 + 561055*uk_103 + 1249875*uk_104 + 172205*uk_105 + 2784375*uk_106 + 383625*uk_107 + 52855*uk_108 + 4913*uk_109 + 862223*uk_11 + 8959*uk_110 + 11560*uk_111 + 29189*uk_112 + 65025*uk_113 + 8959*uk_114 + 16337*uk_115 + 21080*uk_116 + 53227*uk_117 + 118575*uk_118 + 16337*uk_119 + 1572289*uk_12 + 27200*uk_120 + 68680*uk_121 + 153000*uk_122 + 21080*uk_123 + 173417*uk_124 + 386325*uk_125 + 53227*uk_126 + 860625*uk_127 + 118575*uk_128 + 16337*uk_129 + 2028760*uk_13 + 29791*uk_130 + 38440*uk_131 + 97061*uk_132 + 216225*uk_133 + 29791*uk_134 + 49600*uk_135 + 125240*uk_136 + 279000*uk_137 + 38440*uk_138 + 316231*uk_139 + 5122619*uk_14 + 704475*uk_140 + 97061*uk_141 + 1569375*uk_142 + 216225*uk_143 + 29791*uk_144 + 64000*uk_145 + 161600*uk_146 + 360000*uk_147 + 49600*uk_148 + 408040*uk_149 + 11411775*uk_15 + 909000*uk_150 + 125240*uk_151 + 2025000*uk_152 + 279000*uk_153 + 38440*uk_154 + 1030301*uk_155 + 2295225*uk_156 + 316231*uk_157 + 5113125*uk_158 + 704475*uk_159 + 1572289*uk_16 + 97061*uk_160 + 11390625*uk_161 + 1569375*uk_162 + 216225*uk_163 + 29791*uk_164 + 3025*uk_17 + 935*uk_18 + 1705*uk_19 + 55*uk_2 + 2200*uk_20 + 5555*uk_21 + 12375*uk_22 + 1705*uk_23 + 289*uk_24 + 527*uk_25 + 680*uk_26 + 1717*uk_27 + 3825*uk_28 + 527*uk_29 + 17*uk_3 + 961*uk_30 + 1240*uk_31 + 3131*uk_32 + 6975*uk_33 + 961*uk_34 + 1600*uk_35 + 4040*uk_36 + 9000*uk_37 + 1240*uk_38 + 10201*uk_39 + 31*uk_4 + 22725*uk_40 + 3131*uk_41 + 50625*uk_42 + 6975*uk_43 + 961*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 43731088337*uk_47 + 79744925791*uk_48 + 102896678440*uk_49 + 40*uk_5 + 259814113061*uk_50 + 578793816225*uk_51 + 79744925791*uk_52 + 153424975*uk_53 + 47422265*uk_54 + 86475895*uk_55 + 111581800*uk_56 + 281744045*uk_57 + 627647625*uk_58 + 86475895*uk_59 + 101*uk_6 + 14657791*uk_60 + 26728913*uk_61 + 34488920*uk_62 + 87084523*uk_63 + 194000175*uk_64 + 26728913*uk_65 + 48740959*uk_66 + 62891560*uk_67 + 158801189*uk_68 + 353765025*uk_69 + 225*uk_7 + 48740959*uk_70 + 81150400*uk_71 + 204904760*uk_72 + 456471000*uk_73 + 62891560*uk_74 + 517384519*uk_75 + 1152589275*uk_76 + 158801189*uk_77 + 2567649375*uk_78 + 353765025*uk_79 + 31*uk_8 + 48740959*uk_80 + 166375*uk_81 + 51425*uk_82 + 93775*uk_83 + 121000*uk_84 + 305525*uk_85 + 680625*uk_86 + 93775*uk_87 + 15895*uk_88 + 28985*uk_89 + 2572416961*uk_9 + 37400*uk_90 + 94435*uk_91 + 210375*uk_92 + 28985*uk_93 + 52855*uk_94 + 68200*uk_95 + 172205*uk_96 + 383625*uk_97 + 52855*uk_98 + 88000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 226600*uk_100 + 495000*uk_101 + 37400*uk_102 + 583495*uk_103 + 1274625*uk_104 + 96305*uk_105 + 2784375*uk_106 + 210375*uk_107 + 15895*uk_108 + 79507*uk_109 + 2180917*uk_11 + 31433*uk_110 + 73960*uk_111 + 190447*uk_112 + 416025*uk_113 + 31433*uk_114 + 12427*uk_115 + 29240*uk_116 + 75293*uk_117 + 164475*uk_118 + 12427*uk_119 + 862223*uk_12 + 68800*uk_120 + 177160*uk_121 + 387000*uk_122 + 29240*uk_123 + 456187*uk_124 + 996525*uk_125 + 75293*uk_126 + 2176875*uk_127 + 164475*uk_128 + 12427*uk_129 + 2028760*uk_13 + 4913*uk_130 + 11560*uk_131 + 29767*uk_132 + 65025*uk_133 + 4913*uk_134 + 27200*uk_135 + 70040*uk_136 + 153000*uk_137 + 11560*uk_138 + 180353*uk_139 + 5224057*uk_14 + 393975*uk_140 + 29767*uk_141 + 860625*uk_142 + 65025*uk_143 + 4913*uk_144 + 64000*uk_145 + 164800*uk_146 + 360000*uk_147 + 27200*uk_148 + 424360*uk_149 + 11411775*uk_15 + 927000*uk_150 + 70040*uk_151 + 2025000*uk_152 + 153000*uk_153 + 11560*uk_154 + 1092727*uk_155 + 2387025*uk_156 + 180353*uk_157 + 5214375*uk_158 + 393975*uk_159 + 862223*uk_16 + 29767*uk_160 + 11390625*uk_161 + 860625*uk_162 + 65025*uk_163 + 4913*uk_164 + 3025*uk_17 + 2365*uk_18 + 935*uk_19 + 55*uk_2 + 2200*uk_20 + 5665*uk_21 + 12375*uk_22 + 935*uk_23 + 1849*uk_24 + 731*uk_25 + 1720*uk_26 + 4429*uk_27 + 9675*uk_28 + 731*uk_29 + 43*uk_3 + 289*uk_30 + 680*uk_31 + 1751*uk_32 + 3825*uk_33 + 289*uk_34 + 1600*uk_35 + 4120*uk_36 + 9000*uk_37 + 680*uk_38 + 10609*uk_39 + 17*uk_4 + 23175*uk_40 + 1751*uk_41 + 50625*uk_42 + 3825*uk_43 + 289*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 110613929323*uk_47 + 43731088337*uk_48 + 102896678440*uk_49 + 40*uk_5 + 264958946983*uk_50 + 578793816225*uk_51 + 43731088337*uk_52 + 153424975*uk_53 + 119950435*uk_54 + 47422265*uk_55 + 111581800*uk_56 + 287323135*uk_57 + 627647625*uk_58 + 47422265*uk_59 + 103*uk_6 + 93779431*uk_60 + 37075589*uk_61 + 87236680*uk_62 + 224634451*uk_63 + 490706325*uk_64 + 37075589*uk_65 + 14657791*uk_66 + 34488920*uk_67 + 88808969*uk_68 + 194000175*uk_69 + 225*uk_7 + 14657791*uk_70 + 81150400*uk_71 + 208962280*uk_72 + 456471000*uk_73 + 34488920*uk_74 + 538077871*uk_75 + 1175412825*uk_76 + 88808969*uk_77 + 2567649375*uk_78 + 194000175*uk_79 + 17*uk_8 + 14657791*uk_80 + 166375*uk_81 + 130075*uk_82 + 51425*uk_83 + 121000*uk_84 + 311575*uk_85 + 680625*uk_86 + 51425*uk_87 + 101695*uk_88 + 40205*uk_89 + 2572416961*uk_9 + 94600*uk_90 + 243595*uk_91 + 532125*uk_92 + 40205*uk_93 + 15895*uk_94 + 37400*uk_95 + 96305*uk_96 + 210375*uk_97 + 15895*uk_98 + 88000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 207900*uk_100 + 445500*uk_101 + 85140*uk_102 + 606375*uk_103 + 1299375*uk_104 + 248325*uk_105 + 2784375*uk_106 + 532125*uk_107 + 101695*uk_108 + 64*uk_109 + 202876*uk_11 + 688*uk_110 + 576*uk_111 + 1680*uk_112 + 3600*uk_113 + 688*uk_114 + 7396*uk_115 + 6192*uk_116 + 18060*uk_117 + 38700*uk_118 + 7396*uk_119 + 2180917*uk_12 + 5184*uk_120 + 15120*uk_121 + 32400*uk_122 + 6192*uk_123 + 44100*uk_124 + 94500*uk_125 + 18060*uk_126 + 202500*uk_127 + 38700*uk_128 + 7396*uk_129 + 1825884*uk_13 + 79507*uk_130 + 66564*uk_131 + 194145*uk_132 + 416025*uk_133 + 79507*uk_134 + 55728*uk_135 + 162540*uk_136 + 348300*uk_137 + 66564*uk_138 + 474075*uk_139 + 5325495*uk_14 + 1015875*uk_140 + 194145*uk_141 + 2176875*uk_142 + 416025*uk_143 + 79507*uk_144 + 46656*uk_145 + 136080*uk_146 + 291600*uk_147 + 55728*uk_148 + 396900*uk_149 + 11411775*uk_15 + 850500*uk_150 + 162540*uk_151 + 1822500*uk_152 + 348300*uk_153 + 66564*uk_154 + 1157625*uk_155 + 2480625*uk_156 + 474075*uk_157 + 5315625*uk_158 + 1015875*uk_159 + 2180917*uk_16 + 194145*uk_160 + 11390625*uk_161 + 2176875*uk_162 + 416025*uk_163 + 79507*uk_164 + 3025*uk_17 + 220*uk_18 + 2365*uk_19 + 55*uk_2 + 1980*uk_20 + 5775*uk_21 + 12375*uk_22 + 2365*uk_23 + 16*uk_24 + 172*uk_25 + 144*uk_26 + 420*uk_27 + 900*uk_28 + 172*uk_29 + 4*uk_3 + 1849*uk_30 + 1548*uk_31 + 4515*uk_32 + 9675*uk_33 + 1849*uk_34 + 1296*uk_35 + 3780*uk_36 + 8100*uk_37 + 1548*uk_38 + 11025*uk_39 + 43*uk_4 + 23625*uk_40 + 4515*uk_41 + 50625*uk_42 + 9675*uk_43 + 1849*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 10289667844*uk_47 + 110613929323*uk_48 + 92607010596*uk_49 + 36*uk_5 + 270103780905*uk_50 + 578793816225*uk_51 + 110613929323*uk_52 + 153424975*uk_53 + 11158180*uk_54 + 119950435*uk_55 + 100423620*uk_56 + 292902225*uk_57 + 627647625*uk_58 + 119950435*uk_59 + 105*uk_6 + 811504*uk_60 + 8723668*uk_61 + 7303536*uk_62 + 21301980*uk_63 + 45647100*uk_64 + 8723668*uk_65 + 93779431*uk_66 + 78513012*uk_67 + 228996285*uk_68 + 490706325*uk_69 + 225*uk_7 + 93779431*uk_70 + 65731824*uk_71 + 191717820*uk_72 + 410823900*uk_73 + 78513012*uk_74 + 559176975*uk_75 + 1198236375*uk_76 + 228996285*uk_77 + 2567649375*uk_78 + 490706325*uk_79 + 43*uk_8 + 93779431*uk_80 + 166375*uk_81 + 12100*uk_82 + 130075*uk_83 + 108900*uk_84 + 317625*uk_85 + 680625*uk_86 + 130075*uk_87 + 880*uk_88 + 9460*uk_89 + 2572416961*uk_9 + 7920*uk_90 + 23100*uk_91 + 49500*uk_92 + 9460*uk_93 + 101695*uk_94 + 85140*uk_95 + 248325*uk_96 + 532125*uk_97 + 101695*uk_98 + 71280*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 211860*uk_100 + 445500*uk_101 + 7920*uk_102 + 629695*uk_103 + 1324125*uk_104 + 23540*uk_105 + 2784375*uk_106 + 49500*uk_107 + 880*uk_108 + uk_109 + 50719*uk_11 + 4*uk_110 + 36*uk_111 + 107*uk_112 + 225*uk_113 + 4*uk_114 + 16*uk_115 + 144*uk_116 + 428*uk_117 + 900*uk_118 + 16*uk_119 + 202876*uk_12 + 1296*uk_120 + 3852*uk_121 + 8100*uk_122 + 144*uk_123 + 11449*uk_124 + 24075*uk_125 + 428*uk_126 + 50625*uk_127 + 900*uk_128 + 16*uk_129 + 1825884*uk_13 + 64*uk_130 + 576*uk_131 + 1712*uk_132 + 3600*uk_133 + 64*uk_134 + 5184*uk_135 + 15408*uk_136 + 32400*uk_137 + 576*uk_138 + 45796*uk_139 + 5426933*uk_14 + 96300*uk_140 + 1712*uk_141 + 202500*uk_142 + 3600*uk_143 + 64*uk_144 + 46656*uk_145 + 138672*uk_146 + 291600*uk_147 + 5184*uk_148 + 412164*uk_149 + 11411775*uk_15 + 866700*uk_150 + 15408*uk_151 + 1822500*uk_152 + 32400*uk_153 + 576*uk_154 + 1225043*uk_155 + 2576025*uk_156 + 45796*uk_157 + 5416875*uk_158 + 96300*uk_159 + 202876*uk_16 + 1712*uk_160 + 11390625*uk_161 + 202500*uk_162 + 3600*uk_163 + 64*uk_164 + 3025*uk_17 + 55*uk_18 + 220*uk_19 + 55*uk_2 + 1980*uk_20 + 5885*uk_21 + 12375*uk_22 + 220*uk_23 + uk_24 + 4*uk_25 + 36*uk_26 + 107*uk_27 + 225*uk_28 + 4*uk_29 + uk_3 + 16*uk_30 + 144*uk_31 + 428*uk_32 + 900*uk_33 + 16*uk_34 + 1296*uk_35 + 3852*uk_36 + 8100*uk_37 + 144*uk_38 + 11449*uk_39 + 4*uk_4 + 24075*uk_40 + 428*uk_41 + 50625*uk_42 + 900*uk_43 + 16*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 2572416961*uk_47 + 10289667844*uk_48 + 92607010596*uk_49 + 36*uk_5 + 275248614827*uk_50 + 578793816225*uk_51 + 10289667844*uk_52 + 153424975*uk_53 + 2789545*uk_54 + 11158180*uk_55 + 100423620*uk_56 + 298481315*uk_57 + 627647625*uk_58 + 11158180*uk_59 + 107*uk_6 + 50719*uk_60 + 202876*uk_61 + 1825884*uk_62 + 5426933*uk_63 + 11411775*uk_64 + 202876*uk_65 + 811504*uk_66 + 7303536*uk_67 + 21707732*uk_68 + 45647100*uk_69 + 225*uk_7 + 811504*uk_70 + 65731824*uk_71 + 195369588*uk_72 + 410823900*uk_73 + 7303536*uk_74 + 580681831*uk_75 + 1221059925*uk_76 + 21707732*uk_77 + 2567649375*uk_78 + 45647100*uk_79 + 4*uk_8 + 811504*uk_80 + 166375*uk_81 + 3025*uk_82 + 12100*uk_83 + 108900*uk_84 + 323675*uk_85 + 680625*uk_86 + 12100*uk_87 + 55*uk_88 + 220*uk_89 + 2572416961*uk_9 + 1980*uk_90 + 5885*uk_91 + 12375*uk_92 + 220*uk_93 + 880*uk_94 + 7920*uk_95 + 23540*uk_96 + 49500*uk_97 + 880*uk_98 + 71280*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 215820*uk_100 + 445500*uk_101 + 1980*uk_102 + 653455*uk_103 + 1348875*uk_104 + 5995*uk_105 + 2784375*uk_106 + 12375*uk_107 + 55*uk_108 + 39304*uk_109 + 1724446*uk_11 + 1156*uk_110 + 41616*uk_111 + 126004*uk_112 + 260100*uk_113 + 1156*uk_114 + 34*uk_115 + 1224*uk_116 + 3706*uk_117 + 7650*uk_118 + 34*uk_119 + 50719*uk_12 + 44064*uk_120 + 133416*uk_121 + 275400*uk_122 + 1224*uk_123 + 403954*uk_124 + 833850*uk_125 + 3706*uk_126 + 1721250*uk_127 + 7650*uk_128 + 34*uk_129 + 1825884*uk_13 + uk_130 + 36*uk_131 + 109*uk_132 + 225*uk_133 + uk_134 + 1296*uk_135 + 3924*uk_136 + 8100*uk_137 + 36*uk_138 + 11881*uk_139 + 5528371*uk_14 + 24525*uk_140 + 109*uk_141 + 50625*uk_142 + 225*uk_143 + uk_144 + 46656*uk_145 + 141264*uk_146 + 291600*uk_147 + 1296*uk_148 + 427716*uk_149 + 11411775*uk_15 + 882900*uk_150 + 3924*uk_151 + 1822500*uk_152 + 8100*uk_153 + 36*uk_154 + 1295029*uk_155 + 2673225*uk_156 + 11881*uk_157 + 5518125*uk_158 + 24525*uk_159 + 50719*uk_16 + 109*uk_160 + 11390625*uk_161 + 50625*uk_162 + 225*uk_163 + uk_164 + 3025*uk_17 + 1870*uk_18 + 55*uk_19 + 55*uk_2 + 1980*uk_20 + 5995*uk_21 + 12375*uk_22 + 55*uk_23 + 1156*uk_24 + 34*uk_25 + 1224*uk_26 + 3706*uk_27 + 7650*uk_28 + 34*uk_29 + 34*uk_3 + uk_30 + 36*uk_31 + 109*uk_32 + 225*uk_33 + uk_34 + 1296*uk_35 + 3924*uk_36 + 8100*uk_37 + 36*uk_38 + 11881*uk_39 + uk_4 + 24525*uk_40 + 109*uk_41 + 50625*uk_42 + 225*uk_43 + uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 87462176674*uk_47 + 2572416961*uk_48 + 92607010596*uk_49 + 36*uk_5 + 280393448749*uk_50 + 578793816225*uk_51 + 2572416961*uk_52 + 153424975*uk_53 + 94844530*uk_54 + 2789545*uk_55 + 100423620*uk_56 + 304060405*uk_57 + 627647625*uk_58 + 2789545*uk_59 + 109*uk_6 + 58631164*uk_60 + 1724446*uk_61 + 62080056*uk_62 + 187964614*uk_63 + 388000350*uk_64 + 1724446*uk_65 + 50719*uk_66 + 1825884*uk_67 + 5528371*uk_68 + 11411775*uk_69 + 225*uk_7 + 50719*uk_70 + 65731824*uk_71 + 199021356*uk_72 + 410823900*uk_73 + 1825884*uk_74 + 602592439*uk_75 + 1243883475*uk_76 + 5528371*uk_77 + 2567649375*uk_78 + 11411775*uk_79 + uk_8 + 50719*uk_80 + 166375*uk_81 + 102850*uk_82 + 3025*uk_83 + 108900*uk_84 + 329725*uk_85 + 680625*uk_86 + 3025*uk_87 + 63580*uk_88 + 1870*uk_89 + 2572416961*uk_9 + 67320*uk_90 + 203830*uk_91 + 420750*uk_92 + 1870*uk_93 + 55*uk_94 + 1980*uk_95 + 5995*uk_96 + 12375*uk_97 + 55*uk_98 + 71280*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 219780*uk_100 + 445500*uk_101 + 67320*uk_102 + 677655*uk_103 + 1373625*uk_104 + 207570*uk_105 + 2784375*uk_106 + 420750*uk_107 + 63580*uk_108 + 1092727*uk_109 + 5224057*uk_11 + 360706*uk_110 + 381924*uk_111 + 1177599*uk_112 + 2387025*uk_113 + 360706*uk_114 + 119068*uk_115 + 126072*uk_116 + 388722*uk_117 + 787950*uk_118 + 119068*uk_119 + 1724446*uk_12 + 133488*uk_120 + 411588*uk_121 + 834300*uk_122 + 126072*uk_123 + 1269063*uk_124 + 2572425*uk_125 + 388722*uk_126 + 5214375*uk_127 + 787950*uk_128 + 119068*uk_129 + 1825884*uk_13 + 39304*uk_130 + 41616*uk_131 + 128316*uk_132 + 260100*uk_133 + 39304*uk_134 + 44064*uk_135 + 135864*uk_136 + 275400*uk_137 + 41616*uk_138 + 418914*uk_139 + 5629809*uk_14 + 849150*uk_140 + 128316*uk_141 + 1721250*uk_142 + 260100*uk_143 + 39304*uk_144 + 46656*uk_145 + 143856*uk_146 + 291600*uk_147 + 44064*uk_148 + 443556*uk_149 + 11411775*uk_15 + 899100*uk_150 + 135864*uk_151 + 1822500*uk_152 + 275400*uk_153 + 41616*uk_154 + 1367631*uk_155 + 2772225*uk_156 + 418914*uk_157 + 5619375*uk_158 + 849150*uk_159 + 1724446*uk_16 + 128316*uk_160 + 11390625*uk_161 + 1721250*uk_162 + 260100*uk_163 + 39304*uk_164 + 3025*uk_17 + 5665*uk_18 + 1870*uk_19 + 55*uk_2 + 1980*uk_20 + 6105*uk_21 + 12375*uk_22 + 1870*uk_23 + 10609*uk_24 + 3502*uk_25 + 3708*uk_26 + 11433*uk_27 + 23175*uk_28 + 3502*uk_29 + 103*uk_3 + 1156*uk_30 + 1224*uk_31 + 3774*uk_32 + 7650*uk_33 + 1156*uk_34 + 1296*uk_35 + 3996*uk_36 + 8100*uk_37 + 1224*uk_38 + 12321*uk_39 + 34*uk_4 + 24975*uk_40 + 3774*uk_41 + 50625*uk_42 + 7650*uk_43 + 1156*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 264958946983*uk_47 + 87462176674*uk_48 + 92607010596*uk_49 + 36*uk_5 + 285538282671*uk_50 + 578793816225*uk_51 + 87462176674*uk_52 + 153424975*uk_53 + 287323135*uk_54 + 94844530*uk_55 + 100423620*uk_56 + 309639495*uk_57 + 627647625*uk_58 + 94844530*uk_59 + 111*uk_6 + 538077871*uk_60 + 177617938*uk_61 + 188066052*uk_62 + 579870327*uk_63 + 1175412825*uk_64 + 177617938*uk_65 + 58631164*uk_66 + 62080056*uk_67 + 191413506*uk_68 + 388000350*uk_69 + 225*uk_7 + 58631164*uk_70 + 65731824*uk_71 + 202673124*uk_72 + 410823900*uk_73 + 62080056*uk_74 + 624908799*uk_75 + 1266707025*uk_76 + 191413506*uk_77 + 2567649375*uk_78 + 388000350*uk_79 + 34*uk_8 + 58631164*uk_80 + 166375*uk_81 + 311575*uk_82 + 102850*uk_83 + 108900*uk_84 + 335775*uk_85 + 680625*uk_86 + 102850*uk_87 + 583495*uk_88 + 192610*uk_89 + 2572416961*uk_9 + 203940*uk_90 + 628815*uk_91 + 1274625*uk_92 + 192610*uk_93 + 63580*uk_94 + 67320*uk_95 + 207570*uk_96 + 420750*uk_97 + 63580*uk_98 + 71280*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 198880*uk_100 + 396000*uk_101 + 181280*uk_102 + 702295*uk_103 + 1398375*uk_104 + 640145*uk_105 + 2784375*uk_106 + 1274625*uk_107 + 583495*uk_108 + 857375*uk_109 + 4818305*uk_11 + 929575*uk_110 + 288800*uk_111 + 1019825*uk_112 + 2030625*uk_113 + 929575*uk_114 + 1007855*uk_115 + 313120*uk_116 + 1105705*uk_117 + 2201625*uk_118 + 1007855*uk_119 + 5224057*uk_12 + 97280*uk_120 + 343520*uk_121 + 684000*uk_122 + 313120*uk_123 + 1213055*uk_124 + 2415375*uk_125 + 1105705*uk_126 + 4809375*uk_127 + 2201625*uk_128 + 1007855*uk_129 + 1623008*uk_13 + 1092727*uk_130 + 339488*uk_131 + 1198817*uk_132 + 2387025*uk_133 + 1092727*uk_134 + 105472*uk_135 + 372448*uk_136 + 741600*uk_137 + 339488*uk_138 + 1315207*uk_139 + 5731247*uk_14 + 2618775*uk_140 + 1198817*uk_141 + 5214375*uk_142 + 2387025*uk_143 + 1092727*uk_144 + 32768*uk_145 + 115712*uk_146 + 230400*uk_147 + 105472*uk_148 + 408608*uk_149 + 11411775*uk_15 + 813600*uk_150 + 372448*uk_151 + 1620000*uk_152 + 741600*uk_153 + 339488*uk_154 + 1442897*uk_155 + 2873025*uk_156 + 1315207*uk_157 + 5720625*uk_158 + 2618775*uk_159 + 5224057*uk_16 + 1198817*uk_160 + 11390625*uk_161 + 5214375*uk_162 + 2387025*uk_163 + 1092727*uk_164 + 3025*uk_17 + 5225*uk_18 + 5665*uk_19 + 55*uk_2 + 1760*uk_20 + 6215*uk_21 + 12375*uk_22 + 5665*uk_23 + 9025*uk_24 + 9785*uk_25 + 3040*uk_26 + 10735*uk_27 + 21375*uk_28 + 9785*uk_29 + 95*uk_3 + 10609*uk_30 + 3296*uk_31 + 11639*uk_32 + 23175*uk_33 + 10609*uk_34 + 1024*uk_35 + 3616*uk_36 + 7200*uk_37 + 3296*uk_38 + 12769*uk_39 + 103*uk_4 + 25425*uk_40 + 11639*uk_41 + 50625*uk_42 + 23175*uk_43 + 10609*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 244379611295*uk_47 + 264958946983*uk_48 + 82317342752*uk_49 + 32*uk_5 + 290683116593*uk_50 + 578793816225*uk_51 + 264958946983*uk_52 + 153424975*uk_53 + 265006775*uk_54 + 287323135*uk_55 + 89265440*uk_56 + 315218585*uk_57 + 627647625*uk_58 + 287323135*uk_59 + 113*uk_6 + 457738975*uk_60 + 496285415*uk_61 + 154185760*uk_62 + 544468465*uk_63 + 1084118625*uk_64 + 496285415*uk_65 + 538077871*uk_66 + 167169824*uk_67 + 590318441*uk_68 + 1175412825*uk_69 + 225*uk_7 + 538077871*uk_70 + 51936256*uk_71 + 183399904*uk_72 + 365176800*uk_73 + 167169824*uk_74 + 647630911*uk_75 + 1289530575*uk_76 + 590318441*uk_77 + 2567649375*uk_78 + 1175412825*uk_79 + 103*uk_8 + 538077871*uk_80 + 166375*uk_81 + 287375*uk_82 + 311575*uk_83 + 96800*uk_84 + 341825*uk_85 + 680625*uk_86 + 311575*uk_87 + 496375*uk_88 + 538175*uk_89 + 2572416961*uk_9 + 167200*uk_90 + 590425*uk_91 + 1175625*uk_92 + 538175*uk_93 + 583495*uk_94 + 181280*uk_95 + 640145*uk_96 + 1274625*uk_97 + 583495*uk_98 + 56320*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 177100*uk_100 + 346500*uk_101 + 146300*uk_102 + 727375*uk_103 + 1423125*uk_104 + 600875*uk_105 + 2784375*uk_106 + 1175625*uk_107 + 496375*uk_108 + 64*uk_109 + 202876*uk_11 + 1520*uk_110 + 448*uk_111 + 1840*uk_112 + 3600*uk_113 + 1520*uk_114 + 36100*uk_115 + 10640*uk_116 + 43700*uk_117 + 85500*uk_118 + 36100*uk_119 + 4818305*uk_12 + 3136*uk_120 + 12880*uk_121 + 25200*uk_122 + 10640*uk_123 + 52900*uk_124 + 103500*uk_125 + 43700*uk_126 + 202500*uk_127 + 85500*uk_128 + 36100*uk_129 + 1420132*uk_13 + 857375*uk_130 + 252700*uk_131 + 1037875*uk_132 + 2030625*uk_133 + 857375*uk_134 + 74480*uk_135 + 305900*uk_136 + 598500*uk_137 + 252700*uk_138 + 1256375*uk_139 + 5832685*uk_14 + 2458125*uk_140 + 1037875*uk_141 + 4809375*uk_142 + 2030625*uk_143 + 857375*uk_144 + 21952*uk_145 + 90160*uk_146 + 176400*uk_147 + 74480*uk_148 + 370300*uk_149 + 11411775*uk_15 + 724500*uk_150 + 305900*uk_151 + 1417500*uk_152 + 598500*uk_153 + 252700*uk_154 + 1520875*uk_155 + 2975625*uk_156 + 1256375*uk_157 + 5821875*uk_158 + 2458125*uk_159 + 4818305*uk_16 + 1037875*uk_160 + 11390625*uk_161 + 4809375*uk_162 + 2030625*uk_163 + 857375*uk_164 + 3025*uk_17 + 220*uk_18 + 5225*uk_19 + 55*uk_2 + 1540*uk_20 + 6325*uk_21 + 12375*uk_22 + 5225*uk_23 + 16*uk_24 + 380*uk_25 + 112*uk_26 + 460*uk_27 + 900*uk_28 + 380*uk_29 + 4*uk_3 + 9025*uk_30 + 2660*uk_31 + 10925*uk_32 + 21375*uk_33 + 9025*uk_34 + 784*uk_35 + 3220*uk_36 + 6300*uk_37 + 2660*uk_38 + 13225*uk_39 + 95*uk_4 + 25875*uk_40 + 10925*uk_41 + 50625*uk_42 + 21375*uk_43 + 9025*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 10289667844*uk_47 + 244379611295*uk_48 + 72027674908*uk_49 + 28*uk_5 + 295827950515*uk_50 + 578793816225*uk_51 + 244379611295*uk_52 + 153424975*uk_53 + 11158180*uk_54 + 265006775*uk_55 + 78107260*uk_56 + 320797675*uk_57 + 627647625*uk_58 + 265006775*uk_59 + 115*uk_6 + 811504*uk_60 + 19273220*uk_61 + 5680528*uk_62 + 23330740*uk_63 + 45647100*uk_64 + 19273220*uk_65 + 457738975*uk_66 + 134912540*uk_67 + 554105075*uk_68 + 1084118625*uk_69 + 225*uk_7 + 457738975*uk_70 + 39763696*uk_71 + 163315180*uk_72 + 319529700*uk_73 + 134912540*uk_74 + 670758775*uk_75 + 1312354125*uk_76 + 554105075*uk_77 + 2567649375*uk_78 + 1084118625*uk_79 + 95*uk_8 + 457738975*uk_80 + 166375*uk_81 + 12100*uk_82 + 287375*uk_83 + 84700*uk_84 + 347875*uk_85 + 680625*uk_86 + 287375*uk_87 + 880*uk_88 + 20900*uk_89 + 2572416961*uk_9 + 6160*uk_90 + 25300*uk_91 + 49500*uk_92 + 20900*uk_93 + 496375*uk_94 + 146300*uk_95 + 600875*uk_96 + 1175625*uk_97 + 496375*uk_98 + 43120*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 205920*uk_100 + 396000*uk_101 + 7040*uk_102 + 752895*uk_103 + 1447875*uk_104 + 25740*uk_105 + 2784375*uk_106 + 49500*uk_107 + 880*uk_108 + 195112*uk_109 + 2941702*uk_11 + 13456*uk_110 + 107648*uk_111 + 393588*uk_112 + 756900*uk_113 + 13456*uk_114 + 928*uk_115 + 7424*uk_116 + 27144*uk_117 + 52200*uk_118 + 928*uk_119 + 202876*uk_12 + 59392*uk_120 + 217152*uk_121 + 417600*uk_122 + 7424*uk_123 + 793962*uk_124 + 1526850*uk_125 + 27144*uk_126 + 2936250*uk_127 + 52200*uk_128 + 928*uk_129 + 1623008*uk_13 + 64*uk_130 + 512*uk_131 + 1872*uk_132 + 3600*uk_133 + 64*uk_134 + 4096*uk_135 + 14976*uk_136 + 28800*uk_137 + 512*uk_138 + 54756*uk_139 + 5934123*uk_14 + 105300*uk_140 + 1872*uk_141 + 202500*uk_142 + 3600*uk_143 + 64*uk_144 + 32768*uk_145 + 119808*uk_146 + 230400*uk_147 + 4096*uk_148 + 438048*uk_149 + 11411775*uk_15 + 842400*uk_150 + 14976*uk_151 + 1620000*uk_152 + 28800*uk_153 + 512*uk_154 + 1601613*uk_155 + 3080025*uk_156 + 54756*uk_157 + 5923125*uk_158 + 105300*uk_159 + 202876*uk_16 + 1872*uk_160 + 11390625*uk_161 + 202500*uk_162 + 3600*uk_163 + 64*uk_164 + 3025*uk_17 + 3190*uk_18 + 220*uk_19 + 55*uk_2 + 1760*uk_20 + 6435*uk_21 + 12375*uk_22 + 220*uk_23 + 3364*uk_24 + 232*uk_25 + 1856*uk_26 + 6786*uk_27 + 13050*uk_28 + 232*uk_29 + 58*uk_3 + 16*uk_30 + 128*uk_31 + 468*uk_32 + 900*uk_33 + 16*uk_34 + 1024*uk_35 + 3744*uk_36 + 7200*uk_37 + 128*uk_38 + 13689*uk_39 + 4*uk_4 + 26325*uk_40 + 468*uk_41 + 50625*uk_42 + 900*uk_43 + 16*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 149200183738*uk_47 + 10289667844*uk_48 + 82317342752*uk_49 + 32*uk_5 + 300972784437*uk_50 + 578793816225*uk_51 + 10289667844*uk_52 + 153424975*uk_53 + 161793610*uk_54 + 11158180*uk_55 + 89265440*uk_56 + 326376765*uk_57 + 627647625*uk_58 + 11158180*uk_59 + 117*uk_6 + 170618716*uk_60 + 11766808*uk_61 + 94134464*uk_62 + 344179134*uk_63 + 661882950*uk_64 + 11766808*uk_65 + 811504*uk_66 + 6492032*uk_67 + 23736492*uk_68 + 45647100*uk_69 + 225*uk_7 + 811504*uk_70 + 51936256*uk_71 + 189891936*uk_72 + 365176800*uk_73 + 6492032*uk_74 + 694292391*uk_75 + 1335177675*uk_76 + 23736492*uk_77 + 2567649375*uk_78 + 45647100*uk_79 + 4*uk_8 + 811504*uk_80 + 166375*uk_81 + 175450*uk_82 + 12100*uk_83 + 96800*uk_84 + 353925*uk_85 + 680625*uk_86 + 12100*uk_87 + 185020*uk_88 + 12760*uk_89 + 2572416961*uk_9 + 102080*uk_90 + 373230*uk_91 + 717750*uk_92 + 12760*uk_93 + 880*uk_94 + 7040*uk_95 + 25740*uk_96 + 49500*uk_97 + 880*uk_98 + 56320*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 183260*uk_100 + 346500*uk_101 + 89320*uk_102 + 778855*uk_103 + 1472625*uk_104 + 379610*uk_105 + 2784375*uk_106 + 717750*uk_107 + 185020*uk_108 + 15625*uk_109 + 1267975*uk_11 + 36250*uk_110 + 17500*uk_111 + 74375*uk_112 + 140625*uk_113 + 36250*uk_114 + 84100*uk_115 + 40600*uk_116 + 172550*uk_117 + 326250*uk_118 + 84100*uk_119 + 2941702*uk_12 + 19600*uk_120 + 83300*uk_121 + 157500*uk_122 + 40600*uk_123 + 354025*uk_124 + 669375*uk_125 + 172550*uk_126 + 1265625*uk_127 + 326250*uk_128 + 84100*uk_129 + 1420132*uk_13 + 195112*uk_130 + 94192*uk_131 + 400316*uk_132 + 756900*uk_133 + 195112*uk_134 + 45472*uk_135 + 193256*uk_136 + 365400*uk_137 + 94192*uk_138 + 821338*uk_139 + 6035561*uk_14 + 1552950*uk_140 + 400316*uk_141 + 2936250*uk_142 + 756900*uk_143 + 195112*uk_144 + 21952*uk_145 + 93296*uk_146 + 176400*uk_147 + 45472*uk_148 + 396508*uk_149 + 11411775*uk_15 + 749700*uk_150 + 193256*uk_151 + 1417500*uk_152 + 365400*uk_153 + 94192*uk_154 + 1685159*uk_155 + 3186225*uk_156 + 821338*uk_157 + 6024375*uk_158 + 1552950*uk_159 + 2941702*uk_16 + 400316*uk_160 + 11390625*uk_161 + 2936250*uk_162 + 756900*uk_163 + 195112*uk_164 + 3025*uk_17 + 1375*uk_18 + 3190*uk_19 + 55*uk_2 + 1540*uk_20 + 6545*uk_21 + 12375*uk_22 + 3190*uk_23 + 625*uk_24 + 1450*uk_25 + 700*uk_26 + 2975*uk_27 + 5625*uk_28 + 1450*uk_29 + 25*uk_3 + 3364*uk_30 + 1624*uk_31 + 6902*uk_32 + 13050*uk_33 + 3364*uk_34 + 784*uk_35 + 3332*uk_36 + 6300*uk_37 + 1624*uk_38 + 14161*uk_39 + 58*uk_4 + 26775*uk_40 + 6902*uk_41 + 50625*uk_42 + 13050*uk_43 + 3364*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 64310424025*uk_47 + 149200183738*uk_48 + 72027674908*uk_49 + 28*uk_5 + 306117618359*uk_50 + 578793816225*uk_51 + 149200183738*uk_52 + 153424975*uk_53 + 69738625*uk_54 + 161793610*uk_55 + 78107260*uk_56 + 331955855*uk_57 + 627647625*uk_58 + 161793610*uk_59 + 119*uk_6 + 31699375*uk_60 + 73542550*uk_61 + 35503300*uk_62 + 150889025*uk_63 + 285294375*uk_64 + 73542550*uk_65 + 170618716*uk_66 + 82367656*uk_67 + 350062538*uk_68 + 661882950*uk_69 + 225*uk_7 + 170618716*uk_70 + 39763696*uk_71 + 168995708*uk_72 + 319529700*uk_73 + 82367656*uk_74 + 718231759*uk_75 + 1358001225*uk_76 + 350062538*uk_77 + 2567649375*uk_78 + 661882950*uk_79 + 58*uk_8 + 170618716*uk_80 + 166375*uk_81 + 75625*uk_82 + 175450*uk_83 + 84700*uk_84 + 359975*uk_85 + 680625*uk_86 + 175450*uk_87 + 34375*uk_88 + 79750*uk_89 + 2572416961*uk_9 + 38500*uk_90 + 163625*uk_91 + 309375*uk_92 + 79750*uk_93 + 185020*uk_94 + 89320*uk_95 + 379610*uk_96 + 717750*uk_97 + 185020*uk_98 + 43120*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 186340*uk_100 + 346500*uk_101 + 38500*uk_102 + 805255*uk_103 + 1497375*uk_104 + 166375*uk_105 + 2784375*uk_106 + 309375*uk_107 + 34375*uk_108 + 8000*uk_109 + 1014380*uk_11 + 10000*uk_110 + 11200*uk_111 + 48400*uk_112 + 90000*uk_113 + 10000*uk_114 + 12500*uk_115 + 14000*uk_116 + 60500*uk_117 + 112500*uk_118 + 12500*uk_119 + 1267975*uk_12 + 15680*uk_120 + 67760*uk_121 + 126000*uk_122 + 14000*uk_123 + 292820*uk_124 + 544500*uk_125 + 60500*uk_126 + 1012500*uk_127 + 112500*uk_128 + 12500*uk_129 + 1420132*uk_13 + 15625*uk_130 + 17500*uk_131 + 75625*uk_132 + 140625*uk_133 + 15625*uk_134 + 19600*uk_135 + 84700*uk_136 + 157500*uk_137 + 17500*uk_138 + 366025*uk_139 + 6136999*uk_14 + 680625*uk_140 + 75625*uk_141 + 1265625*uk_142 + 140625*uk_143 + 15625*uk_144 + 21952*uk_145 + 94864*uk_146 + 176400*uk_147 + 19600*uk_148 + 409948*uk_149 + 11411775*uk_15 + 762300*uk_150 + 84700*uk_151 + 1417500*uk_152 + 157500*uk_153 + 17500*uk_154 + 1771561*uk_155 + 3294225*uk_156 + 366025*uk_157 + 6125625*uk_158 + 680625*uk_159 + 1267975*uk_16 + 75625*uk_160 + 11390625*uk_161 + 1265625*uk_162 + 140625*uk_163 + 15625*uk_164 + 3025*uk_17 + 1100*uk_18 + 1375*uk_19 + 55*uk_2 + 1540*uk_20 + 6655*uk_21 + 12375*uk_22 + 1375*uk_23 + 400*uk_24 + 500*uk_25 + 560*uk_26 + 2420*uk_27 + 4500*uk_28 + 500*uk_29 + 20*uk_3 + 625*uk_30 + 700*uk_31 + 3025*uk_32 + 5625*uk_33 + 625*uk_34 + 784*uk_35 + 3388*uk_36 + 6300*uk_37 + 700*uk_38 + 14641*uk_39 + 25*uk_4 + 27225*uk_40 + 3025*uk_41 + 50625*uk_42 + 5625*uk_43 + 625*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 51448339220*uk_47 + 64310424025*uk_48 + 72027674908*uk_49 + 28*uk_5 + 311262452281*uk_50 + 578793816225*uk_51 + 64310424025*uk_52 + 153424975*uk_53 + 55790900*uk_54 + 69738625*uk_55 + 78107260*uk_56 + 337534945*uk_57 + 627647625*uk_58 + 69738625*uk_59 + 121*uk_6 + 20287600*uk_60 + 25359500*uk_61 + 28402640*uk_62 + 122739980*uk_63 + 228235500*uk_64 + 25359500*uk_65 + 31699375*uk_66 + 35503300*uk_67 + 153424975*uk_68 + 285294375*uk_69 + 225*uk_7 + 31699375*uk_70 + 39763696*uk_71 + 171835972*uk_72 + 319529700*uk_73 + 35503300*uk_74 + 742576879*uk_75 + 1380824775*uk_76 + 153424975*uk_77 + 2567649375*uk_78 + 285294375*uk_79 + 25*uk_8 + 31699375*uk_80 + 166375*uk_81 + 60500*uk_82 + 75625*uk_83 + 84700*uk_84 + 366025*uk_85 + 680625*uk_86 + 75625*uk_87 + 22000*uk_88 + 27500*uk_89 + 2572416961*uk_9 + 30800*uk_90 + 133100*uk_91 + 247500*uk_92 + 27500*uk_93 + 34375*uk_94 + 38500*uk_95 + 166375*uk_96 + 309375*uk_97 + 34375*uk_98 + 43120*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 189420*uk_100 + 346500*uk_101 + 30800*uk_102 + 832095*uk_103 + 1522125*uk_104 + 135300*uk_105 + 2784375*uk_106 + 247500*uk_107 + 22000*uk_108 + 79507*uk_109 + 2180917*uk_11 + 36980*uk_110 + 51772*uk_111 + 227427*uk_112 + 416025*uk_113 + 36980*uk_114 + 17200*uk_115 + 24080*uk_116 + 105780*uk_117 + 193500*uk_118 + 17200*uk_119 + 1014380*uk_12 + 33712*uk_120 + 148092*uk_121 + 270900*uk_122 + 24080*uk_123 + 650547*uk_124 + 1190025*uk_125 + 105780*uk_126 + 2176875*uk_127 + 193500*uk_128 + 17200*uk_129 + 1420132*uk_13 + 8000*uk_130 + 11200*uk_131 + 49200*uk_132 + 90000*uk_133 + 8000*uk_134 + 15680*uk_135 + 68880*uk_136 + 126000*uk_137 + 11200*uk_138 + 302580*uk_139 + 6238437*uk_14 + 553500*uk_140 + 49200*uk_141 + 1012500*uk_142 + 90000*uk_143 + 8000*uk_144 + 21952*uk_145 + 96432*uk_146 + 176400*uk_147 + 15680*uk_148 + 423612*uk_149 + 11411775*uk_15 + 774900*uk_150 + 68880*uk_151 + 1417500*uk_152 + 126000*uk_153 + 11200*uk_154 + 1860867*uk_155 + 3404025*uk_156 + 302580*uk_157 + 6226875*uk_158 + 553500*uk_159 + 1014380*uk_16 + 49200*uk_160 + 11390625*uk_161 + 1012500*uk_162 + 90000*uk_163 + 8000*uk_164 + 3025*uk_17 + 2365*uk_18 + 1100*uk_19 + 55*uk_2 + 1540*uk_20 + 6765*uk_21 + 12375*uk_22 + 1100*uk_23 + 1849*uk_24 + 860*uk_25 + 1204*uk_26 + 5289*uk_27 + 9675*uk_28 + 860*uk_29 + 43*uk_3 + 400*uk_30 + 560*uk_31 + 2460*uk_32 + 4500*uk_33 + 400*uk_34 + 784*uk_35 + 3444*uk_36 + 6300*uk_37 + 560*uk_38 + 15129*uk_39 + 20*uk_4 + 27675*uk_40 + 2460*uk_41 + 50625*uk_42 + 4500*uk_43 + 400*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 110613929323*uk_47 + 51448339220*uk_48 + 72027674908*uk_49 + 28*uk_5 + 316407286203*uk_50 + 578793816225*uk_51 + 51448339220*uk_52 + 153424975*uk_53 + 119950435*uk_54 + 55790900*uk_55 + 78107260*uk_56 + 343114035*uk_57 + 627647625*uk_58 + 55790900*uk_59 + 123*uk_6 + 93779431*uk_60 + 43618340*uk_61 + 61065676*uk_62 + 268252791*uk_63 + 490706325*uk_64 + 43618340*uk_65 + 20287600*uk_66 + 28402640*uk_67 + 124768740*uk_68 + 228235500*uk_69 + 225*uk_7 + 20287600*uk_70 + 39763696*uk_71 + 174676236*uk_72 + 319529700*uk_73 + 28402640*uk_74 + 767327751*uk_75 + 1403648325*uk_76 + 124768740*uk_77 + 2567649375*uk_78 + 228235500*uk_79 + 20*uk_8 + 20287600*uk_80 + 166375*uk_81 + 130075*uk_82 + 60500*uk_83 + 84700*uk_84 + 372075*uk_85 + 680625*uk_86 + 60500*uk_87 + 101695*uk_88 + 47300*uk_89 + 2572416961*uk_9 + 66220*uk_90 + 290895*uk_91 + 532125*uk_92 + 47300*uk_93 + 22000*uk_94 + 30800*uk_95 + 135300*uk_96 + 247500*uk_97 + 22000*uk_98 + 43120*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 192500*uk_100 + 346500*uk_101 + 66220*uk_102 + 859375*uk_103 + 1546875*uk_104 + 295625*uk_105 + 2784375*uk_106 + 532125*uk_107 + 101695*uk_108 + 830584*uk_109 + 4767586*uk_11 + 379948*uk_110 + 247408*uk_111 + 1104500*uk_112 + 1988100*uk_113 + 379948*uk_114 + 173806*uk_115 + 113176*uk_116 + 505250*uk_117 + 909450*uk_118 + 173806*uk_119 + 2180917*uk_12 + 73696*uk_120 + 329000*uk_121 + 592200*uk_122 + 113176*uk_123 + 1468750*uk_124 + 2643750*uk_125 + 505250*uk_126 + 4758750*uk_127 + 909450*uk_128 + 173806*uk_129 + 1420132*uk_13 + 79507*uk_130 + 51772*uk_131 + 231125*uk_132 + 416025*uk_133 + 79507*uk_134 + 33712*uk_135 + 150500*uk_136 + 270900*uk_137 + 51772*uk_138 + 671875*uk_139 + 6339875*uk_14 + 1209375*uk_140 + 231125*uk_141 + 2176875*uk_142 + 416025*uk_143 + 79507*uk_144 + 21952*uk_145 + 98000*uk_146 + 176400*uk_147 + 33712*uk_148 + 437500*uk_149 + 11411775*uk_15 + 787500*uk_150 + 150500*uk_151 + 1417500*uk_152 + 270900*uk_153 + 51772*uk_154 + 1953125*uk_155 + 3515625*uk_156 + 671875*uk_157 + 6328125*uk_158 + 1209375*uk_159 + 2180917*uk_16 + 231125*uk_160 + 11390625*uk_161 + 2176875*uk_162 + 416025*uk_163 + 79507*uk_164 + 3025*uk_17 + 5170*uk_18 + 2365*uk_19 + 55*uk_2 + 1540*uk_20 + 6875*uk_21 + 12375*uk_22 + 2365*uk_23 + 8836*uk_24 + 4042*uk_25 + 2632*uk_26 + 11750*uk_27 + 21150*uk_28 + 4042*uk_29 + 94*uk_3 + 1849*uk_30 + 1204*uk_31 + 5375*uk_32 + 9675*uk_33 + 1849*uk_34 + 784*uk_35 + 3500*uk_36 + 6300*uk_37 + 1204*uk_38 + 15625*uk_39 + 43*uk_4 + 28125*uk_40 + 5375*uk_41 + 50625*uk_42 + 9675*uk_43 + 1849*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 241807194334*uk_47 + 110613929323*uk_48 + 72027674908*uk_49 + 28*uk_5 + 321552120125*uk_50 + 578793816225*uk_51 + 110613929323*uk_52 + 153424975*uk_53 + 262217230*uk_54 + 119950435*uk_55 + 78107260*uk_56 + 348693125*uk_57 + 627647625*uk_58 + 119950435*uk_59 + 125*uk_6 + 448153084*uk_60 + 205006198*uk_61 + 133492408*uk_62 + 595948250*uk_63 + 1072706850*uk_64 + 205006198*uk_65 + 93779431*uk_66 + 61065676*uk_67 + 272614625*uk_68 + 490706325*uk_69 + 225*uk_7 + 93779431*uk_70 + 39763696*uk_71 + 177516500*uk_72 + 319529700*uk_73 + 61065676*uk_74 + 792484375*uk_75 + 1426471875*uk_76 + 272614625*uk_77 + 2567649375*uk_78 + 490706325*uk_79 + 43*uk_8 + 93779431*uk_80 + 166375*uk_81 + 284350*uk_82 + 130075*uk_83 + 84700*uk_84 + 378125*uk_85 + 680625*uk_86 + 130075*uk_87 + 485980*uk_88 + 222310*uk_89 + 2572416961*uk_9 + 144760*uk_90 + 646250*uk_91 + 1163250*uk_92 + 222310*uk_93 + 101695*uk_94 + 66220*uk_95 + 295625*uk_96 + 532125*uk_97 + 101695*uk_98 + 43120*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 167640*uk_100 + 297000*uk_101 + 124080*uk_102 + 887095*uk_103 + 1571625*uk_104 + 656590*uk_105 + 2784375*uk_106 + 1163250*uk_107 + 485980*uk_108 + 97336*uk_109 + 2333074*uk_11 + 198904*uk_110 + 50784*uk_111 + 268732*uk_112 + 476100*uk_113 + 198904*uk_114 + 406456*uk_115 + 103776*uk_116 + 549148*uk_117 + 972900*uk_118 + 406456*uk_119 + 4767586*uk_12 + 26496*uk_120 + 140208*uk_121 + 248400*uk_122 + 103776*uk_123 + 741934*uk_124 + 1314450*uk_125 + 549148*uk_126 + 2328750*uk_127 + 972900*uk_128 + 406456*uk_129 + 1217256*uk_13 + 830584*uk_130 + 212064*uk_131 + 1122172*uk_132 + 1988100*uk_133 + 830584*uk_134 + 54144*uk_135 + 286512*uk_136 + 507600*uk_137 + 212064*uk_138 + 1516126*uk_139 + 6441313*uk_14 + 2686050*uk_140 + 1122172*uk_141 + 4758750*uk_142 + 1988100*uk_143 + 830584*uk_144 + 13824*uk_145 + 73152*uk_146 + 129600*uk_147 + 54144*uk_148 + 387096*uk_149 + 11411775*uk_15 + 685800*uk_150 + 286512*uk_151 + 1215000*uk_152 + 507600*uk_153 + 212064*uk_154 + 2048383*uk_155 + 3629025*uk_156 + 1516126*uk_157 + 6429375*uk_158 + 2686050*uk_159 + 4767586*uk_16 + 1122172*uk_160 + 11390625*uk_161 + 4758750*uk_162 + 1988100*uk_163 + 830584*uk_164 + 3025*uk_17 + 2530*uk_18 + 5170*uk_19 + 55*uk_2 + 1320*uk_20 + 6985*uk_21 + 12375*uk_22 + 5170*uk_23 + 2116*uk_24 + 4324*uk_25 + 1104*uk_26 + 5842*uk_27 + 10350*uk_28 + 4324*uk_29 + 46*uk_3 + 8836*uk_30 + 2256*uk_31 + 11938*uk_32 + 21150*uk_33 + 8836*uk_34 + 576*uk_35 + 3048*uk_36 + 5400*uk_37 + 2256*uk_38 + 16129*uk_39 + 94*uk_4 + 28575*uk_40 + 11938*uk_41 + 50625*uk_42 + 21150*uk_43 + 8836*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 118331180206*uk_47 + 241807194334*uk_48 + 61738007064*uk_49 + 24*uk_5 + 326696954047*uk_50 + 578793816225*uk_51 + 241807194334*uk_52 + 153424975*uk_53 + 128319070*uk_54 + 262217230*uk_55 + 66949080*uk_56 + 354272215*uk_57 + 627647625*uk_58 + 262217230*uk_59 + 127*uk_6 + 107321404*uk_60 + 219308956*uk_61 + 55993776*uk_62 + 296300398*uk_63 + 524941650*uk_64 + 219308956*uk_65 + 448153084*uk_66 + 114422064*uk_67 + 605483422*uk_68 + 1072706850*uk_69 + 225*uk_7 + 448153084*uk_70 + 29214144*uk_71 + 154591512*uk_72 + 273882600*uk_73 + 114422064*uk_74 + 818046751*uk_75 + 1449295425*uk_76 + 605483422*uk_77 + 2567649375*uk_78 + 1072706850*uk_79 + 94*uk_8 + 448153084*uk_80 + 166375*uk_81 + 139150*uk_82 + 284350*uk_83 + 72600*uk_84 + 384175*uk_85 + 680625*uk_86 + 284350*uk_87 + 116380*uk_88 + 237820*uk_89 + 2572416961*uk_9 + 60720*uk_90 + 321310*uk_91 + 569250*uk_92 + 237820*uk_93 + 485980*uk_94 + 124080*uk_95 + 656590*uk_96 + 1163250*uk_97 + 485980*uk_98 + 31680*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 170280*uk_100 + 297000*uk_101 + 60720*uk_102 + 915255*uk_103 + 1596375*uk_104 + 326370*uk_105 + 2784375*uk_106 + 569250*uk_107 + 116380*uk_108 + 10648*uk_109 + 1115818*uk_11 + 22264*uk_110 + 11616*uk_111 + 62436*uk_112 + 108900*uk_113 + 22264*uk_114 + 46552*uk_115 + 24288*uk_116 + 130548*uk_117 + 227700*uk_118 + 46552*uk_119 + 2333074*uk_12 + 12672*uk_120 + 68112*uk_121 + 118800*uk_122 + 24288*uk_123 + 366102*uk_124 + 638550*uk_125 + 130548*uk_126 + 1113750*uk_127 + 227700*uk_128 + 46552*uk_129 + 1217256*uk_13 + 97336*uk_130 + 50784*uk_131 + 272964*uk_132 + 476100*uk_133 + 97336*uk_134 + 26496*uk_135 + 142416*uk_136 + 248400*uk_137 + 50784*uk_138 + 765486*uk_139 + 6542751*uk_14 + 1335150*uk_140 + 272964*uk_141 + 2328750*uk_142 + 476100*uk_143 + 97336*uk_144 + 13824*uk_145 + 74304*uk_146 + 129600*uk_147 + 26496*uk_148 + 399384*uk_149 + 11411775*uk_15 + 696600*uk_150 + 142416*uk_151 + 1215000*uk_152 + 248400*uk_153 + 50784*uk_154 + 2146689*uk_155 + 3744225*uk_156 + 765486*uk_157 + 6530625*uk_158 + 1335150*uk_159 + 2333074*uk_16 + 272964*uk_160 + 11390625*uk_161 + 2328750*uk_162 + 476100*uk_163 + 97336*uk_164 + 3025*uk_17 + 1210*uk_18 + 2530*uk_19 + 55*uk_2 + 1320*uk_20 + 7095*uk_21 + 12375*uk_22 + 2530*uk_23 + 484*uk_24 + 1012*uk_25 + 528*uk_26 + 2838*uk_27 + 4950*uk_28 + 1012*uk_29 + 22*uk_3 + 2116*uk_30 + 1104*uk_31 + 5934*uk_32 + 10350*uk_33 + 2116*uk_34 + 576*uk_35 + 3096*uk_36 + 5400*uk_37 + 1104*uk_38 + 16641*uk_39 + 46*uk_4 + 29025*uk_40 + 5934*uk_41 + 50625*uk_42 + 10350*uk_43 + 2116*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 56593173142*uk_47 + 118331180206*uk_48 + 61738007064*uk_49 + 24*uk_5 + 331841787969*uk_50 + 578793816225*uk_51 + 118331180206*uk_52 + 153424975*uk_53 + 61369990*uk_54 + 128319070*uk_55 + 66949080*uk_56 + 359851305*uk_57 + 627647625*uk_58 + 128319070*uk_59 + 129*uk_6 + 24547996*uk_60 + 51327628*uk_61 + 26779632*uk_62 + 143940522*uk_63 + 251059050*uk_64 + 51327628*uk_65 + 107321404*uk_66 + 55993776*uk_67 + 300966546*uk_68 + 524941650*uk_69 + 225*uk_7 + 107321404*uk_70 + 29214144*uk_71 + 157026024*uk_72 + 273882600*uk_73 + 55993776*uk_74 + 844014879*uk_75 + 1472118975*uk_76 + 300966546*uk_77 + 2567649375*uk_78 + 524941650*uk_79 + 46*uk_8 + 107321404*uk_80 + 166375*uk_81 + 66550*uk_82 + 139150*uk_83 + 72600*uk_84 + 390225*uk_85 + 680625*uk_86 + 139150*uk_87 + 26620*uk_88 + 55660*uk_89 + 2572416961*uk_9 + 29040*uk_90 + 156090*uk_91 + 272250*uk_92 + 55660*uk_93 + 116380*uk_94 + 60720*uk_95 + 326370*uk_96 + 569250*uk_97 + 116380*uk_98 + 31680*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 172920*uk_100 + 297000*uk_101 + 29040*uk_102 + 943855*uk_103 + 1621125*uk_104 + 158510*uk_105 + 2784375*uk_106 + 272250*uk_107 + 26620*uk_108 + 10648*uk_109 + 1115818*uk_11 + 10648*uk_110 + 11616*uk_111 + 63404*uk_112 + 108900*uk_113 + 10648*uk_114 + 10648*uk_115 + 11616*uk_116 + 63404*uk_117 + 108900*uk_118 + 10648*uk_119 + 1115818*uk_12 + 12672*uk_120 + 69168*uk_121 + 118800*uk_122 + 11616*uk_123 + 377542*uk_124 + 648450*uk_125 + 63404*uk_126 + 1113750*uk_127 + 108900*uk_128 + 10648*uk_129 + 1217256*uk_13 + 10648*uk_130 + 11616*uk_131 + 63404*uk_132 + 108900*uk_133 + 10648*uk_134 + 12672*uk_135 + 69168*uk_136 + 118800*uk_137 + 11616*uk_138 + 377542*uk_139 + 6644189*uk_14 + 648450*uk_140 + 63404*uk_141 + 1113750*uk_142 + 108900*uk_143 + 10648*uk_144 + 13824*uk_145 + 75456*uk_146 + 129600*uk_147 + 12672*uk_148 + 411864*uk_149 + 11411775*uk_15 + 707400*uk_150 + 69168*uk_151 + 1215000*uk_152 + 118800*uk_153 + 11616*uk_154 + 2248091*uk_155 + 3861225*uk_156 + 377542*uk_157 + 6631875*uk_158 + 648450*uk_159 + 1115818*uk_16 + 63404*uk_160 + 11390625*uk_161 + 1113750*uk_162 + 108900*uk_163 + 10648*uk_164 + 3025*uk_17 + 1210*uk_18 + 1210*uk_19 + 55*uk_2 + 1320*uk_20 + 7205*uk_21 + 12375*uk_22 + 1210*uk_23 + 484*uk_24 + 484*uk_25 + 528*uk_26 + 2882*uk_27 + 4950*uk_28 + 484*uk_29 + 22*uk_3 + 484*uk_30 + 528*uk_31 + 2882*uk_32 + 4950*uk_33 + 484*uk_34 + 576*uk_35 + 3144*uk_36 + 5400*uk_37 + 528*uk_38 + 17161*uk_39 + 22*uk_4 + 29475*uk_40 + 2882*uk_41 + 50625*uk_42 + 4950*uk_43 + 484*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 56593173142*uk_47 + 56593173142*uk_48 + 61738007064*uk_49 + 24*uk_5 + 336986621891*uk_50 + 578793816225*uk_51 + 56593173142*uk_52 + 153424975*uk_53 + 61369990*uk_54 + 61369990*uk_55 + 66949080*uk_56 + 365430395*uk_57 + 627647625*uk_58 + 61369990*uk_59 + 131*uk_6 + 24547996*uk_60 + 24547996*uk_61 + 26779632*uk_62 + 146172158*uk_63 + 251059050*uk_64 + 24547996*uk_65 + 24547996*uk_66 + 26779632*uk_67 + 146172158*uk_68 + 251059050*uk_69 + 225*uk_7 + 24547996*uk_70 + 29214144*uk_71 + 159460536*uk_72 + 273882600*uk_73 + 26779632*uk_74 + 870388759*uk_75 + 1494942525*uk_76 + 146172158*uk_77 + 2567649375*uk_78 + 251059050*uk_79 + 22*uk_8 + 24547996*uk_80 + 166375*uk_81 + 66550*uk_82 + 66550*uk_83 + 72600*uk_84 + 396275*uk_85 + 680625*uk_86 + 66550*uk_87 + 26620*uk_88 + 26620*uk_89 + 2572416961*uk_9 + 29040*uk_90 + 158510*uk_91 + 272250*uk_92 + 26620*uk_93 + 26620*uk_94 + 29040*uk_95 + 158510*uk_96 + 272250*uk_97 + 26620*uk_98 + 31680*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 175560*uk_100 + 297000*uk_101 + 29040*uk_102 + 972895*uk_103 + 1645875*uk_104 + 160930*uk_105 + 2784375*uk_106 + 272250*uk_107 + 26620*uk_108 + 97336*uk_109 + 2333074*uk_11 + 46552*uk_110 + 50784*uk_111 + 281428*uk_112 + 476100*uk_113 + 46552*uk_114 + 22264*uk_115 + 24288*uk_116 + 134596*uk_117 + 227700*uk_118 + 22264*uk_119 + 1115818*uk_12 + 26496*uk_120 + 146832*uk_121 + 248400*uk_122 + 24288*uk_123 + 813694*uk_124 + 1376550*uk_125 + 134596*uk_126 + 2328750*uk_127 + 227700*uk_128 + 22264*uk_129 + 1217256*uk_13 + 10648*uk_130 + 11616*uk_131 + 64372*uk_132 + 108900*uk_133 + 10648*uk_134 + 12672*uk_135 + 70224*uk_136 + 118800*uk_137 + 11616*uk_138 + 389158*uk_139 + 6745627*uk_14 + 658350*uk_140 + 64372*uk_141 + 1113750*uk_142 + 108900*uk_143 + 10648*uk_144 + 13824*uk_145 + 76608*uk_146 + 129600*uk_147 + 12672*uk_148 + 424536*uk_149 + 11411775*uk_15 + 718200*uk_150 + 70224*uk_151 + 1215000*uk_152 + 118800*uk_153 + 11616*uk_154 + 2352637*uk_155 + 3980025*uk_156 + 389158*uk_157 + 6733125*uk_158 + 658350*uk_159 + 1115818*uk_16 + 64372*uk_160 + 11390625*uk_161 + 1113750*uk_162 + 108900*uk_163 + 10648*uk_164 + 3025*uk_17 + 2530*uk_18 + 1210*uk_19 + 55*uk_2 + 1320*uk_20 + 7315*uk_21 + 12375*uk_22 + 1210*uk_23 + 2116*uk_24 + 1012*uk_25 + 1104*uk_26 + 6118*uk_27 + 10350*uk_28 + 1012*uk_29 + 46*uk_3 + 484*uk_30 + 528*uk_31 + 2926*uk_32 + 4950*uk_33 + 484*uk_34 + 576*uk_35 + 3192*uk_36 + 5400*uk_37 + 528*uk_38 + 17689*uk_39 + 22*uk_4 + 29925*uk_40 + 2926*uk_41 + 50625*uk_42 + 4950*uk_43 + 484*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 118331180206*uk_47 + 56593173142*uk_48 + 61738007064*uk_49 + 24*uk_5 + 342131455813*uk_50 + 578793816225*uk_51 + 56593173142*uk_52 + 153424975*uk_53 + 128319070*uk_54 + 61369990*uk_55 + 66949080*uk_56 + 371009485*uk_57 + 627647625*uk_58 + 61369990*uk_59 + 133*uk_6 + 107321404*uk_60 + 51327628*uk_61 + 55993776*uk_62 + 310298842*uk_63 + 524941650*uk_64 + 51327628*uk_65 + 24547996*uk_66 + 26779632*uk_67 + 148403794*uk_68 + 251059050*uk_69 + 225*uk_7 + 24547996*uk_70 + 29214144*uk_71 + 161895048*uk_72 + 273882600*uk_73 + 26779632*uk_74 + 897168391*uk_75 + 1517766075*uk_76 + 148403794*uk_77 + 2567649375*uk_78 + 251059050*uk_79 + 22*uk_8 + 24547996*uk_80 + 166375*uk_81 + 139150*uk_82 + 66550*uk_83 + 72600*uk_84 + 402325*uk_85 + 680625*uk_86 + 66550*uk_87 + 116380*uk_88 + 55660*uk_89 + 2572416961*uk_9 + 60720*uk_90 + 336490*uk_91 + 569250*uk_92 + 55660*uk_93 + 26620*uk_94 + 29040*uk_95 + 160930*uk_96 + 272250*uk_97 + 26620*uk_98 + 31680*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 178200*uk_100 + 297000*uk_101 + 60720*uk_102 + 1002375*uk_103 + 1670625*uk_104 + 341550*uk_105 + 2784375*uk_106 + 569250*uk_107 + 116380*uk_108 + 830584*uk_109 + 4767586*uk_11 + 406456*uk_110 + 212064*uk_111 + 1192860*uk_112 + 1988100*uk_113 + 406456*uk_114 + 198904*uk_115 + 103776*uk_116 + 583740*uk_117 + 972900*uk_118 + 198904*uk_119 + 2333074*uk_12 + 54144*uk_120 + 304560*uk_121 + 507600*uk_122 + 103776*uk_123 + 1713150*uk_124 + 2855250*uk_125 + 583740*uk_126 + 4758750*uk_127 + 972900*uk_128 + 198904*uk_129 + 1217256*uk_13 + 97336*uk_130 + 50784*uk_131 + 285660*uk_132 + 476100*uk_133 + 97336*uk_134 + 26496*uk_135 + 149040*uk_136 + 248400*uk_137 + 50784*uk_138 + 838350*uk_139 + 6847065*uk_14 + 1397250*uk_140 + 285660*uk_141 + 2328750*uk_142 + 476100*uk_143 + 97336*uk_144 + 13824*uk_145 + 77760*uk_146 + 129600*uk_147 + 26496*uk_148 + 437400*uk_149 + 11411775*uk_15 + 729000*uk_150 + 149040*uk_151 + 1215000*uk_152 + 248400*uk_153 + 50784*uk_154 + 2460375*uk_155 + 4100625*uk_156 + 838350*uk_157 + 6834375*uk_158 + 1397250*uk_159 + 2333074*uk_16 + 285660*uk_160 + 11390625*uk_161 + 2328750*uk_162 + 476100*uk_163 + 97336*uk_164 + 3025*uk_17 + 5170*uk_18 + 2530*uk_19 + 55*uk_2 + 1320*uk_20 + 7425*uk_21 + 12375*uk_22 + 2530*uk_23 + 8836*uk_24 + 4324*uk_25 + 2256*uk_26 + 12690*uk_27 + 21150*uk_28 + 4324*uk_29 + 94*uk_3 + 2116*uk_30 + 1104*uk_31 + 6210*uk_32 + 10350*uk_33 + 2116*uk_34 + 576*uk_35 + 3240*uk_36 + 5400*uk_37 + 1104*uk_38 + 18225*uk_39 + 46*uk_4 + 30375*uk_40 + 6210*uk_41 + 50625*uk_42 + 10350*uk_43 + 2116*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 241807194334*uk_47 + 118331180206*uk_48 + 61738007064*uk_49 + 24*uk_5 + 347276289735*uk_50 + 578793816225*uk_51 + 118331180206*uk_52 + 153424975*uk_53 + 262217230*uk_54 + 128319070*uk_55 + 66949080*uk_56 + 376588575*uk_57 + 627647625*uk_58 + 128319070*uk_59 + 135*uk_6 + 448153084*uk_60 + 219308956*uk_61 + 114422064*uk_62 + 643624110*uk_63 + 1072706850*uk_64 + 219308956*uk_65 + 107321404*uk_66 + 55993776*uk_67 + 314964990*uk_68 + 524941650*uk_69 + 225*uk_7 + 107321404*uk_70 + 29214144*uk_71 + 164329560*uk_72 + 273882600*uk_73 + 55993776*uk_74 + 924353775*uk_75 + 1540589625*uk_76 + 314964990*uk_77 + 2567649375*uk_78 + 524941650*uk_79 + 46*uk_8 + 107321404*uk_80 + 166375*uk_81 + 284350*uk_82 + 139150*uk_83 + 72600*uk_84 + 408375*uk_85 + 680625*uk_86 + 139150*uk_87 + 485980*uk_88 + 237820*uk_89 + 2572416961*uk_9 + 124080*uk_90 + 697950*uk_91 + 1163250*uk_92 + 237820*uk_93 + 116380*uk_94 + 60720*uk_95 + 341550*uk_96 + 569250*uk_97 + 116380*uk_98 + 31680*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 150700*uk_100 + 247500*uk_101 + 103400*uk_102 + 1032295*uk_103 + 1695375*uk_104 + 708290*uk_105 + 2784375*uk_106 + 1163250*uk_107 + 485980*uk_108 + 24389*uk_109 + 1470851*uk_11 + 79054*uk_110 + 16820*uk_111 + 115217*uk_112 + 189225*uk_113 + 79054*uk_114 + 256244*uk_115 + 54520*uk_116 + 373462*uk_117 + 613350*uk_118 + 256244*uk_119 + 4767586*uk_12 + 11600*uk_120 + 79460*uk_121 + 130500*uk_122 + 54520*uk_123 + 544301*uk_124 + 893925*uk_125 + 373462*uk_126 + 1468125*uk_127 + 613350*uk_128 + 256244*uk_129 + 1014380*uk_13 + 830584*uk_130 + 176720*uk_131 + 1210532*uk_132 + 1988100*uk_133 + 830584*uk_134 + 37600*uk_135 + 257560*uk_136 + 423000*uk_137 + 176720*uk_138 + 1764286*uk_139 + 6948503*uk_14 + 2897550*uk_140 + 1210532*uk_141 + 4758750*uk_142 + 1988100*uk_143 + 830584*uk_144 + 8000*uk_145 + 54800*uk_146 + 90000*uk_147 + 37600*uk_148 + 375380*uk_149 + 11411775*uk_15 + 616500*uk_150 + 257560*uk_151 + 1012500*uk_152 + 423000*uk_153 + 176720*uk_154 + 2571353*uk_155 + 4223025*uk_156 + 1764286*uk_157 + 6935625*uk_158 + 2897550*uk_159 + 4767586*uk_16 + 1210532*uk_160 + 11390625*uk_161 + 4758750*uk_162 + 1988100*uk_163 + 830584*uk_164 + 3025*uk_17 + 1595*uk_18 + 5170*uk_19 + 55*uk_2 + 1100*uk_20 + 7535*uk_21 + 12375*uk_22 + 5170*uk_23 + 841*uk_24 + 2726*uk_25 + 580*uk_26 + 3973*uk_27 + 6525*uk_28 + 2726*uk_29 + 29*uk_3 + 8836*uk_30 + 1880*uk_31 + 12878*uk_32 + 21150*uk_33 + 8836*uk_34 + 400*uk_35 + 2740*uk_36 + 4500*uk_37 + 1880*uk_38 + 18769*uk_39 + 94*uk_4 + 30825*uk_40 + 12878*uk_41 + 50625*uk_42 + 21150*uk_43 + 8836*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 74600091869*uk_47 + 241807194334*uk_48 + 51448339220*uk_49 + 20*uk_5 + 352421123657*uk_50 + 578793816225*uk_51 + 241807194334*uk_52 + 153424975*uk_53 + 80896805*uk_54 + 262217230*uk_55 + 55790900*uk_56 + 382167665*uk_57 + 627647625*uk_58 + 262217230*uk_59 + 137*uk_6 + 42654679*uk_60 + 138259994*uk_61 + 29417020*uk_62 + 201506587*uk_63 + 330941475*uk_64 + 138259994*uk_65 + 448153084*uk_66 + 95351720*uk_67 + 653159282*uk_68 + 1072706850*uk_69 + 225*uk_7 + 448153084*uk_70 + 20287600*uk_71 + 138970060*uk_72 + 228235500*uk_73 + 95351720*uk_74 + 951944911*uk_75 + 1563413175*uk_76 + 653159282*uk_77 + 2567649375*uk_78 + 1072706850*uk_79 + 94*uk_8 + 448153084*uk_80 + 166375*uk_81 + 87725*uk_82 + 284350*uk_83 + 60500*uk_84 + 414425*uk_85 + 680625*uk_86 + 284350*uk_87 + 46255*uk_88 + 149930*uk_89 + 2572416961*uk_9 + 31900*uk_90 + 218515*uk_91 + 358875*uk_92 + 149930*uk_93 + 485980*uk_94 + 103400*uk_95 + 708290*uk_96 + 1163250*uk_97 + 485980*uk_98 + 22000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 183480*uk_100 + 297000*uk_101 + 38280*uk_102 + 1062655*uk_103 + 1720125*uk_104 + 221705*uk_105 + 2784375*uk_106 + 358875*uk_107 + 46255*uk_108 + 1860867*uk_109 + 6238437*uk_11 + 438741*uk_110 + 363096*uk_111 + 2102931*uk_112 + 3404025*uk_113 + 438741*uk_114 + 103443*uk_115 + 85608*uk_116 + 495813*uk_117 + 802575*uk_118 + 103443*uk_119 + 1470851*uk_12 + 70848*uk_120 + 410328*uk_121 + 664200*uk_122 + 85608*uk_123 + 2376483*uk_124 + 3846825*uk_125 + 495813*uk_126 + 6226875*uk_127 + 802575*uk_128 + 103443*uk_129 + 1217256*uk_13 + 24389*uk_130 + 20184*uk_131 + 116899*uk_132 + 189225*uk_133 + 24389*uk_134 + 16704*uk_135 + 96744*uk_136 + 156600*uk_137 + 20184*uk_138 + 560309*uk_139 + 7049941*uk_14 + 906975*uk_140 + 116899*uk_141 + 1468125*uk_142 + 189225*uk_143 + 24389*uk_144 + 13824*uk_145 + 80064*uk_146 + 129600*uk_147 + 16704*uk_148 + 463704*uk_149 + 11411775*uk_15 + 750600*uk_150 + 96744*uk_151 + 1215000*uk_152 + 156600*uk_153 + 20184*uk_154 + 2685619*uk_155 + 4347225*uk_156 + 560309*uk_157 + 7036875*uk_158 + 906975*uk_159 + 1470851*uk_16 + 116899*uk_160 + 11390625*uk_161 + 1468125*uk_162 + 189225*uk_163 + 24389*uk_164 + 3025*uk_17 + 6765*uk_18 + 1595*uk_19 + 55*uk_2 + 1320*uk_20 + 7645*uk_21 + 12375*uk_22 + 1595*uk_23 + 15129*uk_24 + 3567*uk_25 + 2952*uk_26 + 17097*uk_27 + 27675*uk_28 + 3567*uk_29 + 123*uk_3 + 841*uk_30 + 696*uk_31 + 4031*uk_32 + 6525*uk_33 + 841*uk_34 + 576*uk_35 + 3336*uk_36 + 5400*uk_37 + 696*uk_38 + 19321*uk_39 + 29*uk_4 + 31275*uk_40 + 4031*uk_41 + 50625*uk_42 + 6525*uk_43 + 841*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 316407286203*uk_47 + 74600091869*uk_48 + 61738007064*uk_49 + 24*uk_5 + 357565957579*uk_50 + 578793816225*uk_51 + 74600091869*uk_52 + 153424975*uk_53 + 343114035*uk_54 + 80896805*uk_55 + 66949080*uk_56 + 387746755*uk_57 + 627647625*uk_58 + 80896805*uk_59 + 139*uk_6 + 767327751*uk_60 + 180914673*uk_61 + 149722488*uk_62 + 867142743*uk_63 + 1403648325*uk_64 + 180914673*uk_65 + 42654679*uk_66 + 35300424*uk_67 + 204448289*uk_68 + 330941475*uk_69 + 225*uk_7 + 42654679*uk_70 + 29214144*uk_71 + 169198584*uk_72 + 273882600*uk_73 + 35300424*uk_74 + 979941799*uk_75 + 1586236725*uk_76 + 204448289*uk_77 + 2567649375*uk_78 + 330941475*uk_79 + 29*uk_8 + 42654679*uk_80 + 166375*uk_81 + 372075*uk_82 + 87725*uk_83 + 72600*uk_84 + 420475*uk_85 + 680625*uk_86 + 87725*uk_87 + 832095*uk_88 + 196185*uk_89 + 2572416961*uk_9 + 162360*uk_90 + 940335*uk_91 + 1522125*uk_92 + 196185*uk_93 + 46255*uk_94 + 38280*uk_95 + 221705*uk_96 + 358875*uk_97 + 46255*uk_98 + 31680*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 155100*uk_100 + 247500*uk_101 + 135300*uk_102 + 1093455*uk_103 + 1744875*uk_104 + 953865*uk_105 + 2784375*uk_106 + 1522125*uk_107 + 832095*uk_108 + 1000000*uk_109 + 5071900*uk_11 + 1230000*uk_110 + 200000*uk_111 + 1410000*uk_112 + 2250000*uk_113 + 1230000*uk_114 + 1512900*uk_115 + 246000*uk_116 + 1734300*uk_117 + 2767500*uk_118 + 1512900*uk_119 + 6238437*uk_12 + 40000*uk_120 + 282000*uk_121 + 450000*uk_122 + 246000*uk_123 + 1988100*uk_124 + 3172500*uk_125 + 1734300*uk_126 + 5062500*uk_127 + 2767500*uk_128 + 1512900*uk_129 + 1014380*uk_13 + 1860867*uk_130 + 302580*uk_131 + 2133189*uk_132 + 3404025*uk_133 + 1860867*uk_134 + 49200*uk_135 + 346860*uk_136 + 553500*uk_137 + 302580*uk_138 + 2445363*uk_139 + 7151379*uk_14 + 3902175*uk_140 + 2133189*uk_141 + 6226875*uk_142 + 3404025*uk_143 + 1860867*uk_144 + 8000*uk_145 + 56400*uk_146 + 90000*uk_147 + 49200*uk_148 + 397620*uk_149 + 11411775*uk_15 + 634500*uk_150 + 346860*uk_151 + 1012500*uk_152 + 553500*uk_153 + 302580*uk_154 + 2803221*uk_155 + 4473225*uk_156 + 2445363*uk_157 + 7138125*uk_158 + 3902175*uk_159 + 6238437*uk_16 + 2133189*uk_160 + 11390625*uk_161 + 6226875*uk_162 + 3404025*uk_163 + 1860867*uk_164 + 3025*uk_17 + 5500*uk_18 + 6765*uk_19 + 55*uk_2 + 1100*uk_20 + 7755*uk_21 + 12375*uk_22 + 6765*uk_23 + 10000*uk_24 + 12300*uk_25 + 2000*uk_26 + 14100*uk_27 + 22500*uk_28 + 12300*uk_29 + 100*uk_3 + 15129*uk_30 + 2460*uk_31 + 17343*uk_32 + 27675*uk_33 + 15129*uk_34 + 400*uk_35 + 2820*uk_36 + 4500*uk_37 + 2460*uk_38 + 19881*uk_39 + 123*uk_4 + 31725*uk_40 + 17343*uk_41 + 50625*uk_42 + 27675*uk_43 + 15129*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 257241696100*uk_47 + 316407286203*uk_48 + 51448339220*uk_49 + 20*uk_5 + 362710791501*uk_50 + 578793816225*uk_51 + 316407286203*uk_52 + 153424975*uk_53 + 278954500*uk_54 + 343114035*uk_55 + 55790900*uk_56 + 393325845*uk_57 + 627647625*uk_58 + 343114035*uk_59 + 141*uk_6 + 507190000*uk_60 + 623843700*uk_61 + 101438000*uk_62 + 715137900*uk_63 + 1141177500*uk_64 + 623843700*uk_65 + 767327751*uk_66 + 124768740*uk_67 + 879619617*uk_68 + 1403648325*uk_69 + 225*uk_7 + 767327751*uk_70 + 20287600*uk_71 + 143027580*uk_72 + 228235500*uk_73 + 124768740*uk_74 + 1008344439*uk_75 + 1609060275*uk_76 + 879619617*uk_77 + 2567649375*uk_78 + 1403648325*uk_79 + 123*uk_8 + 767327751*uk_80 + 166375*uk_81 + 302500*uk_82 + 372075*uk_83 + 60500*uk_84 + 426525*uk_85 + 680625*uk_86 + 372075*uk_87 + 550000*uk_88 + 676500*uk_89 + 2572416961*uk_9 + 110000*uk_90 + 775500*uk_91 + 1237500*uk_92 + 676500*uk_93 + 832095*uk_94 + 135300*uk_95 + 953865*uk_96 + 1522125*uk_97 + 832095*uk_98 + 22000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 157300*uk_100 + 247500*uk_101 + 110000*uk_102 + 1124695*uk_103 + 1769625*uk_104 + 786500*uk_105 + 2784375*uk_106 + 1237500*uk_107 + 550000*uk_108 + 912673*uk_109 + 4919743*uk_11 + 940900*uk_110 + 188180*uk_111 + 1345487*uk_112 + 2117025*uk_113 + 940900*uk_114 + 970000*uk_115 + 194000*uk_116 + 1387100*uk_117 + 2182500*uk_118 + 970000*uk_119 + 5071900*uk_12 + 38800*uk_120 + 277420*uk_121 + 436500*uk_122 + 194000*uk_123 + 1983553*uk_124 + 3120975*uk_125 + 1387100*uk_126 + 4910625*uk_127 + 2182500*uk_128 + 970000*uk_129 + 1014380*uk_13 + 1000000*uk_130 + 200000*uk_131 + 1430000*uk_132 + 2250000*uk_133 + 1000000*uk_134 + 40000*uk_135 + 286000*uk_136 + 450000*uk_137 + 200000*uk_138 + 2044900*uk_139 + 7252817*uk_14 + 3217500*uk_140 + 1430000*uk_141 + 5062500*uk_142 + 2250000*uk_143 + 1000000*uk_144 + 8000*uk_145 + 57200*uk_146 + 90000*uk_147 + 40000*uk_148 + 408980*uk_149 + 11411775*uk_15 + 643500*uk_150 + 286000*uk_151 + 1012500*uk_152 + 450000*uk_153 + 200000*uk_154 + 2924207*uk_155 + 4601025*uk_156 + 2044900*uk_157 + 7239375*uk_158 + 3217500*uk_159 + 5071900*uk_16 + 1430000*uk_160 + 11390625*uk_161 + 5062500*uk_162 + 2250000*uk_163 + 1000000*uk_164 + 3025*uk_17 + 5335*uk_18 + 5500*uk_19 + 55*uk_2 + 1100*uk_20 + 7865*uk_21 + 12375*uk_22 + 5500*uk_23 + 9409*uk_24 + 9700*uk_25 + 1940*uk_26 + 13871*uk_27 + 21825*uk_28 + 9700*uk_29 + 97*uk_3 + 10000*uk_30 + 2000*uk_31 + 14300*uk_32 + 22500*uk_33 + 10000*uk_34 + 400*uk_35 + 2860*uk_36 + 4500*uk_37 + 2000*uk_38 + 20449*uk_39 + 100*uk_4 + 32175*uk_40 + 14300*uk_41 + 50625*uk_42 + 22500*uk_43 + 10000*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 249524445217*uk_47 + 257241696100*uk_48 + 51448339220*uk_49 + 20*uk_5 + 367855625423*uk_50 + 578793816225*uk_51 + 257241696100*uk_52 + 153424975*uk_53 + 270585865*uk_54 + 278954500*uk_55 + 55790900*uk_56 + 398904935*uk_57 + 627647625*uk_58 + 278954500*uk_59 + 143*uk_6 + 477215071*uk_60 + 491974300*uk_61 + 98394860*uk_62 + 703523249*uk_63 + 1106942175*uk_64 + 491974300*uk_65 + 507190000*uk_66 + 101438000*uk_67 + 725281700*uk_68 + 1141177500*uk_69 + 225*uk_7 + 507190000*uk_70 + 20287600*uk_71 + 145056340*uk_72 + 228235500*uk_73 + 101438000*uk_74 + 1037152831*uk_75 + 1631883825*uk_76 + 725281700*uk_77 + 2567649375*uk_78 + 1141177500*uk_79 + 100*uk_8 + 507190000*uk_80 + 166375*uk_81 + 293425*uk_82 + 302500*uk_83 + 60500*uk_84 + 432575*uk_85 + 680625*uk_86 + 302500*uk_87 + 517495*uk_88 + 533500*uk_89 + 2572416961*uk_9 + 106700*uk_90 + 762905*uk_91 + 1200375*uk_92 + 533500*uk_93 + 550000*uk_94 + 110000*uk_95 + 786500*uk_96 + 1237500*uk_97 + 550000*uk_98 + 22000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 159500*uk_100 + 247500*uk_101 + 106700*uk_102 + 1156375*uk_103 + 1794375*uk_104 + 773575*uk_105 + 2784375*uk_106 + 1200375*uk_107 + 517495*uk_108 + 1481544*uk_109 + 5781966*uk_11 + 1260612*uk_110 + 259920*uk_111 + 1884420*uk_112 + 2924100*uk_113 + 1260612*uk_114 + 1072626*uk_115 + 221160*uk_116 + 1603410*uk_117 + 2488050*uk_118 + 1072626*uk_119 + 4919743*uk_12 + 45600*uk_120 + 330600*uk_121 + 513000*uk_122 + 221160*uk_123 + 2396850*uk_124 + 3719250*uk_125 + 1603410*uk_126 + 5771250*uk_127 + 2488050*uk_128 + 1072626*uk_129 + 1014380*uk_13 + 912673*uk_130 + 188180*uk_131 + 1364305*uk_132 + 2117025*uk_133 + 912673*uk_134 + 38800*uk_135 + 281300*uk_136 + 436500*uk_137 + 188180*uk_138 + 2039425*uk_139 + 7354255*uk_14 + 3164625*uk_140 + 1364305*uk_141 + 4910625*uk_142 + 2117025*uk_143 + 912673*uk_144 + 8000*uk_145 + 58000*uk_146 + 90000*uk_147 + 38800*uk_148 + 420500*uk_149 + 11411775*uk_15 + 652500*uk_150 + 281300*uk_151 + 1012500*uk_152 + 436500*uk_153 + 188180*uk_154 + 3048625*uk_155 + 4730625*uk_156 + 2039425*uk_157 + 7340625*uk_158 + 3164625*uk_159 + 4919743*uk_16 + 1364305*uk_160 + 11390625*uk_161 + 4910625*uk_162 + 2117025*uk_163 + 912673*uk_164 + 3025*uk_17 + 6270*uk_18 + 5335*uk_19 + 55*uk_2 + 1100*uk_20 + 7975*uk_21 + 12375*uk_22 + 5335*uk_23 + 12996*uk_24 + 11058*uk_25 + 2280*uk_26 + 16530*uk_27 + 25650*uk_28 + 11058*uk_29 + 114*uk_3 + 9409*uk_30 + 1940*uk_31 + 14065*uk_32 + 21825*uk_33 + 9409*uk_34 + 400*uk_35 + 2900*uk_36 + 4500*uk_37 + 1940*uk_38 + 21025*uk_39 + 97*uk_4 + 32625*uk_40 + 14065*uk_41 + 50625*uk_42 + 21825*uk_43 + 9409*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 293255533554*uk_47 + 249524445217*uk_48 + 51448339220*uk_49 + 20*uk_5 + 373000459345*uk_50 + 578793816225*uk_51 + 249524445217*uk_52 + 153424975*uk_53 + 318008130*uk_54 + 270585865*uk_55 + 55790900*uk_56 + 404484025*uk_57 + 627647625*uk_58 + 270585865*uk_59 + 145*uk_6 + 659144124*uk_60 + 560850702*uk_61 + 115639320*uk_62 + 838385070*uk_63 + 1300942350*uk_64 + 560850702*uk_65 + 477215071*uk_66 + 98394860*uk_67 + 713362735*uk_68 + 1106942175*uk_69 + 225*uk_7 + 477215071*uk_70 + 20287600*uk_71 + 147085100*uk_72 + 228235500*uk_73 + 98394860*uk_74 + 1066366975*uk_75 + 1654707375*uk_76 + 713362735*uk_77 + 2567649375*uk_78 + 1106942175*uk_79 + 97*uk_8 + 477215071*uk_80 + 166375*uk_81 + 344850*uk_82 + 293425*uk_83 + 60500*uk_84 + 438625*uk_85 + 680625*uk_86 + 293425*uk_87 + 714780*uk_88 + 608190*uk_89 + 2572416961*uk_9 + 125400*uk_90 + 909150*uk_91 + 1410750*uk_92 + 608190*uk_93 + 517495*uk_94 + 106700*uk_95 + 773575*uk_96 + 1200375*uk_97 + 517495*uk_98 + 22000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 129360*uk_100 + 198000*uk_101 + 100320*uk_102 + 1188495*uk_103 + 1819125*uk_104 + 921690*uk_105 + 2784375*uk_106 + 1410750*uk_107 + 714780*uk_108 + 64*uk_109 + 202876*uk_11 + 1824*uk_110 + 256*uk_111 + 2352*uk_112 + 3600*uk_113 + 1824*uk_114 + 51984*uk_115 + 7296*uk_116 + 67032*uk_117 + 102600*uk_118 + 51984*uk_119 + 5781966*uk_12 + 1024*uk_120 + 9408*uk_121 + 14400*uk_122 + 7296*uk_123 + 86436*uk_124 + 132300*uk_125 + 67032*uk_126 + 202500*uk_127 + 102600*uk_128 + 51984*uk_129 + 811504*uk_13 + 1481544*uk_130 + 207936*uk_131 + 1910412*uk_132 + 2924100*uk_133 + 1481544*uk_134 + 29184*uk_135 + 268128*uk_136 + 410400*uk_137 + 207936*uk_138 + 2463426*uk_139 + 7455693*uk_14 + 3770550*uk_140 + 1910412*uk_141 + 5771250*uk_142 + 2924100*uk_143 + 1481544*uk_144 + 4096*uk_145 + 37632*uk_146 + 57600*uk_147 + 29184*uk_148 + 345744*uk_149 + 11411775*uk_15 + 529200*uk_150 + 268128*uk_151 + 810000*uk_152 + 410400*uk_153 + 207936*uk_154 + 3176523*uk_155 + 4862025*uk_156 + 2463426*uk_157 + 7441875*uk_158 + 3770550*uk_159 + 5781966*uk_16 + 1910412*uk_160 + 11390625*uk_161 + 5771250*uk_162 + 2924100*uk_163 + 1481544*uk_164 + 3025*uk_17 + 220*uk_18 + 6270*uk_19 + 55*uk_2 + 880*uk_20 + 8085*uk_21 + 12375*uk_22 + 6270*uk_23 + 16*uk_24 + 456*uk_25 + 64*uk_26 + 588*uk_27 + 900*uk_28 + 456*uk_29 + 4*uk_3 + 12996*uk_30 + 1824*uk_31 + 16758*uk_32 + 25650*uk_33 + 12996*uk_34 + 256*uk_35 + 2352*uk_36 + 3600*uk_37 + 1824*uk_38 + 21609*uk_39 + 114*uk_4 + 33075*uk_40 + 16758*uk_41 + 50625*uk_42 + 25650*uk_43 + 12996*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 10289667844*uk_47 + 293255533554*uk_48 + 41158671376*uk_49 + 16*uk_5 + 378145293267*uk_50 + 578793816225*uk_51 + 293255533554*uk_52 + 153424975*uk_53 + 11158180*uk_54 + 318008130*uk_55 + 44632720*uk_56 + 410063115*uk_57 + 627647625*uk_58 + 318008130*uk_59 + 147*uk_6 + 811504*uk_60 + 23127864*uk_61 + 3246016*uk_62 + 29822772*uk_63 + 45647100*uk_64 + 23127864*uk_65 + 659144124*uk_66 + 92511456*uk_67 + 849949002*uk_68 + 1300942350*uk_69 + 225*uk_7 + 659144124*uk_70 + 12984064*uk_71 + 119291088*uk_72 + 182588400*uk_73 + 92511456*uk_74 + 1095986871*uk_75 + 1677530925*uk_76 + 849949002*uk_77 + 2567649375*uk_78 + 1300942350*uk_79 + 114*uk_8 + 659144124*uk_80 + 166375*uk_81 + 12100*uk_82 + 344850*uk_83 + 48400*uk_84 + 444675*uk_85 + 680625*uk_86 + 344850*uk_87 + 880*uk_88 + 25080*uk_89 + 2572416961*uk_9 + 3520*uk_90 + 32340*uk_91 + 49500*uk_92 + 25080*uk_93 + 714780*uk_94 + 100320*uk_95 + 921690*uk_96 + 1410750*uk_97 + 714780*uk_98 + 14080*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 163900*uk_100 + 247500*uk_101 + 4400*uk_102 + 1221055*uk_103 + 1843875*uk_104 + 32780*uk_105 + 2784375*uk_106 + 49500*uk_107 + 880*uk_108 + 205379*uk_109 + 2992421*uk_11 + 13924*uk_110 + 69620*uk_111 + 518669*uk_112 + 783225*uk_113 + 13924*uk_114 + 944*uk_115 + 4720*uk_116 + 35164*uk_117 + 53100*uk_118 + 944*uk_119 + 202876*uk_12 + 23600*uk_120 + 175820*uk_121 + 265500*uk_122 + 4720*uk_123 + 1309859*uk_124 + 1977975*uk_125 + 35164*uk_126 + 2986875*uk_127 + 53100*uk_128 + 944*uk_129 + 1014380*uk_13 + 64*uk_130 + 320*uk_131 + 2384*uk_132 + 3600*uk_133 + 64*uk_134 + 1600*uk_135 + 11920*uk_136 + 18000*uk_137 + 320*uk_138 + 88804*uk_139 + 7557131*uk_14 + 134100*uk_140 + 2384*uk_141 + 202500*uk_142 + 3600*uk_143 + 64*uk_144 + 8000*uk_145 + 59600*uk_146 + 90000*uk_147 + 1600*uk_148 + 444020*uk_149 + 11411775*uk_15 + 670500*uk_150 + 11920*uk_151 + 1012500*uk_152 + 18000*uk_153 + 320*uk_154 + 3307949*uk_155 + 4995225*uk_156 + 88804*uk_157 + 7543125*uk_158 + 134100*uk_159 + 202876*uk_16 + 2384*uk_160 + 11390625*uk_161 + 202500*uk_162 + 3600*uk_163 + 64*uk_164 + 3025*uk_17 + 3245*uk_18 + 220*uk_19 + 55*uk_2 + 1100*uk_20 + 8195*uk_21 + 12375*uk_22 + 220*uk_23 + 3481*uk_24 + 236*uk_25 + 1180*uk_26 + 8791*uk_27 + 13275*uk_28 + 236*uk_29 + 59*uk_3 + 16*uk_30 + 80*uk_31 + 596*uk_32 + 900*uk_33 + 16*uk_34 + 400*uk_35 + 2980*uk_36 + 4500*uk_37 + 80*uk_38 + 22201*uk_39 + 4*uk_4 + 33525*uk_40 + 596*uk_41 + 50625*uk_42 + 900*uk_43 + 16*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 151772600699*uk_47 + 10289667844*uk_48 + 51448339220*uk_49 + 20*uk_5 + 383290127189*uk_50 + 578793816225*uk_51 + 10289667844*uk_52 + 153424975*uk_53 + 164583155*uk_54 + 11158180*uk_55 + 55790900*uk_56 + 415642205*uk_57 + 627647625*uk_58 + 11158180*uk_59 + 149*uk_6 + 176552839*uk_60 + 11969684*uk_61 + 59848420*uk_62 + 445870729*uk_63 + 673294725*uk_64 + 11969684*uk_65 + 811504*uk_66 + 4057520*uk_67 + 30228524*uk_68 + 45647100*uk_69 + 225*uk_7 + 811504*uk_70 + 20287600*uk_71 + 151142620*uk_72 + 228235500*uk_73 + 4057520*uk_74 + 1126012519*uk_75 + 1700354475*uk_76 + 30228524*uk_77 + 2567649375*uk_78 + 45647100*uk_79 + 4*uk_8 + 811504*uk_80 + 166375*uk_81 + 178475*uk_82 + 12100*uk_83 + 60500*uk_84 + 450725*uk_85 + 680625*uk_86 + 12100*uk_87 + 191455*uk_88 + 12980*uk_89 + 2572416961*uk_9 + 64900*uk_90 + 483505*uk_91 + 730125*uk_92 + 12980*uk_93 + 880*uk_94 + 4400*uk_95 + 32780*uk_96 + 49500*uk_97 + 880*uk_98 + 22000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 166100*uk_100 + 247500*uk_101 + 64900*uk_102 + 1254055*uk_103 + 1868625*uk_104 + 489995*uk_105 + 2784375*uk_106 + 730125*uk_107 + 191455*uk_108 + 2406104*uk_109 + 6796346*uk_11 + 1059404*uk_110 + 359120*uk_111 + 2711356*uk_112 + 4040100*uk_113 + 1059404*uk_114 + 466454*uk_115 + 158120*uk_116 + 1193806*uk_117 + 1778850*uk_118 + 466454*uk_119 + 2992421*uk_12 + 53600*uk_120 + 404680*uk_121 + 603000*uk_122 + 158120*uk_123 + 3055334*uk_124 + 4552650*uk_125 + 1193806*uk_126 + 6783750*uk_127 + 1778850*uk_128 + 466454*uk_129 + 1014380*uk_13 + 205379*uk_130 + 69620*uk_131 + 525631*uk_132 + 783225*uk_133 + 205379*uk_134 + 23600*uk_135 + 178180*uk_136 + 265500*uk_137 + 69620*uk_138 + 1345259*uk_139 + 7658569*uk_14 + 2004525*uk_140 + 525631*uk_141 + 2986875*uk_142 + 783225*uk_143 + 205379*uk_144 + 8000*uk_145 + 60400*uk_146 + 90000*uk_147 + 23600*uk_148 + 456020*uk_149 + 11411775*uk_15 + 679500*uk_150 + 178180*uk_151 + 1012500*uk_152 + 265500*uk_153 + 69620*uk_154 + 3442951*uk_155 + 5130225*uk_156 + 1345259*uk_157 + 7644375*uk_158 + 2004525*uk_159 + 2992421*uk_16 + 525631*uk_160 + 11390625*uk_161 + 2986875*uk_162 + 783225*uk_163 + 205379*uk_164 + 3025*uk_17 + 7370*uk_18 + 3245*uk_19 + 55*uk_2 + 1100*uk_20 + 8305*uk_21 + 12375*uk_22 + 3245*uk_23 + 17956*uk_24 + 7906*uk_25 + 2680*uk_26 + 20234*uk_27 + 30150*uk_28 + 7906*uk_29 + 134*uk_3 + 3481*uk_30 + 1180*uk_31 + 8909*uk_32 + 13275*uk_33 + 3481*uk_34 + 400*uk_35 + 3020*uk_36 + 4500*uk_37 + 1180*uk_38 + 22801*uk_39 + 59*uk_4 + 33975*uk_40 + 8909*uk_41 + 50625*uk_42 + 13275*uk_43 + 3481*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 344703872774*uk_47 + 151772600699*uk_48 + 51448339220*uk_49 + 20*uk_5 + 388434961111*uk_50 + 578793816225*uk_51 + 151772600699*uk_52 + 153424975*uk_53 + 373799030*uk_54 + 164583155*uk_55 + 55790900*uk_56 + 421221295*uk_57 + 627647625*uk_58 + 164583155*uk_59 + 151*uk_6 + 910710364*uk_60 + 400984414*uk_61 + 135926920*uk_62 + 1026248246*uk_63 + 1529177850*uk_64 + 400984414*uk_65 + 176552839*uk_66 + 59848420*uk_67 + 451855571*uk_68 + 673294725*uk_69 + 225*uk_7 + 176552839*uk_70 + 20287600*uk_71 + 153171380*uk_72 + 228235500*uk_73 + 59848420*uk_74 + 1156443919*uk_75 + 1723178025*uk_76 + 451855571*uk_77 + 2567649375*uk_78 + 673294725*uk_79 + 59*uk_8 + 176552839*uk_80 + 166375*uk_81 + 405350*uk_82 + 178475*uk_83 + 60500*uk_84 + 456775*uk_85 + 680625*uk_86 + 178475*uk_87 + 987580*uk_88 + 434830*uk_89 + 2572416961*uk_9 + 147400*uk_90 + 1112870*uk_91 + 1658250*uk_92 + 434830*uk_93 + 191455*uk_94 + 64900*uk_95 + 489995*uk_96 + 730125*uk_97 + 191455*uk_98 + 22000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 134640*uk_100 + 198000*uk_101 + 117920*uk_102 + 1287495*uk_103 + 1893375*uk_104 + 1127610*uk_105 + 2784375*uk_106 + 1658250*uk_107 + 987580*uk_108 + 438976*uk_109 + 3854644*uk_11 + 773984*uk_110 + 92416*uk_111 + 883728*uk_112 + 1299600*uk_113 + 773984*uk_114 + 1364656*uk_115 + 162944*uk_116 + 1558152*uk_117 + 2291400*uk_118 + 1364656*uk_119 + 6796346*uk_12 + 19456*uk_120 + 186048*uk_121 + 273600*uk_122 + 162944*uk_123 + 1779084*uk_124 + 2616300*uk_125 + 1558152*uk_126 + 3847500*uk_127 + 2291400*uk_128 + 1364656*uk_129 + 811504*uk_13 + 2406104*uk_130 + 287296*uk_131 + 2747268*uk_132 + 4040100*uk_133 + 2406104*uk_134 + 34304*uk_135 + 328032*uk_136 + 482400*uk_137 + 287296*uk_138 + 3136806*uk_139 + 7760007*uk_14 + 4612950*uk_140 + 2747268*uk_141 + 6783750*uk_142 + 4040100*uk_143 + 2406104*uk_144 + 4096*uk_145 + 39168*uk_146 + 57600*uk_147 + 34304*uk_148 + 374544*uk_149 + 11411775*uk_15 + 550800*uk_150 + 328032*uk_151 + 810000*uk_152 + 482400*uk_153 + 287296*uk_154 + 3581577*uk_155 + 5267025*uk_156 + 3136806*uk_157 + 7745625*uk_158 + 4612950*uk_159 + 6796346*uk_16 + 2747268*uk_160 + 11390625*uk_161 + 6783750*uk_162 + 4040100*uk_163 + 2406104*uk_164 + 3025*uk_17 + 4180*uk_18 + 7370*uk_19 + 55*uk_2 + 880*uk_20 + 8415*uk_21 + 12375*uk_22 + 7370*uk_23 + 5776*uk_24 + 10184*uk_25 + 1216*uk_26 + 11628*uk_27 + 17100*uk_28 + 10184*uk_29 + 76*uk_3 + 17956*uk_30 + 2144*uk_31 + 20502*uk_32 + 30150*uk_33 + 17956*uk_34 + 256*uk_35 + 2448*uk_36 + 3600*uk_37 + 2144*uk_38 + 23409*uk_39 + 134*uk_4 + 34425*uk_40 + 20502*uk_41 + 50625*uk_42 + 30150*uk_43 + 17956*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 195503689036*uk_47 + 344703872774*uk_48 + 41158671376*uk_49 + 16*uk_5 + 393579795033*uk_50 + 578793816225*uk_51 + 344703872774*uk_52 + 153424975*uk_53 + 212005420*uk_54 + 373799030*uk_55 + 44632720*uk_56 + 426800385*uk_57 + 627647625*uk_58 + 373799030*uk_59 + 153*uk_6 + 292952944*uk_60 + 516522296*uk_61 + 61674304*uk_62 + 589760532*uk_63 + 867294900*uk_64 + 516522296*uk_65 + 910710364*uk_66 + 108741536*uk_67 + 1039840938*uk_68 + 1529177850*uk_69 + 225*uk_7 + 910710364*uk_70 + 12984064*uk_71 + 124160112*uk_72 + 182588400*uk_73 + 108741536*uk_74 + 1187281071*uk_75 + 1746001575*uk_76 + 1039840938*uk_77 + 2567649375*uk_78 + 1529177850*uk_79 + 134*uk_8 + 910710364*uk_80 + 166375*uk_81 + 229900*uk_82 + 405350*uk_83 + 48400*uk_84 + 462825*uk_85 + 680625*uk_86 + 405350*uk_87 + 317680*uk_88 + 560120*uk_89 + 2572416961*uk_9 + 66880*uk_90 + 639540*uk_91 + 940500*uk_92 + 560120*uk_93 + 987580*uk_94 + 117920*uk_95 + 1127610*uk_96 + 1658250*uk_97 + 987580*uk_98 + 14080*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 136400*uk_100 + 198000*uk_101 + 66880*uk_102 + 1321375*uk_103 + 1918125*uk_104 + 647900*uk_105 + 2784375*uk_106 + 940500*uk_107 + 317680*uk_108 + 39304*uk_109 + 1724446*uk_11 + 87856*uk_110 + 18496*uk_111 + 179180*uk_112 + 260100*uk_113 + 87856*uk_114 + 196384*uk_115 + 41344*uk_116 + 400520*uk_117 + 581400*uk_118 + 196384*uk_119 + 3854644*uk_12 + 8704*uk_120 + 84320*uk_121 + 122400*uk_122 + 41344*uk_123 + 816850*uk_124 + 1185750*uk_125 + 400520*uk_126 + 1721250*uk_127 + 581400*uk_128 + 196384*uk_129 + 811504*uk_13 + 438976*uk_130 + 92416*uk_131 + 895280*uk_132 + 1299600*uk_133 + 438976*uk_134 + 19456*uk_135 + 188480*uk_136 + 273600*uk_137 + 92416*uk_138 + 1825900*uk_139 + 7861445*uk_14 + 2650500*uk_140 + 895280*uk_141 + 3847500*uk_142 + 1299600*uk_143 + 438976*uk_144 + 4096*uk_145 + 39680*uk_146 + 57600*uk_147 + 19456*uk_148 + 384400*uk_149 + 11411775*uk_15 + 558000*uk_150 + 188480*uk_151 + 810000*uk_152 + 273600*uk_153 + 92416*uk_154 + 3723875*uk_155 + 5405625*uk_156 + 1825900*uk_157 + 7846875*uk_158 + 2650500*uk_159 + 3854644*uk_16 + 895280*uk_160 + 11390625*uk_161 + 3847500*uk_162 + 1299600*uk_163 + 438976*uk_164 + 3025*uk_17 + 1870*uk_18 + 4180*uk_19 + 55*uk_2 + 880*uk_20 + 8525*uk_21 + 12375*uk_22 + 4180*uk_23 + 1156*uk_24 + 2584*uk_25 + 544*uk_26 + 5270*uk_27 + 7650*uk_28 + 2584*uk_29 + 34*uk_3 + 5776*uk_30 + 1216*uk_31 + 11780*uk_32 + 17100*uk_33 + 5776*uk_34 + 256*uk_35 + 2480*uk_36 + 3600*uk_37 + 1216*uk_38 + 24025*uk_39 + 76*uk_4 + 34875*uk_40 + 11780*uk_41 + 50625*uk_42 + 17100*uk_43 + 5776*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 87462176674*uk_47 + 195503689036*uk_48 + 41158671376*uk_49 + 16*uk_5 + 398724628955*uk_50 + 578793816225*uk_51 + 195503689036*uk_52 + 153424975*uk_53 + 94844530*uk_54 + 212005420*uk_55 + 44632720*uk_56 + 432379475*uk_57 + 627647625*uk_58 + 212005420*uk_59 + 155*uk_6 + 58631164*uk_60 + 131057896*uk_61 + 27591136*uk_62 + 267289130*uk_63 + 388000350*uk_64 + 131057896*uk_65 + 292952944*uk_66 + 61674304*uk_67 + 597469820*uk_68 + 867294900*uk_69 + 225*uk_7 + 292952944*uk_70 + 12984064*uk_71 + 125783120*uk_72 + 182588400*uk_73 + 61674304*uk_74 + 1218523975*uk_75 + 1768825125*uk_76 + 597469820*uk_77 + 2567649375*uk_78 + 867294900*uk_79 + 76*uk_8 + 292952944*uk_80 + 166375*uk_81 + 102850*uk_82 + 229900*uk_83 + 48400*uk_84 + 468875*uk_85 + 680625*uk_86 + 229900*uk_87 + 63580*uk_88 + 142120*uk_89 + 2572416961*uk_9 + 29920*uk_90 + 289850*uk_91 + 420750*uk_92 + 142120*uk_93 + 317680*uk_94 + 66880*uk_95 + 647900*uk_96 + 940500*uk_97 + 317680*uk_98 + 14080*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 138160*uk_100 + 198000*uk_101 + 29920*uk_102 + 1355695*uk_103 + 1942875*uk_104 + 293590*uk_105 + 2784375*uk_106 + 420750*uk_107 + 63580*uk_108 + 512*uk_109 + 405752*uk_11 + 2176*uk_110 + 1024*uk_111 + 10048*uk_112 + 14400*uk_113 + 2176*uk_114 + 9248*uk_115 + 4352*uk_116 + 42704*uk_117 + 61200*uk_118 + 9248*uk_119 + 1724446*uk_12 + 2048*uk_120 + 20096*uk_121 + 28800*uk_122 + 4352*uk_123 + 197192*uk_124 + 282600*uk_125 + 42704*uk_126 + 405000*uk_127 + 61200*uk_128 + 9248*uk_129 + 811504*uk_13 + 39304*uk_130 + 18496*uk_131 + 181492*uk_132 + 260100*uk_133 + 39304*uk_134 + 8704*uk_135 + 85408*uk_136 + 122400*uk_137 + 18496*uk_138 + 838066*uk_139 + 7962883*uk_14 + 1201050*uk_140 + 181492*uk_141 + 1721250*uk_142 + 260100*uk_143 + 39304*uk_144 + 4096*uk_145 + 40192*uk_146 + 57600*uk_147 + 8704*uk_148 + 394384*uk_149 + 11411775*uk_15 + 565200*uk_150 + 85408*uk_151 + 810000*uk_152 + 122400*uk_153 + 18496*uk_154 + 3869893*uk_155 + 5546025*uk_156 + 838066*uk_157 + 7948125*uk_158 + 1201050*uk_159 + 1724446*uk_16 + 181492*uk_160 + 11390625*uk_161 + 1721250*uk_162 + 260100*uk_163 + 39304*uk_164 + 3025*uk_17 + 440*uk_18 + 1870*uk_19 + 55*uk_2 + 880*uk_20 + 8635*uk_21 + 12375*uk_22 + 1870*uk_23 + 64*uk_24 + 272*uk_25 + 128*uk_26 + 1256*uk_27 + 1800*uk_28 + 272*uk_29 + 8*uk_3 + 1156*uk_30 + 544*uk_31 + 5338*uk_32 + 7650*uk_33 + 1156*uk_34 + 256*uk_35 + 2512*uk_36 + 3600*uk_37 + 544*uk_38 + 24649*uk_39 + 34*uk_4 + 35325*uk_40 + 5338*uk_41 + 50625*uk_42 + 7650*uk_43 + 1156*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 20579335688*uk_47 + 87462176674*uk_48 + 41158671376*uk_49 + 16*uk_5 + 403869462877*uk_50 + 578793816225*uk_51 + 87462176674*uk_52 + 153424975*uk_53 + 22316360*uk_54 + 94844530*uk_55 + 44632720*uk_56 + 437958565*uk_57 + 627647625*uk_58 + 94844530*uk_59 + 157*uk_6 + 3246016*uk_60 + 13795568*uk_61 + 6492032*uk_62 + 63703064*uk_63 + 91294200*uk_64 + 13795568*uk_65 + 58631164*uk_66 + 27591136*uk_67 + 270738022*uk_68 + 388000350*uk_69 + 225*uk_7 + 58631164*uk_70 + 12984064*uk_71 + 127406128*uk_72 + 182588400*uk_73 + 27591136*uk_74 + 1250172631*uk_75 + 1791648675*uk_76 + 270738022*uk_77 + 2567649375*uk_78 + 388000350*uk_79 + 34*uk_8 + 58631164*uk_80 + 166375*uk_81 + 24200*uk_82 + 102850*uk_83 + 48400*uk_84 + 474925*uk_85 + 680625*uk_86 + 102850*uk_87 + 3520*uk_88 + 14960*uk_89 + 2572416961*uk_9 + 7040*uk_90 + 69080*uk_91 + 99000*uk_92 + 14960*uk_93 + 63580*uk_94 + 29920*uk_95 + 293590*uk_96 + 420750*uk_97 + 63580*uk_98 + 14080*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 174900*uk_100 + 247500*uk_101 + 8800*uk_102 + 1390455*uk_103 + 1967625*uk_104 + 69960*uk_105 + 2784375*uk_106 + 99000*uk_107 + 3520*uk_108 + 3869893*uk_109 + 7962883*uk_11 + 197192*uk_110 + 492980*uk_111 + 3919191*uk_112 + 5546025*uk_113 + 197192*uk_114 + 10048*uk_115 + 25120*uk_116 + 199704*uk_117 + 282600*uk_118 + 10048*uk_119 + 405752*uk_12 + 62800*uk_120 + 499260*uk_121 + 706500*uk_122 + 25120*uk_123 + 3969117*uk_124 + 5616675*uk_125 + 199704*uk_126 + 7948125*uk_127 + 282600*uk_128 + 10048*uk_129 + 1014380*uk_13 + 512*uk_130 + 1280*uk_131 + 10176*uk_132 + 14400*uk_133 + 512*uk_134 + 3200*uk_135 + 25440*uk_136 + 36000*uk_137 + 1280*uk_138 + 202248*uk_139 + 8064321*uk_14 + 286200*uk_140 + 10176*uk_141 + 405000*uk_142 + 14400*uk_143 + 512*uk_144 + 8000*uk_145 + 63600*uk_146 + 90000*uk_147 + 3200*uk_148 + 505620*uk_149 + 11411775*uk_15 + 715500*uk_150 + 25440*uk_151 + 1012500*uk_152 + 36000*uk_153 + 1280*uk_154 + 4019679*uk_155 + 5688225*uk_156 + 202248*uk_157 + 8049375*uk_158 + 286200*uk_159 + 405752*uk_16 + 10176*uk_160 + 11390625*uk_161 + 405000*uk_162 + 14400*uk_163 + 512*uk_164 + 3025*uk_17 + 8635*uk_18 + 440*uk_19 + 55*uk_2 + 1100*uk_20 + 8745*uk_21 + 12375*uk_22 + 440*uk_23 + 24649*uk_24 + 1256*uk_25 + 3140*uk_26 + 24963*uk_27 + 35325*uk_28 + 1256*uk_29 + 157*uk_3 + 64*uk_30 + 160*uk_31 + 1272*uk_32 + 1800*uk_33 + 64*uk_34 + 400*uk_35 + 3180*uk_36 + 4500*uk_37 + 160*uk_38 + 25281*uk_39 + 8*uk_4 + 35775*uk_40 + 1272*uk_41 + 50625*uk_42 + 1800*uk_43 + 64*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 403869462877*uk_47 + 20579335688*uk_48 + 51448339220*uk_49 + 20*uk_5 + 409014296799*uk_50 + 578793816225*uk_51 + 20579335688*uk_52 + 153424975*uk_53 + 437958565*uk_54 + 22316360*uk_55 + 55790900*uk_56 + 443537655*uk_57 + 627647625*uk_58 + 22316360*uk_59 + 159*uk_6 + 1250172631*uk_60 + 63703064*uk_61 + 159257660*uk_62 + 1266098397*uk_63 + 1791648675*uk_64 + 63703064*uk_65 + 3246016*uk_66 + 8115040*uk_67 + 64514568*uk_68 + 91294200*uk_69 + 225*uk_7 + 3246016*uk_70 + 20287600*uk_71 + 161286420*uk_72 + 228235500*uk_73 + 8115040*uk_74 + 1282227039*uk_75 + 1814472225*uk_76 + 64514568*uk_77 + 2567649375*uk_78 + 91294200*uk_79 + 8*uk_8 + 3246016*uk_80 + 166375*uk_81 + 474925*uk_82 + 24200*uk_83 + 60500*uk_84 + 480975*uk_85 + 680625*uk_86 + 24200*uk_87 + 1355695*uk_88 + 69080*uk_89 + 2572416961*uk_9 + 172700*uk_90 + 1372965*uk_91 + 1942875*uk_92 + 69080*uk_93 + 3520*uk_94 + 8800*uk_95 + 69960*uk_96 + 99000*uk_97 + 3520*uk_98 + 22000*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 106260*uk_100 + 148500*uk_101 + 103620*uk_102 + 1425655*uk_103 + 1992375*uk_104 + 1390235*uk_105 + 2784375*uk_106 + 1942875*uk_107 + 1355695*uk_108 + 64*uk_109 + 202876*uk_11 + 2512*uk_110 + 192*uk_111 + 2576*uk_112 + 3600*uk_113 + 2512*uk_114 + 98596*uk_115 + 7536*uk_116 + 101108*uk_117 + 141300*uk_118 + 98596*uk_119 + 7962883*uk_12 + 576*uk_120 + 7728*uk_121 + 10800*uk_122 + 7536*uk_123 + 103684*uk_124 + 144900*uk_125 + 101108*uk_126 + 202500*uk_127 + 141300*uk_128 + 98596*uk_129 + 608628*uk_13 + 3869893*uk_130 + 295788*uk_131 + 3968489*uk_132 + 5546025*uk_133 + 3869893*uk_134 + 22608*uk_135 + 303324*uk_136 + 423900*uk_137 + 295788*uk_138 + 4069597*uk_139 + 8165759*uk_14 + 5687325*uk_140 + 3968489*uk_141 + 7948125*uk_142 + 5546025*uk_143 + 3869893*uk_144 + 1728*uk_145 + 23184*uk_146 + 32400*uk_147 + 22608*uk_148 + 311052*uk_149 + 11411775*uk_15 + 434700*uk_150 + 303324*uk_151 + 607500*uk_152 + 423900*uk_153 + 295788*uk_154 + 4173281*uk_155 + 5832225*uk_156 + 4069597*uk_157 + 8150625*uk_158 + 5687325*uk_159 + 7962883*uk_16 + 3968489*uk_160 + 11390625*uk_161 + 7948125*uk_162 + 5546025*uk_163 + 3869893*uk_164 + 3025*uk_17 + 220*uk_18 + 8635*uk_19 + 55*uk_2 + 660*uk_20 + 8855*uk_21 + 12375*uk_22 + 8635*uk_23 + 16*uk_24 + 628*uk_25 + 48*uk_26 + 644*uk_27 + 900*uk_28 + 628*uk_29 + 4*uk_3 + 24649*uk_30 + 1884*uk_31 + 25277*uk_32 + 35325*uk_33 + 24649*uk_34 + 144*uk_35 + 1932*uk_36 + 2700*uk_37 + 1884*uk_38 + 25921*uk_39 + 157*uk_4 + 36225*uk_40 + 25277*uk_41 + 50625*uk_42 + 35325*uk_43 + 24649*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 10289667844*uk_47 + 403869462877*uk_48 + 30869003532*uk_49 + 12*uk_5 + 414159130721*uk_50 + 578793816225*uk_51 + 403869462877*uk_52 + 153424975*uk_53 + 11158180*uk_54 + 437958565*uk_55 + 33474540*uk_56 + 449116745*uk_57 + 627647625*uk_58 + 437958565*uk_59 + 161*uk_6 + 811504*uk_60 + 31851532*uk_61 + 2434512*uk_62 + 32663036*uk_63 + 45647100*uk_64 + 31851532*uk_65 + 1250172631*uk_66 + 95554596*uk_67 + 1282024163*uk_68 + 1791648675*uk_69 + 225*uk_7 + 1250172631*uk_70 + 7303536*uk_71 + 97989108*uk_72 + 136941300*uk_73 + 95554596*uk_74 + 1314687199*uk_75 + 1837295775*uk_76 + 1282024163*uk_77 + 2567649375*uk_78 + 1791648675*uk_79 + 157*uk_8 + 1250172631*uk_80 + 166375*uk_81 + 12100*uk_82 + 474925*uk_83 + 36300*uk_84 + 487025*uk_85 + 680625*uk_86 + 474925*uk_87 + 880*uk_88 + 34540*uk_89 + 2572416961*uk_9 + 2640*uk_90 + 35420*uk_91 + 49500*uk_92 + 34540*uk_93 + 1355695*uk_94 + 103620*uk_95 + 1390235*uk_96 + 1942875*uk_97 + 1355695*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 143440*uk_100 + 198000*uk_101 + 3520*uk_102 + 1461295*uk_103 + 2017125*uk_104 + 35860*uk_105 + 2784375*uk_106 + 49500*uk_107 + 880*uk_108 + 17576*uk_109 + 1318694*uk_11 + 2704*uk_110 + 10816*uk_111 + 110188*uk_112 + 152100*uk_113 + 2704*uk_114 + 416*uk_115 + 1664*uk_116 + 16952*uk_117 + 23400*uk_118 + 416*uk_119 + 202876*uk_12 + 6656*uk_120 + 67808*uk_121 + 93600*uk_122 + 1664*uk_123 + 690794*uk_124 + 953550*uk_125 + 16952*uk_126 + 1316250*uk_127 + 23400*uk_128 + 416*uk_129 + 811504*uk_13 + 64*uk_130 + 256*uk_131 + 2608*uk_132 + 3600*uk_133 + 64*uk_134 + 1024*uk_135 + 10432*uk_136 + 14400*uk_137 + 256*uk_138 + 106276*uk_139 + 8267197*uk_14 + 146700*uk_140 + 2608*uk_141 + 202500*uk_142 + 3600*uk_143 + 64*uk_144 + 4096*uk_145 + 41728*uk_146 + 57600*uk_147 + 1024*uk_148 + 425104*uk_149 + 11411775*uk_15 + 586800*uk_150 + 10432*uk_151 + 810000*uk_152 + 14400*uk_153 + 256*uk_154 + 4330747*uk_155 + 5978025*uk_156 + 106276*uk_157 + 8251875*uk_158 + 146700*uk_159 + 202876*uk_16 + 2608*uk_160 + 11390625*uk_161 + 202500*uk_162 + 3600*uk_163 + 64*uk_164 + 3025*uk_17 + 1430*uk_18 + 220*uk_19 + 55*uk_2 + 880*uk_20 + 8965*uk_21 + 12375*uk_22 + 220*uk_23 + 676*uk_24 + 104*uk_25 + 416*uk_26 + 4238*uk_27 + 5850*uk_28 + 104*uk_29 + 26*uk_3 + 16*uk_30 + 64*uk_31 + 652*uk_32 + 900*uk_33 + 16*uk_34 + 256*uk_35 + 2608*uk_36 + 3600*uk_37 + 64*uk_38 + 26569*uk_39 + 4*uk_4 + 36675*uk_40 + 652*uk_41 + 50625*uk_42 + 900*uk_43 + 16*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 66882840986*uk_47 + 10289667844*uk_48 + 41158671376*uk_49 + 16*uk_5 + 419303964643*uk_50 + 578793816225*uk_51 + 10289667844*uk_52 + 153424975*uk_53 + 72528170*uk_54 + 11158180*uk_55 + 44632720*uk_56 + 454695835*uk_57 + 627647625*uk_58 + 11158180*uk_59 + 163*uk_6 + 34286044*uk_60 + 5274776*uk_61 + 21099104*uk_62 + 214947122*uk_63 + 296706150*uk_64 + 5274776*uk_65 + 811504*uk_66 + 3246016*uk_67 + 33068788*uk_68 + 45647100*uk_69 + 225*uk_7 + 811504*uk_70 + 12984064*uk_71 + 132275152*uk_72 + 182588400*uk_73 + 3246016*uk_74 + 1347553111*uk_75 + 1860119325*uk_76 + 33068788*uk_77 + 2567649375*uk_78 + 45647100*uk_79 + 4*uk_8 + 811504*uk_80 + 166375*uk_81 + 78650*uk_82 + 12100*uk_83 + 48400*uk_84 + 493075*uk_85 + 680625*uk_86 + 12100*uk_87 + 37180*uk_88 + 5720*uk_89 + 2572416961*uk_9 + 22880*uk_90 + 233090*uk_91 + 321750*uk_92 + 5720*uk_93 + 880*uk_94 + 3520*uk_95 + 35860*uk_96 + 49500*uk_97 + 880*uk_98 + 14080*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 145200*uk_100 + 198000*uk_101 + 22880*uk_102 + 1497375*uk_103 + 2041875*uk_104 + 235950*uk_105 + 2784375*uk_106 + 321750*uk_107 + 37180*uk_108 + 262144*uk_109 + 3246016*uk_11 + 106496*uk_110 + 65536*uk_111 + 675840*uk_112 + 921600*uk_113 + 106496*uk_114 + 43264*uk_115 + 26624*uk_116 + 274560*uk_117 + 374400*uk_118 + 43264*uk_119 + 1318694*uk_12 + 16384*uk_120 + 168960*uk_121 + 230400*uk_122 + 26624*uk_123 + 1742400*uk_124 + 2376000*uk_125 + 274560*uk_126 + 3240000*uk_127 + 374400*uk_128 + 43264*uk_129 + 811504*uk_13 + 17576*uk_130 + 10816*uk_131 + 111540*uk_132 + 152100*uk_133 + 17576*uk_134 + 6656*uk_135 + 68640*uk_136 + 93600*uk_137 + 10816*uk_138 + 707850*uk_139 + 8368635*uk_14 + 965250*uk_140 + 111540*uk_141 + 1316250*uk_142 + 152100*uk_143 + 17576*uk_144 + 4096*uk_145 + 42240*uk_146 + 57600*uk_147 + 6656*uk_148 + 435600*uk_149 + 11411775*uk_15 + 594000*uk_150 + 68640*uk_151 + 810000*uk_152 + 93600*uk_153 + 10816*uk_154 + 4492125*uk_155 + 6125625*uk_156 + 707850*uk_157 + 8353125*uk_158 + 965250*uk_159 + 1318694*uk_16 + 111540*uk_160 + 11390625*uk_161 + 1316250*uk_162 + 152100*uk_163 + 17576*uk_164 + 3025*uk_17 + 3520*uk_18 + 1430*uk_19 + 55*uk_2 + 880*uk_20 + 9075*uk_21 + 12375*uk_22 + 1430*uk_23 + 4096*uk_24 + 1664*uk_25 + 1024*uk_26 + 10560*uk_27 + 14400*uk_28 + 1664*uk_29 + 64*uk_3 + 676*uk_30 + 416*uk_31 + 4290*uk_32 + 5850*uk_33 + 676*uk_34 + 256*uk_35 + 2640*uk_36 + 3600*uk_37 + 416*uk_38 + 27225*uk_39 + 26*uk_4 + 37125*uk_40 + 4290*uk_41 + 50625*uk_42 + 5850*uk_43 + 676*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 164634685504*uk_47 + 66882840986*uk_48 + 41158671376*uk_49 + 16*uk_5 + 424448798565*uk_50 + 578793816225*uk_51 + 66882840986*uk_52 + 153424975*uk_53 + 178530880*uk_54 + 72528170*uk_55 + 44632720*uk_56 + 460274925*uk_57 + 627647625*uk_58 + 72528170*uk_59 + 165*uk_6 + 207745024*uk_60 + 84396416*uk_61 + 51936256*uk_62 + 535592640*uk_63 + 730353600*uk_64 + 84396416*uk_65 + 34286044*uk_66 + 21099104*uk_67 + 217584510*uk_68 + 296706150*uk_69 + 225*uk_7 + 34286044*uk_70 + 12984064*uk_71 + 133898160*uk_72 + 182588400*uk_73 + 21099104*uk_74 + 1380824775*uk_75 + 1882942875*uk_76 + 217584510*uk_77 + 2567649375*uk_78 + 296706150*uk_79 + 26*uk_8 + 34286044*uk_80 + 166375*uk_81 + 193600*uk_82 + 78650*uk_83 + 48400*uk_84 + 499125*uk_85 + 680625*uk_86 + 78650*uk_87 + 225280*uk_88 + 91520*uk_89 + 2572416961*uk_9 + 56320*uk_90 + 580800*uk_91 + 792000*uk_92 + 91520*uk_93 + 37180*uk_94 + 22880*uk_95 + 235950*uk_96 + 321750*uk_97 + 37180*uk_98 + 14080*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 146960*uk_100 + 198000*uk_101 + 56320*uk_102 + 1533895*uk_103 + 2066625*uk_104 + 587840*uk_105 + 2784375*uk_106 + 792000*uk_107 + 225280*uk_108 + 1643032*uk_109 + 5984842*uk_11 + 891136*uk_110 + 222784*uk_111 + 2325308*uk_112 + 3132900*uk_113 + 891136*uk_114 + 483328*uk_115 + 120832*uk_116 + 1261184*uk_117 + 1699200*uk_118 + 483328*uk_119 + 3246016*uk_12 + 30208*uk_120 + 315296*uk_121 + 424800*uk_122 + 120832*uk_123 + 3290902*uk_124 + 4433850*uk_125 + 1261184*uk_126 + 5973750*uk_127 + 1699200*uk_128 + 483328*uk_129 + 811504*uk_13 + 262144*uk_130 + 65536*uk_131 + 684032*uk_132 + 921600*uk_133 + 262144*uk_134 + 16384*uk_135 + 171008*uk_136 + 230400*uk_137 + 65536*uk_138 + 1784896*uk_139 + 8470073*uk_14 + 2404800*uk_140 + 684032*uk_141 + 3240000*uk_142 + 921600*uk_143 + 262144*uk_144 + 4096*uk_145 + 42752*uk_146 + 57600*uk_147 + 16384*uk_148 + 446224*uk_149 + 11411775*uk_15 + 601200*uk_150 + 171008*uk_151 + 810000*uk_152 + 230400*uk_153 + 65536*uk_154 + 4657463*uk_155 + 6275025*uk_156 + 1784896*uk_157 + 8454375*uk_158 + 2404800*uk_159 + 3246016*uk_16 + 684032*uk_160 + 11390625*uk_161 + 3240000*uk_162 + 921600*uk_163 + 262144*uk_164 + 3025*uk_17 + 6490*uk_18 + 3520*uk_19 + 55*uk_2 + 880*uk_20 + 9185*uk_21 + 12375*uk_22 + 3520*uk_23 + 13924*uk_24 + 7552*uk_25 + 1888*uk_26 + 19706*uk_27 + 26550*uk_28 + 7552*uk_29 + 118*uk_3 + 4096*uk_30 + 1024*uk_31 + 10688*uk_32 + 14400*uk_33 + 4096*uk_34 + 256*uk_35 + 2672*uk_36 + 3600*uk_37 + 1024*uk_38 + 27889*uk_39 + 64*uk_4 + 37575*uk_40 + 10688*uk_41 + 50625*uk_42 + 14400*uk_43 + 4096*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 303545201398*uk_47 + 164634685504*uk_48 + 41158671376*uk_49 + 16*uk_5 + 429593632487*uk_50 + 578793816225*uk_51 + 164634685504*uk_52 + 153424975*uk_53 + 329166310*uk_54 + 178530880*uk_55 + 44632720*uk_56 + 465854015*uk_57 + 627647625*uk_58 + 178530880*uk_59 + 167*uk_6 + 706211356*uk_60 + 383029888*uk_61 + 95757472*uk_62 + 999468614*uk_63 + 1346589450*uk_64 + 383029888*uk_65 + 207745024*uk_66 + 51936256*uk_67 + 542084672*uk_68 + 730353600*uk_69 + 225*uk_7 + 207745024*uk_70 + 12984064*uk_71 + 135521168*uk_72 + 182588400*uk_73 + 51936256*uk_74 + 1414502191*uk_75 + 1905766425*uk_76 + 542084672*uk_77 + 2567649375*uk_78 + 730353600*uk_79 + 64*uk_8 + 207745024*uk_80 + 166375*uk_81 + 356950*uk_82 + 193600*uk_83 + 48400*uk_84 + 505175*uk_85 + 680625*uk_86 + 193600*uk_87 + 765820*uk_88 + 415360*uk_89 + 2572416961*uk_9 + 103840*uk_90 + 1083830*uk_91 + 1460250*uk_92 + 415360*uk_93 + 225280*uk_94 + 56320*uk_95 + 587840*uk_96 + 792000*uk_97 + 225280*uk_98 + 14080*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 111540*uk_100 + 148500*uk_101 + 77880*uk_102 + 1570855*uk_103 + 2091375*uk_104 + 1096810*uk_105 + 2784375*uk_106 + 1460250*uk_107 + 765820*uk_108 + 6859*uk_109 + 963661*uk_11 + 42598*uk_110 + 4332*uk_111 + 61009*uk_112 + 81225*uk_113 + 42598*uk_114 + 264556*uk_115 + 26904*uk_116 + 378898*uk_117 + 504450*uk_118 + 264556*uk_119 + 5984842*uk_12 + 2736*uk_120 + 38532*uk_121 + 51300*uk_122 + 26904*uk_123 + 542659*uk_124 + 722475*uk_125 + 378898*uk_126 + 961875*uk_127 + 504450*uk_128 + 264556*uk_129 + 608628*uk_13 + 1643032*uk_130 + 167088*uk_131 + 2353156*uk_132 + 3132900*uk_133 + 1643032*uk_134 + 16992*uk_135 + 239304*uk_136 + 318600*uk_137 + 167088*uk_138 + 3370198*uk_139 + 8571511*uk_14 + 4486950*uk_140 + 2353156*uk_141 + 5973750*uk_142 + 3132900*uk_143 + 1643032*uk_144 + 1728*uk_145 + 24336*uk_146 + 32400*uk_147 + 16992*uk_148 + 342732*uk_149 + 11411775*uk_15 + 456300*uk_150 + 239304*uk_151 + 607500*uk_152 + 318600*uk_153 + 167088*uk_154 + 4826809*uk_155 + 6426225*uk_156 + 3370198*uk_157 + 8555625*uk_158 + 4486950*uk_159 + 5984842*uk_16 + 2353156*uk_160 + 11390625*uk_161 + 5973750*uk_162 + 3132900*uk_163 + 1643032*uk_164 + 3025*uk_17 + 1045*uk_18 + 6490*uk_19 + 55*uk_2 + 660*uk_20 + 9295*uk_21 + 12375*uk_22 + 6490*uk_23 + 361*uk_24 + 2242*uk_25 + 228*uk_26 + 3211*uk_27 + 4275*uk_28 + 2242*uk_29 + 19*uk_3 + 13924*uk_30 + 1416*uk_31 + 19942*uk_32 + 26550*uk_33 + 13924*uk_34 + 144*uk_35 + 2028*uk_36 + 2700*uk_37 + 1416*uk_38 + 28561*uk_39 + 118*uk_4 + 38025*uk_40 + 19942*uk_41 + 50625*uk_42 + 26550*uk_43 + 13924*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 48875922259*uk_47 + 303545201398*uk_48 + 30869003532*uk_49 + 12*uk_5 + 434738466409*uk_50 + 578793816225*uk_51 + 303545201398*uk_52 + 153424975*uk_53 + 53001355*uk_54 + 329166310*uk_55 + 33474540*uk_56 + 471433105*uk_57 + 627647625*uk_58 + 329166310*uk_59 + 169*uk_6 + 18309559*uk_60 + 113711998*uk_61 + 11563932*uk_62 + 162858709*uk_63 + 216823725*uk_64 + 113711998*uk_65 + 706211356*uk_66 + 71818104*uk_67 + 1011438298*uk_68 + 1346589450*uk_69 + 225*uk_7 + 706211356*uk_70 + 7303536*uk_71 + 102858132*uk_72 + 136941300*uk_73 + 71818104*uk_74 + 1448585359*uk_75 + 1928589975*uk_76 + 1011438298*uk_77 + 2567649375*uk_78 + 1346589450*uk_79 + 118*uk_8 + 706211356*uk_80 + 166375*uk_81 + 57475*uk_82 + 356950*uk_83 + 36300*uk_84 + 511225*uk_85 + 680625*uk_86 + 356950*uk_87 + 19855*uk_88 + 123310*uk_89 + 2572416961*uk_9 + 12540*uk_90 + 176605*uk_91 + 235125*uk_92 + 123310*uk_93 + 765820*uk_94 + 77880*uk_95 + 1096810*uk_96 + 1460250*uk_97 + 765820*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 150480*uk_100 + 198000*uk_101 + 16720*uk_102 + 1608255*uk_103 + 2116125*uk_104 + 178695*uk_105 + 2784375*uk_106 + 235125*uk_107 + 19855*uk_108 + 1092727*uk_109 + 5224057*uk_11 + 201571*uk_110 + 169744*uk_111 + 1814139*uk_112 + 2387025*uk_113 + 201571*uk_114 + 37183*uk_115 + 31312*uk_116 + 334647*uk_117 + 440325*uk_118 + 37183*uk_119 + 963661*uk_12 + 26368*uk_120 + 281808*uk_121 + 370800*uk_122 + 31312*uk_123 + 3011823*uk_124 + 3962925*uk_125 + 334647*uk_126 + 5214375*uk_127 + 440325*uk_128 + 37183*uk_129 + 811504*uk_13 + 6859*uk_130 + 5776*uk_131 + 61731*uk_132 + 81225*uk_133 + 6859*uk_134 + 4864*uk_135 + 51984*uk_136 + 68400*uk_137 + 5776*uk_138 + 555579*uk_139 + 8672949*uk_14 + 731025*uk_140 + 61731*uk_141 + 961875*uk_142 + 81225*uk_143 + 6859*uk_144 + 4096*uk_145 + 43776*uk_146 + 57600*uk_147 + 4864*uk_148 + 467856*uk_149 + 11411775*uk_15 + 615600*uk_150 + 51984*uk_151 + 810000*uk_152 + 68400*uk_153 + 5776*uk_154 + 5000211*uk_155 + 6579225*uk_156 + 555579*uk_157 + 8656875*uk_158 + 731025*uk_159 + 963661*uk_16 + 61731*uk_160 + 11390625*uk_161 + 961875*uk_162 + 81225*uk_163 + 6859*uk_164 + 3025*uk_17 + 5665*uk_18 + 1045*uk_19 + 55*uk_2 + 880*uk_20 + 9405*uk_21 + 12375*uk_22 + 1045*uk_23 + 10609*uk_24 + 1957*uk_25 + 1648*uk_26 + 17613*uk_27 + 23175*uk_28 + 1957*uk_29 + 103*uk_3 + 361*uk_30 + 304*uk_31 + 3249*uk_32 + 4275*uk_33 + 361*uk_34 + 256*uk_35 + 2736*uk_36 + 3600*uk_37 + 304*uk_38 + 29241*uk_39 + 19*uk_4 + 38475*uk_40 + 3249*uk_41 + 50625*uk_42 + 4275*uk_43 + 361*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 264958946983*uk_47 + 48875922259*uk_48 + 41158671376*uk_49 + 16*uk_5 + 439883300331*uk_50 + 578793816225*uk_51 + 48875922259*uk_52 + 153424975*uk_53 + 287323135*uk_54 + 53001355*uk_55 + 44632720*uk_56 + 477012195*uk_57 + 627647625*uk_58 + 53001355*uk_59 + 171*uk_6 + 538077871*uk_60 + 99257083*uk_61 + 83584912*uk_62 + 893313747*uk_63 + 1175412825*uk_64 + 99257083*uk_65 + 18309559*uk_66 + 15418576*uk_67 + 164786031*uk_68 + 216823725*uk_69 + 225*uk_7 + 18309559*uk_70 + 12984064*uk_71 + 138767184*uk_72 + 182588400*uk_73 + 15418576*uk_74 + 1483074279*uk_75 + 1951413525*uk_76 + 164786031*uk_77 + 2567649375*uk_78 + 216823725*uk_79 + 19*uk_8 + 18309559*uk_80 + 166375*uk_81 + 311575*uk_82 + 57475*uk_83 + 48400*uk_84 + 517275*uk_85 + 680625*uk_86 + 57475*uk_87 + 583495*uk_88 + 107635*uk_89 + 2572416961*uk_9 + 90640*uk_90 + 968715*uk_91 + 1274625*uk_92 + 107635*uk_93 + 19855*uk_94 + 16720*uk_95 + 178695*uk_96 + 235125*uk_97 + 19855*uk_98 + 14080*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 114180*uk_100 + 148500*uk_101 + 67980*uk_102 + 1646095*uk_103 + 2140875*uk_104 + 980045*uk_105 + 2784375*uk_106 + 1274625*uk_107 + 583495*uk_108 + 27000*uk_109 + 1521570*uk_11 + 92700*uk_110 + 10800*uk_111 + 155700*uk_112 + 202500*uk_113 + 92700*uk_114 + 318270*uk_115 + 37080*uk_116 + 534570*uk_117 + 695250*uk_118 + 318270*uk_119 + 5224057*uk_12 + 4320*uk_120 + 62280*uk_121 + 81000*uk_122 + 37080*uk_123 + 897870*uk_124 + 1167750*uk_125 + 534570*uk_126 + 1518750*uk_127 + 695250*uk_128 + 318270*uk_129 + 608628*uk_13 + 1092727*uk_130 + 127308*uk_131 + 1835357*uk_132 + 2387025*uk_133 + 1092727*uk_134 + 14832*uk_135 + 213828*uk_136 + 278100*uk_137 + 127308*uk_138 + 3082687*uk_139 + 8774387*uk_14 + 4009275*uk_140 + 1835357*uk_141 + 5214375*uk_142 + 2387025*uk_143 + 1092727*uk_144 + 1728*uk_145 + 24912*uk_146 + 32400*uk_147 + 14832*uk_148 + 359148*uk_149 + 11411775*uk_15 + 467100*uk_150 + 213828*uk_151 + 607500*uk_152 + 278100*uk_153 + 127308*uk_154 + 5177717*uk_155 + 6734025*uk_156 + 3082687*uk_157 + 8758125*uk_158 + 4009275*uk_159 + 5224057*uk_16 + 1835357*uk_160 + 11390625*uk_161 + 5214375*uk_162 + 2387025*uk_163 + 1092727*uk_164 + 3025*uk_17 + 1650*uk_18 + 5665*uk_19 + 55*uk_2 + 660*uk_20 + 9515*uk_21 + 12375*uk_22 + 5665*uk_23 + 900*uk_24 + 3090*uk_25 + 360*uk_26 + 5190*uk_27 + 6750*uk_28 + 3090*uk_29 + 30*uk_3 + 10609*uk_30 + 1236*uk_31 + 17819*uk_32 + 23175*uk_33 + 10609*uk_34 + 144*uk_35 + 2076*uk_36 + 2700*uk_37 + 1236*uk_38 + 29929*uk_39 + 103*uk_4 + 38925*uk_40 + 17819*uk_41 + 50625*uk_42 + 23175*uk_43 + 10609*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 77172508830*uk_47 + 264958946983*uk_48 + 30869003532*uk_49 + 12*uk_5 + 445028134253*uk_50 + 578793816225*uk_51 + 264958946983*uk_52 + 153424975*uk_53 + 83686350*uk_54 + 287323135*uk_55 + 33474540*uk_56 + 482591285*uk_57 + 627647625*uk_58 + 287323135*uk_59 + 173*uk_6 + 45647100*uk_60 + 156721710*uk_61 + 18258840*uk_62 + 263231610*uk_63 + 342353250*uk_64 + 156721710*uk_65 + 538077871*uk_66 + 62688684*uk_67 + 903761861*uk_68 + 1175412825*uk_69 + 225*uk_7 + 538077871*uk_70 + 7303536*uk_71 + 105292644*uk_72 + 136941300*uk_73 + 62688684*uk_74 + 1517968951*uk_75 + 1974237075*uk_76 + 903761861*uk_77 + 2567649375*uk_78 + 1175412825*uk_79 + 103*uk_8 + 538077871*uk_80 + 166375*uk_81 + 90750*uk_82 + 311575*uk_83 + 36300*uk_84 + 523325*uk_85 + 680625*uk_86 + 311575*uk_87 + 49500*uk_88 + 169950*uk_89 + 2572416961*uk_9 + 19800*uk_90 + 285450*uk_91 + 371250*uk_92 + 169950*uk_93 + 583495*uk_94 + 67980*uk_95 + 980045*uk_96 + 1274625*uk_97 + 583495*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 154000*uk_100 + 198000*uk_101 + 26400*uk_102 + 1684375*uk_103 + 2165625*uk_104 + 288750*uk_105 + 2784375*uk_106 + 371250*uk_107 + 49500*uk_108 + 2985984*uk_109 + 7303536*uk_11 + 622080*uk_110 + 331776*uk_111 + 3628800*uk_112 + 4665600*uk_113 + 622080*uk_114 + 129600*uk_115 + 69120*uk_116 + 756000*uk_117 + 972000*uk_118 + 129600*uk_119 + 1521570*uk_12 + 36864*uk_120 + 403200*uk_121 + 518400*uk_122 + 69120*uk_123 + 4410000*uk_124 + 5670000*uk_125 + 756000*uk_126 + 7290000*uk_127 + 972000*uk_128 + 129600*uk_129 + 811504*uk_13 + 27000*uk_130 + 14400*uk_131 + 157500*uk_132 + 202500*uk_133 + 27000*uk_134 + 7680*uk_135 + 84000*uk_136 + 108000*uk_137 + 14400*uk_138 + 918750*uk_139 + 8875825*uk_14 + 1181250*uk_140 + 157500*uk_141 + 1518750*uk_142 + 202500*uk_143 + 27000*uk_144 + 4096*uk_145 + 44800*uk_146 + 57600*uk_147 + 7680*uk_148 + 490000*uk_149 + 11411775*uk_15 + 630000*uk_150 + 84000*uk_151 + 810000*uk_152 + 108000*uk_153 + 14400*uk_154 + 5359375*uk_155 + 6890625*uk_156 + 918750*uk_157 + 8859375*uk_158 + 1181250*uk_159 + 1521570*uk_16 + 157500*uk_160 + 11390625*uk_161 + 1518750*uk_162 + 202500*uk_163 + 27000*uk_164 + 3025*uk_17 + 7920*uk_18 + 1650*uk_19 + 55*uk_2 + 880*uk_20 + 9625*uk_21 + 12375*uk_22 + 1650*uk_23 + 20736*uk_24 + 4320*uk_25 + 2304*uk_26 + 25200*uk_27 + 32400*uk_28 + 4320*uk_29 + 144*uk_3 + 900*uk_30 + 480*uk_31 + 5250*uk_32 + 6750*uk_33 + 900*uk_34 + 256*uk_35 + 2800*uk_36 + 3600*uk_37 + 480*uk_38 + 30625*uk_39 + 30*uk_4 + 39375*uk_40 + 5250*uk_41 + 50625*uk_42 + 6750*uk_43 + 900*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 370428042384*uk_47 + 77172508830*uk_48 + 41158671376*uk_49 + 16*uk_5 + 450172968175*uk_50 + 578793816225*uk_51 + 77172508830*uk_52 + 153424975*uk_53 + 401694480*uk_54 + 83686350*uk_55 + 44632720*uk_56 + 488170375*uk_57 + 627647625*uk_58 + 83686350*uk_59 + 175*uk_6 + 1051709184*uk_60 + 219106080*uk_61 + 116856576*uk_62 + 1278118800*uk_63 + 1643295600*uk_64 + 219106080*uk_65 + 45647100*uk_66 + 24345120*uk_67 + 266274750*uk_68 + 342353250*uk_69 + 225*uk_7 + 45647100*uk_70 + 12984064*uk_71 + 142013200*uk_72 + 182588400*uk_73 + 24345120*uk_74 + 1553269375*uk_75 + 1997060625*uk_76 + 266274750*uk_77 + 2567649375*uk_78 + 342353250*uk_79 + 30*uk_8 + 45647100*uk_80 + 166375*uk_81 + 435600*uk_82 + 90750*uk_83 + 48400*uk_84 + 529375*uk_85 + 680625*uk_86 + 90750*uk_87 + 1140480*uk_88 + 237600*uk_89 + 2572416961*uk_9 + 126720*uk_90 + 1386000*uk_91 + 1782000*uk_92 + 237600*uk_93 + 49500*uk_94 + 26400*uk_95 + 288750*uk_96 + 371250*uk_97 + 49500*uk_98 + 14080*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 116820*uk_100 + 148500*uk_101 + 95040*uk_102 + 1723095*uk_103 + 2190375*uk_104 + 1401840*uk_105 + 2784375*uk_106 + 1782000*uk_107 + 1140480*uk_108 + 912673*uk_109 + 4919743*uk_11 + 1354896*uk_110 + 112908*uk_111 + 1665393*uk_112 + 2117025*uk_113 + 1354896*uk_114 + 2011392*uk_115 + 167616*uk_116 + 2472336*uk_117 + 3142800*uk_118 + 2011392*uk_119 + 7303536*uk_12 + 13968*uk_120 + 206028*uk_121 + 261900*uk_122 + 167616*uk_123 + 3038913*uk_124 + 3863025*uk_125 + 2472336*uk_126 + 4910625*uk_127 + 3142800*uk_128 + 2011392*uk_129 + 608628*uk_13 + 2985984*uk_130 + 248832*uk_131 + 3670272*uk_132 + 4665600*uk_133 + 2985984*uk_134 + 20736*uk_135 + 305856*uk_136 + 388800*uk_137 + 248832*uk_138 + 4511376*uk_139 + 8977263*uk_14 + 5734800*uk_140 + 3670272*uk_141 + 7290000*uk_142 + 4665600*uk_143 + 2985984*uk_144 + 1728*uk_145 + 25488*uk_146 + 32400*uk_147 + 20736*uk_148 + 375948*uk_149 + 11411775*uk_15 + 477900*uk_150 + 305856*uk_151 + 607500*uk_152 + 388800*uk_153 + 248832*uk_154 + 5545233*uk_155 + 7049025*uk_156 + 4511376*uk_157 + 8960625*uk_158 + 5734800*uk_159 + 7303536*uk_16 + 3670272*uk_160 + 11390625*uk_161 + 7290000*uk_162 + 4665600*uk_163 + 2985984*uk_164 + 3025*uk_17 + 5335*uk_18 + 7920*uk_19 + 55*uk_2 + 660*uk_20 + 9735*uk_21 + 12375*uk_22 + 7920*uk_23 + 9409*uk_24 + 13968*uk_25 + 1164*uk_26 + 17169*uk_27 + 21825*uk_28 + 13968*uk_29 + 97*uk_3 + 20736*uk_30 + 1728*uk_31 + 25488*uk_32 + 32400*uk_33 + 20736*uk_34 + 144*uk_35 + 2124*uk_36 + 2700*uk_37 + 1728*uk_38 + 31329*uk_39 + 144*uk_4 + 39825*uk_40 + 25488*uk_41 + 50625*uk_42 + 32400*uk_43 + 20736*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 249524445217*uk_47 + 370428042384*uk_48 + 30869003532*uk_49 + 12*uk_5 + 455317802097*uk_50 + 578793816225*uk_51 + 370428042384*uk_52 + 153424975*uk_53 + 270585865*uk_54 + 401694480*uk_55 + 33474540*uk_56 + 493749465*uk_57 + 627647625*uk_58 + 401694480*uk_59 + 177*uk_6 + 477215071*uk_60 + 708442992*uk_61 + 59036916*uk_62 + 870794511*uk_63 + 1106942175*uk_64 + 708442992*uk_65 + 1051709184*uk_66 + 87642432*uk_67 + 1292725872*uk_68 + 1643295600*uk_69 + 225*uk_7 + 1051709184*uk_70 + 7303536*uk_71 + 107727156*uk_72 + 136941300*uk_73 + 87642432*uk_74 + 1588975551*uk_75 + 2019884175*uk_76 + 1292725872*uk_77 + 2567649375*uk_78 + 1643295600*uk_79 + 144*uk_8 + 1051709184*uk_80 + 166375*uk_81 + 293425*uk_82 + 435600*uk_83 + 36300*uk_84 + 535425*uk_85 + 680625*uk_86 + 435600*uk_87 + 517495*uk_88 + 768240*uk_89 + 2572416961*uk_9 + 64020*uk_90 + 944295*uk_91 + 1200375*uk_92 + 768240*uk_93 + 1140480*uk_94 + 95040*uk_95 + 1401840*uk_96 + 1782000*uk_97 + 1140480*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 118140*uk_100 + 148500*uk_101 + 64020*uk_102 + 1762255*uk_103 + 2215125*uk_104 + 954965*uk_105 + 2784375*uk_106 + 1200375*uk_107 + 517495*uk_108 + 238328*uk_109 + 3144578*uk_11 + 372868*uk_110 + 46128*uk_111 + 688076*uk_112 + 864900*uk_113 + 372868*uk_114 + 583358*uk_115 + 72168*uk_116 + 1076506*uk_117 + 1353150*uk_118 + 583358*uk_119 + 4919743*uk_12 + 8928*uk_120 + 133176*uk_121 + 167400*uk_122 + 72168*uk_123 + 1986542*uk_124 + 2497050*uk_125 + 1076506*uk_126 + 3138750*uk_127 + 1353150*uk_128 + 583358*uk_129 + 608628*uk_13 + 912673*uk_130 + 112908*uk_131 + 1684211*uk_132 + 2117025*uk_133 + 912673*uk_134 + 13968*uk_135 + 208356*uk_136 + 261900*uk_137 + 112908*uk_138 + 3107977*uk_139 + 9078701*uk_14 + 3906675*uk_140 + 1684211*uk_141 + 4910625*uk_142 + 2117025*uk_143 + 912673*uk_144 + 1728*uk_145 + 25776*uk_146 + 32400*uk_147 + 13968*uk_148 + 384492*uk_149 + 11411775*uk_15 + 483300*uk_150 + 208356*uk_151 + 607500*uk_152 + 261900*uk_153 + 112908*uk_154 + 5735339*uk_155 + 7209225*uk_156 + 3107977*uk_157 + 9061875*uk_158 + 3906675*uk_159 + 4919743*uk_16 + 1684211*uk_160 + 11390625*uk_161 + 4910625*uk_162 + 2117025*uk_163 + 912673*uk_164 + 3025*uk_17 + 3410*uk_18 + 5335*uk_19 + 55*uk_2 + 660*uk_20 + 9845*uk_21 + 12375*uk_22 + 5335*uk_23 + 3844*uk_24 + 6014*uk_25 + 744*uk_26 + 11098*uk_27 + 13950*uk_28 + 6014*uk_29 + 62*uk_3 + 9409*uk_30 + 1164*uk_31 + 17363*uk_32 + 21825*uk_33 + 9409*uk_34 + 144*uk_35 + 2148*uk_36 + 2700*uk_37 + 1164*uk_38 + 32041*uk_39 + 97*uk_4 + 40275*uk_40 + 17363*uk_41 + 50625*uk_42 + 21825*uk_43 + 9409*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 159489851582*uk_47 + 249524445217*uk_48 + 30869003532*uk_49 + 12*uk_5 + 460462636019*uk_50 + 578793816225*uk_51 + 249524445217*uk_52 + 153424975*uk_53 + 172951790*uk_54 + 270585865*uk_55 + 33474540*uk_56 + 499328555*uk_57 + 627647625*uk_58 + 270585865*uk_59 + 179*uk_6 + 194963836*uk_60 + 305024066*uk_61 + 37734936*uk_62 + 562879462*uk_63 + 707530050*uk_64 + 305024066*uk_65 + 477215071*uk_66 + 59036916*uk_67 + 880633997*uk_68 + 1106942175*uk_69 + 225*uk_7 + 477215071*uk_70 + 7303536*uk_71 + 108944412*uk_72 + 136941300*uk_73 + 59036916*uk_74 + 1625087479*uk_75 + 2042707725*uk_76 + 880633997*uk_77 + 2567649375*uk_78 + 1106942175*uk_79 + 97*uk_8 + 477215071*uk_80 + 166375*uk_81 + 187550*uk_82 + 293425*uk_83 + 36300*uk_84 + 541475*uk_85 + 680625*uk_86 + 293425*uk_87 + 211420*uk_88 + 330770*uk_89 + 2572416961*uk_9 + 40920*uk_90 + 610390*uk_91 + 767250*uk_92 + 330770*uk_93 + 517495*uk_94 + 64020*uk_95 + 954965*uk_96 + 1200375*uk_97 + 517495*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 119460*uk_100 + 148500*uk_101 + 40920*uk_102 + 1801855*uk_103 + 2239875*uk_104 + 617210*uk_105 + 2784375*uk_106 + 767250*uk_107 + 211420*uk_108 + 59319*uk_109 + 1978041*uk_11 + 94302*uk_110 + 18252*uk_111 + 275301*uk_112 + 342225*uk_113 + 94302*uk_114 + 149916*uk_115 + 29016*uk_116 + 437658*uk_117 + 544050*uk_118 + 149916*uk_119 + 3144578*uk_12 + 5616*uk_120 + 84708*uk_121 + 105300*uk_122 + 29016*uk_123 + 1277679*uk_124 + 1588275*uk_125 + 437658*uk_126 + 1974375*uk_127 + 544050*uk_128 + 149916*uk_129 + 608628*uk_13 + 238328*uk_130 + 46128*uk_131 + 695764*uk_132 + 864900*uk_133 + 238328*uk_134 + 8928*uk_135 + 134664*uk_136 + 167400*uk_137 + 46128*uk_138 + 2031182*uk_139 + 9180139*uk_14 + 2524950*uk_140 + 695764*uk_141 + 3138750*uk_142 + 864900*uk_143 + 238328*uk_144 + 1728*uk_145 + 26064*uk_146 + 32400*uk_147 + 8928*uk_148 + 393132*uk_149 + 11411775*uk_15 + 488700*uk_150 + 134664*uk_151 + 607500*uk_152 + 167400*uk_153 + 46128*uk_154 + 5929741*uk_155 + 7371225*uk_156 + 2031182*uk_157 + 9163125*uk_158 + 2524950*uk_159 + 3144578*uk_16 + 695764*uk_160 + 11390625*uk_161 + 3138750*uk_162 + 864900*uk_163 + 238328*uk_164 + 3025*uk_17 + 2145*uk_18 + 3410*uk_19 + 55*uk_2 + 660*uk_20 + 9955*uk_21 + 12375*uk_22 + 3410*uk_23 + 1521*uk_24 + 2418*uk_25 + 468*uk_26 + 7059*uk_27 + 8775*uk_28 + 2418*uk_29 + 39*uk_3 + 3844*uk_30 + 744*uk_31 + 11222*uk_32 + 13950*uk_33 + 3844*uk_34 + 144*uk_35 + 2172*uk_36 + 2700*uk_37 + 744*uk_38 + 32761*uk_39 + 62*uk_4 + 40725*uk_40 + 11222*uk_41 + 50625*uk_42 + 13950*uk_43 + 3844*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 100324261479*uk_47 + 159489851582*uk_48 + 30869003532*uk_49 + 12*uk_5 + 465607469941*uk_50 + 578793816225*uk_51 + 159489851582*uk_52 + 153424975*uk_53 + 108792255*uk_54 + 172951790*uk_55 + 33474540*uk_56 + 504907645*uk_57 + 627647625*uk_58 + 172951790*uk_59 + 181*uk_6 + 77143599*uk_60 + 122638542*uk_61 + 23736492*uk_62 + 358025421*uk_63 + 445059225*uk_64 + 122638542*uk_65 + 194963836*uk_66 + 37734936*uk_67 + 569168618*uk_68 + 707530050*uk_69 + 225*uk_7 + 194963836*uk_70 + 7303536*uk_71 + 110161668*uk_72 + 136941300*uk_73 + 37734936*uk_74 + 1661605159*uk_75 + 2065531275*uk_76 + 569168618*uk_77 + 2567649375*uk_78 + 707530050*uk_79 + 62*uk_8 + 194963836*uk_80 + 166375*uk_81 + 117975*uk_82 + 187550*uk_83 + 36300*uk_84 + 547525*uk_85 + 680625*uk_86 + 187550*uk_87 + 83655*uk_88 + 132990*uk_89 + 2572416961*uk_9 + 25740*uk_90 + 388245*uk_91 + 482625*uk_92 + 132990*uk_93 + 211420*uk_94 + 40920*uk_95 + 617210*uk_96 + 767250*uk_97 + 211420*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 120780*uk_100 + 148500*uk_101 + 25740*uk_102 + 1841895*uk_103 + 2264625*uk_104 + 392535*uk_105 + 2784375*uk_106 + 482625*uk_107 + 83655*uk_108 + 21952*uk_109 + 1420132*uk_11 + 30576*uk_110 + 9408*uk_111 + 143472*uk_112 + 176400*uk_113 + 30576*uk_114 + 42588*uk_115 + 13104*uk_116 + 199836*uk_117 + 245700*uk_118 + 42588*uk_119 + 1978041*uk_12 + 4032*uk_120 + 61488*uk_121 + 75600*uk_122 + 13104*uk_123 + 937692*uk_124 + 1152900*uk_125 + 199836*uk_126 + 1417500*uk_127 + 245700*uk_128 + 42588*uk_129 + 608628*uk_13 + 59319*uk_130 + 18252*uk_131 + 278343*uk_132 + 342225*uk_133 + 59319*uk_134 + 5616*uk_135 + 85644*uk_136 + 105300*uk_137 + 18252*uk_138 + 1306071*uk_139 + 9281577*uk_14 + 1605825*uk_140 + 278343*uk_141 + 1974375*uk_142 + 342225*uk_143 + 59319*uk_144 + 1728*uk_145 + 26352*uk_146 + 32400*uk_147 + 5616*uk_148 + 401868*uk_149 + 11411775*uk_15 + 494100*uk_150 + 85644*uk_151 + 607500*uk_152 + 105300*uk_153 + 18252*uk_154 + 6128487*uk_155 + 7535025*uk_156 + 1306071*uk_157 + 9264375*uk_158 + 1605825*uk_159 + 1978041*uk_16 + 278343*uk_160 + 11390625*uk_161 + 1974375*uk_162 + 342225*uk_163 + 59319*uk_164 + 3025*uk_17 + 1540*uk_18 + 2145*uk_19 + 55*uk_2 + 660*uk_20 + 10065*uk_21 + 12375*uk_22 + 2145*uk_23 + 784*uk_24 + 1092*uk_25 + 336*uk_26 + 5124*uk_27 + 6300*uk_28 + 1092*uk_29 + 28*uk_3 + 1521*uk_30 + 468*uk_31 + 7137*uk_32 + 8775*uk_33 + 1521*uk_34 + 144*uk_35 + 2196*uk_36 + 2700*uk_37 + 468*uk_38 + 33489*uk_39 + 39*uk_4 + 41175*uk_40 + 7137*uk_41 + 50625*uk_42 + 8775*uk_43 + 1521*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 72027674908*uk_47 + 100324261479*uk_48 + 30869003532*uk_49 + 12*uk_5 + 470752303863*uk_50 + 578793816225*uk_51 + 100324261479*uk_52 + 153424975*uk_53 + 78107260*uk_54 + 108792255*uk_55 + 33474540*uk_56 + 510486735*uk_57 + 627647625*uk_58 + 108792255*uk_59 + 183*uk_6 + 39763696*uk_60 + 55385148*uk_61 + 17041584*uk_62 + 259884156*uk_63 + 319529700*uk_64 + 55385148*uk_65 + 77143599*uk_66 + 23736492*uk_67 + 361981503*uk_68 + 445059225*uk_69 + 225*uk_7 + 77143599*uk_70 + 7303536*uk_71 + 111378924*uk_72 + 136941300*uk_73 + 23736492*uk_74 + 1698528591*uk_75 + 2088354825*uk_76 + 361981503*uk_77 + 2567649375*uk_78 + 445059225*uk_79 + 39*uk_8 + 77143599*uk_80 + 166375*uk_81 + 84700*uk_82 + 117975*uk_83 + 36300*uk_84 + 553575*uk_85 + 680625*uk_86 + 117975*uk_87 + 43120*uk_88 + 60060*uk_89 + 2572416961*uk_9 + 18480*uk_90 + 281820*uk_91 + 346500*uk_92 + 60060*uk_93 + 83655*uk_94 + 25740*uk_95 + 392535*uk_96 + 482625*uk_97 + 83655*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 122100*uk_100 + 148500*uk_101 + 18480*uk_102 + 1882375*uk_103 + 2289375*uk_104 + 284900*uk_105 + 2784375*uk_106 + 346500*uk_107 + 43120*uk_108 + 24389*uk_109 + 1470851*uk_11 + 23548*uk_110 + 10092*uk_111 + 155585*uk_112 + 189225*uk_113 + 23548*uk_114 + 22736*uk_115 + 9744*uk_116 + 150220*uk_117 + 182700*uk_118 + 22736*uk_119 + 1420132*uk_12 + 4176*uk_120 + 64380*uk_121 + 78300*uk_122 + 9744*uk_123 + 992525*uk_124 + 1207125*uk_125 + 150220*uk_126 + 1468125*uk_127 + 182700*uk_128 + 22736*uk_129 + 608628*uk_13 + 21952*uk_130 + 9408*uk_131 + 145040*uk_132 + 176400*uk_133 + 21952*uk_134 + 4032*uk_135 + 62160*uk_136 + 75600*uk_137 + 9408*uk_138 + 958300*uk_139 + 9383015*uk_14 + 1165500*uk_140 + 145040*uk_141 + 1417500*uk_142 + 176400*uk_143 + 21952*uk_144 + 1728*uk_145 + 26640*uk_146 + 32400*uk_147 + 4032*uk_148 + 410700*uk_149 + 11411775*uk_15 + 499500*uk_150 + 62160*uk_151 + 607500*uk_152 + 75600*uk_153 + 9408*uk_154 + 6331625*uk_155 + 7700625*uk_156 + 958300*uk_157 + 9365625*uk_158 + 1165500*uk_159 + 1420132*uk_16 + 145040*uk_160 + 11390625*uk_161 + 1417500*uk_162 + 176400*uk_163 + 21952*uk_164 + 3025*uk_17 + 1595*uk_18 + 1540*uk_19 + 55*uk_2 + 660*uk_20 + 10175*uk_21 + 12375*uk_22 + 1540*uk_23 + 841*uk_24 + 812*uk_25 + 348*uk_26 + 5365*uk_27 + 6525*uk_28 + 812*uk_29 + 29*uk_3 + 784*uk_30 + 336*uk_31 + 5180*uk_32 + 6300*uk_33 + 784*uk_34 + 144*uk_35 + 2220*uk_36 + 2700*uk_37 + 336*uk_38 + 34225*uk_39 + 28*uk_4 + 41625*uk_40 + 5180*uk_41 + 50625*uk_42 + 6300*uk_43 + 784*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 74600091869*uk_47 + 72027674908*uk_48 + 30869003532*uk_49 + 12*uk_5 + 475897137785*uk_50 + 578793816225*uk_51 + 72027674908*uk_52 + 153424975*uk_53 + 80896805*uk_54 + 78107260*uk_55 + 33474540*uk_56 + 516065825*uk_57 + 627647625*uk_58 + 78107260*uk_59 + 185*uk_6 + 42654679*uk_60 + 41183828*uk_61 + 17650212*uk_62 + 272107435*uk_63 + 330941475*uk_64 + 41183828*uk_65 + 39763696*uk_66 + 17041584*uk_67 + 262724420*uk_68 + 319529700*uk_69 + 225*uk_7 + 39763696*uk_70 + 7303536*uk_71 + 112596180*uk_72 + 136941300*uk_73 + 17041584*uk_74 + 1735857775*uk_75 + 2111178375*uk_76 + 262724420*uk_77 + 2567649375*uk_78 + 319529700*uk_79 + 28*uk_8 + 39763696*uk_80 + 166375*uk_81 + 87725*uk_82 + 84700*uk_83 + 36300*uk_84 + 559625*uk_85 + 680625*uk_86 + 84700*uk_87 + 46255*uk_88 + 44660*uk_89 + 2572416961*uk_9 + 19140*uk_90 + 295075*uk_91 + 358875*uk_92 + 44660*uk_93 + 43120*uk_94 + 18480*uk_95 + 284900*uk_96 + 346500*uk_97 + 43120*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 123420*uk_100 + 148500*uk_101 + 19140*uk_102 + 1923295*uk_103 + 2314125*uk_104 + 298265*uk_105 + 2784375*uk_106 + 358875*uk_107 + 46255*uk_108 + 74088*uk_109 + 2130198*uk_11 + 51156*uk_110 + 21168*uk_111 + 329868*uk_112 + 396900*uk_113 + 51156*uk_114 + 35322*uk_115 + 14616*uk_116 + 227766*uk_117 + 274050*uk_118 + 35322*uk_119 + 1470851*uk_12 + 6048*uk_120 + 94248*uk_121 + 113400*uk_122 + 14616*uk_123 + 1468698*uk_124 + 1767150*uk_125 + 227766*uk_126 + 2126250*uk_127 + 274050*uk_128 + 35322*uk_129 + 608628*uk_13 + 24389*uk_130 + 10092*uk_131 + 157267*uk_132 + 189225*uk_133 + 24389*uk_134 + 4176*uk_135 + 65076*uk_136 + 78300*uk_137 + 10092*uk_138 + 1014101*uk_139 + 9484453*uk_14 + 1220175*uk_140 + 157267*uk_141 + 1468125*uk_142 + 189225*uk_143 + 24389*uk_144 + 1728*uk_145 + 26928*uk_146 + 32400*uk_147 + 4176*uk_148 + 419628*uk_149 + 11411775*uk_15 + 504900*uk_150 + 65076*uk_151 + 607500*uk_152 + 78300*uk_153 + 10092*uk_154 + 6539203*uk_155 + 7868025*uk_156 + 1014101*uk_157 + 9466875*uk_158 + 1220175*uk_159 + 1470851*uk_16 + 157267*uk_160 + 11390625*uk_161 + 1468125*uk_162 + 189225*uk_163 + 24389*uk_164 + 3025*uk_17 + 2310*uk_18 + 1595*uk_19 + 55*uk_2 + 660*uk_20 + 10285*uk_21 + 12375*uk_22 + 1595*uk_23 + 1764*uk_24 + 1218*uk_25 + 504*uk_26 + 7854*uk_27 + 9450*uk_28 + 1218*uk_29 + 42*uk_3 + 841*uk_30 + 348*uk_31 + 5423*uk_32 + 6525*uk_33 + 841*uk_34 + 144*uk_35 + 2244*uk_36 + 2700*uk_37 + 348*uk_38 + 34969*uk_39 + 29*uk_4 + 42075*uk_40 + 5423*uk_41 + 50625*uk_42 + 6525*uk_43 + 841*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 108041512362*uk_47 + 74600091869*uk_48 + 30869003532*uk_49 + 12*uk_5 + 481041971707*uk_50 + 578793816225*uk_51 + 74600091869*uk_52 + 153424975*uk_53 + 117160890*uk_54 + 80896805*uk_55 + 33474540*uk_56 + 521644915*uk_57 + 627647625*uk_58 + 80896805*uk_59 + 187*uk_6 + 89468316*uk_60 + 61775742*uk_61 + 25562376*uk_62 + 398347026*uk_63 + 479294550*uk_64 + 61775742*uk_65 + 42654679*uk_66 + 17650212*uk_67 + 275049137*uk_68 + 330941475*uk_69 + 225*uk_7 + 42654679*uk_70 + 7303536*uk_71 + 113813436*uk_72 + 136941300*uk_73 + 17650212*uk_74 + 1773592711*uk_75 + 2134001925*uk_76 + 275049137*uk_77 + 2567649375*uk_78 + 330941475*uk_79 + 29*uk_8 + 42654679*uk_80 + 166375*uk_81 + 127050*uk_82 + 87725*uk_83 + 36300*uk_84 + 565675*uk_85 + 680625*uk_86 + 87725*uk_87 + 97020*uk_88 + 66990*uk_89 + 2572416961*uk_9 + 27720*uk_90 + 431970*uk_91 + 519750*uk_92 + 66990*uk_93 + 46255*uk_94 + 19140*uk_95 + 298265*uk_96 + 358875*uk_97 + 46255*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 124740*uk_100 + 148500*uk_101 + 27720*uk_102 + 1964655*uk_103 + 2338875*uk_104 + 436590*uk_105 + 2784375*uk_106 + 519750*uk_107 + 97020*uk_108 + 300763*uk_109 + 3398173*uk_11 + 188538*uk_110 + 53868*uk_111 + 848421*uk_112 + 1010025*uk_113 + 188538*uk_114 + 118188*uk_115 + 33768*uk_116 + 531846*uk_117 + 633150*uk_118 + 118188*uk_119 + 2130198*uk_12 + 9648*uk_120 + 151956*uk_121 + 180900*uk_122 + 33768*uk_123 + 2393307*uk_124 + 2849175*uk_125 + 531846*uk_126 + 3391875*uk_127 + 633150*uk_128 + 118188*uk_129 + 608628*uk_13 + 74088*uk_130 + 21168*uk_131 + 333396*uk_132 + 396900*uk_133 + 74088*uk_134 + 6048*uk_135 + 95256*uk_136 + 113400*uk_137 + 21168*uk_138 + 1500282*uk_139 + 9585891*uk_14 + 1786050*uk_140 + 333396*uk_141 + 2126250*uk_142 + 396900*uk_143 + 74088*uk_144 + 1728*uk_145 + 27216*uk_146 + 32400*uk_147 + 6048*uk_148 + 428652*uk_149 + 11411775*uk_15 + 510300*uk_150 + 95256*uk_151 + 607500*uk_152 + 113400*uk_153 + 21168*uk_154 + 6751269*uk_155 + 8037225*uk_156 + 1500282*uk_157 + 9568125*uk_158 + 1786050*uk_159 + 2130198*uk_16 + 333396*uk_160 + 11390625*uk_161 + 2126250*uk_162 + 396900*uk_163 + 74088*uk_164 + 3025*uk_17 + 3685*uk_18 + 2310*uk_19 + 55*uk_2 + 660*uk_20 + 10395*uk_21 + 12375*uk_22 + 2310*uk_23 + 4489*uk_24 + 2814*uk_25 + 804*uk_26 + 12663*uk_27 + 15075*uk_28 + 2814*uk_29 + 67*uk_3 + 1764*uk_30 + 504*uk_31 + 7938*uk_32 + 9450*uk_33 + 1764*uk_34 + 144*uk_35 + 2268*uk_36 + 2700*uk_37 + 504*uk_38 + 35721*uk_39 + 42*uk_4 + 42525*uk_40 + 7938*uk_41 + 50625*uk_42 + 9450*uk_43 + 1764*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 172351936387*uk_47 + 108041512362*uk_48 + 30869003532*uk_49 + 12*uk_5 + 486186805629*uk_50 + 578793816225*uk_51 + 108041512362*uk_52 + 153424975*uk_53 + 186899515*uk_54 + 117160890*uk_55 + 33474540*uk_56 + 527224005*uk_57 + 627647625*uk_58 + 117160890*uk_59 + 189*uk_6 + 227677591*uk_60 + 142723266*uk_61 + 40778076*uk_62 + 642254697*uk_63 + 764588925*uk_64 + 142723266*uk_65 + 89468316*uk_66 + 25562376*uk_67 + 402607422*uk_68 + 479294550*uk_69 + 225*uk_7 + 89468316*uk_70 + 7303536*uk_71 + 115030692*uk_72 + 136941300*uk_73 + 25562376*uk_74 + 1811733399*uk_75 + 2156825475*uk_76 + 402607422*uk_77 + 2567649375*uk_78 + 479294550*uk_79 + 42*uk_8 + 89468316*uk_80 + 166375*uk_81 + 202675*uk_82 + 127050*uk_83 + 36300*uk_84 + 571725*uk_85 + 680625*uk_86 + 127050*uk_87 + 246895*uk_88 + 154770*uk_89 + 2572416961*uk_9 + 44220*uk_90 + 696465*uk_91 + 829125*uk_92 + 154770*uk_93 + 97020*uk_94 + 27720*uk_95 + 436590*uk_96 + 519750*uk_97 + 97020*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 126060*uk_100 + 148500*uk_101 + 44220*uk_102 + 2006455*uk_103 + 2363625*uk_104 + 703835*uk_105 + 2784375*uk_106 + 829125*uk_107 + 246895*uk_108 + 1124864*uk_109 + 5274776*uk_11 + 724672*uk_110 + 129792*uk_111 + 2065856*uk_112 + 2433600*uk_113 + 724672*uk_114 + 466856*uk_115 + 83616*uk_116 + 1330888*uk_117 + 1567800*uk_118 + 466856*uk_119 + 3398173*uk_12 + 14976*uk_120 + 238368*uk_121 + 280800*uk_122 + 83616*uk_123 + 3794024*uk_124 + 4469400*uk_125 + 1330888*uk_126 + 5265000*uk_127 + 1567800*uk_128 + 466856*uk_129 + 608628*uk_13 + 300763*uk_130 + 53868*uk_131 + 857399*uk_132 + 1010025*uk_133 + 300763*uk_134 + 9648*uk_135 + 153564*uk_136 + 180900*uk_137 + 53868*uk_138 + 2444227*uk_139 + 9687329*uk_14 + 2879325*uk_140 + 857399*uk_141 + 3391875*uk_142 + 1010025*uk_143 + 300763*uk_144 + 1728*uk_145 + 27504*uk_146 + 32400*uk_147 + 9648*uk_148 + 437772*uk_149 + 11411775*uk_15 + 515700*uk_150 + 153564*uk_151 + 607500*uk_152 + 180900*uk_153 + 53868*uk_154 + 6967871*uk_155 + 8208225*uk_156 + 2444227*uk_157 + 9669375*uk_158 + 2879325*uk_159 + 3398173*uk_16 + 857399*uk_160 + 11390625*uk_161 + 3391875*uk_162 + 1010025*uk_163 + 300763*uk_164 + 3025*uk_17 + 5720*uk_18 + 3685*uk_19 + 55*uk_2 + 660*uk_20 + 10505*uk_21 + 12375*uk_22 + 3685*uk_23 + 10816*uk_24 + 6968*uk_25 + 1248*uk_26 + 19864*uk_27 + 23400*uk_28 + 6968*uk_29 + 104*uk_3 + 4489*uk_30 + 804*uk_31 + 12797*uk_32 + 15075*uk_33 + 4489*uk_34 + 144*uk_35 + 2292*uk_36 + 2700*uk_37 + 804*uk_38 + 36481*uk_39 + 67*uk_4 + 42975*uk_40 + 12797*uk_41 + 50625*uk_42 + 15075*uk_43 + 4489*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 267531363944*uk_47 + 172351936387*uk_48 + 30869003532*uk_49 + 12*uk_5 + 491331639551*uk_50 + 578793816225*uk_51 + 172351936387*uk_52 + 153424975*uk_53 + 290112680*uk_54 + 186899515*uk_55 + 33474540*uk_56 + 532803095*uk_57 + 627647625*uk_58 + 186899515*uk_59 + 191*uk_6 + 548576704*uk_60 + 353409992*uk_61 + 63297312*uk_62 + 1007482216*uk_63 + 1186824600*uk_64 + 353409992*uk_65 + 227677591*uk_66 + 40778076*uk_67 + 649051043*uk_68 + 764588925*uk_69 + 225*uk_7 + 227677591*uk_70 + 7303536*uk_71 + 116247948*uk_72 + 136941300*uk_73 + 40778076*uk_74 + 1850279839*uk_75 + 2179649025*uk_76 + 649051043*uk_77 + 2567649375*uk_78 + 764588925*uk_79 + 67*uk_8 + 227677591*uk_80 + 166375*uk_81 + 314600*uk_82 + 202675*uk_83 + 36300*uk_84 + 577775*uk_85 + 680625*uk_86 + 202675*uk_87 + 594880*uk_88 + 383240*uk_89 + 2572416961*uk_9 + 68640*uk_90 + 1092520*uk_91 + 1287000*uk_92 + 383240*uk_93 + 246895*uk_94 + 44220*uk_95 + 703835*uk_96 + 829125*uk_97 + 246895*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 127380*uk_100 + 148500*uk_101 + 68640*uk_102 + 2048695*uk_103 + 2388375*uk_104 + 1103960*uk_105 + 2784375*uk_106 + 1287000*uk_107 + 594880*uk_108 + 3581577*uk_109 + 7760007*uk_11 + 2434536*uk_110 + 280908*uk_111 + 4517937*uk_112 + 5267025*uk_113 + 2434536*uk_114 + 1654848*uk_115 + 190944*uk_116 + 3071016*uk_117 + 3580200*uk_118 + 1654848*uk_119 + 5274776*uk_12 + 22032*uk_120 + 354348*uk_121 + 413100*uk_122 + 190944*uk_123 + 5699097*uk_124 + 6644025*uk_125 + 3071016*uk_126 + 7745625*uk_127 + 3580200*uk_128 + 1654848*uk_129 + 608628*uk_13 + 1124864*uk_130 + 129792*uk_131 + 2087488*uk_132 + 2433600*uk_133 + 1124864*uk_134 + 14976*uk_135 + 240864*uk_136 + 280800*uk_137 + 129792*uk_138 + 3873896*uk_139 + 9788767*uk_14 + 4516200*uk_140 + 2087488*uk_141 + 5265000*uk_142 + 2433600*uk_143 + 1124864*uk_144 + 1728*uk_145 + 27792*uk_146 + 32400*uk_147 + 14976*uk_148 + 446988*uk_149 + 11411775*uk_15 + 521100*uk_150 + 240864*uk_151 + 607500*uk_152 + 280800*uk_153 + 129792*uk_154 + 7189057*uk_155 + 8381025*uk_156 + 3873896*uk_157 + 9770625*uk_158 + 4516200*uk_159 + 5274776*uk_16 + 2087488*uk_160 + 11390625*uk_161 + 5265000*uk_162 + 2433600*uk_163 + 1124864*uk_164 + 3025*uk_17 + 8415*uk_18 + 5720*uk_19 + 55*uk_2 + 660*uk_20 + 10615*uk_21 + 12375*uk_22 + 5720*uk_23 + 23409*uk_24 + 15912*uk_25 + 1836*uk_26 + 29529*uk_27 + 34425*uk_28 + 15912*uk_29 + 153*uk_3 + 10816*uk_30 + 1248*uk_31 + 20072*uk_32 + 23400*uk_33 + 10816*uk_34 + 144*uk_35 + 2316*uk_36 + 2700*uk_37 + 1248*uk_38 + 37249*uk_39 + 104*uk_4 + 43425*uk_40 + 20072*uk_41 + 50625*uk_42 + 23400*uk_43 + 10816*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 393579795033*uk_47 + 267531363944*uk_48 + 30869003532*uk_49 + 12*uk_5 + 496476473473*uk_50 + 578793816225*uk_51 + 267531363944*uk_52 + 153424975*uk_53 + 426800385*uk_54 + 290112680*uk_55 + 33474540*uk_56 + 538382185*uk_57 + 627647625*uk_58 + 290112680*uk_59 + 193*uk_6 + 1187281071*uk_60 + 807040728*uk_61 + 93120084*uk_62 + 1497681351*uk_63 + 1746001575*uk_64 + 807040728*uk_65 + 548576704*uk_66 + 63297312*uk_67 + 1018031768*uk_68 + 1186824600*uk_69 + 225*uk_7 + 548576704*uk_70 + 7303536*uk_71 + 117465204*uk_72 + 136941300*uk_73 + 63297312*uk_74 + 1889232031*uk_75 + 2202472575*uk_76 + 1018031768*uk_77 + 2567649375*uk_78 + 1186824600*uk_79 + 104*uk_8 + 548576704*uk_80 + 166375*uk_81 + 462825*uk_82 + 314600*uk_83 + 36300*uk_84 + 583825*uk_85 + 680625*uk_86 + 314600*uk_87 + 1287495*uk_88 + 875160*uk_89 + 2572416961*uk_9 + 100980*uk_90 + 1624095*uk_91 + 1893375*uk_92 + 875160*uk_93 + 594880*uk_94 + 68640*uk_95 + 1103960*uk_96 + 1287000*uk_97 + 594880*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 85800*uk_100 + 99000*uk_101 + 67320*uk_102 + 2091375*uk_103 + 2413125*uk_104 + 1640925*uk_105 + 2784375*uk_106 + 1893375*uk_107 + 1287495*uk_108 + 6859*uk_109 + 963661*uk_11 + 55233*uk_110 + 2888*uk_111 + 70395*uk_112 + 81225*uk_113 + 55233*uk_114 + 444771*uk_115 + 23256*uk_116 + 566865*uk_117 + 654075*uk_118 + 444771*uk_119 + 7760007*uk_12 + 1216*uk_120 + 29640*uk_121 + 34200*uk_122 + 23256*uk_123 + 722475*uk_124 + 833625*uk_125 + 566865*uk_126 + 961875*uk_127 + 654075*uk_128 + 444771*uk_129 + 405752*uk_13 + 3581577*uk_130 + 187272*uk_131 + 4564755*uk_132 + 5267025*uk_133 + 3581577*uk_134 + 9792*uk_135 + 238680*uk_136 + 275400*uk_137 + 187272*uk_138 + 5817825*uk_139 + 9890205*uk_14 + 6712875*uk_140 + 4564755*uk_141 + 7745625*uk_142 + 5267025*uk_143 + 3581577*uk_144 + 512*uk_145 + 12480*uk_146 + 14400*uk_147 + 9792*uk_148 + 304200*uk_149 + 11411775*uk_15 + 351000*uk_150 + 238680*uk_151 + 405000*uk_152 + 275400*uk_153 + 187272*uk_154 + 7414875*uk_155 + 8555625*uk_156 + 5817825*uk_157 + 9871875*uk_158 + 6712875*uk_159 + 7760007*uk_16 + 4564755*uk_160 + 11390625*uk_161 + 7745625*uk_162 + 5267025*uk_163 + 3581577*uk_164 + 3025*uk_17 + 1045*uk_18 + 8415*uk_19 + 55*uk_2 + 440*uk_20 + 10725*uk_21 + 12375*uk_22 + 8415*uk_23 + 361*uk_24 + 2907*uk_25 + 152*uk_26 + 3705*uk_27 + 4275*uk_28 + 2907*uk_29 + 19*uk_3 + 23409*uk_30 + 1224*uk_31 + 29835*uk_32 + 34425*uk_33 + 23409*uk_34 + 64*uk_35 + 1560*uk_36 + 1800*uk_37 + 1224*uk_38 + 38025*uk_39 + 153*uk_4 + 43875*uk_40 + 29835*uk_41 + 50625*uk_42 + 34425*uk_43 + 23409*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 48875922259*uk_47 + 393579795033*uk_48 + 20579335688*uk_49 + 8*uk_5 + 501621307395*uk_50 + 578793816225*uk_51 + 393579795033*uk_52 + 153424975*uk_53 + 53001355*uk_54 + 426800385*uk_55 + 22316360*uk_56 + 543961275*uk_57 + 627647625*uk_58 + 426800385*uk_59 + 195*uk_6 + 18309559*uk_60 + 147440133*uk_61 + 7709288*uk_62 + 187913895*uk_63 + 216823725*uk_64 + 147440133*uk_65 + 1187281071*uk_66 + 62080056*uk_67 + 1513201365*uk_68 + 1746001575*uk_69 + 225*uk_7 + 1187281071*uk_70 + 3246016*uk_71 + 79121640*uk_72 + 91294200*uk_73 + 62080056*uk_74 + 1928589975*uk_75 + 2225296125*uk_76 + 1513201365*uk_77 + 2567649375*uk_78 + 1746001575*uk_79 + 153*uk_8 + 1187281071*uk_80 + 166375*uk_81 + 57475*uk_82 + 462825*uk_83 + 24200*uk_84 + 589875*uk_85 + 680625*uk_86 + 462825*uk_87 + 19855*uk_88 + 159885*uk_89 + 2572416961*uk_9 + 8360*uk_90 + 203775*uk_91 + 235125*uk_92 + 159885*uk_93 + 1287495*uk_94 + 67320*uk_95 + 1640925*uk_96 + 1893375*uk_97 + 1287495*uk_98 + 3520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 130020*uk_100 + 148500*uk_101 + 12540*uk_102 + 2134495*uk_103 + 2437875*uk_104 + 205865*uk_105 + 2784375*uk_106 + 235125*uk_107 + 19855*uk_108 + 729000*uk_109 + 4564710*uk_11 + 153900*uk_110 + 97200*uk_111 + 1595700*uk_112 + 1822500*uk_113 + 153900*uk_114 + 32490*uk_115 + 20520*uk_116 + 336870*uk_117 + 384750*uk_118 + 32490*uk_119 + 963661*uk_12 + 12960*uk_120 + 212760*uk_121 + 243000*uk_122 + 20520*uk_123 + 3492810*uk_124 + 3989250*uk_125 + 336870*uk_126 + 4556250*uk_127 + 384750*uk_128 + 32490*uk_129 + 608628*uk_13 + 6859*uk_130 + 4332*uk_131 + 71117*uk_132 + 81225*uk_133 + 6859*uk_134 + 2736*uk_135 + 44916*uk_136 + 51300*uk_137 + 4332*uk_138 + 737371*uk_139 + 9991643*uk_14 + 842175*uk_140 + 71117*uk_141 + 961875*uk_142 + 81225*uk_143 + 6859*uk_144 + 1728*uk_145 + 28368*uk_146 + 32400*uk_147 + 2736*uk_148 + 465708*uk_149 + 11411775*uk_15 + 531900*uk_150 + 44916*uk_151 + 607500*uk_152 + 51300*uk_153 + 4332*uk_154 + 7645373*uk_155 + 8732025*uk_156 + 737371*uk_157 + 9973125*uk_158 + 842175*uk_159 + 963661*uk_16 + 71117*uk_160 + 11390625*uk_161 + 961875*uk_162 + 81225*uk_163 + 6859*uk_164 + 3025*uk_17 + 4950*uk_18 + 1045*uk_19 + 55*uk_2 + 660*uk_20 + 10835*uk_21 + 12375*uk_22 + 1045*uk_23 + 8100*uk_24 + 1710*uk_25 + 1080*uk_26 + 17730*uk_27 + 20250*uk_28 + 1710*uk_29 + 90*uk_3 + 361*uk_30 + 228*uk_31 + 3743*uk_32 + 4275*uk_33 + 361*uk_34 + 144*uk_35 + 2364*uk_36 + 2700*uk_37 + 228*uk_38 + 38809*uk_39 + 19*uk_4 + 44325*uk_40 + 3743*uk_41 + 50625*uk_42 + 4275*uk_43 + 361*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 231517526490*uk_47 + 48875922259*uk_48 + 30869003532*uk_49 + 12*uk_5 + 506766141317*uk_50 + 578793816225*uk_51 + 48875922259*uk_52 + 153424975*uk_53 + 251059050*uk_54 + 53001355*uk_55 + 33474540*uk_56 + 549540365*uk_57 + 627647625*uk_58 + 53001355*uk_59 + 197*uk_6 + 410823900*uk_60 + 86729490*uk_61 + 54776520*uk_62 + 899247870*uk_63 + 1027059750*uk_64 + 86729490*uk_65 + 18309559*uk_66 + 11563932*uk_67 + 189841217*uk_68 + 216823725*uk_69 + 225*uk_7 + 18309559*uk_70 + 7303536*uk_71 + 119899716*uk_72 + 136941300*uk_73 + 11563932*uk_74 + 1968353671*uk_75 + 2248119675*uk_76 + 189841217*uk_77 + 2567649375*uk_78 + 216823725*uk_79 + 19*uk_8 + 18309559*uk_80 + 166375*uk_81 + 272250*uk_82 + 57475*uk_83 + 36300*uk_84 + 595925*uk_85 + 680625*uk_86 + 57475*uk_87 + 445500*uk_88 + 94050*uk_89 + 2572416961*uk_9 + 59400*uk_90 + 975150*uk_91 + 1113750*uk_92 + 94050*uk_93 + 19855*uk_94 + 12540*uk_95 + 205865*uk_96 + 235125*uk_97 + 19855*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 131340*uk_100 + 148500*uk_101 + 59400*uk_102 + 2178055*uk_103 + 2462625*uk_104 + 985050*uk_105 + 2784375*uk_106 + 1113750*uk_107 + 445500*uk_108 + 5177717*uk_109 + 8774387*uk_11 + 2693610*uk_110 + 359148*uk_111 + 5955871*uk_112 + 6734025*uk_113 + 2693610*uk_114 + 1401300*uk_115 + 186840*uk_116 + 3098430*uk_117 + 3503250*uk_118 + 1401300*uk_119 + 4564710*uk_12 + 24912*uk_120 + 413124*uk_121 + 467100*uk_122 + 186840*uk_123 + 6850973*uk_124 + 7746075*uk_125 + 3098430*uk_126 + 8758125*uk_127 + 3503250*uk_128 + 1401300*uk_129 + 608628*uk_13 + 729000*uk_130 + 97200*uk_131 + 1611900*uk_132 + 1822500*uk_133 + 729000*uk_134 + 12960*uk_135 + 214920*uk_136 + 243000*uk_137 + 97200*uk_138 + 3564090*uk_139 + 10093081*uk_14 + 4029750*uk_140 + 1611900*uk_141 + 4556250*uk_142 + 1822500*uk_143 + 729000*uk_144 + 1728*uk_145 + 28656*uk_146 + 32400*uk_147 + 12960*uk_148 + 475212*uk_149 + 11411775*uk_15 + 537300*uk_150 + 214920*uk_151 + 607500*uk_152 + 243000*uk_153 + 97200*uk_154 + 7880599*uk_155 + 8910225*uk_156 + 3564090*uk_157 + 10074375*uk_158 + 4029750*uk_159 + 4564710*uk_16 + 1611900*uk_160 + 11390625*uk_161 + 4556250*uk_162 + 1822500*uk_163 + 729000*uk_164 + 3025*uk_17 + 9515*uk_18 + 4950*uk_19 + 55*uk_2 + 660*uk_20 + 10945*uk_21 + 12375*uk_22 + 4950*uk_23 + 29929*uk_24 + 15570*uk_25 + 2076*uk_26 + 34427*uk_27 + 38925*uk_28 + 15570*uk_29 + 173*uk_3 + 8100*uk_30 + 1080*uk_31 + 17910*uk_32 + 20250*uk_33 + 8100*uk_34 + 144*uk_35 + 2388*uk_36 + 2700*uk_37 + 1080*uk_38 + 39601*uk_39 + 90*uk_4 + 44775*uk_40 + 17910*uk_41 + 50625*uk_42 + 20250*uk_43 + 8100*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 445028134253*uk_47 + 231517526490*uk_48 + 30869003532*uk_49 + 12*uk_5 + 511910975239*uk_50 + 578793816225*uk_51 + 231517526490*uk_52 + 153424975*uk_53 + 482591285*uk_54 + 251059050*uk_55 + 33474540*uk_56 + 555119455*uk_57 + 627647625*uk_58 + 251059050*uk_59 + 199*uk_6 + 1517968951*uk_60 + 789694830*uk_61 + 105292644*uk_62 + 1746103013*uk_63 + 1974237075*uk_64 + 789694830*uk_65 + 410823900*uk_66 + 54776520*uk_67 + 908377290*uk_68 + 1027059750*uk_69 + 225*uk_7 + 410823900*uk_70 + 7303536*uk_71 + 121116972*uk_72 + 136941300*uk_73 + 54776520*uk_74 + 2008523119*uk_75 + 2270943225*uk_76 + 908377290*uk_77 + 2567649375*uk_78 + 1027059750*uk_79 + 90*uk_8 + 410823900*uk_80 + 166375*uk_81 + 523325*uk_82 + 272250*uk_83 + 36300*uk_84 + 601975*uk_85 + 680625*uk_86 + 272250*uk_87 + 1646095*uk_88 + 856350*uk_89 + 2572416961*uk_9 + 114180*uk_90 + 1893485*uk_91 + 2140875*uk_92 + 856350*uk_93 + 445500*uk_94 + 59400*uk_95 + 985050*uk_96 + 1113750*uk_97 + 445500*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 88440*uk_100 + 99000*uk_101 + 76120*uk_102 + 2222055*uk_103 + 2487375*uk_104 + 1912515*uk_105 + 2784375*uk_106 + 2140875*uk_107 + 1646095*uk_108 + 300763*uk_109 + 3398173*uk_11 + 776597*uk_110 + 35912*uk_111 + 902289*uk_112 + 1010025*uk_113 + 776597*uk_114 + 2005243*uk_115 + 92728*uk_116 + 2329791*uk_117 + 2607975*uk_118 + 2005243*uk_119 + 8774387*uk_12 + 4288*uk_120 + 107736*uk_121 + 120600*uk_122 + 92728*uk_123 + 2706867*uk_124 + 3030075*uk_125 + 2329791*uk_126 + 3391875*uk_127 + 2607975*uk_128 + 2005243*uk_129 + 405752*uk_13 + 5177717*uk_130 + 239432*uk_131 + 6015729*uk_132 + 6734025*uk_133 + 5177717*uk_134 + 11072*uk_135 + 278184*uk_136 + 311400*uk_137 + 239432*uk_138 + 6989373*uk_139 + 10194519*uk_14 + 7823925*uk_140 + 6015729*uk_141 + 8758125*uk_142 + 6734025*uk_143 + 5177717*uk_144 + 512*uk_145 + 12864*uk_146 + 14400*uk_147 + 11072*uk_148 + 323208*uk_149 + 11411775*uk_15 + 361800*uk_150 + 278184*uk_151 + 405000*uk_152 + 311400*uk_153 + 239432*uk_154 + 8120601*uk_155 + 9090225*uk_156 + 6989373*uk_157 + 10175625*uk_158 + 7823925*uk_159 + 8774387*uk_16 + 6015729*uk_160 + 11390625*uk_161 + 8758125*uk_162 + 6734025*uk_163 + 5177717*uk_164 + 3025*uk_17 + 3685*uk_18 + 9515*uk_19 + 55*uk_2 + 440*uk_20 + 11055*uk_21 + 12375*uk_22 + 9515*uk_23 + 4489*uk_24 + 11591*uk_25 + 536*uk_26 + 13467*uk_27 + 15075*uk_28 + 11591*uk_29 + 67*uk_3 + 29929*uk_30 + 1384*uk_31 + 34773*uk_32 + 38925*uk_33 + 29929*uk_34 + 64*uk_35 + 1608*uk_36 + 1800*uk_37 + 1384*uk_38 + 40401*uk_39 + 173*uk_4 + 45225*uk_40 + 34773*uk_41 + 50625*uk_42 + 38925*uk_43 + 29929*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 172351936387*uk_47 + 445028134253*uk_48 + 20579335688*uk_49 + 8*uk_5 + 517055809161*uk_50 + 578793816225*uk_51 + 445028134253*uk_52 + 153424975*uk_53 + 186899515*uk_54 + 482591285*uk_55 + 22316360*uk_56 + 560698545*uk_57 + 627647625*uk_58 + 482591285*uk_59 + 201*uk_6 + 227677591*uk_60 + 587883929*uk_61 + 27185384*uk_62 + 683032773*uk_63 + 764588925*uk_64 + 587883929*uk_65 + 1517968951*uk_66 + 70195096*uk_67 + 1763651787*uk_68 + 1974237075*uk_69 + 225*uk_7 + 1517968951*uk_70 + 3246016*uk_71 + 81556152*uk_72 + 91294200*uk_73 + 70195096*uk_74 + 2049098319*uk_75 + 2293766775*uk_76 + 1763651787*uk_77 + 2567649375*uk_78 + 1974237075*uk_79 + 173*uk_8 + 1517968951*uk_80 + 166375*uk_81 + 202675*uk_82 + 523325*uk_83 + 24200*uk_84 + 608025*uk_85 + 680625*uk_86 + 523325*uk_87 + 246895*uk_88 + 637505*uk_89 + 2572416961*uk_9 + 29480*uk_90 + 740685*uk_91 + 829125*uk_92 + 637505*uk_93 + 1646095*uk_94 + 76120*uk_95 + 1912515*uk_96 + 2140875*uk_97 + 1646095*uk_98 + 3520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 133980*uk_100 + 148500*uk_101 + 44220*uk_102 + 2266495*uk_103 + 2512125*uk_104 + 748055*uk_105 + 2784375*uk_106 + 829125*uk_107 + 246895*uk_108 + 5088448*uk_109 + 8723668*uk_11 + 1982128*uk_110 + 355008*uk_111 + 6005552*uk_112 + 6656400*uk_113 + 1982128*uk_114 + 772108*uk_115 + 138288*uk_116 + 2339372*uk_117 + 2592900*uk_118 + 772108*uk_119 + 3398173*uk_12 + 24768*uk_120 + 418992*uk_121 + 464400*uk_122 + 138288*uk_123 + 7087948*uk_124 + 7856100*uk_125 + 2339372*uk_126 + 8707500*uk_127 + 2592900*uk_128 + 772108*uk_129 + 608628*uk_13 + 300763*uk_130 + 53868*uk_131 + 911267*uk_132 + 1010025*uk_133 + 300763*uk_134 + 9648*uk_135 + 163212*uk_136 + 180900*uk_137 + 53868*uk_138 + 2761003*uk_139 + 10295957*uk_14 + 3060225*uk_140 + 911267*uk_141 + 3391875*uk_142 + 1010025*uk_143 + 300763*uk_144 + 1728*uk_145 + 29232*uk_146 + 32400*uk_147 + 9648*uk_148 + 494508*uk_149 + 11411775*uk_15 + 548100*uk_150 + 163212*uk_151 + 607500*uk_152 + 180900*uk_153 + 53868*uk_154 + 8365427*uk_155 + 9272025*uk_156 + 2761003*uk_157 + 10276875*uk_158 + 3060225*uk_159 + 3398173*uk_16 + 911267*uk_160 + 11390625*uk_161 + 3391875*uk_162 + 1010025*uk_163 + 300763*uk_164 + 3025*uk_17 + 9460*uk_18 + 3685*uk_19 + 55*uk_2 + 660*uk_20 + 11165*uk_21 + 12375*uk_22 + 3685*uk_23 + 29584*uk_24 + 11524*uk_25 + 2064*uk_26 + 34916*uk_27 + 38700*uk_28 + 11524*uk_29 + 172*uk_3 + 4489*uk_30 + 804*uk_31 + 13601*uk_32 + 15075*uk_33 + 4489*uk_34 + 144*uk_35 + 2436*uk_36 + 2700*uk_37 + 804*uk_38 + 41209*uk_39 + 67*uk_4 + 45675*uk_40 + 13601*uk_41 + 50625*uk_42 + 15075*uk_43 + 4489*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 442455717292*uk_47 + 172351936387*uk_48 + 30869003532*uk_49 + 12*uk_5 + 522200643083*uk_50 + 578793816225*uk_51 + 172351936387*uk_52 + 153424975*uk_53 + 479801740*uk_54 + 186899515*uk_55 + 33474540*uk_56 + 566277635*uk_57 + 627647625*uk_58 + 186899515*uk_59 + 203*uk_6 + 1500470896*uk_60 + 584485756*uk_61 + 104684016*uk_62 + 1770904604*uk_63 + 1962825300*uk_64 + 584485756*uk_65 + 227677591*uk_66 + 40778076*uk_67 + 689829119*uk_68 + 764588925*uk_69 + 225*uk_7 + 227677591*uk_70 + 7303536*uk_71 + 123551484*uk_72 + 136941300*uk_73 + 40778076*uk_74 + 2090079271*uk_75 + 2316590325*uk_76 + 689829119*uk_77 + 2567649375*uk_78 + 764588925*uk_79 + 67*uk_8 + 227677591*uk_80 + 166375*uk_81 + 520300*uk_82 + 202675*uk_83 + 36300*uk_84 + 614075*uk_85 + 680625*uk_86 + 202675*uk_87 + 1627120*uk_88 + 633820*uk_89 + 2572416961*uk_9 + 113520*uk_90 + 1920380*uk_91 + 2128500*uk_92 + 633820*uk_93 + 246895*uk_94 + 44220*uk_95 + 748055*uk_96 + 829125*uk_97 + 246895*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 90200*uk_100 + 99000*uk_101 + 75680*uk_102 + 2311375*uk_103 + 2536875*uk_104 + 1939300*uk_105 + 2784375*uk_106 + 2128500*uk_107 + 1627120*uk_108 + 592704*uk_109 + 4260396*uk_11 + 1213632*uk_110 + 56448*uk_111 + 1446480*uk_112 + 1587600*uk_113 + 1213632*uk_114 + 2485056*uk_115 + 115584*uk_116 + 2961840*uk_117 + 3250800*uk_118 + 2485056*uk_119 + 8723668*uk_12 + 5376*uk_120 + 137760*uk_121 + 151200*uk_122 + 115584*uk_123 + 3530100*uk_124 + 3874500*uk_125 + 2961840*uk_126 + 4252500*uk_127 + 3250800*uk_128 + 2485056*uk_129 + 405752*uk_13 + 5088448*uk_130 + 236672*uk_131 + 6064720*uk_132 + 6656400*uk_133 + 5088448*uk_134 + 11008*uk_135 + 282080*uk_136 + 309600*uk_137 + 236672*uk_138 + 7228300*uk_139 + 10397395*uk_14 + 7933500*uk_140 + 6064720*uk_141 + 8707500*uk_142 + 6656400*uk_143 + 5088448*uk_144 + 512*uk_145 + 13120*uk_146 + 14400*uk_147 + 11008*uk_148 + 336200*uk_149 + 11411775*uk_15 + 369000*uk_150 + 282080*uk_151 + 405000*uk_152 + 309600*uk_153 + 236672*uk_154 + 8615125*uk_155 + 9455625*uk_156 + 7228300*uk_157 + 10378125*uk_158 + 7933500*uk_159 + 8723668*uk_16 + 6064720*uk_160 + 11390625*uk_161 + 8707500*uk_162 + 6656400*uk_163 + 5088448*uk_164 + 3025*uk_17 + 4620*uk_18 + 9460*uk_19 + 55*uk_2 + 440*uk_20 + 11275*uk_21 + 12375*uk_22 + 9460*uk_23 + 7056*uk_24 + 14448*uk_25 + 672*uk_26 + 17220*uk_27 + 18900*uk_28 + 14448*uk_29 + 84*uk_3 + 29584*uk_30 + 1376*uk_31 + 35260*uk_32 + 38700*uk_33 + 29584*uk_34 + 64*uk_35 + 1640*uk_36 + 1800*uk_37 + 1376*uk_38 + 42025*uk_39 + 172*uk_4 + 46125*uk_40 + 35260*uk_41 + 50625*uk_42 + 38700*uk_43 + 29584*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 216083024724*uk_47 + 442455717292*uk_48 + 20579335688*uk_49 + 8*uk_5 + 527345477005*uk_50 + 578793816225*uk_51 + 442455717292*uk_52 + 153424975*uk_53 + 234321780*uk_54 + 479801740*uk_55 + 22316360*uk_56 + 571856725*uk_57 + 627647625*uk_58 + 479801740*uk_59 + 205*uk_6 + 357873264*uk_60 + 732788112*uk_61 + 34083168*uk_62 + 873381180*uk_63 + 958589100*uk_64 + 732788112*uk_65 + 1500470896*uk_66 + 69789344*uk_67 + 1788351940*uk_68 + 1962825300*uk_69 + 225*uk_7 + 1500470896*uk_70 + 3246016*uk_71 + 83179160*uk_72 + 91294200*uk_73 + 69789344*uk_74 + 2131465975*uk_75 + 2339413875*uk_76 + 1788351940*uk_77 + 2567649375*uk_78 + 1962825300*uk_79 + 172*uk_8 + 1500470896*uk_80 + 166375*uk_81 + 254100*uk_82 + 520300*uk_83 + 24200*uk_84 + 620125*uk_85 + 680625*uk_86 + 520300*uk_87 + 388080*uk_88 + 794640*uk_89 + 2572416961*uk_9 + 36960*uk_90 + 947100*uk_91 + 1039500*uk_92 + 794640*uk_93 + 1627120*uk_94 + 75680*uk_95 + 1939300*uk_96 + 2128500*uk_97 + 1627120*uk_98 + 3520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 91080*uk_100 + 99000*uk_101 + 36960*uk_102 + 2356695*uk_103 + 2561625*uk_104 + 956340*uk_105 + 2784375*uk_106 + 1039500*uk_107 + 388080*uk_108 + 64*uk_109 + 202876*uk_11 + 1344*uk_110 + 128*uk_111 + 3312*uk_112 + 3600*uk_113 + 1344*uk_114 + 28224*uk_115 + 2688*uk_116 + 69552*uk_117 + 75600*uk_118 + 28224*uk_119 + 4260396*uk_12 + 256*uk_120 + 6624*uk_121 + 7200*uk_122 + 2688*uk_123 + 171396*uk_124 + 186300*uk_125 + 69552*uk_126 + 202500*uk_127 + 75600*uk_128 + 28224*uk_129 + 405752*uk_13 + 592704*uk_130 + 56448*uk_131 + 1460592*uk_132 + 1587600*uk_133 + 592704*uk_134 + 5376*uk_135 + 139104*uk_136 + 151200*uk_137 + 56448*uk_138 + 3599316*uk_139 + 10498833*uk_14 + 3912300*uk_140 + 1460592*uk_141 + 4252500*uk_142 + 1587600*uk_143 + 592704*uk_144 + 512*uk_145 + 13248*uk_146 + 14400*uk_147 + 5376*uk_148 + 342792*uk_149 + 11411775*uk_15 + 372600*uk_150 + 139104*uk_151 + 405000*uk_152 + 151200*uk_153 + 56448*uk_154 + 8869743*uk_155 + 9641025*uk_156 + 3599316*uk_157 + 10479375*uk_158 + 3912300*uk_159 + 4260396*uk_16 + 1460592*uk_160 + 11390625*uk_161 + 4252500*uk_162 + 1587600*uk_163 + 592704*uk_164 + 3025*uk_17 + 220*uk_18 + 4620*uk_19 + 55*uk_2 + 440*uk_20 + 11385*uk_21 + 12375*uk_22 + 4620*uk_23 + 16*uk_24 + 336*uk_25 + 32*uk_26 + 828*uk_27 + 900*uk_28 + 336*uk_29 + 4*uk_3 + 7056*uk_30 + 672*uk_31 + 17388*uk_32 + 18900*uk_33 + 7056*uk_34 + 64*uk_35 + 1656*uk_36 + 1800*uk_37 + 672*uk_38 + 42849*uk_39 + 84*uk_4 + 46575*uk_40 + 17388*uk_41 + 50625*uk_42 + 18900*uk_43 + 7056*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 10289667844*uk_47 + 216083024724*uk_48 + 20579335688*uk_49 + 8*uk_5 + 532490310927*uk_50 + 578793816225*uk_51 + 216083024724*uk_52 + 153424975*uk_53 + 11158180*uk_54 + 234321780*uk_55 + 22316360*uk_56 + 577435815*uk_57 + 627647625*uk_58 + 234321780*uk_59 + 207*uk_6 + 811504*uk_60 + 17041584*uk_61 + 1623008*uk_62 + 41995332*uk_63 + 45647100*uk_64 + 17041584*uk_65 + 357873264*uk_66 + 34083168*uk_67 + 881901972*uk_68 + 958589100*uk_69 + 225*uk_7 + 357873264*uk_70 + 3246016*uk_71 + 83990664*uk_72 + 91294200*uk_73 + 34083168*uk_74 + 2173258431*uk_75 + 2362237425*uk_76 + 881901972*uk_77 + 2567649375*uk_78 + 958589100*uk_79 + 84*uk_8 + 357873264*uk_80 + 166375*uk_81 + 12100*uk_82 + 254100*uk_83 + 24200*uk_84 + 626175*uk_85 + 680625*uk_86 + 254100*uk_87 + 880*uk_88 + 18480*uk_89 + 2572416961*uk_9 + 1760*uk_90 + 45540*uk_91 + 49500*uk_92 + 18480*uk_93 + 388080*uk_94 + 36960*uk_95 + 956340*uk_96 + 1039500*uk_97 + 388080*uk_98 + 3520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 137940*uk_100 + 148500*uk_101 + 2640*uk_102 + 2402455*uk_103 + 2586375*uk_104 + 45980*uk_105 + 2784375*uk_106 + 49500*uk_107 + 880*uk_108 + 2803221*uk_109 + 7151379*uk_11 + 79524*uk_110 + 238572*uk_111 + 4155129*uk_112 + 4473225*uk_113 + 79524*uk_114 + 2256*uk_115 + 6768*uk_116 + 117876*uk_117 + 126900*uk_118 + 2256*uk_119 + 202876*uk_12 + 20304*uk_120 + 353628*uk_121 + 380700*uk_122 + 6768*uk_123 + 6159021*uk_124 + 6630525*uk_125 + 117876*uk_126 + 7138125*uk_127 + 126900*uk_128 + 2256*uk_129 + 608628*uk_13 + 64*uk_130 + 192*uk_131 + 3344*uk_132 + 3600*uk_133 + 64*uk_134 + 576*uk_135 + 10032*uk_136 + 10800*uk_137 + 192*uk_138 + 174724*uk_139 + 10600271*uk_14 + 188100*uk_140 + 3344*uk_141 + 202500*uk_142 + 3600*uk_143 + 64*uk_144 + 1728*uk_145 + 30096*uk_146 + 32400*uk_147 + 576*uk_148 + 524172*uk_149 + 11411775*uk_15 + 564300*uk_150 + 10032*uk_151 + 607500*uk_152 + 10800*uk_153 + 192*uk_154 + 9129329*uk_155 + 9828225*uk_156 + 174724*uk_157 + 10580625*uk_158 + 188100*uk_159 + 202876*uk_16 + 3344*uk_160 + 11390625*uk_161 + 202500*uk_162 + 3600*uk_163 + 64*uk_164 + 3025*uk_17 + 7755*uk_18 + 220*uk_19 + 55*uk_2 + 660*uk_20 + 11495*uk_21 + 12375*uk_22 + 220*uk_23 + 19881*uk_24 + 564*uk_25 + 1692*uk_26 + 29469*uk_27 + 31725*uk_28 + 564*uk_29 + 141*uk_3 + 16*uk_30 + 48*uk_31 + 836*uk_32 + 900*uk_33 + 16*uk_34 + 144*uk_35 + 2508*uk_36 + 2700*uk_37 + 48*uk_38 + 43681*uk_39 + 4*uk_4 + 47025*uk_40 + 836*uk_41 + 50625*uk_42 + 900*uk_43 + 16*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 362710791501*uk_47 + 10289667844*uk_48 + 30869003532*uk_49 + 12*uk_5 + 537635144849*uk_50 + 578793816225*uk_51 + 10289667844*uk_52 + 153424975*uk_53 + 393325845*uk_54 + 11158180*uk_55 + 33474540*uk_56 + 583014905*uk_57 + 627647625*uk_58 + 11158180*uk_59 + 209*uk_6 + 1008344439*uk_60 + 28605516*uk_61 + 85816548*uk_62 + 1494638211*uk_63 + 1609060275*uk_64 + 28605516*uk_65 + 811504*uk_66 + 2434512*uk_67 + 42401084*uk_68 + 45647100*uk_69 + 225*uk_7 + 811504*uk_70 + 7303536*uk_71 + 127203252*uk_72 + 136941300*uk_73 + 2434512*uk_74 + 2215456639*uk_75 + 2385060975*uk_76 + 42401084*uk_77 + 2567649375*uk_78 + 45647100*uk_79 + 4*uk_8 + 811504*uk_80 + 166375*uk_81 + 426525*uk_82 + 12100*uk_83 + 36300*uk_84 + 632225*uk_85 + 680625*uk_86 + 12100*uk_87 + 1093455*uk_88 + 31020*uk_89 + 2572416961*uk_9 + 93060*uk_90 + 1620795*uk_91 + 1744875*uk_92 + 31020*uk_93 + 880*uk_94 + 2640*uk_95 + 45980*uk_96 + 49500*uk_97 + 880*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 92840*uk_100 + 99000*uk_101 + 62040*uk_102 + 2448655*uk_103 + 2611125*uk_104 + 1636305*uk_105 + 2784375*uk_106 + 1744875*uk_107 + 1093455*uk_108 + 493039*uk_109 + 4006801*uk_11 + 879981*uk_110 + 49928*uk_111 + 1316851*uk_112 + 1404225*uk_113 + 879981*uk_114 + 1570599*uk_115 + 89112*uk_116 + 2350329*uk_117 + 2506275*uk_118 + 1570599*uk_119 + 7151379*uk_12 + 5056*uk_120 + 133352*uk_121 + 142200*uk_122 + 89112*uk_123 + 3517159*uk_124 + 3750525*uk_125 + 2350329*uk_126 + 3999375*uk_127 + 2506275*uk_128 + 1570599*uk_129 + 405752*uk_13 + 2803221*uk_130 + 159048*uk_131 + 4194891*uk_132 + 4473225*uk_133 + 2803221*uk_134 + 9024*uk_135 + 238008*uk_136 + 253800*uk_137 + 159048*uk_138 + 6277461*uk_139 + 10701709*uk_14 + 6693975*uk_140 + 4194891*uk_141 + 7138125*uk_142 + 4473225*uk_143 + 2803221*uk_144 + 512*uk_145 + 13504*uk_146 + 14400*uk_147 + 9024*uk_148 + 356168*uk_149 + 11411775*uk_15 + 379800*uk_150 + 238008*uk_151 + 405000*uk_152 + 253800*uk_153 + 159048*uk_154 + 9393931*uk_155 + 10017225*uk_156 + 6277461*uk_157 + 10681875*uk_158 + 6693975*uk_159 + 7151379*uk_16 + 4194891*uk_160 + 11390625*uk_161 + 7138125*uk_162 + 4473225*uk_163 + 2803221*uk_164 + 3025*uk_17 + 4345*uk_18 + 7755*uk_19 + 55*uk_2 + 440*uk_20 + 11605*uk_21 + 12375*uk_22 + 7755*uk_23 + 6241*uk_24 + 11139*uk_25 + 632*uk_26 + 16669*uk_27 + 17775*uk_28 + 11139*uk_29 + 79*uk_3 + 19881*uk_30 + 1128*uk_31 + 29751*uk_32 + 31725*uk_33 + 19881*uk_34 + 64*uk_35 + 1688*uk_36 + 1800*uk_37 + 1128*uk_38 + 44521*uk_39 + 141*uk_4 + 47475*uk_40 + 29751*uk_41 + 50625*uk_42 + 31725*uk_43 + 19881*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 203220939919*uk_47 + 362710791501*uk_48 + 20579335688*uk_49 + 8*uk_5 + 542779978771*uk_50 + 578793816225*uk_51 + 362710791501*uk_52 + 153424975*uk_53 + 220374055*uk_54 + 393325845*uk_55 + 22316360*uk_56 + 588593995*uk_57 + 627647625*uk_58 + 393325845*uk_59 + 211*uk_6 + 316537279*uk_60 + 564958941*uk_61 + 32054408*uk_62 + 845435011*uk_63 + 901530225*uk_64 + 564958941*uk_65 + 1008344439*uk_66 + 57211032*uk_67 + 1508940969*uk_68 + 1609060275*uk_69 + 225*uk_7 + 1008344439*uk_70 + 3246016*uk_71 + 85613672*uk_72 + 91294200*uk_73 + 57211032*uk_74 + 2258060599*uk_75 + 2407884525*uk_76 + 1508940969*uk_77 + 2567649375*uk_78 + 1609060275*uk_79 + 141*uk_8 + 1008344439*uk_80 + 166375*uk_81 + 238975*uk_82 + 426525*uk_83 + 24200*uk_84 + 638275*uk_85 + 680625*uk_86 + 426525*uk_87 + 343255*uk_88 + 612645*uk_89 + 2572416961*uk_9 + 34760*uk_90 + 916795*uk_91 + 977625*uk_92 + 612645*uk_93 + 1093455*uk_94 + 62040*uk_95 + 1636305*uk_96 + 1744875*uk_97 + 1093455*uk_98 + 3520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 93720*uk_100 + 99000*uk_101 + 34760*uk_102 + 2495295*uk_103 + 2635875*uk_104 + 925485*uk_105 + 2784375*uk_106 + 977625*uk_107 + 343255*uk_108 + 15625*uk_109 + 1267975*uk_11 + 49375*uk_110 + 5000*uk_111 + 133125*uk_112 + 140625*uk_113 + 49375*uk_114 + 156025*uk_115 + 15800*uk_116 + 420675*uk_117 + 444375*uk_118 + 156025*uk_119 + 4006801*uk_12 + 1600*uk_120 + 42600*uk_121 + 45000*uk_122 + 15800*uk_123 + 1134225*uk_124 + 1198125*uk_125 + 420675*uk_126 + 1265625*uk_127 + 444375*uk_128 + 156025*uk_129 + 405752*uk_13 + 493039*uk_130 + 49928*uk_131 + 1329333*uk_132 + 1404225*uk_133 + 493039*uk_134 + 5056*uk_135 + 134616*uk_136 + 142200*uk_137 + 49928*uk_138 + 3584151*uk_139 + 10803147*uk_14 + 3786075*uk_140 + 1329333*uk_141 + 3999375*uk_142 + 1404225*uk_143 + 493039*uk_144 + 512*uk_145 + 13632*uk_146 + 14400*uk_147 + 5056*uk_148 + 362952*uk_149 + 11411775*uk_15 + 383400*uk_150 + 134616*uk_151 + 405000*uk_152 + 142200*uk_153 + 49928*uk_154 + 9663597*uk_155 + 10208025*uk_156 + 3584151*uk_157 + 10783125*uk_158 + 3786075*uk_159 + 4006801*uk_16 + 1329333*uk_160 + 11390625*uk_161 + 3999375*uk_162 + 1404225*uk_163 + 493039*uk_164 + 3025*uk_17 + 1375*uk_18 + 4345*uk_19 + 55*uk_2 + 440*uk_20 + 11715*uk_21 + 12375*uk_22 + 4345*uk_23 + 625*uk_24 + 1975*uk_25 + 200*uk_26 + 5325*uk_27 + 5625*uk_28 + 1975*uk_29 + 25*uk_3 + 6241*uk_30 + 632*uk_31 + 16827*uk_32 + 17775*uk_33 + 6241*uk_34 + 64*uk_35 + 1704*uk_36 + 1800*uk_37 + 632*uk_38 + 45369*uk_39 + 79*uk_4 + 47925*uk_40 + 16827*uk_41 + 50625*uk_42 + 17775*uk_43 + 6241*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 64310424025*uk_47 + 203220939919*uk_48 + 20579335688*uk_49 + 8*uk_5 + 547924812693*uk_50 + 578793816225*uk_51 + 203220939919*uk_52 + 153424975*uk_53 + 69738625*uk_54 + 220374055*uk_55 + 22316360*uk_56 + 594173085*uk_57 + 627647625*uk_58 + 220374055*uk_59 + 213*uk_6 + 31699375*uk_60 + 100170025*uk_61 + 10143800*uk_62 + 270078675*uk_63 + 285294375*uk_64 + 100170025*uk_65 + 316537279*uk_66 + 32054408*uk_67 + 853448613*uk_68 + 901530225*uk_69 + 225*uk_7 + 316537279*uk_70 + 3246016*uk_71 + 86425176*uk_72 + 91294200*uk_73 + 32054408*uk_74 + 2301070311*uk_75 + 2430708075*uk_76 + 853448613*uk_77 + 2567649375*uk_78 + 901530225*uk_79 + 79*uk_8 + 316537279*uk_80 + 166375*uk_81 + 75625*uk_82 + 238975*uk_83 + 24200*uk_84 + 644325*uk_85 + 680625*uk_86 + 238975*uk_87 + 34375*uk_88 + 108625*uk_89 + 2572416961*uk_9 + 11000*uk_90 + 292875*uk_91 + 309375*uk_92 + 108625*uk_93 + 343255*uk_94 + 34760*uk_95 + 925485*uk_96 + 977625*uk_97 + 343255*uk_98 + 3520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 141900*uk_100 + 148500*uk_101 + 16500*uk_102 + 2542375*uk_103 + 2660625*uk_104 + 295625*uk_105 + 2784375*uk_106 + 309375*uk_107 + 34375*uk_108 + 7301384*uk_109 + 9839486*uk_11 + 940900*uk_110 + 451632*uk_111 + 8091740*uk_112 + 8468100*uk_113 + 940900*uk_114 + 121250*uk_115 + 58200*uk_116 + 1042750*uk_117 + 1091250*uk_118 + 121250*uk_119 + 1267975*uk_12 + 27936*uk_120 + 500520*uk_121 + 523800*uk_122 + 58200*uk_123 + 8967650*uk_124 + 9384750*uk_125 + 1042750*uk_126 + 9821250*uk_127 + 1091250*uk_128 + 121250*uk_129 + 608628*uk_13 + 15625*uk_130 + 7500*uk_131 + 134375*uk_132 + 140625*uk_133 + 15625*uk_134 + 3600*uk_135 + 64500*uk_136 + 67500*uk_137 + 7500*uk_138 + 1155625*uk_139 + 10904585*uk_14 + 1209375*uk_140 + 134375*uk_141 + 1265625*uk_142 + 140625*uk_143 + 15625*uk_144 + 1728*uk_145 + 30960*uk_146 + 32400*uk_147 + 3600*uk_148 + 554700*uk_149 + 11411775*uk_15 + 580500*uk_150 + 64500*uk_151 + 607500*uk_152 + 67500*uk_153 + 7500*uk_154 + 9938375*uk_155 + 10400625*uk_156 + 1155625*uk_157 + 10884375*uk_158 + 1209375*uk_159 + 1267975*uk_16 + 134375*uk_160 + 11390625*uk_161 + 1265625*uk_162 + 140625*uk_163 + 15625*uk_164 + 3025*uk_17 + 10670*uk_18 + 1375*uk_19 + 55*uk_2 + 660*uk_20 + 11825*uk_21 + 12375*uk_22 + 1375*uk_23 + 37636*uk_24 + 4850*uk_25 + 2328*uk_26 + 41710*uk_27 + 43650*uk_28 + 4850*uk_29 + 194*uk_3 + 625*uk_30 + 300*uk_31 + 5375*uk_32 + 5625*uk_33 + 625*uk_34 + 144*uk_35 + 2580*uk_36 + 2700*uk_37 + 300*uk_38 + 46225*uk_39 + 25*uk_4 + 48375*uk_40 + 5375*uk_41 + 50625*uk_42 + 5625*uk_43 + 625*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 499048890434*uk_47 + 64310424025*uk_48 + 30869003532*uk_49 + 12*uk_5 + 553069646615*uk_50 + 578793816225*uk_51 + 64310424025*uk_52 + 153424975*uk_53 + 541171730*uk_54 + 69738625*uk_55 + 33474540*uk_56 + 599752175*uk_57 + 627647625*uk_58 + 69738625*uk_59 + 215*uk_6 + 1908860284*uk_60 + 245987150*uk_61 + 118073832*uk_62 + 2115489490*uk_63 + 2213884350*uk_64 + 245987150*uk_65 + 31699375*uk_66 + 15215700*uk_67 + 272614625*uk_68 + 285294375*uk_69 + 225*uk_7 + 31699375*uk_70 + 7303536*uk_71 + 130855020*uk_72 + 136941300*uk_73 + 15215700*uk_74 + 2344485775*uk_75 + 2453531625*uk_76 + 272614625*uk_77 + 2567649375*uk_78 + 285294375*uk_79 + 25*uk_8 + 31699375*uk_80 + 166375*uk_81 + 586850*uk_82 + 75625*uk_83 + 36300*uk_84 + 650375*uk_85 + 680625*uk_86 + 75625*uk_87 + 2069980*uk_88 + 266750*uk_89 + 2572416961*uk_9 + 128040*uk_90 + 2294050*uk_91 + 2400750*uk_92 + 266750*uk_93 + 34375*uk_94 + 16500*uk_95 + 295625*uk_96 + 309375*uk_97 + 34375*uk_98 + 7920*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 95480*uk_100 + 99000*uk_101 + 85360*uk_102 + 2589895*uk_103 + 2685375*uk_104 + 2315390*uk_105 + 2784375*uk_106 + 2400750*uk_107 + 2069980*uk_108 + 3944312*uk_109 + 8013602*uk_11 + 4843016*uk_110 + 199712*uk_111 + 5417188*uk_112 + 5616900*uk_113 + 4843016*uk_114 + 5946488*uk_115 + 245216*uk_116 + 6651484*uk_117 + 6896700*uk_118 + 5946488*uk_119 + 9839486*uk_12 + 10112*uk_120 + 274288*uk_121 + 284400*uk_122 + 245216*uk_123 + 7440062*uk_124 + 7714350*uk_125 + 6651484*uk_126 + 7998750*uk_127 + 6896700*uk_128 + 5946488*uk_129 + 405752*uk_13 + 7301384*uk_130 + 301088*uk_131 + 8167012*uk_132 + 8468100*uk_133 + 7301384*uk_134 + 12416*uk_135 + 336784*uk_136 + 349200*uk_137 + 301088*uk_138 + 9135266*uk_139 + 11006023*uk_14 + 9472050*uk_140 + 8167012*uk_141 + 9821250*uk_142 + 8468100*uk_143 + 7301384*uk_144 + 512*uk_145 + 13888*uk_146 + 14400*uk_147 + 12416*uk_148 + 376712*uk_149 + 11411775*uk_15 + 390600*uk_150 + 336784*uk_151 + 405000*uk_152 + 349200*uk_153 + 301088*uk_154 + 10218313*uk_155 + 10595025*uk_156 + 9135266*uk_157 + 10985625*uk_158 + 9472050*uk_159 + 9839486*uk_16 + 8167012*uk_160 + 11390625*uk_161 + 9821250*uk_162 + 8468100*uk_163 + 7301384*uk_164 + 3025*uk_17 + 8690*uk_18 + 10670*uk_19 + 55*uk_2 + 440*uk_20 + 11935*uk_21 + 12375*uk_22 + 10670*uk_23 + 24964*uk_24 + 30652*uk_25 + 1264*uk_26 + 34286*uk_27 + 35550*uk_28 + 30652*uk_29 + 158*uk_3 + 37636*uk_30 + 1552*uk_31 + 42098*uk_32 + 43650*uk_33 + 37636*uk_34 + 64*uk_35 + 1736*uk_36 + 1800*uk_37 + 1552*uk_38 + 47089*uk_39 + 194*uk_4 + 48825*uk_40 + 42098*uk_41 + 50625*uk_42 + 43650*uk_43 + 37636*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 406441879838*uk_47 + 499048890434*uk_48 + 20579335688*uk_49 + 8*uk_5 + 558214480537*uk_50 + 578793816225*uk_51 + 499048890434*uk_52 + 153424975*uk_53 + 440748110*uk_54 + 541171730*uk_55 + 22316360*uk_56 + 605331265*uk_57 + 627647625*uk_58 + 541171730*uk_59 + 217*uk_6 + 1266149116*uk_60 + 1554638788*uk_61 + 64108816*uk_62 + 1738951634*uk_63 + 1803060450*uk_64 + 1554638788*uk_65 + 1908860284*uk_66 + 78715888*uk_67 + 2135168462*uk_68 + 2213884350*uk_69 + 225*uk_7 + 1908860284*uk_70 + 3246016*uk_71 + 88048184*uk_72 + 91294200*uk_73 + 78715888*uk_74 + 2388306991*uk_75 + 2476355175*uk_76 + 2135168462*uk_77 + 2567649375*uk_78 + 2213884350*uk_79 + 194*uk_8 + 1908860284*uk_80 + 166375*uk_81 + 477950*uk_82 + 586850*uk_83 + 24200*uk_84 + 656425*uk_85 + 680625*uk_86 + 586850*uk_87 + 1373020*uk_88 + 1685860*uk_89 + 2572416961*uk_9 + 69520*uk_90 + 1885730*uk_91 + 1955250*uk_92 + 1685860*uk_93 + 2069980*uk_94 + 85360*uk_95 + 2315390*uk_96 + 2400750*uk_97 + 2069980*uk_98 + 3520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 96360*uk_100 + 99000*uk_101 + 69520*uk_102 + 2637855*uk_103 + 2710125*uk_104 + 1903110*uk_105 + 2784375*uk_106 + 1955250*uk_107 + 1373020*uk_108 + 2197000*uk_109 + 6593470*uk_11 + 2670200*uk_110 + 135200*uk_111 + 3701100*uk_112 + 3802500*uk_113 + 2670200*uk_114 + 3245320*uk_115 + 164320*uk_116 + 4498260*uk_117 + 4621500*uk_118 + 3245320*uk_119 + 8013602*uk_12 + 8320*uk_120 + 227760*uk_121 + 234000*uk_122 + 164320*uk_123 + 6234930*uk_124 + 6405750*uk_125 + 4498260*uk_126 + 6581250*uk_127 + 4621500*uk_128 + 3245320*uk_129 + 405752*uk_13 + 3944312*uk_130 + 199712*uk_131 + 5467116*uk_132 + 5616900*uk_133 + 3944312*uk_134 + 10112*uk_135 + 276816*uk_136 + 284400*uk_137 + 199712*uk_138 + 7577838*uk_139 + 11107461*uk_14 + 7785450*uk_140 + 5467116*uk_141 + 7998750*uk_142 + 5616900*uk_143 + 3944312*uk_144 + 512*uk_145 + 14016*uk_146 + 14400*uk_147 + 10112*uk_148 + 383688*uk_149 + 11411775*uk_15 + 394200*uk_150 + 276816*uk_151 + 405000*uk_152 + 284400*uk_153 + 199712*uk_154 + 10503459*uk_155 + 10791225*uk_156 + 7577838*uk_157 + 11086875*uk_158 + 7785450*uk_159 + 8013602*uk_16 + 5467116*uk_160 + 11390625*uk_161 + 7998750*uk_162 + 5616900*uk_163 + 3944312*uk_164 + 3025*uk_17 + 7150*uk_18 + 8690*uk_19 + 55*uk_2 + 440*uk_20 + 12045*uk_21 + 12375*uk_22 + 8690*uk_23 + 16900*uk_24 + 20540*uk_25 + 1040*uk_26 + 28470*uk_27 + 29250*uk_28 + 20540*uk_29 + 130*uk_3 + 24964*uk_30 + 1264*uk_31 + 34602*uk_32 + 35550*uk_33 + 24964*uk_34 + 64*uk_35 + 1752*uk_36 + 1800*uk_37 + 1264*uk_38 + 47961*uk_39 + 158*uk_4 + 49275*uk_40 + 34602*uk_41 + 50625*uk_42 + 35550*uk_43 + 24964*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 334414204930*uk_47 + 406441879838*uk_48 + 20579335688*uk_49 + 8*uk_5 + 563359314459*uk_50 + 578793816225*uk_51 + 406441879838*uk_52 + 153424975*uk_53 + 362640850*uk_54 + 440748110*uk_55 + 22316360*uk_56 + 610910355*uk_57 + 627647625*uk_58 + 440748110*uk_59 + 219*uk_6 + 857151100*uk_60 + 1041768260*uk_61 + 52747760*uk_62 + 1443969930*uk_63 + 1483530750*uk_64 + 1041768260*uk_65 + 1266149116*uk_66 + 64108816*uk_67 + 1754978838*uk_68 + 1803060450*uk_69 + 225*uk_7 + 1266149116*uk_70 + 3246016*uk_71 + 88859688*uk_72 + 91294200*uk_73 + 64108816*uk_74 + 2432533959*uk_75 + 2499178725*uk_76 + 1754978838*uk_77 + 2567649375*uk_78 + 1803060450*uk_79 + 158*uk_8 + 1266149116*uk_80 + 166375*uk_81 + 393250*uk_82 + 477950*uk_83 + 24200*uk_84 + 662475*uk_85 + 680625*uk_86 + 477950*uk_87 + 929500*uk_88 + 1129700*uk_89 + 2572416961*uk_9 + 57200*uk_90 + 1565850*uk_91 + 1608750*uk_92 + 1129700*uk_93 + 1373020*uk_94 + 69520*uk_95 + 1903110*uk_96 + 1955250*uk_97 + 1373020*uk_98 + 3520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 97240*uk_100 + 99000*uk_101 + 57200*uk_102 + 2686255*uk_103 + 2734875*uk_104 + 1580150*uk_105 + 2784375*uk_106 + 1608750*uk_107 + 929500*uk_108 + 1331000*uk_109 + 5579090*uk_11 + 1573000*uk_110 + 96800*uk_111 + 2674100*uk_112 + 2722500*uk_113 + 1573000*uk_114 + 1859000*uk_115 + 114400*uk_116 + 3160300*uk_117 + 3217500*uk_118 + 1859000*uk_119 + 6593470*uk_12 + 7040*uk_120 + 194480*uk_121 + 198000*uk_122 + 114400*uk_123 + 5372510*uk_124 + 5469750*uk_125 + 3160300*uk_126 + 5568750*uk_127 + 3217500*uk_128 + 1859000*uk_129 + 405752*uk_13 + 2197000*uk_130 + 135200*uk_131 + 3734900*uk_132 + 3802500*uk_133 + 2197000*uk_134 + 8320*uk_135 + 229840*uk_136 + 234000*uk_137 + 135200*uk_138 + 6349330*uk_139 + 11208899*uk_14 + 6464250*uk_140 + 3734900*uk_141 + 6581250*uk_142 + 3802500*uk_143 + 2197000*uk_144 + 512*uk_145 + 14144*uk_146 + 14400*uk_147 + 8320*uk_148 + 390728*uk_149 + 11411775*uk_15 + 397800*uk_150 + 229840*uk_151 + 405000*uk_152 + 234000*uk_153 + 135200*uk_154 + 10793861*uk_155 + 10989225*uk_156 + 6349330*uk_157 + 11188125*uk_158 + 6464250*uk_159 + 6593470*uk_16 + 3734900*uk_160 + 11390625*uk_161 + 6581250*uk_162 + 3802500*uk_163 + 2197000*uk_164 + 3025*uk_17 + 6050*uk_18 + 7150*uk_19 + 55*uk_2 + 440*uk_20 + 12155*uk_21 + 12375*uk_22 + 7150*uk_23 + 12100*uk_24 + 14300*uk_25 + 880*uk_26 + 24310*uk_27 + 24750*uk_28 + 14300*uk_29 + 110*uk_3 + 16900*uk_30 + 1040*uk_31 + 28730*uk_32 + 29250*uk_33 + 16900*uk_34 + 64*uk_35 + 1768*uk_36 + 1800*uk_37 + 1040*uk_38 + 48841*uk_39 + 130*uk_4 + 49725*uk_40 + 28730*uk_41 + 50625*uk_42 + 29250*uk_43 + 16900*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 282965865710*uk_47 + 334414204930*uk_48 + 20579335688*uk_49 + 8*uk_5 + 568504148381*uk_50 + 578793816225*uk_51 + 334414204930*uk_52 + 153424975*uk_53 + 306849950*uk_54 + 362640850*uk_55 + 22316360*uk_56 + 616489445*uk_57 + 627647625*uk_58 + 362640850*uk_59 + 221*uk_6 + 613699900*uk_60 + 725281700*uk_61 + 44632720*uk_62 + 1232978890*uk_63 + 1255295250*uk_64 + 725281700*uk_65 + 857151100*uk_66 + 52747760*uk_67 + 1457156870*uk_68 + 1483530750*uk_69 + 225*uk_7 + 857151100*uk_70 + 3246016*uk_71 + 89671192*uk_72 + 91294200*uk_73 + 52747760*uk_74 + 2477166679*uk_75 + 2522002275*uk_76 + 1457156870*uk_77 + 2567649375*uk_78 + 1483530750*uk_79 + 130*uk_8 + 857151100*uk_80 + 166375*uk_81 + 332750*uk_82 + 393250*uk_83 + 24200*uk_84 + 668525*uk_85 + 680625*uk_86 + 393250*uk_87 + 665500*uk_88 + 786500*uk_89 + 2572416961*uk_9 + 48400*uk_90 + 1337050*uk_91 + 1361250*uk_92 + 786500*uk_93 + 929500*uk_94 + 57200*uk_95 + 1580150*uk_96 + 1608750*uk_97 + 929500*uk_98 + 3520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 98120*uk_100 + 99000*uk_101 + 48400*uk_102 + 2735095*uk_103 + 2759625*uk_104 + 1349150*uk_105 + 2784375*uk_106 + 1361250*uk_107 + 665500*uk_108 + 941192*uk_109 + 4970462*uk_11 + 1056440*uk_110 + 76832*uk_111 + 2141692*uk_112 + 2160900*uk_113 + 1056440*uk_114 + 1185800*uk_115 + 86240*uk_116 + 2403940*uk_117 + 2425500*uk_118 + 1185800*uk_119 + 5579090*uk_12 + 6272*uk_120 + 174832*uk_121 + 176400*uk_122 + 86240*uk_123 + 4873442*uk_124 + 4917150*uk_125 + 2403940*uk_126 + 4961250*uk_127 + 2425500*uk_128 + 1185800*uk_129 + 405752*uk_13 + 1331000*uk_130 + 96800*uk_131 + 2698300*uk_132 + 2722500*uk_133 + 1331000*uk_134 + 7040*uk_135 + 196240*uk_136 + 198000*uk_137 + 96800*uk_138 + 5470190*uk_139 + 11310337*uk_14 + 5519250*uk_140 + 2698300*uk_141 + 5568750*uk_142 + 2722500*uk_143 + 1331000*uk_144 + 512*uk_145 + 14272*uk_146 + 14400*uk_147 + 7040*uk_148 + 397832*uk_149 + 11411775*uk_15 + 401400*uk_150 + 196240*uk_151 + 405000*uk_152 + 198000*uk_153 + 96800*uk_154 + 11089567*uk_155 + 11189025*uk_156 + 5470190*uk_157 + 11289375*uk_158 + 5519250*uk_159 + 5579090*uk_16 + 2698300*uk_160 + 11390625*uk_161 + 5568750*uk_162 + 2722500*uk_163 + 1331000*uk_164 + 3025*uk_17 + 5390*uk_18 + 6050*uk_19 + 55*uk_2 + 440*uk_20 + 12265*uk_21 + 12375*uk_22 + 6050*uk_23 + 9604*uk_24 + 10780*uk_25 + 784*uk_26 + 21854*uk_27 + 22050*uk_28 + 10780*uk_29 + 98*uk_3 + 12100*uk_30 + 880*uk_31 + 24530*uk_32 + 24750*uk_33 + 12100*uk_34 + 64*uk_35 + 1784*uk_36 + 1800*uk_37 + 880*uk_38 + 49729*uk_39 + 110*uk_4 + 50175*uk_40 + 24530*uk_41 + 50625*uk_42 + 24750*uk_43 + 12100*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 252096862178*uk_47 + 282965865710*uk_48 + 20579335688*uk_49 + 8*uk_5 + 573648982303*uk_50 + 578793816225*uk_51 + 282965865710*uk_52 + 153424975*uk_53 + 273375410*uk_54 + 306849950*uk_55 + 22316360*uk_56 + 622068535*uk_57 + 627647625*uk_58 + 306849950*uk_59 + 223*uk_6 + 487105276*uk_60 + 546750820*uk_61 + 39763696*uk_62 + 1108413026*uk_63 + 1118353950*uk_64 + 546750820*uk_65 + 613699900*uk_66 + 44632720*uk_67 + 1244137070*uk_68 + 1255295250*uk_69 + 225*uk_7 + 613699900*uk_70 + 3246016*uk_71 + 90482696*uk_72 + 91294200*uk_73 + 44632720*uk_74 + 2522205151*uk_75 + 2544825825*uk_76 + 1244137070*uk_77 + 2567649375*uk_78 + 1255295250*uk_79 + 110*uk_8 + 613699900*uk_80 + 166375*uk_81 + 296450*uk_82 + 332750*uk_83 + 24200*uk_84 + 674575*uk_85 + 680625*uk_86 + 332750*uk_87 + 528220*uk_88 + 592900*uk_89 + 2572416961*uk_9 + 43120*uk_90 + 1201970*uk_91 + 1212750*uk_92 + 592900*uk_93 + 665500*uk_94 + 48400*uk_95 + 1349150*uk_96 + 1361250*uk_97 + 665500*uk_98 + 3520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 99000*uk_100 + 99000*uk_101 + 43120*uk_102 + 2784375*uk_103 + 2784375*uk_104 + 1212750*uk_105 + 2784375*uk_106 + 1212750*uk_107 + 528220*uk_108 + 830584*uk_109 + 4767586*uk_11 + 865928*uk_110 + 70688*uk_111 + 1988100*uk_112 + 1988100*uk_113 + 865928*uk_114 + 902776*uk_115 + 73696*uk_116 + 2072700*uk_117 + 2072700*uk_118 + 902776*uk_119 + 4970462*uk_12 + 6016*uk_120 + 169200*uk_121 + 169200*uk_122 + 73696*uk_123 + 4758750*uk_124 + 4758750*uk_125 + 2072700*uk_126 + 4758750*uk_127 + 2072700*uk_128 + 902776*uk_129 + 405752*uk_13 + 941192*uk_130 + 76832*uk_131 + 2160900*uk_132 + 2160900*uk_133 + 941192*uk_134 + 6272*uk_135 + 176400*uk_136 + 176400*uk_137 + 76832*uk_138 + 4961250*uk_139 + 11411775*uk_14 + 4961250*uk_140 + 2160900*uk_141 + 4961250*uk_142 + 2160900*uk_143 + 941192*uk_144 + 512*uk_145 + 14400*uk_146 + 14400*uk_147 + 6272*uk_148 + 405000*uk_149 + 11411775*uk_15 + 405000*uk_150 + 176400*uk_151 + 405000*uk_152 + 176400*uk_153 + 76832*uk_154 + 11390625*uk_155 + 11390625*uk_156 + 4961250*uk_157 + 11390625*uk_158 + 4961250*uk_159 + 4970462*uk_16 + 2160900*uk_160 + 11390625*uk_161 + 4961250*uk_162 + 2160900*uk_163 + 941192*uk_164 + 3025*uk_17 + 5170*uk_18 + 5390*uk_19 + 55*uk_2 + 440*uk_20 + 12375*uk_21 + 12375*uk_22 + 5390*uk_23 + 8836*uk_24 + 9212*uk_25 + 752*uk_26 + 21150*uk_27 + 21150*uk_28 + 9212*uk_29 + 94*uk_3 + 9604*uk_30 + 784*uk_31 + 22050*uk_32 + 22050*uk_33 + 9604*uk_34 + 64*uk_35 + 1800*uk_36 + 1800*uk_37 + 784*uk_38 + 50625*uk_39 + 98*uk_4 + 50625*uk_40 + 22050*uk_41 + 50625*uk_42 + 22050*uk_43 + 9604*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 241807194334*uk_47 + 252096862178*uk_48 + 20579335688*uk_49 + 8*uk_5 + 578793816225*uk_50 + 578793816225*uk_51 + 252096862178*uk_52 + 153424975*uk_53 + 262217230*uk_54 + 273375410*uk_55 + 22316360*uk_56 + 627647625*uk_57 + 627647625*uk_58 + 273375410*uk_59 + 225*uk_6 + 448153084*uk_60 + 467223428*uk_61 + 38140688*uk_62 + 1072706850*uk_63 + 1072706850*uk_64 + 467223428*uk_65 + 487105276*uk_66 + 39763696*uk_67 + 1118353950*uk_68 + 1118353950*uk_69 + 225*uk_7 + 487105276*uk_70 + 3246016*uk_71 + 91294200*uk_72 + 91294200*uk_73 + 39763696*uk_74 + 2567649375*uk_75 + 2567649375*uk_76 + 1118353950*uk_77 + 2567649375*uk_78 + 1118353950*uk_79 + 98*uk_8 + 487105276*uk_80 + 166375*uk_81 + 284350*uk_82 + 296450*uk_83 + 24200*uk_84 + 680625*uk_85 + 680625*uk_86 + 296450*uk_87 + 485980*uk_88 + 506660*uk_89 + 2572416961*uk_9 + 41360*uk_90 + 1163250*uk_91 + 1163250*uk_92 + 506660*uk_93 + 528220*uk_94 + 43120*uk_95 + 1212750*uk_96 + 1212750*uk_97 + 528220*uk_98 + 3520*uk_99, + uk_0 + 50719*uk_1 + 2789545*uk_10 + 99880*uk_100 + 99000*uk_101 + 41360*uk_102 + 2834095*uk_103 + 2809125*uk_104 + 1173590*uk_105 + 2784375*uk_106 + 1163250*uk_107 + 485980*uk_108 + 941192*uk_109 + 4970462*uk_11 + 902776*uk_110 + 76832*uk_111 + 2180108*uk_112 + 2160900*uk_113 + 902776*uk_114 + 865928*uk_115 + 73696*uk_116 + 2091124*uk_117 + 2072700*uk_118 + 865928*uk_119 + 4767586*uk_12 + 6272*uk_120 + 177968*uk_121 + 176400*uk_122 + 73696*uk_123 + 5049842*uk_124 + 5005350*uk_125 + 2091124*uk_126 + 4961250*uk_127 + 2072700*uk_128 + 865928*uk_129 + 405752*uk_13 + 830584*uk_130 + 70688*uk_131 + 2005772*uk_132 + 1988100*uk_133 + 830584*uk_134 + 6016*uk_135 + 170704*uk_136 + 169200*uk_137 + 70688*uk_138 + 4843726*uk_139 + 11513213*uk_14 + 4801050*uk_140 + 2005772*uk_141 + 4758750*uk_142 + 1988100*uk_143 + 830584*uk_144 + 512*uk_145 + 14528*uk_146 + 14400*uk_147 + 6016*uk_148 + 412232*uk_149 + 11411775*uk_15 + 408600*uk_150 + 170704*uk_151 + 405000*uk_152 + 169200*uk_153 + 70688*uk_154 + 11697083*uk_155 + 11594025*uk_156 + 4843726*uk_157 + 11491875*uk_158 + 4801050*uk_159 + 4767586*uk_16 + 2005772*uk_160 + 11390625*uk_161 + 4758750*uk_162 + 1988100*uk_163 + 830584*uk_164 + 3025*uk_17 + 5390*uk_18 + 5170*uk_19 + 55*uk_2 + 440*uk_20 + 12485*uk_21 + 12375*uk_22 + 5170*uk_23 + 9604*uk_24 + 9212*uk_25 + 784*uk_26 + 22246*uk_27 + 22050*uk_28 + 9212*uk_29 + 98*uk_3 + 8836*uk_30 + 752*uk_31 + 21338*uk_32 + 21150*uk_33 + 8836*uk_34 + 64*uk_35 + 1816*uk_36 + 1800*uk_37 + 752*uk_38 + 51529*uk_39 + 94*uk_4 + 51075*uk_40 + 21338*uk_41 + 50625*uk_42 + 21150*uk_43 + 8836*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 252096862178*uk_47 + 241807194334*uk_48 + 20579335688*uk_49 + 8*uk_5 + 583938650147*uk_50 + 578793816225*uk_51 + 241807194334*uk_52 + 153424975*uk_53 + 273375410*uk_54 + 262217230*uk_55 + 22316360*uk_56 + 633226715*uk_57 + 627647625*uk_58 + 262217230*uk_59 + 227*uk_6 + 487105276*uk_60 + 467223428*uk_61 + 39763696*uk_62 + 1128294874*uk_63 + 1118353950*uk_64 + 467223428*uk_65 + 448153084*uk_66 + 38140688*uk_67 + 1082242022*uk_68 + 1072706850*uk_69 + 225*uk_7 + 448153084*uk_70 + 3246016*uk_71 + 92105704*uk_72 + 91294200*uk_73 + 38140688*uk_74 + 2613499351*uk_75 + 2590472925*uk_76 + 1082242022*uk_77 + 2567649375*uk_78 + 1072706850*uk_79 + 94*uk_8 + 448153084*uk_80 + 166375*uk_81 + 296450*uk_82 + 284350*uk_83 + 24200*uk_84 + 686675*uk_85 + 680625*uk_86 + 284350*uk_87 + 528220*uk_88 + 506660*uk_89 + 2572416961*uk_9 + 43120*uk_90 + 1223530*uk_91 + 1212750*uk_92 + 506660*uk_93 + 485980*uk_94 + 41360*uk_95 + 1173590*uk_96 + 1163250*uk_97 + 485980*uk_98 + 3520*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 396900*uk_100 + 1367100*uk_101 + 250047*uk_103 + 861273*uk_104 + 2966607*uk_106 + 64000*uk_109 + 1894120*uk_11 + 27200*uk_110 + 160000*uk_111 + 100800*uk_112 + 347200*uk_113 + 11560*uk_115 + 68000*uk_116 + 42840*uk_117 + 147560*uk_118 + 805001*uk_12 + 400000*uk_120 + 252000*uk_121 + 868000*uk_122 + 158760*uk_124 + 546840*uk_125 + 1883560*uk_127 + 4735300*uk_13 + 4913*uk_130 + 28900*uk_131 + 18207*uk_132 + 62713*uk_133 + 170000*uk_135 + 107100*uk_136 + 368900*uk_137 + 67473*uk_139 + 2983239*uk_14 + 232407*uk_140 + 800513*uk_142 + 1000000*uk_145 + 630000*uk_146 + 2170000*uk_147 + 396900*uk_149 + 10275601*uk_15 + 1367100*uk_150 + 4708900*uk_152 + 250047*uk_155 + 861273*uk_156 + 2966607*uk_158 + 10218313*uk_161 + 3969*uk_17 + 2520*uk_18 + 1071*uk_19 + 63*uk_2 + 6300*uk_20 + 3969*uk_21 + 13671*uk_22 + 1600*uk_24 + 680*uk_25 + 4000*uk_26 + 2520*uk_27 + 8680*uk_28 + 40*uk_3 + 289*uk_30 + 1700*uk_31 + 1071*uk_32 + 3689*uk_33 + 10000*uk_35 + 6300*uk_36 + 21700*uk_37 + 3969*uk_39 + 17*uk_4 + 13671*uk_40 + 47089*uk_42 + 106179944855977*uk_45 + 141265316367*uk_46 + 89692264360*uk_47 + 38119212353*uk_48 + 224230660900*uk_49 + 100*uk_5 + 141265316367*uk_50 + 486580534153*uk_51 + 187944057*uk_53 + 119329560*uk_54 + 50715063*uk_55 + 298323900*uk_56 + 187944057*uk_57 + 647362863*uk_58 + 63*uk_6 + 75764800*uk_60 + 32200040*uk_61 + 189412000*uk_62 + 119329560*uk_63 + 411024040*uk_64 + 13685017*uk_66 + 80500100*uk_67 + 50715063*uk_68 + 174685217*uk_69 + 217*uk_7 + 473530000*uk_71 + 298323900*uk_72 + 1027560100*uk_73 + 187944057*uk_75 + 647362863*uk_76 + 2229805417*uk_78 + 250047*uk_81 + 158760*uk_82 + 67473*uk_83 + 396900*uk_84 + 250047*uk_85 + 861273*uk_86 + 100800*uk_88 + 42840*uk_89 + 2242306609*uk_9 + 252000*uk_90 + 158760*uk_91 + 546840*uk_92 + 18207*uk_94 + 107100*uk_95 + 67473*uk_96 + 232407*uk_97 + 630000*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 376740*uk_100 + 1257732*uk_101 + 231840*uk_102 + 266175*uk_103 + 888615*uk_104 + 163800*uk_105 + 2966607*uk_106 + 546840*uk_107 + 100800*uk_108 + 35937*uk_109 + 1562649*uk_11 + 43560*uk_110 + 100188*uk_111 + 70785*uk_112 + 236313*uk_113 + 43560*uk_114 + 52800*uk_115 + 121440*uk_116 + 85800*uk_117 + 286440*uk_118 + 52800*uk_119 + 1894120*uk_12 + 279312*uk_120 + 197340*uk_121 + 658812*uk_122 + 121440*uk_123 + 139425*uk_124 + 465465*uk_125 + 85800*uk_126 + 1553937*uk_127 + 286440*uk_128 + 52800*uk_129 + 4356476*uk_13 + 64000*uk_130 + 147200*uk_131 + 104000*uk_132 + 347200*uk_133 + 64000*uk_134 + 338560*uk_135 + 239200*uk_136 + 798560*uk_137 + 147200*uk_138 + 169000*uk_139 + 3077945*uk_14 + 564200*uk_140 + 104000*uk_141 + 1883560*uk_142 + 347200*uk_143 + 64000*uk_144 + 778688*uk_145 + 550160*uk_146 + 1836688*uk_147 + 338560*uk_148 + 388700*uk_149 + 10275601*uk_15 + 1297660*uk_150 + 239200*uk_151 + 4332188*uk_152 + 798560*uk_153 + 147200*uk_154 + 274625*uk_155 + 916825*uk_156 + 169000*uk_157 + 3060785*uk_158 + 564200*uk_159 + 1894120*uk_16 + 104000*uk_160 + 10218313*uk_161 + 1883560*uk_162 + 347200*uk_163 + 64000*uk_164 + 3969*uk_17 + 2079*uk_18 + 2520*uk_19 + 63*uk_2 + 5796*uk_20 + 4095*uk_21 + 13671*uk_22 + 2520*uk_23 + 1089*uk_24 + 1320*uk_25 + 3036*uk_26 + 2145*uk_27 + 7161*uk_28 + 1320*uk_29 + 33*uk_3 + 1600*uk_30 + 3680*uk_31 + 2600*uk_32 + 8680*uk_33 + 1600*uk_34 + 8464*uk_35 + 5980*uk_36 + 19964*uk_37 + 3680*uk_38 + 4225*uk_39 + 40*uk_4 + 14105*uk_40 + 2600*uk_41 + 47089*uk_42 + 8680*uk_43 + 1600*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 73996118097*uk_47 + 89692264360*uk_48 + 206292208028*uk_49 + 92*uk_5 + 145749929585*uk_50 + 486580534153*uk_51 + 89692264360*uk_52 + 187944057*uk_53 + 98446887*uk_54 + 119329560*uk_55 + 274457988*uk_56 + 193910535*uk_57 + 647362863*uk_58 + 119329560*uk_59 + 65*uk_6 + 51567417*uk_60 + 62505960*uk_61 + 143763708*uk_62 + 101572185*uk_63 + 339094833*uk_64 + 62505960*uk_65 + 75764800*uk_66 + 174259040*uk_67 + 123117800*uk_68 + 411024040*uk_69 + 217*uk_7 + 75764800*uk_70 + 400795792*uk_71 + 283170940*uk_72 + 945355292*uk_73 + 174259040*uk_74 + 200066425*uk_75 + 667914065*uk_76 + 123117800*uk_77 + 2229805417*uk_78 + 411024040*uk_79 + 40*uk_8 + 75764800*uk_80 + 250047*uk_81 + 130977*uk_82 + 158760*uk_83 + 365148*uk_84 + 257985*uk_85 + 861273*uk_86 + 158760*uk_87 + 68607*uk_88 + 83160*uk_89 + 2242306609*uk_9 + 191268*uk_90 + 135135*uk_91 + 451143*uk_92 + 83160*uk_93 + 100800*uk_94 + 231840*uk_95 + 163800*uk_96 + 546840*uk_97 + 100800*uk_98 + 533232*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 371448*uk_100 + 1203048*uk_101 + 182952*uk_102 + 282807*uk_103 + 915957*uk_104 + 139293*uk_105 + 2966607*uk_106 + 451143*uk_107 + 68607*uk_108 + 132651*uk_109 + 2415003*uk_11 + 85833*uk_110 + 228888*uk_111 + 174267*uk_112 + 564417*uk_113 + 85833*uk_114 + 55539*uk_115 + 148104*uk_116 + 112761*uk_117 + 365211*uk_118 + 55539*uk_119 + 1562649*uk_12 + 394944*uk_120 + 300696*uk_121 + 973896*uk_122 + 148104*uk_123 + 228939*uk_124 + 741489*uk_125 + 112761*uk_126 + 2401539*uk_127 + 365211*uk_128 + 55539*uk_129 + 4167064*uk_13 + 35937*uk_130 + 95832*uk_131 + 72963*uk_132 + 236313*uk_133 + 35937*uk_134 + 255552*uk_135 + 194568*uk_136 + 630168*uk_137 + 95832*uk_138 + 148137*uk_139 + 3172651*uk_14 + 479787*uk_140 + 72963*uk_141 + 1553937*uk_142 + 236313*uk_143 + 35937*uk_144 + 681472*uk_145 + 518848*uk_146 + 1680448*uk_147 + 255552*uk_148 + 395032*uk_149 + 10275601*uk_15 + 1279432*uk_150 + 194568*uk_151 + 4143832*uk_152 + 630168*uk_153 + 95832*uk_154 + 300763*uk_155 + 974113*uk_156 + 148137*uk_157 + 3154963*uk_158 + 479787*uk_159 + 1562649*uk_16 + 72963*uk_160 + 10218313*uk_161 + 1553937*uk_162 + 236313*uk_163 + 35937*uk_164 + 3969*uk_17 + 3213*uk_18 + 2079*uk_19 + 63*uk_2 + 5544*uk_20 + 4221*uk_21 + 13671*uk_22 + 2079*uk_23 + 2601*uk_24 + 1683*uk_25 + 4488*uk_26 + 3417*uk_27 + 11067*uk_28 + 1683*uk_29 + 51*uk_3 + 1089*uk_30 + 2904*uk_31 + 2211*uk_32 + 7161*uk_33 + 1089*uk_34 + 7744*uk_35 + 5896*uk_36 + 19096*uk_37 + 2904*uk_38 + 4489*uk_39 + 33*uk_4 + 14539*uk_40 + 2211*uk_41 + 47089*uk_42 + 7161*uk_43 + 1089*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 114357637059*uk_47 + 73996118097*uk_48 + 197322981592*uk_49 + 88*uk_5 + 150234542803*uk_50 + 486580534153*uk_51 + 73996118097*uk_52 + 187944057*uk_53 + 152145189*uk_54 + 98446887*uk_55 + 262525032*uk_56 + 199877013*uk_57 + 647362863*uk_58 + 98446887*uk_59 + 67*uk_6 + 123165153*uk_60 + 79695099*uk_61 + 212520264*uk_62 + 161805201*uk_63 + 524055651*uk_64 + 79695099*uk_65 + 51567417*uk_66 + 137513112*uk_67 + 104697483*uk_68 + 339094833*uk_69 + 217*uk_7 + 51567417*uk_70 + 366701632*uk_71 + 279193288*uk_72 + 904252888*uk_73 + 137513112*uk_74 + 212567617*uk_75 + 688465267*uk_76 + 104697483*uk_77 + 2229805417*uk_78 + 339094833*uk_79 + 33*uk_8 + 51567417*uk_80 + 250047*uk_81 + 202419*uk_82 + 130977*uk_83 + 349272*uk_84 + 265923*uk_85 + 861273*uk_86 + 130977*uk_87 + 163863*uk_88 + 106029*uk_89 + 2242306609*uk_9 + 282744*uk_90 + 215271*uk_91 + 697221*uk_92 + 106029*uk_93 + 68607*uk_94 + 182952*uk_95 + 139293*uk_96 + 451143*uk_97 + 68607*uk_98 + 487872*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 347760*uk_100 + 1093680*uk_101 + 257040*uk_102 + 299943*uk_103 + 943299*uk_104 + 221697*uk_105 + 2966607*uk_106 + 697221*uk_107 + 163863*uk_108 + 6859*uk_109 + 899707*uk_11 + 18411*uk_110 + 28880*uk_111 + 24909*uk_112 + 78337*uk_113 + 18411*uk_114 + 49419*uk_115 + 77520*uk_116 + 66861*uk_117 + 210273*uk_118 + 49419*uk_119 + 2415003*uk_12 + 121600*uk_120 + 104880*uk_121 + 329840*uk_122 + 77520*uk_123 + 90459*uk_124 + 284487*uk_125 + 66861*uk_126 + 894691*uk_127 + 210273*uk_128 + 49419*uk_129 + 3788240*uk_13 + 132651*uk_130 + 208080*uk_131 + 179469*uk_132 + 564417*uk_133 + 132651*uk_134 + 326400*uk_135 + 281520*uk_136 + 885360*uk_137 + 208080*uk_138 + 242811*uk_139 + 3267357*uk_14 + 763623*uk_140 + 179469*uk_141 + 2401539*uk_142 + 564417*uk_143 + 132651*uk_144 + 512000*uk_145 + 441600*uk_146 + 1388800*uk_147 + 326400*uk_148 + 380880*uk_149 + 10275601*uk_15 + 1197840*uk_150 + 281520*uk_151 + 3767120*uk_152 + 885360*uk_153 + 208080*uk_154 + 328509*uk_155 + 1033137*uk_156 + 242811*uk_157 + 3249141*uk_158 + 763623*uk_159 + 2415003*uk_16 + 179469*uk_160 + 10218313*uk_161 + 2401539*uk_162 + 564417*uk_163 + 132651*uk_164 + 3969*uk_17 + 1197*uk_18 + 3213*uk_19 + 63*uk_2 + 5040*uk_20 + 4347*uk_21 + 13671*uk_22 + 3213*uk_23 + 361*uk_24 + 969*uk_25 + 1520*uk_26 + 1311*uk_27 + 4123*uk_28 + 969*uk_29 + 19*uk_3 + 2601*uk_30 + 4080*uk_31 + 3519*uk_32 + 11067*uk_33 + 2601*uk_34 + 6400*uk_35 + 5520*uk_36 + 17360*uk_37 + 4080*uk_38 + 4761*uk_39 + 51*uk_4 + 14973*uk_40 + 3519*uk_41 + 47089*uk_42 + 11067*uk_43 + 2601*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 42603825571*uk_47 + 114357637059*uk_48 + 179384528720*uk_49 + 80*uk_5 + 154719156021*uk_50 + 486580534153*uk_51 + 114357637059*uk_52 + 187944057*uk_53 + 56681541*uk_54 + 152145189*uk_55 + 238659120*uk_56 + 205843491*uk_57 + 647362863*uk_58 + 152145189*uk_59 + 69*uk_6 + 17094433*uk_60 + 45885057*uk_61 + 71976560*uk_62 + 62079783*uk_63 + 195236419*uk_64 + 45885057*uk_65 + 123165153*uk_66 + 193200240*uk_67 + 166635207*uk_68 + 524055651*uk_69 + 217*uk_7 + 123165153*uk_70 + 303059200*uk_71 + 261388560*uk_72 + 822048080*uk_73 + 193200240*uk_74 + 225447633*uk_75 + 709016469*uk_76 + 166635207*uk_77 + 2229805417*uk_78 + 524055651*uk_79 + 51*uk_8 + 123165153*uk_80 + 250047*uk_81 + 75411*uk_82 + 202419*uk_83 + 317520*uk_84 + 273861*uk_85 + 861273*uk_86 + 202419*uk_87 + 22743*uk_88 + 61047*uk_89 + 2242306609*uk_9 + 95760*uk_90 + 82593*uk_91 + 259749*uk_92 + 61047*uk_93 + 163863*uk_94 + 257040*uk_95 + 221697*uk_96 + 697221*uk_97 + 163863*uk_98 + 403200*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 357840*uk_100 + 1093680*uk_101 + 95760*uk_102 + 317583*uk_103 + 970641*uk_104 + 84987*uk_105 + 2966607*uk_106 + 259749*uk_107 + 22743*uk_108 + 300763*uk_109 + 3172651*uk_11 + 85291*uk_110 + 359120*uk_111 + 318719*uk_112 + 974113*uk_113 + 85291*uk_114 + 24187*uk_115 + 101840*uk_116 + 90383*uk_117 + 276241*uk_118 + 24187*uk_119 + 899707*uk_12 + 428800*uk_120 + 380560*uk_121 + 1163120*uk_122 + 101840*uk_123 + 337747*uk_124 + 1032269*uk_125 + 90383*uk_126 + 3154963*uk_127 + 276241*uk_128 + 24187*uk_129 + 3788240*uk_13 + 6859*uk_130 + 28880*uk_131 + 25631*uk_132 + 78337*uk_133 + 6859*uk_134 + 121600*uk_135 + 107920*uk_136 + 329840*uk_137 + 28880*uk_138 + 95779*uk_139 + 3362063*uk_14 + 292733*uk_140 + 25631*uk_141 + 894691*uk_142 + 78337*uk_143 + 6859*uk_144 + 512000*uk_145 + 454400*uk_146 + 1388800*uk_147 + 121600*uk_148 + 403280*uk_149 + 10275601*uk_15 + 1232560*uk_150 + 107920*uk_151 + 3767120*uk_152 + 329840*uk_153 + 28880*uk_154 + 357911*uk_155 + 1093897*uk_156 + 95779*uk_157 + 3343319*uk_158 + 292733*uk_159 + 899707*uk_16 + 25631*uk_160 + 10218313*uk_161 + 894691*uk_162 + 78337*uk_163 + 6859*uk_164 + 3969*uk_17 + 4221*uk_18 + 1197*uk_19 + 63*uk_2 + 5040*uk_20 + 4473*uk_21 + 13671*uk_22 + 1197*uk_23 + 4489*uk_24 + 1273*uk_25 + 5360*uk_26 + 4757*uk_27 + 14539*uk_28 + 1273*uk_29 + 67*uk_3 + 361*uk_30 + 1520*uk_31 + 1349*uk_32 + 4123*uk_33 + 361*uk_34 + 6400*uk_35 + 5680*uk_36 + 17360*uk_37 + 1520*uk_38 + 5041*uk_39 + 19*uk_4 + 15407*uk_40 + 1349*uk_41 + 47089*uk_42 + 4123*uk_43 + 361*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 150234542803*uk_47 + 42603825571*uk_48 + 179384528720*uk_49 + 80*uk_5 + 159203769239*uk_50 + 486580534153*uk_51 + 42603825571*uk_52 + 187944057*uk_53 + 199877013*uk_54 + 56681541*uk_55 + 238659120*uk_56 + 211809969*uk_57 + 647362863*uk_58 + 56681541*uk_59 + 71*uk_6 + 212567617*uk_60 + 60280369*uk_61 + 253812080*uk_62 + 225258221*uk_63 + 688465267*uk_64 + 60280369*uk_65 + 17094433*uk_66 + 71976560*uk_67 + 63879197*uk_68 + 195236419*uk_69 + 217*uk_7 + 17094433*uk_70 + 303059200*uk_71 + 268965040*uk_72 + 822048080*uk_73 + 71976560*uk_74 + 238706473*uk_75 + 729567671*uk_76 + 63879197*uk_77 + 2229805417*uk_78 + 195236419*uk_79 + 19*uk_8 + 17094433*uk_80 + 250047*uk_81 + 265923*uk_82 + 75411*uk_83 + 317520*uk_84 + 281799*uk_85 + 861273*uk_86 + 75411*uk_87 + 282807*uk_88 + 80199*uk_89 + 2242306609*uk_9 + 337680*uk_90 + 299691*uk_91 + 915957*uk_92 + 80199*uk_93 + 22743*uk_94 + 95760*uk_95 + 84987*uk_96 + 259749*uk_97 + 22743*uk_98 + 403200*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 331128*uk_100 + 984312*uk_101 + 303912*uk_102 + 335727*uk_103 + 997983*uk_104 + 308133*uk_105 + 2966607*uk_106 + 915957*uk_107 + 282807*uk_108 + 117649*uk_109 + 2320297*uk_11 + 160867*uk_110 + 172872*uk_111 + 175273*uk_112 + 521017*uk_113 + 160867*uk_114 + 219961*uk_115 + 236376*uk_116 + 239659*uk_117 + 712411*uk_118 + 219961*uk_119 + 3172651*uk_12 + 254016*uk_120 + 257544*uk_121 + 765576*uk_122 + 236376*uk_123 + 261121*uk_124 + 776209*uk_125 + 239659*uk_126 + 2307361*uk_127 + 712411*uk_128 + 219961*uk_129 + 3409416*uk_13 + 300763*uk_130 + 323208*uk_131 + 327697*uk_132 + 974113*uk_133 + 300763*uk_134 + 347328*uk_135 + 352152*uk_136 + 1046808*uk_137 + 323208*uk_138 + 357043*uk_139 + 3456769*uk_14 + 1061347*uk_140 + 327697*uk_141 + 3154963*uk_142 + 974113*uk_143 + 300763*uk_144 + 373248*uk_145 + 378432*uk_146 + 1124928*uk_147 + 347328*uk_148 + 383688*uk_149 + 10275601*uk_15 + 1140552*uk_150 + 352152*uk_151 + 3390408*uk_152 + 1046808*uk_153 + 323208*uk_154 + 389017*uk_155 + 1156393*uk_156 + 357043*uk_157 + 3437497*uk_158 + 1061347*uk_159 + 3172651*uk_16 + 327697*uk_160 + 10218313*uk_161 + 3154963*uk_162 + 974113*uk_163 + 300763*uk_164 + 3969*uk_17 + 3087*uk_18 + 4221*uk_19 + 63*uk_2 + 4536*uk_20 + 4599*uk_21 + 13671*uk_22 + 4221*uk_23 + 2401*uk_24 + 3283*uk_25 + 3528*uk_26 + 3577*uk_27 + 10633*uk_28 + 3283*uk_29 + 49*uk_3 + 4489*uk_30 + 4824*uk_31 + 4891*uk_32 + 14539*uk_33 + 4489*uk_34 + 5184*uk_35 + 5256*uk_36 + 15624*uk_37 + 4824*uk_38 + 5329*uk_39 + 67*uk_4 + 15841*uk_40 + 4891*uk_41 + 47089*uk_42 + 14539*uk_43 + 4489*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 109873023841*uk_47 + 150234542803*uk_48 + 161446075848*uk_49 + 72*uk_5 + 163688382457*uk_50 + 486580534153*uk_51 + 150234542803*uk_52 + 187944057*uk_53 + 146178711*uk_54 + 199877013*uk_55 + 214793208*uk_56 + 217776447*uk_57 + 647362863*uk_58 + 199877013*uk_59 + 73*uk_6 + 113694553*uk_60 + 155459899*uk_61 + 167061384*uk_62 + 169381681*uk_63 + 503504449*uk_64 + 155459899*uk_65 + 212567617*uk_66 + 228430872*uk_67 + 231603523*uk_68 + 688465267*uk_69 + 217*uk_7 + 212567617*uk_70 + 245477952*uk_71 + 248887368*uk_72 + 739843272*uk_73 + 228430872*uk_74 + 252344137*uk_75 + 750118873*uk_76 + 231603523*uk_77 + 2229805417*uk_78 + 688465267*uk_79 + 67*uk_8 + 212567617*uk_80 + 250047*uk_81 + 194481*uk_82 + 265923*uk_83 + 285768*uk_84 + 289737*uk_85 + 861273*uk_86 + 265923*uk_87 + 151263*uk_88 + 206829*uk_89 + 2242306609*uk_9 + 222264*uk_90 + 225351*uk_91 + 669879*uk_92 + 206829*uk_93 + 282807*uk_94 + 303912*uk_95 + 308133*uk_96 + 915957*uk_97 + 282807*uk_98 + 326592*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 321300*uk_100 + 929628*uk_101 + 209916*uk_102 + 354375*uk_103 + 1025325*uk_104 + 231525*uk_105 + 2966607*uk_106 + 669879*uk_107 + 151263*uk_108 + 21952*uk_109 + 1325884*uk_11 + 38416*uk_110 + 53312*uk_111 + 58800*uk_112 + 170128*uk_113 + 38416*uk_114 + 67228*uk_115 + 93296*uk_116 + 102900*uk_117 + 297724*uk_118 + 67228*uk_119 + 2320297*uk_12 + 129472*uk_120 + 142800*uk_121 + 413168*uk_122 + 93296*uk_123 + 157500*uk_124 + 455700*uk_125 + 102900*uk_126 + 1318492*uk_127 + 297724*uk_128 + 67228*uk_129 + 3220004*uk_13 + 117649*uk_130 + 163268*uk_131 + 180075*uk_132 + 521017*uk_133 + 117649*uk_134 + 226576*uk_135 + 249900*uk_136 + 723044*uk_137 + 163268*uk_138 + 275625*uk_139 + 3551475*uk_14 + 797475*uk_140 + 180075*uk_141 + 2307361*uk_142 + 521017*uk_143 + 117649*uk_144 + 314432*uk_145 + 346800*uk_146 + 1003408*uk_147 + 226576*uk_148 + 382500*uk_149 + 10275601*uk_15 + 1106700*uk_150 + 249900*uk_151 + 3202052*uk_152 + 723044*uk_153 + 163268*uk_154 + 421875*uk_155 + 1220625*uk_156 + 275625*uk_157 + 3531675*uk_158 + 797475*uk_159 + 2320297*uk_16 + 180075*uk_160 + 10218313*uk_161 + 2307361*uk_162 + 521017*uk_163 + 117649*uk_164 + 3969*uk_17 + 1764*uk_18 + 3087*uk_19 + 63*uk_2 + 4284*uk_20 + 4725*uk_21 + 13671*uk_22 + 3087*uk_23 + 784*uk_24 + 1372*uk_25 + 1904*uk_26 + 2100*uk_27 + 6076*uk_28 + 1372*uk_29 + 28*uk_3 + 2401*uk_30 + 3332*uk_31 + 3675*uk_32 + 10633*uk_33 + 2401*uk_34 + 4624*uk_35 + 5100*uk_36 + 14756*uk_37 + 3332*uk_38 + 5625*uk_39 + 49*uk_4 + 16275*uk_40 + 3675*uk_41 + 47089*uk_42 + 10633*uk_43 + 2401*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 62784585052*uk_47 + 109873023841*uk_48 + 152476849412*uk_49 + 68*uk_5 + 168172995675*uk_50 + 486580534153*uk_51 + 109873023841*uk_52 + 187944057*uk_53 + 83530692*uk_54 + 146178711*uk_55 + 202860252*uk_56 + 223742925*uk_57 + 647362863*uk_58 + 146178711*uk_59 + 75*uk_6 + 37124752*uk_60 + 64968316*uk_61 + 90160112*uk_62 + 99441300*uk_63 + 287716828*uk_64 + 64968316*uk_65 + 113694553*uk_66 + 157780196*uk_67 + 174022275*uk_68 + 503504449*uk_69 + 217*uk_7 + 113694553*uk_70 + 218960272*uk_71 + 241500300*uk_72 + 698740868*uk_73 + 157780196*uk_74 + 266360625*uk_75 + 770670075*uk_76 + 174022275*uk_77 + 2229805417*uk_78 + 503504449*uk_79 + 49*uk_8 + 113694553*uk_80 + 250047*uk_81 + 111132*uk_82 + 194481*uk_83 + 269892*uk_84 + 297675*uk_85 + 861273*uk_86 + 194481*uk_87 + 49392*uk_88 + 86436*uk_89 + 2242306609*uk_9 + 119952*uk_90 + 132300*uk_91 + 382788*uk_92 + 86436*uk_93 + 151263*uk_94 + 209916*uk_95 + 231525*uk_96 + 669879*uk_97 + 151263*uk_98 + 291312*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 329868*uk_100 + 929628*uk_101 + 119952*uk_102 + 373527*uk_103 + 1052667*uk_104 + 135828*uk_105 + 2966607*uk_106 + 382788*uk_107 + 49392*uk_108 + 421875*uk_109 + 3551475*uk_11 + 157500*uk_110 + 382500*uk_111 + 433125*uk_112 + 1220625*uk_113 + 157500*uk_114 + 58800*uk_115 + 142800*uk_116 + 161700*uk_117 + 455700*uk_118 + 58800*uk_119 + 1325884*uk_12 + 346800*uk_120 + 392700*uk_121 + 1106700*uk_122 + 142800*uk_123 + 444675*uk_124 + 1253175*uk_125 + 161700*uk_126 + 3531675*uk_127 + 455700*uk_128 + 58800*uk_129 + 3220004*uk_13 + 21952*uk_130 + 53312*uk_131 + 60368*uk_132 + 170128*uk_133 + 21952*uk_134 + 129472*uk_135 + 146608*uk_136 + 413168*uk_137 + 53312*uk_138 + 166012*uk_139 + 3646181*uk_14 + 467852*uk_140 + 60368*uk_141 + 1318492*uk_142 + 170128*uk_143 + 21952*uk_144 + 314432*uk_145 + 356048*uk_146 + 1003408*uk_147 + 129472*uk_148 + 403172*uk_149 + 10275601*uk_15 + 1136212*uk_150 + 146608*uk_151 + 3202052*uk_152 + 413168*uk_153 + 53312*uk_154 + 456533*uk_155 + 1286593*uk_156 + 166012*uk_157 + 3625853*uk_158 + 467852*uk_159 + 1325884*uk_16 + 60368*uk_160 + 10218313*uk_161 + 1318492*uk_162 + 170128*uk_163 + 21952*uk_164 + 3969*uk_17 + 4725*uk_18 + 1764*uk_19 + 63*uk_2 + 4284*uk_20 + 4851*uk_21 + 13671*uk_22 + 1764*uk_23 + 5625*uk_24 + 2100*uk_25 + 5100*uk_26 + 5775*uk_27 + 16275*uk_28 + 2100*uk_29 + 75*uk_3 + 784*uk_30 + 1904*uk_31 + 2156*uk_32 + 6076*uk_33 + 784*uk_34 + 4624*uk_35 + 5236*uk_36 + 14756*uk_37 + 1904*uk_38 + 5929*uk_39 + 28*uk_4 + 16709*uk_40 + 2156*uk_41 + 47089*uk_42 + 6076*uk_43 + 784*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 168172995675*uk_47 + 62784585052*uk_48 + 152476849412*uk_49 + 68*uk_5 + 172657608893*uk_50 + 486580534153*uk_51 + 62784585052*uk_52 + 187944057*uk_53 + 223742925*uk_54 + 83530692*uk_55 + 202860252*uk_56 + 229709403*uk_57 + 647362863*uk_58 + 83530692*uk_59 + 77*uk_6 + 266360625*uk_60 + 99441300*uk_61 + 241500300*uk_62 + 273463575*uk_63 + 770670075*uk_64 + 99441300*uk_65 + 37124752*uk_66 + 90160112*uk_67 + 102093068*uk_68 + 287716828*uk_69 + 217*uk_7 + 37124752*uk_70 + 218960272*uk_71 + 247940308*uk_72 + 698740868*uk_73 + 90160112*uk_74 + 280755937*uk_75 + 791221277*uk_76 + 102093068*uk_77 + 2229805417*uk_78 + 287716828*uk_79 + 28*uk_8 + 37124752*uk_80 + 250047*uk_81 + 297675*uk_82 + 111132*uk_83 + 269892*uk_84 + 305613*uk_85 + 861273*uk_86 + 111132*uk_87 + 354375*uk_88 + 132300*uk_89 + 2242306609*uk_9 + 321300*uk_90 + 363825*uk_91 + 1025325*uk_92 + 132300*uk_93 + 49392*uk_94 + 119952*uk_95 + 135828*uk_96 + 382788*uk_97 + 49392*uk_98 + 291312*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 298620*uk_100 + 820260*uk_101 + 283500*uk_102 + 393183*uk_103 + 1080009*uk_104 + 373275*uk_105 + 2966607*uk_106 + 1025325*uk_107 + 354375*uk_108 + 32768*uk_109 + 1515296*uk_11 + 76800*uk_110 + 61440*uk_111 + 80896*uk_112 + 222208*uk_113 + 76800*uk_114 + 180000*uk_115 + 144000*uk_116 + 189600*uk_117 + 520800*uk_118 + 180000*uk_119 + 3551475*uk_12 + 115200*uk_120 + 151680*uk_121 + 416640*uk_122 + 144000*uk_123 + 199712*uk_124 + 548576*uk_125 + 189600*uk_126 + 1506848*uk_127 + 520800*uk_128 + 180000*uk_129 + 2841180*uk_13 + 421875*uk_130 + 337500*uk_131 + 444375*uk_132 + 1220625*uk_133 + 421875*uk_134 + 270000*uk_135 + 355500*uk_136 + 976500*uk_137 + 337500*uk_138 + 468075*uk_139 + 3740887*uk_14 + 1285725*uk_140 + 444375*uk_141 + 3531675*uk_142 + 1220625*uk_143 + 421875*uk_144 + 216000*uk_145 + 284400*uk_146 + 781200*uk_147 + 270000*uk_148 + 374460*uk_149 + 10275601*uk_15 + 1028580*uk_150 + 355500*uk_151 + 2825340*uk_152 + 976500*uk_153 + 337500*uk_154 + 493039*uk_155 + 1354297*uk_156 + 468075*uk_157 + 3720031*uk_158 + 1285725*uk_159 + 3551475*uk_16 + 444375*uk_160 + 10218313*uk_161 + 3531675*uk_162 + 1220625*uk_163 + 421875*uk_164 + 3969*uk_17 + 2016*uk_18 + 4725*uk_19 + 63*uk_2 + 3780*uk_20 + 4977*uk_21 + 13671*uk_22 + 4725*uk_23 + 1024*uk_24 + 2400*uk_25 + 1920*uk_26 + 2528*uk_27 + 6944*uk_28 + 2400*uk_29 + 32*uk_3 + 5625*uk_30 + 4500*uk_31 + 5925*uk_32 + 16275*uk_33 + 5625*uk_34 + 3600*uk_35 + 4740*uk_36 + 13020*uk_37 + 4500*uk_38 + 6241*uk_39 + 75*uk_4 + 17143*uk_40 + 5925*uk_41 + 47089*uk_42 + 16275*uk_43 + 5625*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 71753811488*uk_47 + 168172995675*uk_48 + 134538396540*uk_49 + 60*uk_5 + 177142222111*uk_50 + 486580534153*uk_51 + 168172995675*uk_52 + 187944057*uk_53 + 95463648*uk_54 + 223742925*uk_55 + 178994340*uk_56 + 235675881*uk_57 + 647362863*uk_58 + 223742925*uk_59 + 79*uk_6 + 48489472*uk_60 + 113647200*uk_61 + 90917760*uk_62 + 119708384*uk_63 + 328819232*uk_64 + 113647200*uk_65 + 266360625*uk_66 + 213088500*uk_67 + 280566525*uk_68 + 770670075*uk_69 + 217*uk_7 + 266360625*uk_70 + 170470800*uk_71 + 224453220*uk_72 + 616536060*uk_73 + 213088500*uk_74 + 295530073*uk_75 + 811772479*uk_76 + 280566525*uk_77 + 2229805417*uk_78 + 770670075*uk_79 + 75*uk_8 + 266360625*uk_80 + 250047*uk_81 + 127008*uk_82 + 297675*uk_83 + 238140*uk_84 + 313551*uk_85 + 861273*uk_86 + 297675*uk_87 + 64512*uk_88 + 151200*uk_89 + 2242306609*uk_9 + 120960*uk_90 + 159264*uk_91 + 437472*uk_92 + 151200*uk_93 + 354375*uk_94 + 283500*uk_95 + 373275*uk_96 + 1025325*uk_97 + 354375*uk_98 + 226800*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 306180*uk_100 + 820260*uk_101 + 120960*uk_102 + 413343*uk_103 + 1107351*uk_104 + 163296*uk_105 + 2966607*uk_106 + 437472*uk_107 + 64512*uk_108 + 117649*uk_109 + 2320297*uk_11 + 76832*uk_110 + 144060*uk_111 + 194481*uk_112 + 521017*uk_113 + 76832*uk_114 + 50176*uk_115 + 94080*uk_116 + 127008*uk_117 + 340256*uk_118 + 50176*uk_119 + 1515296*uk_12 + 176400*uk_120 + 238140*uk_121 + 637980*uk_122 + 94080*uk_123 + 321489*uk_124 + 861273*uk_125 + 127008*uk_126 + 2307361*uk_127 + 340256*uk_128 + 50176*uk_129 + 2841180*uk_13 + 32768*uk_130 + 61440*uk_131 + 82944*uk_132 + 222208*uk_133 + 32768*uk_134 + 115200*uk_135 + 155520*uk_136 + 416640*uk_137 + 61440*uk_138 + 209952*uk_139 + 3835593*uk_14 + 562464*uk_140 + 82944*uk_141 + 1506848*uk_142 + 222208*uk_143 + 32768*uk_144 + 216000*uk_145 + 291600*uk_146 + 781200*uk_147 + 115200*uk_148 + 393660*uk_149 + 10275601*uk_15 + 1054620*uk_150 + 155520*uk_151 + 2825340*uk_152 + 416640*uk_153 + 61440*uk_154 + 531441*uk_155 + 1423737*uk_156 + 209952*uk_157 + 3814209*uk_158 + 562464*uk_159 + 1515296*uk_16 + 82944*uk_160 + 10218313*uk_161 + 1506848*uk_162 + 222208*uk_163 + 32768*uk_164 + 3969*uk_17 + 3087*uk_18 + 2016*uk_19 + 63*uk_2 + 3780*uk_20 + 5103*uk_21 + 13671*uk_22 + 2016*uk_23 + 2401*uk_24 + 1568*uk_25 + 2940*uk_26 + 3969*uk_27 + 10633*uk_28 + 1568*uk_29 + 49*uk_3 + 1024*uk_30 + 1920*uk_31 + 2592*uk_32 + 6944*uk_33 + 1024*uk_34 + 3600*uk_35 + 4860*uk_36 + 13020*uk_37 + 1920*uk_38 + 6561*uk_39 + 32*uk_4 + 17577*uk_40 + 2592*uk_41 + 47089*uk_42 + 6944*uk_43 + 1024*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 109873023841*uk_47 + 71753811488*uk_48 + 134538396540*uk_49 + 60*uk_5 + 181626835329*uk_50 + 486580534153*uk_51 + 71753811488*uk_52 + 187944057*uk_53 + 146178711*uk_54 + 95463648*uk_55 + 178994340*uk_56 + 241642359*uk_57 + 647362863*uk_58 + 95463648*uk_59 + 81*uk_6 + 113694553*uk_60 + 74249504*uk_61 + 139217820*uk_62 + 187944057*uk_63 + 503504449*uk_64 + 74249504*uk_65 + 48489472*uk_66 + 90917760*uk_67 + 122738976*uk_68 + 328819232*uk_69 + 217*uk_7 + 48489472*uk_70 + 170470800*uk_71 + 230135580*uk_72 + 616536060*uk_73 + 90917760*uk_74 + 310683033*uk_75 + 832323681*uk_76 + 122738976*uk_77 + 2229805417*uk_78 + 328819232*uk_79 + 32*uk_8 + 48489472*uk_80 + 250047*uk_81 + 194481*uk_82 + 127008*uk_83 + 238140*uk_84 + 321489*uk_85 + 861273*uk_86 + 127008*uk_87 + 151263*uk_88 + 98784*uk_89 + 2242306609*uk_9 + 185220*uk_90 + 250047*uk_91 + 669879*uk_92 + 98784*uk_93 + 64512*uk_94 + 120960*uk_95 + 163296*uk_96 + 437472*uk_97 + 64512*uk_98 + 226800*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 292824*uk_100 + 765576*uk_101 + 172872*uk_102 + 434007*uk_103 + 1134693*uk_104 + 256221*uk_105 + 2966607*uk_106 + 669879*uk_107 + 151263*uk_108 + 79507*uk_109 + 2036179*uk_11 + 90601*uk_110 + 103544*uk_111 + 153467*uk_112 + 401233*uk_113 + 90601*uk_114 + 103243*uk_115 + 117992*uk_116 + 174881*uk_117 + 457219*uk_118 + 103243*uk_119 + 2320297*uk_12 + 134848*uk_120 + 199864*uk_121 + 522536*uk_122 + 117992*uk_123 + 296227*uk_124 + 774473*uk_125 + 174881*uk_126 + 2024827*uk_127 + 457219*uk_128 + 103243*uk_129 + 2651768*uk_13 + 117649*uk_130 + 134456*uk_131 + 199283*uk_132 + 521017*uk_133 + 117649*uk_134 + 153664*uk_135 + 227752*uk_136 + 595448*uk_137 + 134456*uk_138 + 337561*uk_139 + 3930299*uk_14 + 882539*uk_140 + 199283*uk_141 + 2307361*uk_142 + 521017*uk_143 + 117649*uk_144 + 175616*uk_145 + 260288*uk_146 + 680512*uk_147 + 153664*uk_148 + 385784*uk_149 + 10275601*uk_15 + 1008616*uk_150 + 227752*uk_151 + 2636984*uk_152 + 595448*uk_153 + 134456*uk_154 + 571787*uk_155 + 1494913*uk_156 + 337561*uk_157 + 3908387*uk_158 + 882539*uk_159 + 2320297*uk_16 + 199283*uk_160 + 10218313*uk_161 + 2307361*uk_162 + 521017*uk_163 + 117649*uk_164 + 3969*uk_17 + 2709*uk_18 + 3087*uk_19 + 63*uk_2 + 3528*uk_20 + 5229*uk_21 + 13671*uk_22 + 3087*uk_23 + 1849*uk_24 + 2107*uk_25 + 2408*uk_26 + 3569*uk_27 + 9331*uk_28 + 2107*uk_29 + 43*uk_3 + 2401*uk_30 + 2744*uk_31 + 4067*uk_32 + 10633*uk_33 + 2401*uk_34 + 3136*uk_35 + 4648*uk_36 + 12152*uk_37 + 2744*uk_38 + 6889*uk_39 + 49*uk_4 + 18011*uk_40 + 4067*uk_41 + 47089*uk_42 + 10633*uk_43 + 2401*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 96419184187*uk_47 + 109873023841*uk_48 + 125569170104*uk_49 + 56*uk_5 + 186111448547*uk_50 + 486580534153*uk_51 + 109873023841*uk_52 + 187944057*uk_53 + 128279277*uk_54 + 146178711*uk_55 + 167061384*uk_56 + 247608837*uk_57 + 647362863*uk_58 + 146178711*uk_59 + 83*uk_6 + 87555697*uk_60 + 99772771*uk_61 + 114026024*uk_62 + 169002857*uk_63 + 441850843*uk_64 + 99772771*uk_65 + 113694553*uk_66 + 129936632*uk_67 + 192584651*uk_68 + 503504449*uk_69 + 217*uk_7 + 113694553*uk_70 + 148499008*uk_71 + 220096744*uk_72 + 575433656*uk_73 + 129936632*uk_74 + 326214817*uk_75 + 852874883*uk_76 + 192584651*uk_77 + 2229805417*uk_78 + 503504449*uk_79 + 49*uk_8 + 113694553*uk_80 + 250047*uk_81 + 170667*uk_82 + 194481*uk_83 + 222264*uk_84 + 329427*uk_85 + 861273*uk_86 + 194481*uk_87 + 116487*uk_88 + 132741*uk_89 + 2242306609*uk_9 + 151704*uk_90 + 224847*uk_91 + 587853*uk_92 + 132741*uk_93 + 151263*uk_94 + 172872*uk_95 + 256221*uk_96 + 669879*uk_97 + 151263*uk_98 + 197568*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 278460*uk_100 + 710892*uk_101 + 140868*uk_102 + 455175*uk_103 + 1162035*uk_104 + 230265*uk_105 + 2966607*uk_106 + 587853*uk_107 + 116487*uk_108 + 512*uk_109 + 378824*uk_11 + 2752*uk_110 + 3328*uk_111 + 5440*uk_112 + 13888*uk_113 + 2752*uk_114 + 14792*uk_115 + 17888*uk_116 + 29240*uk_117 + 74648*uk_118 + 14792*uk_119 + 2036179*uk_12 + 21632*uk_120 + 35360*uk_121 + 90272*uk_122 + 17888*uk_123 + 57800*uk_124 + 147560*uk_125 + 29240*uk_126 + 376712*uk_127 + 74648*uk_128 + 14792*uk_129 + 2462356*uk_13 + 79507*uk_130 + 96148*uk_131 + 157165*uk_132 + 401233*uk_133 + 79507*uk_134 + 116272*uk_135 + 190060*uk_136 + 485212*uk_137 + 96148*uk_138 + 310675*uk_139 + 4025005*uk_14 + 793135*uk_140 + 157165*uk_141 + 2024827*uk_142 + 401233*uk_143 + 79507*uk_144 + 140608*uk_145 + 229840*uk_146 + 586768*uk_147 + 116272*uk_148 + 375700*uk_149 + 10275601*uk_15 + 959140*uk_150 + 190060*uk_151 + 2448628*uk_152 + 485212*uk_153 + 96148*uk_154 + 614125*uk_155 + 1567825*uk_156 + 310675*uk_157 + 4002565*uk_158 + 793135*uk_159 + 2036179*uk_16 + 157165*uk_160 + 10218313*uk_161 + 2024827*uk_162 + 401233*uk_163 + 79507*uk_164 + 3969*uk_17 + 504*uk_18 + 2709*uk_19 + 63*uk_2 + 3276*uk_20 + 5355*uk_21 + 13671*uk_22 + 2709*uk_23 + 64*uk_24 + 344*uk_25 + 416*uk_26 + 680*uk_27 + 1736*uk_28 + 344*uk_29 + 8*uk_3 + 1849*uk_30 + 2236*uk_31 + 3655*uk_32 + 9331*uk_33 + 1849*uk_34 + 2704*uk_35 + 4420*uk_36 + 11284*uk_37 + 2236*uk_38 + 7225*uk_39 + 43*uk_4 + 18445*uk_40 + 3655*uk_41 + 47089*uk_42 + 9331*uk_43 + 1849*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 17938452872*uk_47 + 96419184187*uk_48 + 116599943668*uk_49 + 52*uk_5 + 190596061765*uk_50 + 486580534153*uk_51 + 96419184187*uk_52 + 187944057*uk_53 + 23865912*uk_54 + 128279277*uk_55 + 155128428*uk_56 + 253575315*uk_57 + 647362863*uk_58 + 128279277*uk_59 + 85*uk_6 + 3030592*uk_60 + 16289432*uk_61 + 19698848*uk_62 + 32200040*uk_63 + 82204808*uk_64 + 16289432*uk_65 + 87555697*uk_66 + 105881308*uk_67 + 173075215*uk_68 + 441850843*uk_69 + 217*uk_7 + 87555697*uk_70 + 128042512*uk_71 + 209300260*uk_72 + 534331252*uk_73 + 105881308*uk_74 + 342125425*uk_75 + 873426085*uk_76 + 173075215*uk_77 + 2229805417*uk_78 + 441850843*uk_79 + 43*uk_8 + 87555697*uk_80 + 250047*uk_81 + 31752*uk_82 + 170667*uk_83 + 206388*uk_84 + 337365*uk_85 + 861273*uk_86 + 170667*uk_87 + 4032*uk_88 + 21672*uk_89 + 2242306609*uk_9 + 26208*uk_90 + 42840*uk_91 + 109368*uk_92 + 21672*uk_93 + 116487*uk_94 + 140868*uk_95 + 230265*uk_96 + 587853*uk_97 + 116487*uk_98 + 170352*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 285012*uk_100 + 710892*uk_101 + 26208*uk_102 + 476847*uk_103 + 1189377*uk_104 + 43848*uk_105 + 2966607*uk_106 + 109368*uk_107 + 4032*uk_108 + 15625*uk_109 + 1183825*uk_11 + 5000*uk_110 + 32500*uk_111 + 54375*uk_112 + 135625*uk_113 + 5000*uk_114 + 1600*uk_115 + 10400*uk_116 + 17400*uk_117 + 43400*uk_118 + 1600*uk_119 + 378824*uk_12 + 67600*uk_120 + 113100*uk_121 + 282100*uk_122 + 10400*uk_123 + 189225*uk_124 + 471975*uk_125 + 17400*uk_126 + 1177225*uk_127 + 43400*uk_128 + 1600*uk_129 + 2462356*uk_13 + 512*uk_130 + 3328*uk_131 + 5568*uk_132 + 13888*uk_133 + 512*uk_134 + 21632*uk_135 + 36192*uk_136 + 90272*uk_137 + 3328*uk_138 + 60552*uk_139 + 4119711*uk_14 + 151032*uk_140 + 5568*uk_141 + 376712*uk_142 + 13888*uk_143 + 512*uk_144 + 140608*uk_145 + 235248*uk_146 + 586768*uk_147 + 21632*uk_148 + 393588*uk_149 + 10275601*uk_15 + 981708*uk_150 + 36192*uk_151 + 2448628*uk_152 + 90272*uk_153 + 3328*uk_154 + 658503*uk_155 + 1642473*uk_156 + 60552*uk_157 + 4096743*uk_158 + 151032*uk_159 + 378824*uk_16 + 5568*uk_160 + 10218313*uk_161 + 376712*uk_162 + 13888*uk_163 + 512*uk_164 + 3969*uk_17 + 1575*uk_18 + 504*uk_19 + 63*uk_2 + 3276*uk_20 + 5481*uk_21 + 13671*uk_22 + 504*uk_23 + 625*uk_24 + 200*uk_25 + 1300*uk_26 + 2175*uk_27 + 5425*uk_28 + 200*uk_29 + 25*uk_3 + 64*uk_30 + 416*uk_31 + 696*uk_32 + 1736*uk_33 + 64*uk_34 + 2704*uk_35 + 4524*uk_36 + 11284*uk_37 + 416*uk_38 + 7569*uk_39 + 8*uk_4 + 18879*uk_40 + 696*uk_41 + 47089*uk_42 + 1736*uk_43 + 64*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 56057665225*uk_47 + 17938452872*uk_48 + 116599943668*uk_49 + 52*uk_5 + 195080674983*uk_50 + 486580534153*uk_51 + 17938452872*uk_52 + 187944057*uk_53 + 74580975*uk_54 + 23865912*uk_55 + 155128428*uk_56 + 259541793*uk_57 + 647362863*uk_58 + 23865912*uk_59 + 87*uk_6 + 29595625*uk_60 + 9470600*uk_61 + 61558900*uk_62 + 102992775*uk_63 + 256890025*uk_64 + 9470600*uk_65 + 3030592*uk_66 + 19698848*uk_67 + 32957688*uk_68 + 82204808*uk_69 + 217*uk_7 + 3030592*uk_70 + 128042512*uk_71 + 214224972*uk_72 + 534331252*uk_73 + 19698848*uk_74 + 358414857*uk_75 + 893977287*uk_76 + 32957688*uk_77 + 2229805417*uk_78 + 82204808*uk_79 + 8*uk_8 + 3030592*uk_80 + 250047*uk_81 + 99225*uk_82 + 31752*uk_83 + 206388*uk_84 + 345303*uk_85 + 861273*uk_86 + 31752*uk_87 + 39375*uk_88 + 12600*uk_89 + 2242306609*uk_9 + 81900*uk_90 + 137025*uk_91 + 341775*uk_92 + 12600*uk_93 + 4032*uk_94 + 26208*uk_95 + 43848*uk_96 + 109368*uk_97 + 4032*uk_98 + 170352*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 269136*uk_100 + 656208*uk_101 + 75600*uk_102 + 499023*uk_103 + 1216719*uk_104 + 140175*uk_105 + 2966607*uk_106 + 341775*uk_107 + 39375*uk_108 + 125*uk_109 + 236765*uk_11 + 625*uk_110 + 1200*uk_111 + 2225*uk_112 + 5425*uk_113 + 625*uk_114 + 3125*uk_115 + 6000*uk_116 + 11125*uk_117 + 27125*uk_118 + 3125*uk_119 + 1183825*uk_12 + 11520*uk_120 + 21360*uk_121 + 52080*uk_122 + 6000*uk_123 + 39605*uk_124 + 96565*uk_125 + 11125*uk_126 + 235445*uk_127 + 27125*uk_128 + 3125*uk_129 + 2272944*uk_13 + 15625*uk_130 + 30000*uk_131 + 55625*uk_132 + 135625*uk_133 + 15625*uk_134 + 57600*uk_135 + 106800*uk_136 + 260400*uk_137 + 30000*uk_138 + 198025*uk_139 + 4214417*uk_14 + 482825*uk_140 + 55625*uk_141 + 1177225*uk_142 + 135625*uk_143 + 15625*uk_144 + 110592*uk_145 + 205056*uk_146 + 499968*uk_147 + 57600*uk_148 + 380208*uk_149 + 10275601*uk_15 + 927024*uk_150 + 106800*uk_151 + 2260272*uk_152 + 260400*uk_153 + 30000*uk_154 + 704969*uk_155 + 1718857*uk_156 + 198025*uk_157 + 4190921*uk_158 + 482825*uk_159 + 1183825*uk_16 + 55625*uk_160 + 10218313*uk_161 + 1177225*uk_162 + 135625*uk_163 + 15625*uk_164 + 3969*uk_17 + 315*uk_18 + 1575*uk_19 + 63*uk_2 + 3024*uk_20 + 5607*uk_21 + 13671*uk_22 + 1575*uk_23 + 25*uk_24 + 125*uk_25 + 240*uk_26 + 445*uk_27 + 1085*uk_28 + 125*uk_29 + 5*uk_3 + 625*uk_30 + 1200*uk_31 + 2225*uk_32 + 5425*uk_33 + 625*uk_34 + 2304*uk_35 + 4272*uk_36 + 10416*uk_37 + 1200*uk_38 + 7921*uk_39 + 25*uk_4 + 19313*uk_40 + 2225*uk_41 + 47089*uk_42 + 5425*uk_43 + 625*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 11211533045*uk_47 + 56057665225*uk_48 + 107630717232*uk_49 + 48*uk_5 + 199565288201*uk_50 + 486580534153*uk_51 + 56057665225*uk_52 + 187944057*uk_53 + 14916195*uk_54 + 74580975*uk_55 + 143195472*uk_56 + 265508271*uk_57 + 647362863*uk_58 + 74580975*uk_59 + 89*uk_6 + 1183825*uk_60 + 5919125*uk_61 + 11364720*uk_62 + 21072085*uk_63 + 51378005*uk_64 + 5919125*uk_65 + 29595625*uk_66 + 56823600*uk_67 + 105360425*uk_68 + 256890025*uk_69 + 217*uk_7 + 29595625*uk_70 + 109101312*uk_71 + 202292016*uk_72 + 493228848*uk_73 + 56823600*uk_74 + 375083113*uk_75 + 914528489*uk_76 + 105360425*uk_77 + 2229805417*uk_78 + 256890025*uk_79 + 25*uk_8 + 29595625*uk_80 + 250047*uk_81 + 19845*uk_82 + 99225*uk_83 + 190512*uk_84 + 353241*uk_85 + 861273*uk_86 + 99225*uk_87 + 1575*uk_88 + 7875*uk_89 + 2242306609*uk_9 + 15120*uk_90 + 28035*uk_91 + 68355*uk_92 + 7875*uk_93 + 39375*uk_94 + 75600*uk_95 + 140175*uk_96 + 341775*uk_97 + 39375*uk_98 + 145152*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 275184*uk_100 + 656208*uk_101 + 15120*uk_102 + 521703*uk_103 + 1244061*uk_104 + 28665*uk_105 + 2966607*uk_106 + 68355*uk_107 + 1575*uk_108 + 35937*uk_109 + 1562649*uk_11 + 5445*uk_110 + 52272*uk_111 + 99099*uk_112 + 236313*uk_113 + 5445*uk_114 + 825*uk_115 + 7920*uk_116 + 15015*uk_117 + 35805*uk_118 + 825*uk_119 + 236765*uk_12 + 76032*uk_120 + 144144*uk_121 + 343728*uk_122 + 7920*uk_123 + 273273*uk_124 + 651651*uk_125 + 15015*uk_126 + 1553937*uk_127 + 35805*uk_128 + 825*uk_129 + 2272944*uk_13 + 125*uk_130 + 1200*uk_131 + 2275*uk_132 + 5425*uk_133 + 125*uk_134 + 11520*uk_135 + 21840*uk_136 + 52080*uk_137 + 1200*uk_138 + 41405*uk_139 + 4309123*uk_14 + 98735*uk_140 + 2275*uk_141 + 235445*uk_142 + 5425*uk_143 + 125*uk_144 + 110592*uk_145 + 209664*uk_146 + 499968*uk_147 + 11520*uk_148 + 397488*uk_149 + 10275601*uk_15 + 947856*uk_150 + 21840*uk_151 + 2260272*uk_152 + 52080*uk_153 + 1200*uk_154 + 753571*uk_155 + 1796977*uk_156 + 41405*uk_157 + 4285099*uk_158 + 98735*uk_159 + 236765*uk_16 + 2275*uk_160 + 10218313*uk_161 + 235445*uk_162 + 5425*uk_163 + 125*uk_164 + 3969*uk_17 + 2079*uk_18 + 315*uk_19 + 63*uk_2 + 3024*uk_20 + 5733*uk_21 + 13671*uk_22 + 315*uk_23 + 1089*uk_24 + 165*uk_25 + 1584*uk_26 + 3003*uk_27 + 7161*uk_28 + 165*uk_29 + 33*uk_3 + 25*uk_30 + 240*uk_31 + 455*uk_32 + 1085*uk_33 + 25*uk_34 + 2304*uk_35 + 4368*uk_36 + 10416*uk_37 + 240*uk_38 + 8281*uk_39 + 5*uk_4 + 19747*uk_40 + 455*uk_41 + 47089*uk_42 + 1085*uk_43 + 25*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 73996118097*uk_47 + 11211533045*uk_48 + 107630717232*uk_49 + 48*uk_5 + 204049901419*uk_50 + 486580534153*uk_51 + 11211533045*uk_52 + 187944057*uk_53 + 98446887*uk_54 + 14916195*uk_55 + 143195472*uk_56 + 271474749*uk_57 + 647362863*uk_58 + 14916195*uk_59 + 91*uk_6 + 51567417*uk_60 + 7813245*uk_61 + 75007152*uk_62 + 142201059*uk_63 + 339094833*uk_64 + 7813245*uk_65 + 1183825*uk_66 + 11364720*uk_67 + 21545615*uk_68 + 51378005*uk_69 + 217*uk_7 + 1183825*uk_70 + 109101312*uk_71 + 206837904*uk_72 + 493228848*uk_73 + 11364720*uk_74 + 392130193*uk_75 + 935079691*uk_76 + 21545615*uk_77 + 2229805417*uk_78 + 51378005*uk_79 + 5*uk_8 + 1183825*uk_80 + 250047*uk_81 + 130977*uk_82 + 19845*uk_83 + 190512*uk_84 + 361179*uk_85 + 861273*uk_86 + 19845*uk_87 + 68607*uk_88 + 10395*uk_89 + 2242306609*uk_9 + 99792*uk_90 + 189189*uk_91 + 451143*uk_92 + 10395*uk_93 + 1575*uk_94 + 15120*uk_95 + 28665*uk_96 + 68355*uk_97 + 1575*uk_98 + 145152*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 257796*uk_100 + 601524*uk_101 + 91476*uk_102 + 544887*uk_103 + 1271403*uk_104 + 193347*uk_105 + 2966607*uk_106 + 451143*uk_107 + 68607*uk_108 + 4096*uk_109 + 757648*uk_11 + 8448*uk_110 + 11264*uk_111 + 23808*uk_112 + 55552*uk_113 + 8448*uk_114 + 17424*uk_115 + 23232*uk_116 + 49104*uk_117 + 114576*uk_118 + 17424*uk_119 + 1562649*uk_12 + 30976*uk_120 + 65472*uk_121 + 152768*uk_122 + 23232*uk_123 + 138384*uk_124 + 322896*uk_125 + 49104*uk_126 + 753424*uk_127 + 114576*uk_128 + 17424*uk_129 + 2083532*uk_13 + 35937*uk_130 + 47916*uk_131 + 101277*uk_132 + 236313*uk_133 + 35937*uk_134 + 63888*uk_135 + 135036*uk_136 + 315084*uk_137 + 47916*uk_138 + 285417*uk_139 + 4403829*uk_14 + 665973*uk_140 + 101277*uk_141 + 1553937*uk_142 + 236313*uk_143 + 35937*uk_144 + 85184*uk_145 + 180048*uk_146 + 420112*uk_147 + 63888*uk_148 + 380556*uk_149 + 10275601*uk_15 + 887964*uk_150 + 135036*uk_151 + 2071916*uk_152 + 315084*uk_153 + 47916*uk_154 + 804357*uk_155 + 1876833*uk_156 + 285417*uk_157 + 4379277*uk_158 + 665973*uk_159 + 1562649*uk_16 + 101277*uk_160 + 10218313*uk_161 + 1553937*uk_162 + 236313*uk_163 + 35937*uk_164 + 3969*uk_17 + 1008*uk_18 + 2079*uk_19 + 63*uk_2 + 2772*uk_20 + 5859*uk_21 + 13671*uk_22 + 2079*uk_23 + 256*uk_24 + 528*uk_25 + 704*uk_26 + 1488*uk_27 + 3472*uk_28 + 528*uk_29 + 16*uk_3 + 1089*uk_30 + 1452*uk_31 + 3069*uk_32 + 7161*uk_33 + 1089*uk_34 + 1936*uk_35 + 4092*uk_36 + 9548*uk_37 + 1452*uk_38 + 8649*uk_39 + 33*uk_4 + 20181*uk_40 + 3069*uk_41 + 47089*uk_42 + 7161*uk_43 + 1089*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 35876905744*uk_47 + 73996118097*uk_48 + 98661490796*uk_49 + 44*uk_5 + 208534514637*uk_50 + 486580534153*uk_51 + 73996118097*uk_52 + 187944057*uk_53 + 47731824*uk_54 + 98446887*uk_55 + 131262516*uk_56 + 277441227*uk_57 + 647362863*uk_58 + 98446887*uk_59 + 93*uk_6 + 12122368*uk_60 + 25002384*uk_61 + 33336512*uk_62 + 70461264*uk_63 + 164409616*uk_64 + 25002384*uk_65 + 51567417*uk_66 + 68756556*uk_67 + 145326357*uk_68 + 339094833*uk_69 + 217*uk_7 + 51567417*uk_70 + 91675408*uk_71 + 193768476*uk_72 + 452126444*uk_73 + 68756556*uk_74 + 409556097*uk_75 + 955630893*uk_76 + 145326357*uk_77 + 2229805417*uk_78 + 339094833*uk_79 + 33*uk_8 + 51567417*uk_80 + 250047*uk_81 + 63504*uk_82 + 130977*uk_83 + 174636*uk_84 + 369117*uk_85 + 861273*uk_86 + 130977*uk_87 + 16128*uk_88 + 33264*uk_89 + 2242306609*uk_9 + 44352*uk_90 + 93744*uk_91 + 218736*uk_92 + 33264*uk_93 + 68607*uk_94 + 91476*uk_95 + 193347*uk_96 + 451143*uk_97 + 68607*uk_98 + 121968*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 263340*uk_100 + 601524*uk_101 + 44352*uk_102 + 568575*uk_103 + 1298745*uk_104 + 95760*uk_105 + 2966607*uk_106 + 218736*uk_107 + 16128*uk_108 + 79507*uk_109 + 2036179*uk_11 + 29584*uk_110 + 81356*uk_111 + 175655*uk_112 + 401233*uk_113 + 29584*uk_114 + 11008*uk_115 + 30272*uk_116 + 65360*uk_117 + 149296*uk_118 + 11008*uk_119 + 757648*uk_12 + 83248*uk_120 + 179740*uk_121 + 410564*uk_122 + 30272*uk_123 + 388075*uk_124 + 886445*uk_125 + 65360*uk_126 + 2024827*uk_127 + 149296*uk_128 + 11008*uk_129 + 2083532*uk_13 + 4096*uk_130 + 11264*uk_131 + 24320*uk_132 + 55552*uk_133 + 4096*uk_134 + 30976*uk_135 + 66880*uk_136 + 152768*uk_137 + 11264*uk_138 + 144400*uk_139 + 4498535*uk_14 + 329840*uk_140 + 24320*uk_141 + 753424*uk_142 + 55552*uk_143 + 4096*uk_144 + 85184*uk_145 + 183920*uk_146 + 420112*uk_147 + 30976*uk_148 + 397100*uk_149 + 10275601*uk_15 + 907060*uk_150 + 66880*uk_151 + 2071916*uk_152 + 152768*uk_153 + 11264*uk_154 + 857375*uk_155 + 1958425*uk_156 + 144400*uk_157 + 4473455*uk_158 + 329840*uk_159 + 757648*uk_16 + 24320*uk_160 + 10218313*uk_161 + 753424*uk_162 + 55552*uk_163 + 4096*uk_164 + 3969*uk_17 + 2709*uk_18 + 1008*uk_19 + 63*uk_2 + 2772*uk_20 + 5985*uk_21 + 13671*uk_22 + 1008*uk_23 + 1849*uk_24 + 688*uk_25 + 1892*uk_26 + 4085*uk_27 + 9331*uk_28 + 688*uk_29 + 43*uk_3 + 256*uk_30 + 704*uk_31 + 1520*uk_32 + 3472*uk_33 + 256*uk_34 + 1936*uk_35 + 4180*uk_36 + 9548*uk_37 + 704*uk_38 + 9025*uk_39 + 16*uk_4 + 20615*uk_40 + 1520*uk_41 + 47089*uk_42 + 3472*uk_43 + 256*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 96419184187*uk_47 + 35876905744*uk_48 + 98661490796*uk_49 + 44*uk_5 + 213019127855*uk_50 + 486580534153*uk_51 + 35876905744*uk_52 + 187944057*uk_53 + 128279277*uk_54 + 47731824*uk_55 + 131262516*uk_56 + 283407705*uk_57 + 647362863*uk_58 + 47731824*uk_59 + 95*uk_6 + 87555697*uk_60 + 32578864*uk_61 + 89591876*uk_62 + 193437005*uk_63 + 441850843*uk_64 + 32578864*uk_65 + 12122368*uk_66 + 33336512*uk_67 + 71976560*uk_68 + 164409616*uk_69 + 217*uk_7 + 12122368*uk_70 + 91675408*uk_71 + 197935540*uk_72 + 452126444*uk_73 + 33336512*uk_74 + 427360825*uk_75 + 976182095*uk_76 + 71976560*uk_77 + 2229805417*uk_78 + 164409616*uk_79 + 16*uk_8 + 12122368*uk_80 + 250047*uk_81 + 170667*uk_82 + 63504*uk_83 + 174636*uk_84 + 377055*uk_85 + 861273*uk_86 + 63504*uk_87 + 116487*uk_88 + 43344*uk_89 + 2242306609*uk_9 + 119196*uk_90 + 257355*uk_91 + 587853*uk_92 + 43344*uk_93 + 16128*uk_94 + 44352*uk_95 + 95760*uk_96 + 218736*uk_97 + 16128*uk_98 + 121968*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 244440*uk_100 + 546840*uk_101 + 108360*uk_102 + 592767*uk_103 + 1326087*uk_104 + 262773*uk_105 + 2966607*uk_106 + 587853*uk_107 + 116487*uk_108 + 4913*uk_109 + 805001*uk_11 + 12427*uk_110 + 11560*uk_111 + 28033*uk_112 + 62713*uk_113 + 12427*uk_114 + 31433*uk_115 + 29240*uk_116 + 70907*uk_117 + 158627*uk_118 + 31433*uk_119 + 2036179*uk_12 + 27200*uk_120 + 65960*uk_121 + 147560*uk_122 + 29240*uk_123 + 159953*uk_124 + 357833*uk_125 + 70907*uk_126 + 800513*uk_127 + 158627*uk_128 + 31433*uk_129 + 1894120*uk_13 + 79507*uk_130 + 73960*uk_131 + 179353*uk_132 + 401233*uk_133 + 79507*uk_134 + 68800*uk_135 + 166840*uk_136 + 373240*uk_137 + 73960*uk_138 + 404587*uk_139 + 4593241*uk_14 + 905107*uk_140 + 179353*uk_141 + 2024827*uk_142 + 401233*uk_143 + 79507*uk_144 + 64000*uk_145 + 155200*uk_146 + 347200*uk_147 + 68800*uk_148 + 376360*uk_149 + 10275601*uk_15 + 841960*uk_150 + 166840*uk_151 + 1883560*uk_152 + 373240*uk_153 + 73960*uk_154 + 912673*uk_155 + 2041753*uk_156 + 404587*uk_157 + 4567633*uk_158 + 905107*uk_159 + 2036179*uk_16 + 179353*uk_160 + 10218313*uk_161 + 2024827*uk_162 + 401233*uk_163 + 79507*uk_164 + 3969*uk_17 + 1071*uk_18 + 2709*uk_19 + 63*uk_2 + 2520*uk_20 + 6111*uk_21 + 13671*uk_22 + 2709*uk_23 + 289*uk_24 + 731*uk_25 + 680*uk_26 + 1649*uk_27 + 3689*uk_28 + 731*uk_29 + 17*uk_3 + 1849*uk_30 + 1720*uk_31 + 4171*uk_32 + 9331*uk_33 + 1849*uk_34 + 1600*uk_35 + 3880*uk_36 + 8680*uk_37 + 1720*uk_38 + 9409*uk_39 + 43*uk_4 + 21049*uk_40 + 4171*uk_41 + 47089*uk_42 + 9331*uk_43 + 1849*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 38119212353*uk_47 + 96419184187*uk_48 + 89692264360*uk_49 + 40*uk_5 + 217503741073*uk_50 + 486580534153*uk_51 + 96419184187*uk_52 + 187944057*uk_53 + 50715063*uk_54 + 128279277*uk_55 + 119329560*uk_56 + 289374183*uk_57 + 647362863*uk_58 + 128279277*uk_59 + 97*uk_6 + 13685017*uk_60 + 34615043*uk_61 + 32200040*uk_62 + 78085097*uk_63 + 174685217*uk_64 + 34615043*uk_65 + 87555697*uk_66 + 81447160*uk_67 + 197509363*uk_68 + 441850843*uk_69 + 217*uk_7 + 87555697*uk_70 + 75764800*uk_71 + 183729640*uk_72 + 411024040*uk_73 + 81447160*uk_74 + 445544377*uk_75 + 996733297*uk_76 + 197509363*uk_77 + 2229805417*uk_78 + 441850843*uk_79 + 43*uk_8 + 87555697*uk_80 + 250047*uk_81 + 67473*uk_82 + 170667*uk_83 + 158760*uk_84 + 384993*uk_85 + 861273*uk_86 + 170667*uk_87 + 18207*uk_88 + 46053*uk_89 + 2242306609*uk_9 + 42840*uk_90 + 103887*uk_91 + 232407*uk_92 + 46053*uk_93 + 116487*uk_94 + 108360*uk_95 + 262773*uk_96 + 587853*uk_97 + 116487*uk_98 + 100800*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 249480*uk_100 + 546840*uk_101 + 42840*uk_102 + 617463*uk_103 + 1353429*uk_104 + 106029*uk_105 + 2966607*uk_106 + 232407*uk_107 + 18207*uk_108 + 29791*uk_109 + 1467943*uk_11 + 16337*uk_110 + 38440*uk_111 + 95139*uk_112 + 208537*uk_113 + 16337*uk_114 + 8959*uk_115 + 21080*uk_116 + 52173*uk_117 + 114359*uk_118 + 8959*uk_119 + 805001*uk_12 + 49600*uk_120 + 122760*uk_121 + 269080*uk_122 + 21080*uk_123 + 303831*uk_124 + 665973*uk_125 + 52173*uk_126 + 1459759*uk_127 + 114359*uk_128 + 8959*uk_129 + 1894120*uk_13 + 4913*uk_130 + 11560*uk_131 + 28611*uk_132 + 62713*uk_133 + 4913*uk_134 + 27200*uk_135 + 67320*uk_136 + 147560*uk_137 + 11560*uk_138 + 166617*uk_139 + 4687947*uk_14 + 365211*uk_140 + 28611*uk_141 + 800513*uk_142 + 62713*uk_143 + 4913*uk_144 + 64000*uk_145 + 158400*uk_146 + 347200*uk_147 + 27200*uk_148 + 392040*uk_149 + 10275601*uk_15 + 859320*uk_150 + 67320*uk_151 + 1883560*uk_152 + 147560*uk_153 + 11560*uk_154 + 970299*uk_155 + 2126817*uk_156 + 166617*uk_157 + 4661811*uk_158 + 365211*uk_159 + 805001*uk_16 + 28611*uk_160 + 10218313*uk_161 + 800513*uk_162 + 62713*uk_163 + 4913*uk_164 + 3969*uk_17 + 1953*uk_18 + 1071*uk_19 + 63*uk_2 + 2520*uk_20 + 6237*uk_21 + 13671*uk_22 + 1071*uk_23 + 961*uk_24 + 527*uk_25 + 1240*uk_26 + 3069*uk_27 + 6727*uk_28 + 527*uk_29 + 31*uk_3 + 289*uk_30 + 680*uk_31 + 1683*uk_32 + 3689*uk_33 + 289*uk_34 + 1600*uk_35 + 3960*uk_36 + 8680*uk_37 + 680*uk_38 + 9801*uk_39 + 17*uk_4 + 21483*uk_40 + 1683*uk_41 + 47089*uk_42 + 3689*uk_43 + 289*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 69511504879*uk_47 + 38119212353*uk_48 + 89692264360*uk_49 + 40*uk_5 + 221988354291*uk_50 + 486580534153*uk_51 + 38119212353*uk_52 + 187944057*uk_53 + 92480409*uk_54 + 50715063*uk_55 + 119329560*uk_56 + 295340661*uk_57 + 647362863*uk_58 + 50715063*uk_59 + 99*uk_6 + 45506233*uk_60 + 24955031*uk_61 + 58717720*uk_62 + 145326357*uk_63 + 318543631*uk_64 + 24955031*uk_65 + 13685017*uk_66 + 32200040*uk_67 + 79695099*uk_68 + 174685217*uk_69 + 217*uk_7 + 13685017*uk_70 + 75764800*uk_71 + 187517880*uk_72 + 411024040*uk_73 + 32200040*uk_74 + 464106753*uk_75 + 1017284499*uk_76 + 79695099*uk_77 + 2229805417*uk_78 + 174685217*uk_79 + 17*uk_8 + 13685017*uk_80 + 250047*uk_81 + 123039*uk_82 + 67473*uk_83 + 158760*uk_84 + 392931*uk_85 + 861273*uk_86 + 67473*uk_87 + 60543*uk_88 + 33201*uk_89 + 2242306609*uk_9 + 78120*uk_90 + 193347*uk_91 + 423801*uk_92 + 33201*uk_93 + 18207*uk_94 + 42840*uk_95 + 106029*uk_96 + 232407*uk_97 + 18207*uk_98 + 100800*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 254520*uk_100 + 546840*uk_101 + 78120*uk_102 + 642663*uk_103 + 1380771*uk_104 + 197253*uk_105 + 2966607*uk_106 + 423801*uk_107 + 60543*uk_108 + 614125*uk_109 + 4025005*uk_11 + 223975*uk_110 + 289000*uk_111 + 729725*uk_112 + 1567825*uk_113 + 223975*uk_114 + 81685*uk_115 + 105400*uk_116 + 266135*uk_117 + 571795*uk_118 + 81685*uk_119 + 1467943*uk_12 + 136000*uk_120 + 343400*uk_121 + 737800*uk_122 + 105400*uk_123 + 867085*uk_124 + 1862945*uk_125 + 266135*uk_126 + 4002565*uk_127 + 571795*uk_128 + 81685*uk_129 + 1894120*uk_13 + 29791*uk_130 + 38440*uk_131 + 97061*uk_132 + 208537*uk_133 + 29791*uk_134 + 49600*uk_135 + 125240*uk_136 + 269080*uk_137 + 38440*uk_138 + 316231*uk_139 + 4782653*uk_14 + 679427*uk_140 + 97061*uk_141 + 1459759*uk_142 + 208537*uk_143 + 29791*uk_144 + 64000*uk_145 + 161600*uk_146 + 347200*uk_147 + 49600*uk_148 + 408040*uk_149 + 10275601*uk_15 + 876680*uk_150 + 125240*uk_151 + 1883560*uk_152 + 269080*uk_153 + 38440*uk_154 + 1030301*uk_155 + 2213617*uk_156 + 316231*uk_157 + 4755989*uk_158 + 679427*uk_159 + 1467943*uk_16 + 97061*uk_160 + 10218313*uk_161 + 1459759*uk_162 + 208537*uk_163 + 29791*uk_164 + 3969*uk_17 + 5355*uk_18 + 1953*uk_19 + 63*uk_2 + 2520*uk_20 + 6363*uk_21 + 13671*uk_22 + 1953*uk_23 + 7225*uk_24 + 2635*uk_25 + 3400*uk_26 + 8585*uk_27 + 18445*uk_28 + 2635*uk_29 + 85*uk_3 + 961*uk_30 + 1240*uk_31 + 3131*uk_32 + 6727*uk_33 + 961*uk_34 + 1600*uk_35 + 4040*uk_36 + 8680*uk_37 + 1240*uk_38 + 10201*uk_39 + 31*uk_4 + 21917*uk_40 + 3131*uk_41 + 47089*uk_42 + 6727*uk_43 + 961*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 190596061765*uk_47 + 69511504879*uk_48 + 89692264360*uk_49 + 40*uk_5 + 226472967509*uk_50 + 486580534153*uk_51 + 69511504879*uk_52 + 187944057*uk_53 + 253575315*uk_54 + 92480409*uk_55 + 119329560*uk_56 + 301307139*uk_57 + 647362863*uk_58 + 92480409*uk_59 + 101*uk_6 + 342125425*uk_60 + 124775155*uk_61 + 161000200*uk_62 + 406525505*uk_63 + 873426085*uk_64 + 124775155*uk_65 + 45506233*uk_66 + 58717720*uk_67 + 148262243*uk_68 + 318543631*uk_69 + 217*uk_7 + 45506233*uk_70 + 75764800*uk_71 + 191306120*uk_72 + 411024040*uk_73 + 58717720*uk_74 + 483047953*uk_75 + 1037835701*uk_76 + 148262243*uk_77 + 2229805417*uk_78 + 318543631*uk_79 + 31*uk_8 + 45506233*uk_80 + 250047*uk_81 + 337365*uk_82 + 123039*uk_83 + 158760*uk_84 + 400869*uk_85 + 861273*uk_86 + 123039*uk_87 + 455175*uk_88 + 166005*uk_89 + 2242306609*uk_9 + 214200*uk_90 + 540855*uk_91 + 1162035*uk_92 + 166005*uk_93 + 60543*uk_94 + 78120*uk_95 + 197253*uk_96 + 423801*uk_97 + 60543*uk_98 + 100800*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 233604*uk_100 + 492156*uk_101 + 192780*uk_102 + 668367*uk_103 + 1408113*uk_104 + 551565*uk_105 + 2966607*uk_106 + 1162035*uk_107 + 455175*uk_108 + 438976*uk_109 + 3598828*uk_11 + 490960*uk_110 + 207936*uk_111 + 594928*uk_112 + 1253392*uk_113 + 490960*uk_114 + 549100*uk_115 + 232560*uk_116 + 665380*uk_117 + 1401820*uk_118 + 549100*uk_119 + 4025005*uk_12 + 98496*uk_120 + 281808*uk_121 + 593712*uk_122 + 232560*uk_123 + 806284*uk_124 + 1698676*uk_125 + 665380*uk_126 + 3578764*uk_127 + 1401820*uk_128 + 549100*uk_129 + 1704708*uk_13 + 614125*uk_130 + 260100*uk_131 + 744175*uk_132 + 1567825*uk_133 + 614125*uk_134 + 110160*uk_135 + 315180*uk_136 + 664020*uk_137 + 260100*uk_138 + 901765*uk_139 + 4877359*uk_14 + 1899835*uk_140 + 744175*uk_141 + 4002565*uk_142 + 1567825*uk_143 + 614125*uk_144 + 46656*uk_145 + 133488*uk_146 + 281232*uk_147 + 110160*uk_148 + 381924*uk_149 + 10275601*uk_15 + 804636*uk_150 + 315180*uk_151 + 1695204*uk_152 + 664020*uk_153 + 260100*uk_154 + 1092727*uk_155 + 2302153*uk_156 + 901765*uk_157 + 4850167*uk_158 + 1899835*uk_159 + 4025005*uk_16 + 744175*uk_160 + 10218313*uk_161 + 4002565*uk_162 + 1567825*uk_163 + 614125*uk_164 + 3969*uk_17 + 4788*uk_18 + 5355*uk_19 + 63*uk_2 + 2268*uk_20 + 6489*uk_21 + 13671*uk_22 + 5355*uk_23 + 5776*uk_24 + 6460*uk_25 + 2736*uk_26 + 7828*uk_27 + 16492*uk_28 + 6460*uk_29 + 76*uk_3 + 7225*uk_30 + 3060*uk_31 + 8755*uk_32 + 18445*uk_33 + 7225*uk_34 + 1296*uk_35 + 3708*uk_36 + 7812*uk_37 + 3060*uk_38 + 10609*uk_39 + 85*uk_4 + 22351*uk_40 + 8755*uk_41 + 47089*uk_42 + 18445*uk_43 + 7225*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 170415302284*uk_47 + 190596061765*uk_48 + 80723037924*uk_49 + 36*uk_5 + 230957580727*uk_50 + 486580534153*uk_51 + 190596061765*uk_52 + 187944057*uk_53 + 226726164*uk_54 + 253575315*uk_55 + 107396604*uk_56 + 307273617*uk_57 + 647362863*uk_58 + 253575315*uk_59 + 103*uk_6 + 273510928*uk_60 + 305900380*uk_61 + 129557808*uk_62 + 370679284*uk_63 + 780945676*uk_64 + 305900380*uk_65 + 342125425*uk_66 + 144900180*uk_67 + 414575515*uk_68 + 873426085*uk_69 + 217*uk_7 + 342125425*uk_70 + 61369488*uk_71 + 175584924*uk_72 + 369921636*uk_73 + 144900180*uk_74 + 502367977*uk_75 + 1058386903*uk_76 + 414575515*uk_77 + 2229805417*uk_78 + 873426085*uk_79 + 85*uk_8 + 342125425*uk_80 + 250047*uk_81 + 301644*uk_82 + 337365*uk_83 + 142884*uk_84 + 408807*uk_85 + 861273*uk_86 + 337365*uk_87 + 363888*uk_88 + 406980*uk_89 + 2242306609*uk_9 + 172368*uk_90 + 493164*uk_91 + 1038996*uk_92 + 406980*uk_93 + 455175*uk_94 + 192780*uk_95 + 551565*uk_96 + 1162035*uk_97 + 455175*uk_98 + 81648*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 238140*uk_100 + 492156*uk_101 + 172368*uk_102 + 694575*uk_103 + 1435455*uk_104 + 502740*uk_105 + 2966607*uk_106 + 1038996*uk_107 + 363888*uk_108 + 1092727*uk_109 + 4877359*uk_11 + 806284*uk_110 + 381924*uk_111 + 1113945*uk_112 + 2302153*uk_113 + 806284*uk_114 + 594928*uk_115 + 281808*uk_116 + 821940*uk_117 + 1698676*uk_118 + 594928*uk_119 + 3598828*uk_12 + 133488*uk_120 + 389340*uk_121 + 804636*uk_122 + 281808*uk_123 + 1135575*uk_124 + 2346855*uk_125 + 821940*uk_126 + 4850167*uk_127 + 1698676*uk_128 + 594928*uk_129 + 1704708*uk_13 + 438976*uk_130 + 207936*uk_131 + 606480*uk_132 + 1253392*uk_133 + 438976*uk_134 + 98496*uk_135 + 287280*uk_136 + 593712*uk_137 + 207936*uk_138 + 837900*uk_139 + 4972065*uk_14 + 1731660*uk_140 + 606480*uk_141 + 3578764*uk_142 + 1253392*uk_143 + 438976*uk_144 + 46656*uk_145 + 136080*uk_146 + 281232*uk_147 + 98496*uk_148 + 396900*uk_149 + 10275601*uk_15 + 820260*uk_150 + 287280*uk_151 + 1695204*uk_152 + 593712*uk_153 + 207936*uk_154 + 1157625*uk_155 + 2392425*uk_156 + 837900*uk_157 + 4944345*uk_158 + 1731660*uk_159 + 3598828*uk_16 + 606480*uk_160 + 10218313*uk_161 + 3578764*uk_162 + 1253392*uk_163 + 438976*uk_164 + 3969*uk_17 + 6489*uk_18 + 4788*uk_19 + 63*uk_2 + 2268*uk_20 + 6615*uk_21 + 13671*uk_22 + 4788*uk_23 + 10609*uk_24 + 7828*uk_25 + 3708*uk_26 + 10815*uk_27 + 22351*uk_28 + 7828*uk_29 + 103*uk_3 + 5776*uk_30 + 2736*uk_31 + 7980*uk_32 + 16492*uk_33 + 5776*uk_34 + 1296*uk_35 + 3780*uk_36 + 7812*uk_37 + 2736*uk_38 + 11025*uk_39 + 76*uk_4 + 22785*uk_40 + 7980*uk_41 + 47089*uk_42 + 16492*uk_43 + 5776*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 230957580727*uk_47 + 170415302284*uk_48 + 80723037924*uk_49 + 36*uk_5 + 235442193945*uk_50 + 486580534153*uk_51 + 170415302284*uk_52 + 187944057*uk_53 + 307273617*uk_54 + 226726164*uk_55 + 107396604*uk_56 + 313240095*uk_57 + 647362863*uk_58 + 226726164*uk_59 + 105*uk_6 + 502367977*uk_60 + 370679284*uk_61 + 175584924*uk_62 + 512122695*uk_63 + 1058386903*uk_64 + 370679284*uk_65 + 273510928*uk_66 + 129557808*uk_67 + 377876940*uk_68 + 780945676*uk_69 + 217*uk_7 + 273510928*uk_70 + 61369488*uk_71 + 178994340*uk_72 + 369921636*uk_73 + 129557808*uk_74 + 522066825*uk_75 + 1078938105*uk_76 + 377876940*uk_77 + 2229805417*uk_78 + 780945676*uk_79 + 76*uk_8 + 273510928*uk_80 + 250047*uk_81 + 408807*uk_82 + 301644*uk_83 + 142884*uk_84 + 416745*uk_85 + 861273*uk_86 + 301644*uk_87 + 668367*uk_88 + 493164*uk_89 + 2242306609*uk_9 + 233604*uk_90 + 681345*uk_91 + 1408113*uk_92 + 493164*uk_93 + 363888*uk_94 + 172368*uk_95 + 502740*uk_96 + 1038996*uk_97 + 363888*uk_98 + 81648*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 215712*uk_100 + 437472*uk_101 + 207648*uk_102 + 721287*uk_103 + 1462797*uk_104 + 694323*uk_105 + 2966607*uk_106 + 1408113*uk_107 + 668367*uk_108 + 205379*uk_109 + 2793827*uk_11 + 358543*uk_110 + 111392*uk_111 + 372467*uk_112 + 755377*uk_113 + 358543*uk_114 + 625931*uk_115 + 194464*uk_116 + 650239*uk_117 + 1318709*uk_118 + 625931*uk_119 + 4877359*uk_12 + 60416*uk_120 + 202016*uk_121 + 409696*uk_122 + 194464*uk_123 + 675491*uk_124 + 1369921*uk_125 + 650239*uk_126 + 2778251*uk_127 + 1318709*uk_128 + 625931*uk_129 + 1515296*uk_13 + 1092727*uk_130 + 339488*uk_131 + 1135163*uk_132 + 2302153*uk_133 + 1092727*uk_134 + 105472*uk_135 + 352672*uk_136 + 715232*uk_137 + 339488*uk_138 + 1179247*uk_139 + 5066771*uk_14 + 2391557*uk_140 + 1135163*uk_141 + 4850167*uk_142 + 2302153*uk_143 + 1092727*uk_144 + 32768*uk_145 + 109568*uk_146 + 222208*uk_147 + 105472*uk_148 + 366368*uk_149 + 10275601*uk_15 + 743008*uk_150 + 352672*uk_151 + 1506848*uk_152 + 715232*uk_153 + 339488*uk_154 + 1225043*uk_155 + 2484433*uk_156 + 1179247*uk_157 + 5038523*uk_158 + 2391557*uk_159 + 4877359*uk_16 + 1135163*uk_160 + 10218313*uk_161 + 4850167*uk_162 + 2302153*uk_163 + 1092727*uk_164 + 3969*uk_17 + 3717*uk_18 + 6489*uk_19 + 63*uk_2 + 2016*uk_20 + 6741*uk_21 + 13671*uk_22 + 6489*uk_23 + 3481*uk_24 + 6077*uk_25 + 1888*uk_26 + 6313*uk_27 + 12803*uk_28 + 6077*uk_29 + 59*uk_3 + 10609*uk_30 + 3296*uk_31 + 11021*uk_32 + 22351*uk_33 + 10609*uk_34 + 1024*uk_35 + 3424*uk_36 + 6944*uk_37 + 3296*uk_38 + 11449*uk_39 + 103*uk_4 + 23219*uk_40 + 11021*uk_41 + 47089*uk_42 + 22351*uk_43 + 10609*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 132296089931*uk_47 + 230957580727*uk_48 + 71753811488*uk_49 + 32*uk_5 + 239926807163*uk_50 + 486580534153*uk_51 + 230957580727*uk_52 + 187944057*uk_53 + 176011101*uk_54 + 307273617*uk_55 + 95463648*uk_56 + 319206573*uk_57 + 647362863*uk_58 + 307273617*uk_59 + 107*uk_6 + 164835793*uk_60 + 287764181*uk_61 + 89402464*uk_62 + 298939489*uk_63 + 606260459*uk_64 + 287764181*uk_65 + 502367977*uk_66 + 156075488*uk_67 + 521877413*uk_68 + 1058386903*uk_69 + 217*uk_7 + 502367977*uk_70 + 48489472*uk_71 + 162136672*uk_72 + 328819232*uk_73 + 156075488*uk_74 + 542144497*uk_75 + 1099489307*uk_76 + 521877413*uk_77 + 2229805417*uk_78 + 1058386903*uk_79 + 103*uk_8 + 502367977*uk_80 + 250047*uk_81 + 234171*uk_82 + 408807*uk_83 + 127008*uk_84 + 424683*uk_85 + 861273*uk_86 + 408807*uk_87 + 219303*uk_88 + 382851*uk_89 + 2242306609*uk_9 + 118944*uk_90 + 397719*uk_91 + 806589*uk_92 + 382851*uk_93 + 668367*uk_94 + 207648*uk_95 + 694323*uk_96 + 1408113*uk_97 + 668367*uk_98 + 64512*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 219744*uk_100 + 437472*uk_101 + 118944*uk_102 + 748503*uk_103 + 1490139*uk_104 + 405153*uk_105 + 2966607*uk_106 + 806589*uk_107 + 219303*uk_108 + 103823*uk_109 + 2225591*uk_11 + 130331*uk_110 + 70688*uk_111 + 240781*uk_112 + 479353*uk_113 + 130331*uk_114 + 163607*uk_115 + 88736*uk_116 + 302257*uk_117 + 601741*uk_118 + 163607*uk_119 + 2793827*uk_12 + 48128*uk_120 + 163936*uk_121 + 326368*uk_122 + 88736*uk_123 + 558407*uk_124 + 1111691*uk_125 + 302257*uk_126 + 2213183*uk_127 + 601741*uk_128 + 163607*uk_129 + 1515296*uk_13 + 205379*uk_130 + 111392*uk_131 + 379429*uk_132 + 755377*uk_133 + 205379*uk_134 + 60416*uk_135 + 205792*uk_136 + 409696*uk_137 + 111392*uk_138 + 700979*uk_139 + 5161477*uk_14 + 1395527*uk_140 + 379429*uk_141 + 2778251*uk_142 + 755377*uk_143 + 205379*uk_144 + 32768*uk_145 + 111616*uk_146 + 222208*uk_147 + 60416*uk_148 + 380192*uk_149 + 10275601*uk_15 + 756896*uk_150 + 205792*uk_151 + 1506848*uk_152 + 409696*uk_153 + 111392*uk_154 + 1295029*uk_155 + 2578177*uk_156 + 700979*uk_157 + 5132701*uk_158 + 1395527*uk_159 + 2793827*uk_16 + 379429*uk_160 + 10218313*uk_161 + 2778251*uk_162 + 755377*uk_163 + 205379*uk_164 + 3969*uk_17 + 2961*uk_18 + 3717*uk_19 + 63*uk_2 + 2016*uk_20 + 6867*uk_21 + 13671*uk_22 + 3717*uk_23 + 2209*uk_24 + 2773*uk_25 + 1504*uk_26 + 5123*uk_27 + 10199*uk_28 + 2773*uk_29 + 47*uk_3 + 3481*uk_30 + 1888*uk_31 + 6431*uk_32 + 12803*uk_33 + 3481*uk_34 + 1024*uk_35 + 3488*uk_36 + 6944*uk_37 + 1888*uk_38 + 11881*uk_39 + 59*uk_4 + 23653*uk_40 + 6431*uk_41 + 47089*uk_42 + 12803*uk_43 + 3481*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 105388410623*uk_47 + 132296089931*uk_48 + 71753811488*uk_49 + 32*uk_5 + 244411420381*uk_50 + 486580534153*uk_51 + 132296089931*uk_52 + 187944057*uk_53 + 140212233*uk_54 + 176011101*uk_55 + 95463648*uk_56 + 325173051*uk_57 + 647362863*uk_58 + 176011101*uk_59 + 109*uk_6 + 104602777*uk_60 + 131309869*uk_61 + 71218912*uk_62 + 242589419*uk_63 + 482953247*uk_64 + 131309869*uk_65 + 164835793*uk_66 + 89402464*uk_67 + 304527143*uk_68 + 606260459*uk_69 + 217*uk_7 + 164835793*uk_70 + 48489472*uk_71 + 165167264*uk_72 + 328819232*uk_73 + 89402464*uk_74 + 562600993*uk_75 + 1120040509*uk_76 + 304527143*uk_77 + 2229805417*uk_78 + 606260459*uk_79 + 59*uk_8 + 164835793*uk_80 + 250047*uk_81 + 186543*uk_82 + 234171*uk_83 + 127008*uk_84 + 432621*uk_85 + 861273*uk_86 + 234171*uk_87 + 139167*uk_88 + 174699*uk_89 + 2242306609*uk_9 + 94752*uk_90 + 322749*uk_91 + 642537*uk_92 + 174699*uk_93 + 219303*uk_94 + 118944*uk_95 + 405153*uk_96 + 806589*uk_97 + 219303*uk_98 + 64512*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 223776*uk_100 + 437472*uk_101 + 94752*uk_102 + 776223*uk_103 + 1517481*uk_104 + 328671*uk_105 + 2966607*uk_106 + 642537*uk_107 + 139167*uk_108 + 300763*uk_109 + 3172651*uk_11 + 210983*uk_110 + 143648*uk_111 + 498279*uk_112 + 974113*uk_113 + 210983*uk_114 + 148003*uk_115 + 100768*uk_116 + 349539*uk_117 + 683333*uk_118 + 148003*uk_119 + 2225591*uk_12 + 68608*uk_120 + 237984*uk_121 + 465248*uk_122 + 100768*uk_123 + 825507*uk_124 + 1613829*uk_125 + 349539*uk_126 + 3154963*uk_127 + 683333*uk_128 + 148003*uk_129 + 1515296*uk_13 + 103823*uk_130 + 70688*uk_131 + 245199*uk_132 + 479353*uk_133 + 103823*uk_134 + 48128*uk_135 + 166944*uk_136 + 326368*uk_137 + 70688*uk_138 + 579087*uk_139 + 5256183*uk_14 + 1132089*uk_140 + 245199*uk_141 + 2213183*uk_142 + 479353*uk_143 + 103823*uk_144 + 32768*uk_145 + 113664*uk_146 + 222208*uk_147 + 48128*uk_148 + 394272*uk_149 + 10275601*uk_15 + 770784*uk_150 + 166944*uk_151 + 1506848*uk_152 + 326368*uk_153 + 70688*uk_154 + 1367631*uk_155 + 2673657*uk_156 + 579087*uk_157 + 5226879*uk_158 + 1132089*uk_159 + 2225591*uk_16 + 245199*uk_160 + 10218313*uk_161 + 2213183*uk_162 + 479353*uk_163 + 103823*uk_164 + 3969*uk_17 + 4221*uk_18 + 2961*uk_19 + 63*uk_2 + 2016*uk_20 + 6993*uk_21 + 13671*uk_22 + 2961*uk_23 + 4489*uk_24 + 3149*uk_25 + 2144*uk_26 + 7437*uk_27 + 14539*uk_28 + 3149*uk_29 + 67*uk_3 + 2209*uk_30 + 1504*uk_31 + 5217*uk_32 + 10199*uk_33 + 2209*uk_34 + 1024*uk_35 + 3552*uk_36 + 6944*uk_37 + 1504*uk_38 + 12321*uk_39 + 47*uk_4 + 24087*uk_40 + 5217*uk_41 + 47089*uk_42 + 10199*uk_43 + 2209*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 150234542803*uk_47 + 105388410623*uk_48 + 71753811488*uk_49 + 32*uk_5 + 248896033599*uk_50 + 486580534153*uk_51 + 105388410623*uk_52 + 187944057*uk_53 + 199877013*uk_54 + 140212233*uk_55 + 95463648*uk_56 + 331139529*uk_57 + 647362863*uk_58 + 140212233*uk_59 + 111*uk_6 + 212567617*uk_60 + 149114597*uk_61 + 101524832*uk_62 + 352164261*uk_63 + 688465267*uk_64 + 149114597*uk_65 + 104602777*uk_66 + 71218912*uk_67 + 247040601*uk_68 + 482953247*uk_69 + 217*uk_7 + 104602777*uk_70 + 48489472*uk_71 + 168197856*uk_72 + 328819232*uk_73 + 71218912*uk_74 + 583436313*uk_75 + 1140591711*uk_76 + 247040601*uk_77 + 2229805417*uk_78 + 482953247*uk_79 + 47*uk_8 + 104602777*uk_80 + 250047*uk_81 + 265923*uk_82 + 186543*uk_83 + 127008*uk_84 + 440559*uk_85 + 861273*uk_86 + 186543*uk_87 + 282807*uk_88 + 198387*uk_89 + 2242306609*uk_9 + 135072*uk_90 + 468531*uk_91 + 915957*uk_92 + 198387*uk_93 + 139167*uk_94 + 94752*uk_95 + 328671*uk_96 + 642537*uk_97 + 139167*uk_98 + 64512*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 199332*uk_100 + 382788*uk_101 + 118188*uk_102 + 804447*uk_103 + 1544823*uk_104 + 476973*uk_105 + 2966607*uk_106 + 915957*uk_107 + 282807*uk_108 + 216*uk_109 + 284118*uk_11 + 2412*uk_110 + 1008*uk_111 + 4068*uk_112 + 7812*uk_113 + 2412*uk_114 + 26934*uk_115 + 11256*uk_116 + 45426*uk_117 + 87234*uk_118 + 26934*uk_119 + 3172651*uk_12 + 4704*uk_120 + 18984*uk_121 + 36456*uk_122 + 11256*uk_123 + 76614*uk_124 + 147126*uk_125 + 45426*uk_126 + 282534*uk_127 + 87234*uk_128 + 26934*uk_129 + 1325884*uk_13 + 300763*uk_130 + 125692*uk_131 + 507257*uk_132 + 974113*uk_133 + 300763*uk_134 + 52528*uk_135 + 211988*uk_136 + 407092*uk_137 + 125692*uk_138 + 855523*uk_139 + 5350889*uk_14 + 1642907*uk_140 + 507257*uk_141 + 3154963*uk_142 + 974113*uk_143 + 300763*uk_144 + 21952*uk_145 + 88592*uk_146 + 170128*uk_147 + 52528*uk_148 + 357532*uk_149 + 10275601*uk_15 + 686588*uk_150 + 211988*uk_151 + 1318492*uk_152 + 407092*uk_153 + 125692*uk_154 + 1442897*uk_155 + 2770873*uk_156 + 855523*uk_157 + 5321057*uk_158 + 1642907*uk_159 + 3172651*uk_16 + 507257*uk_160 + 10218313*uk_161 + 3154963*uk_162 + 974113*uk_163 + 300763*uk_164 + 3969*uk_17 + 378*uk_18 + 4221*uk_19 + 63*uk_2 + 1764*uk_20 + 7119*uk_21 + 13671*uk_22 + 4221*uk_23 + 36*uk_24 + 402*uk_25 + 168*uk_26 + 678*uk_27 + 1302*uk_28 + 402*uk_29 + 6*uk_3 + 4489*uk_30 + 1876*uk_31 + 7571*uk_32 + 14539*uk_33 + 4489*uk_34 + 784*uk_35 + 3164*uk_36 + 6076*uk_37 + 1876*uk_38 + 12769*uk_39 + 67*uk_4 + 24521*uk_40 + 7571*uk_41 + 47089*uk_42 + 14539*uk_43 + 4489*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 13453839654*uk_47 + 150234542803*uk_48 + 62784585052*uk_49 + 28*uk_5 + 253380646817*uk_50 + 486580534153*uk_51 + 150234542803*uk_52 + 187944057*uk_53 + 17899434*uk_54 + 199877013*uk_55 + 83530692*uk_56 + 337106007*uk_57 + 647362863*uk_58 + 199877013*uk_59 + 113*uk_6 + 1704708*uk_60 + 19035906*uk_61 + 7955304*uk_62 + 32105334*uk_63 + 61653606*uk_64 + 19035906*uk_65 + 212567617*uk_66 + 88834228*uk_67 + 358509563*uk_68 + 688465267*uk_69 + 217*uk_7 + 212567617*uk_70 + 37124752*uk_71 + 149824892*uk_72 + 287716828*uk_73 + 88834228*uk_74 + 604650457*uk_75 + 1161142913*uk_76 + 358509563*uk_77 + 2229805417*uk_78 + 688465267*uk_79 + 67*uk_8 + 212567617*uk_80 + 250047*uk_81 + 23814*uk_82 + 265923*uk_83 + 111132*uk_84 + 448497*uk_85 + 861273*uk_86 + 265923*uk_87 + 2268*uk_88 + 25326*uk_89 + 2242306609*uk_9 + 10584*uk_90 + 42714*uk_91 + 82026*uk_92 + 25326*uk_93 + 282807*uk_94 + 118188*uk_95 + 476973*uk_96 + 915957*uk_97 + 282807*uk_98 + 49392*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 231840*uk_100 + 437472*uk_101 + 12096*uk_102 + 833175*uk_103 + 1572165*uk_104 + 43470*uk_105 + 2966607*uk_106 + 82026*uk_107 + 2268*uk_108 + 681472*uk_109 + 4167064*uk_11 + 46464*uk_110 + 247808*uk_111 + 890560*uk_112 + 1680448*uk_113 + 46464*uk_114 + 3168*uk_115 + 16896*uk_116 + 60720*uk_117 + 114576*uk_118 + 3168*uk_119 + 284118*uk_12 + 90112*uk_120 + 323840*uk_121 + 611072*uk_122 + 16896*uk_123 + 1163800*uk_124 + 2196040*uk_125 + 60720*uk_126 + 4143832*uk_127 + 114576*uk_128 + 3168*uk_129 + 1515296*uk_13 + 216*uk_130 + 1152*uk_131 + 4140*uk_132 + 7812*uk_133 + 216*uk_134 + 6144*uk_135 + 22080*uk_136 + 41664*uk_137 + 1152*uk_138 + 79350*uk_139 + 5445595*uk_14 + 149730*uk_140 + 4140*uk_141 + 282534*uk_142 + 7812*uk_143 + 216*uk_144 + 32768*uk_145 + 117760*uk_146 + 222208*uk_147 + 6144*uk_148 + 423200*uk_149 + 10275601*uk_15 + 798560*uk_150 + 22080*uk_151 + 1506848*uk_152 + 41664*uk_153 + 1152*uk_154 + 1520875*uk_155 + 2869825*uk_156 + 79350*uk_157 + 5415235*uk_158 + 149730*uk_159 + 284118*uk_16 + 4140*uk_160 + 10218313*uk_161 + 282534*uk_162 + 7812*uk_163 + 216*uk_164 + 3969*uk_17 + 5544*uk_18 + 378*uk_19 + 63*uk_2 + 2016*uk_20 + 7245*uk_21 + 13671*uk_22 + 378*uk_23 + 7744*uk_24 + 528*uk_25 + 2816*uk_26 + 10120*uk_27 + 19096*uk_28 + 528*uk_29 + 88*uk_3 + 36*uk_30 + 192*uk_31 + 690*uk_32 + 1302*uk_33 + 36*uk_34 + 1024*uk_35 + 3680*uk_36 + 6944*uk_37 + 192*uk_38 + 13225*uk_39 + 6*uk_4 + 24955*uk_40 + 690*uk_41 + 47089*uk_42 + 1302*uk_43 + 36*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 197322981592*uk_47 + 13453839654*uk_48 + 71753811488*uk_49 + 32*uk_5 + 257865260035*uk_50 + 486580534153*uk_51 + 13453839654*uk_52 + 187944057*uk_53 + 262525032*uk_54 + 17899434*uk_55 + 95463648*uk_56 + 343072485*uk_57 + 647362863*uk_58 + 17899434*uk_59 + 115*uk_6 + 366701632*uk_60 + 25002384*uk_61 + 133346048*uk_62 + 479212360*uk_63 + 904252888*uk_64 + 25002384*uk_65 + 1704708*uk_66 + 9091776*uk_67 + 32673570*uk_68 + 61653606*uk_69 + 217*uk_7 + 1704708*uk_70 + 48489472*uk_71 + 174259040*uk_72 + 328819232*uk_73 + 9091776*uk_74 + 626243425*uk_75 + 1181694115*uk_76 + 32673570*uk_77 + 2229805417*uk_78 + 61653606*uk_79 + 6*uk_8 + 1704708*uk_80 + 250047*uk_81 + 349272*uk_82 + 23814*uk_83 + 127008*uk_84 + 456435*uk_85 + 861273*uk_86 + 23814*uk_87 + 487872*uk_88 + 33264*uk_89 + 2242306609*uk_9 + 177408*uk_90 + 637560*uk_91 + 1203048*uk_92 + 33264*uk_93 + 2268*uk_94 + 12096*uk_95 + 43470*uk_96 + 82026*uk_97 + 2268*uk_98 + 64512*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 206388*uk_100 + 382788*uk_101 + 155232*uk_102 + 862407*uk_103 + 1599507*uk_104 + 648648*uk_105 + 2966607*uk_106 + 1203048*uk_107 + 487872*uk_108 + 614125*uk_109 + 4025005*uk_11 + 635800*uk_110 + 202300*uk_111 + 845325*uk_112 + 1567825*uk_113 + 635800*uk_114 + 658240*uk_115 + 209440*uk_116 + 875160*uk_117 + 1623160*uk_118 + 658240*uk_119 + 4167064*uk_12 + 66640*uk_120 + 278460*uk_121 + 516460*uk_122 + 209440*uk_123 + 1163565*uk_124 + 2158065*uk_125 + 875160*uk_126 + 4002565*uk_127 + 1623160*uk_128 + 658240*uk_129 + 1325884*uk_13 + 681472*uk_130 + 216832*uk_131 + 906048*uk_132 + 1680448*uk_133 + 681472*uk_134 + 68992*uk_135 + 288288*uk_136 + 534688*uk_137 + 216832*uk_138 + 1204632*uk_139 + 5540301*uk_14 + 2234232*uk_140 + 906048*uk_141 + 4143832*uk_142 + 1680448*uk_143 + 681472*uk_144 + 21952*uk_145 + 91728*uk_146 + 170128*uk_147 + 68992*uk_148 + 383292*uk_149 + 10275601*uk_15 + 710892*uk_150 + 288288*uk_151 + 1318492*uk_152 + 534688*uk_153 + 216832*uk_154 + 1601613*uk_155 + 2970513*uk_156 + 1204632*uk_157 + 5509413*uk_158 + 2234232*uk_159 + 4167064*uk_16 + 906048*uk_160 + 10218313*uk_161 + 4143832*uk_162 + 1680448*uk_163 + 681472*uk_164 + 3969*uk_17 + 5355*uk_18 + 5544*uk_19 + 63*uk_2 + 1764*uk_20 + 7371*uk_21 + 13671*uk_22 + 5544*uk_23 + 7225*uk_24 + 7480*uk_25 + 2380*uk_26 + 9945*uk_27 + 18445*uk_28 + 7480*uk_29 + 85*uk_3 + 7744*uk_30 + 2464*uk_31 + 10296*uk_32 + 19096*uk_33 + 7744*uk_34 + 784*uk_35 + 3276*uk_36 + 6076*uk_37 + 2464*uk_38 + 13689*uk_39 + 88*uk_4 + 25389*uk_40 + 10296*uk_41 + 47089*uk_42 + 19096*uk_43 + 7744*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 190596061765*uk_47 + 197322981592*uk_48 + 62784585052*uk_49 + 28*uk_5 + 262349873253*uk_50 + 486580534153*uk_51 + 197322981592*uk_52 + 187944057*uk_53 + 253575315*uk_54 + 262525032*uk_55 + 83530692*uk_56 + 349038963*uk_57 + 647362863*uk_58 + 262525032*uk_59 + 117*uk_6 + 342125425*uk_60 + 354200440*uk_61 + 112700140*uk_62 + 470925585*uk_63 + 873426085*uk_64 + 354200440*uk_65 + 366701632*uk_66 + 116677792*uk_67 + 487546488*uk_68 + 904252888*uk_69 + 217*uk_7 + 366701632*uk_70 + 37124752*uk_71 + 155128428*uk_72 + 287716828*uk_73 + 116677792*uk_74 + 648215217*uk_75 + 1202245317*uk_76 + 487546488*uk_77 + 2229805417*uk_78 + 904252888*uk_79 + 88*uk_8 + 366701632*uk_80 + 250047*uk_81 + 337365*uk_82 + 349272*uk_83 + 111132*uk_84 + 464373*uk_85 + 861273*uk_86 + 349272*uk_87 + 455175*uk_88 + 471240*uk_89 + 2242306609*uk_9 + 149940*uk_90 + 626535*uk_91 + 1162035*uk_92 + 471240*uk_93 + 487872*uk_94 + 155232*uk_95 + 648648*uk_96 + 1203048*uk_97 + 487872*uk_98 + 49392*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 209916*uk_100 + 382788*uk_101 + 149940*uk_102 + 892143*uk_103 + 1626849*uk_104 + 637245*uk_105 + 2966607*uk_106 + 1162035*uk_107 + 455175*uk_108 + 1331000*uk_109 + 5208830*uk_11 + 1028500*uk_110 + 338800*uk_111 + 1439900*uk_112 + 2625700*uk_113 + 1028500*uk_114 + 794750*uk_115 + 261800*uk_116 + 1112650*uk_117 + 2028950*uk_118 + 794750*uk_119 + 4025005*uk_12 + 86240*uk_120 + 366520*uk_121 + 668360*uk_122 + 261800*uk_123 + 1557710*uk_124 + 2840530*uk_125 + 1112650*uk_126 + 5179790*uk_127 + 2028950*uk_128 + 794750*uk_129 + 1325884*uk_13 + 614125*uk_130 + 202300*uk_131 + 859775*uk_132 + 1567825*uk_133 + 614125*uk_134 + 66640*uk_135 + 283220*uk_136 + 516460*uk_137 + 202300*uk_138 + 1203685*uk_139 + 5635007*uk_14 + 2194955*uk_140 + 859775*uk_141 + 4002565*uk_142 + 1567825*uk_143 + 614125*uk_144 + 21952*uk_145 + 93296*uk_146 + 170128*uk_147 + 66640*uk_148 + 396508*uk_149 + 10275601*uk_15 + 723044*uk_150 + 283220*uk_151 + 1318492*uk_152 + 516460*uk_153 + 202300*uk_154 + 1685159*uk_155 + 3072937*uk_156 + 1203685*uk_157 + 5603591*uk_158 + 2194955*uk_159 + 4025005*uk_16 + 859775*uk_160 + 10218313*uk_161 + 4002565*uk_162 + 1567825*uk_163 + 614125*uk_164 + 3969*uk_17 + 6930*uk_18 + 5355*uk_19 + 63*uk_2 + 1764*uk_20 + 7497*uk_21 + 13671*uk_22 + 5355*uk_23 + 12100*uk_24 + 9350*uk_25 + 3080*uk_26 + 13090*uk_27 + 23870*uk_28 + 9350*uk_29 + 110*uk_3 + 7225*uk_30 + 2380*uk_31 + 10115*uk_32 + 18445*uk_33 + 7225*uk_34 + 784*uk_35 + 3332*uk_36 + 6076*uk_37 + 2380*uk_38 + 14161*uk_39 + 85*uk_4 + 25823*uk_40 + 10115*uk_41 + 47089*uk_42 + 18445*uk_43 + 7225*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 246653726990*uk_47 + 190596061765*uk_48 + 62784585052*uk_49 + 28*uk_5 + 266834486471*uk_50 + 486580534153*uk_51 + 190596061765*uk_52 + 187944057*uk_53 + 328156290*uk_54 + 253575315*uk_55 + 83530692*uk_56 + 355005441*uk_57 + 647362863*uk_58 + 253575315*uk_59 + 119*uk_6 + 572971300*uk_60 + 442750550*uk_61 + 145847240*uk_62 + 619850770*uk_63 + 1130316110*uk_64 + 442750550*uk_65 + 342125425*uk_66 + 112700140*uk_67 + 478975595*uk_68 + 873426085*uk_69 + 217*uk_7 + 342125425*uk_70 + 37124752*uk_71 + 157780196*uk_72 + 287716828*uk_73 + 112700140*uk_74 + 670565833*uk_75 + 1222796519*uk_76 + 478975595*uk_77 + 2229805417*uk_78 + 873426085*uk_79 + 85*uk_8 + 342125425*uk_80 + 250047*uk_81 + 436590*uk_82 + 337365*uk_83 + 111132*uk_84 + 472311*uk_85 + 861273*uk_86 + 337365*uk_87 + 762300*uk_88 + 589050*uk_89 + 2242306609*uk_9 + 194040*uk_90 + 824670*uk_91 + 1503810*uk_92 + 589050*uk_93 + 455175*uk_94 + 149940*uk_95 + 637245*uk_96 + 1162035*uk_97 + 455175*uk_98 + 49392*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 182952*uk_100 + 328104*uk_101 + 166320*uk_102 + 922383*uk_103 + 1654191*uk_104 + 838530*uk_105 + 2966607*uk_106 + 1503810*uk_107 + 762300*uk_108 + 74088*uk_109 + 1988826*uk_11 + 194040*uk_110 + 42336*uk_111 + 213444*uk_112 + 382788*uk_113 + 194040*uk_114 + 508200*uk_115 + 110880*uk_116 + 559020*uk_117 + 1002540*uk_118 + 508200*uk_119 + 5208830*uk_12 + 24192*uk_120 + 121968*uk_121 + 218736*uk_122 + 110880*uk_123 + 614922*uk_124 + 1102794*uk_125 + 559020*uk_126 + 1977738*uk_127 + 1002540*uk_128 + 508200*uk_129 + 1136472*uk_13 + 1331000*uk_130 + 290400*uk_131 + 1464100*uk_132 + 2625700*uk_133 + 1331000*uk_134 + 63360*uk_135 + 319440*uk_136 + 572880*uk_137 + 290400*uk_138 + 1610510*uk_139 + 5729713*uk_14 + 2888270*uk_140 + 1464100*uk_141 + 5179790*uk_142 + 2625700*uk_143 + 1331000*uk_144 + 13824*uk_145 + 69696*uk_146 + 124992*uk_147 + 63360*uk_148 + 351384*uk_149 + 10275601*uk_15 + 630168*uk_150 + 319440*uk_151 + 1130136*uk_152 + 572880*uk_153 + 290400*uk_154 + 1771561*uk_155 + 3177097*uk_156 + 1610510*uk_157 + 5697769*uk_158 + 2888270*uk_159 + 5208830*uk_16 + 1464100*uk_160 + 10218313*uk_161 + 5179790*uk_162 + 2625700*uk_163 + 1331000*uk_164 + 3969*uk_17 + 2646*uk_18 + 6930*uk_19 + 63*uk_2 + 1512*uk_20 + 7623*uk_21 + 13671*uk_22 + 6930*uk_23 + 1764*uk_24 + 4620*uk_25 + 1008*uk_26 + 5082*uk_27 + 9114*uk_28 + 4620*uk_29 + 42*uk_3 + 12100*uk_30 + 2640*uk_31 + 13310*uk_32 + 23870*uk_33 + 12100*uk_34 + 576*uk_35 + 2904*uk_36 + 5208*uk_37 + 2640*uk_38 + 14641*uk_39 + 110*uk_4 + 26257*uk_40 + 13310*uk_41 + 47089*uk_42 + 23870*uk_43 + 12100*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 94176877578*uk_47 + 246653726990*uk_48 + 53815358616*uk_49 + 24*uk_5 + 271319099689*uk_50 + 486580534153*uk_51 + 246653726990*uk_52 + 187944057*uk_53 + 125296038*uk_54 + 328156290*uk_55 + 71597736*uk_56 + 360971919*uk_57 + 647362863*uk_58 + 328156290*uk_59 + 121*uk_6 + 83530692*uk_60 + 218770860*uk_61 + 47731824*uk_62 + 240647946*uk_63 + 431575242*uk_64 + 218770860*uk_65 + 572971300*uk_66 + 125011920*uk_67 + 630268430*uk_68 + 1130316110*uk_69 + 217*uk_7 + 572971300*uk_70 + 27275328*uk_71 + 137513112*uk_72 + 246614424*uk_73 + 125011920*uk_74 + 693295273*uk_75 + 1243347721*uk_76 + 630268430*uk_77 + 2229805417*uk_78 + 1130316110*uk_79 + 110*uk_8 + 572971300*uk_80 + 250047*uk_81 + 166698*uk_82 + 436590*uk_83 + 95256*uk_84 + 480249*uk_85 + 861273*uk_86 + 436590*uk_87 + 111132*uk_88 + 291060*uk_89 + 2242306609*uk_9 + 63504*uk_90 + 320166*uk_91 + 574182*uk_92 + 291060*uk_93 + 762300*uk_94 + 166320*uk_95 + 838530*uk_96 + 1503810*uk_97 + 762300*uk_98 + 36288*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 216972*uk_100 + 382788*uk_101 + 74088*uk_102 + 953127*uk_103 + 1681533*uk_104 + 325458*uk_105 + 2966607*uk_106 + 574182*uk_107 + 111132*uk_108 + 1771561*uk_109 + 5729713*uk_11 + 614922*uk_110 + 409948*uk_111 + 1800843*uk_112 + 3177097*uk_113 + 614922*uk_114 + 213444*uk_115 + 142296*uk_116 + 625086*uk_117 + 1102794*uk_118 + 213444*uk_119 + 1988826*uk_12 + 94864*uk_120 + 416724*uk_121 + 735196*uk_122 + 142296*uk_123 + 1830609*uk_124 + 3229611*uk_125 + 625086*uk_126 + 5697769*uk_127 + 1102794*uk_128 + 213444*uk_129 + 1325884*uk_13 + 74088*uk_130 + 49392*uk_131 + 216972*uk_132 + 382788*uk_133 + 74088*uk_134 + 32928*uk_135 + 144648*uk_136 + 255192*uk_137 + 49392*uk_138 + 635418*uk_139 + 5824419*uk_14 + 1121022*uk_140 + 216972*uk_141 + 1977738*uk_142 + 382788*uk_143 + 74088*uk_144 + 21952*uk_145 + 96432*uk_146 + 170128*uk_147 + 32928*uk_148 + 423612*uk_149 + 10275601*uk_15 + 747348*uk_150 + 144648*uk_151 + 1318492*uk_152 + 255192*uk_153 + 49392*uk_154 + 1860867*uk_155 + 3282993*uk_156 + 635418*uk_157 + 5791947*uk_158 + 1121022*uk_159 + 1988826*uk_16 + 216972*uk_160 + 10218313*uk_161 + 1977738*uk_162 + 382788*uk_163 + 74088*uk_164 + 3969*uk_17 + 7623*uk_18 + 2646*uk_19 + 63*uk_2 + 1764*uk_20 + 7749*uk_21 + 13671*uk_22 + 2646*uk_23 + 14641*uk_24 + 5082*uk_25 + 3388*uk_26 + 14883*uk_27 + 26257*uk_28 + 5082*uk_29 + 121*uk_3 + 1764*uk_30 + 1176*uk_31 + 5166*uk_32 + 9114*uk_33 + 1764*uk_34 + 784*uk_35 + 3444*uk_36 + 6076*uk_37 + 1176*uk_38 + 15129*uk_39 + 42*uk_4 + 26691*uk_40 + 5166*uk_41 + 47089*uk_42 + 9114*uk_43 + 1764*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 271319099689*uk_47 + 94176877578*uk_48 + 62784585052*uk_49 + 28*uk_5 + 275803712907*uk_50 + 486580534153*uk_51 + 94176877578*uk_52 + 187944057*uk_53 + 360971919*uk_54 + 125296038*uk_55 + 83530692*uk_56 + 366938397*uk_57 + 647362863*uk_58 + 125296038*uk_59 + 123*uk_6 + 693295273*uk_60 + 240647946*uk_61 + 160431964*uk_62 + 704754699*uk_63 + 1243347721*uk_64 + 240647946*uk_65 + 83530692*uk_66 + 55687128*uk_67 + 244625598*uk_68 + 431575242*uk_69 + 217*uk_7 + 83530692*uk_70 + 37124752*uk_71 + 163083732*uk_72 + 287716828*uk_73 + 55687128*uk_74 + 716403537*uk_75 + 1263898923*uk_76 + 244625598*uk_77 + 2229805417*uk_78 + 431575242*uk_79 + 42*uk_8 + 83530692*uk_80 + 250047*uk_81 + 480249*uk_82 + 166698*uk_83 + 111132*uk_84 + 488187*uk_85 + 861273*uk_86 + 166698*uk_87 + 922383*uk_88 + 320166*uk_89 + 2242306609*uk_9 + 213444*uk_90 + 937629*uk_91 + 1654191*uk_92 + 320166*uk_93 + 111132*uk_94 + 74088*uk_95 + 325458*uk_96 + 574182*uk_97 + 111132*uk_98 + 49392*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 189000*uk_100 + 328104*uk_101 + 182952*uk_102 + 984375*uk_103 + 1708875*uk_104 + 952875*uk_105 + 2966607*uk_106 + 1654191*uk_107 + 922383*uk_108 + 1092727*uk_109 + 4877359*uk_11 + 1283689*uk_110 + 254616*uk_111 + 1326125*uk_112 + 2302153*uk_113 + 1283689*uk_114 + 1508023*uk_115 + 299112*uk_116 + 1557875*uk_117 + 2704471*uk_118 + 1508023*uk_119 + 5729713*uk_12 + 59328*uk_120 + 309000*uk_121 + 536424*uk_122 + 299112*uk_123 + 1609375*uk_124 + 2793875*uk_125 + 1557875*uk_126 + 4850167*uk_127 + 2704471*uk_128 + 1508023*uk_129 + 1136472*uk_13 + 1771561*uk_130 + 351384*uk_131 + 1830125*uk_132 + 3177097*uk_133 + 1771561*uk_134 + 69696*uk_135 + 363000*uk_136 + 630168*uk_137 + 351384*uk_138 + 1890625*uk_139 + 5919125*uk_14 + 3282125*uk_140 + 1830125*uk_141 + 5697769*uk_142 + 3177097*uk_143 + 1771561*uk_144 + 13824*uk_145 + 72000*uk_146 + 124992*uk_147 + 69696*uk_148 + 375000*uk_149 + 10275601*uk_15 + 651000*uk_150 + 363000*uk_151 + 1130136*uk_152 + 630168*uk_153 + 351384*uk_154 + 1953125*uk_155 + 3390625*uk_156 + 1890625*uk_157 + 5886125*uk_158 + 3282125*uk_159 + 5729713*uk_16 + 1830125*uk_160 + 10218313*uk_161 + 5697769*uk_162 + 3177097*uk_163 + 1771561*uk_164 + 3969*uk_17 + 6489*uk_18 + 7623*uk_19 + 63*uk_2 + 1512*uk_20 + 7875*uk_21 + 13671*uk_22 + 7623*uk_23 + 10609*uk_24 + 12463*uk_25 + 2472*uk_26 + 12875*uk_27 + 22351*uk_28 + 12463*uk_29 + 103*uk_3 + 14641*uk_30 + 2904*uk_31 + 15125*uk_32 + 26257*uk_33 + 14641*uk_34 + 576*uk_35 + 3000*uk_36 + 5208*uk_37 + 2904*uk_38 + 15625*uk_39 + 121*uk_4 + 27125*uk_40 + 15125*uk_41 + 47089*uk_42 + 26257*uk_43 + 14641*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 230957580727*uk_47 + 271319099689*uk_48 + 53815358616*uk_49 + 24*uk_5 + 280288326125*uk_50 + 486580534153*uk_51 + 271319099689*uk_52 + 187944057*uk_53 + 307273617*uk_54 + 360971919*uk_55 + 71597736*uk_56 + 372904875*uk_57 + 647362863*uk_58 + 360971919*uk_59 + 125*uk_6 + 502367977*uk_60 + 590160439*uk_61 + 117056616*uk_62 + 609669875*uk_63 + 1058386903*uk_64 + 590160439*uk_65 + 693295273*uk_66 + 137513112*uk_67 + 716214125*uk_68 + 1243347721*uk_69 + 217*uk_7 + 693295273*uk_70 + 27275328*uk_71 + 142059000*uk_72 + 246614424*uk_73 + 137513112*uk_74 + 739890625*uk_75 + 1284450125*uk_76 + 716214125*uk_77 + 2229805417*uk_78 + 1243347721*uk_79 + 121*uk_8 + 693295273*uk_80 + 250047*uk_81 + 408807*uk_82 + 480249*uk_83 + 95256*uk_84 + 496125*uk_85 + 861273*uk_86 + 480249*uk_87 + 668367*uk_88 + 785169*uk_89 + 2242306609*uk_9 + 155736*uk_90 + 811125*uk_91 + 1408113*uk_92 + 785169*uk_93 + 922383*uk_94 + 182952*uk_95 + 952875*uk_96 + 1654191*uk_97 + 922383*uk_98 + 36288*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 192024*uk_100 + 328104*uk_101 + 155736*uk_102 + 1016127*uk_103 + 1736217*uk_104 + 824103*uk_105 + 2966607*uk_106 + 1408113*uk_107 + 668367*uk_108 + 1295029*uk_109 + 5161477*uk_11 + 1223743*uk_110 + 285144*uk_111 + 1508887*uk_112 + 2578177*uk_113 + 1223743*uk_114 + 1156381*uk_115 + 269448*uk_116 + 1425829*uk_117 + 2436259*uk_118 + 1156381*uk_119 + 4877359*uk_12 + 62784*uk_120 + 332232*uk_121 + 567672*uk_122 + 269448*uk_123 + 1758061*uk_124 + 3003931*uk_125 + 1425829*uk_126 + 5132701*uk_127 + 2436259*uk_128 + 1156381*uk_129 + 1136472*uk_13 + 1092727*uk_130 + 254616*uk_131 + 1347343*uk_132 + 2302153*uk_133 + 1092727*uk_134 + 59328*uk_135 + 313944*uk_136 + 536424*uk_137 + 254616*uk_138 + 1661287*uk_139 + 6013831*uk_14 + 2838577*uk_140 + 1347343*uk_141 + 4850167*uk_142 + 2302153*uk_143 + 1092727*uk_144 + 13824*uk_145 + 73152*uk_146 + 124992*uk_147 + 59328*uk_148 + 387096*uk_149 + 10275601*uk_15 + 661416*uk_150 + 313944*uk_151 + 1130136*uk_152 + 536424*uk_153 + 254616*uk_154 + 2048383*uk_155 + 3499993*uk_156 + 1661287*uk_157 + 5980303*uk_158 + 2838577*uk_159 + 4877359*uk_16 + 1347343*uk_160 + 10218313*uk_161 + 4850167*uk_162 + 2302153*uk_163 + 1092727*uk_164 + 3969*uk_17 + 6867*uk_18 + 6489*uk_19 + 63*uk_2 + 1512*uk_20 + 8001*uk_21 + 13671*uk_22 + 6489*uk_23 + 11881*uk_24 + 11227*uk_25 + 2616*uk_26 + 13843*uk_27 + 23653*uk_28 + 11227*uk_29 + 109*uk_3 + 10609*uk_30 + 2472*uk_31 + 13081*uk_32 + 22351*uk_33 + 10609*uk_34 + 576*uk_35 + 3048*uk_36 + 5208*uk_37 + 2472*uk_38 + 16129*uk_39 + 103*uk_4 + 27559*uk_40 + 13081*uk_41 + 47089*uk_42 + 22351*uk_43 + 10609*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 244411420381*uk_47 + 230957580727*uk_48 + 53815358616*uk_49 + 24*uk_5 + 284772939343*uk_50 + 486580534153*uk_51 + 230957580727*uk_52 + 187944057*uk_53 + 325173051*uk_54 + 307273617*uk_55 + 71597736*uk_56 + 378871353*uk_57 + 647362863*uk_58 + 307273617*uk_59 + 127*uk_6 + 562600993*uk_60 + 531632131*uk_61 + 123875448*uk_62 + 655507579*uk_63 + 1120040509*uk_64 + 531632131*uk_65 + 502367977*uk_66 + 117056616*uk_67 + 619424593*uk_68 + 1058386903*uk_69 + 217*uk_7 + 502367977*uk_70 + 27275328*uk_71 + 144331944*uk_72 + 246614424*uk_73 + 117056616*uk_74 + 763756537*uk_75 + 1305001327*uk_76 + 619424593*uk_77 + 2229805417*uk_78 + 1058386903*uk_79 + 103*uk_8 + 502367977*uk_80 + 250047*uk_81 + 432621*uk_82 + 408807*uk_83 + 95256*uk_84 + 504063*uk_85 + 861273*uk_86 + 408807*uk_87 + 748503*uk_88 + 707301*uk_89 + 2242306609*uk_9 + 164808*uk_90 + 872109*uk_91 + 1490139*uk_92 + 707301*uk_93 + 668367*uk_94 + 155736*uk_95 + 824103*uk_96 + 1408113*uk_97 + 668367*uk_98 + 36288*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 162540*uk_100 + 273420*uk_101 + 137340*uk_102 + 1048383*uk_103 + 1763559*uk_104 + 885843*uk_105 + 2966607*uk_106 + 1490139*uk_107 + 748503*uk_108 + 1000*uk_109 + 473530*uk_11 + 10900*uk_110 + 2000*uk_111 + 12900*uk_112 + 21700*uk_113 + 10900*uk_114 + 118810*uk_115 + 21800*uk_116 + 140610*uk_117 + 236530*uk_118 + 118810*uk_119 + 5161477*uk_12 + 4000*uk_120 + 25800*uk_121 + 43400*uk_122 + 21800*uk_123 + 166410*uk_124 + 279930*uk_125 + 140610*uk_126 + 470890*uk_127 + 236530*uk_128 + 118810*uk_129 + 947060*uk_13 + 1295029*uk_130 + 237620*uk_131 + 1532649*uk_132 + 2578177*uk_133 + 1295029*uk_134 + 43600*uk_135 + 281220*uk_136 + 473060*uk_137 + 237620*uk_138 + 1813869*uk_139 + 6108537*uk_14 + 3051237*uk_140 + 1532649*uk_141 + 5132701*uk_142 + 2578177*uk_143 + 1295029*uk_144 + 8000*uk_145 + 51600*uk_146 + 86800*uk_147 + 43600*uk_148 + 332820*uk_149 + 10275601*uk_15 + 559860*uk_150 + 281220*uk_151 + 941780*uk_152 + 473060*uk_153 + 237620*uk_154 + 2146689*uk_155 + 3611097*uk_156 + 1813869*uk_157 + 6074481*uk_158 + 3051237*uk_159 + 5161477*uk_16 + 1532649*uk_160 + 10218313*uk_161 + 5132701*uk_162 + 2578177*uk_163 + 1295029*uk_164 + 3969*uk_17 + 630*uk_18 + 6867*uk_19 + 63*uk_2 + 1260*uk_20 + 8127*uk_21 + 13671*uk_22 + 6867*uk_23 + 100*uk_24 + 1090*uk_25 + 200*uk_26 + 1290*uk_27 + 2170*uk_28 + 1090*uk_29 + 10*uk_3 + 11881*uk_30 + 2180*uk_31 + 14061*uk_32 + 23653*uk_33 + 11881*uk_34 + 400*uk_35 + 2580*uk_36 + 4340*uk_37 + 2180*uk_38 + 16641*uk_39 + 109*uk_4 + 27993*uk_40 + 14061*uk_41 + 47089*uk_42 + 23653*uk_43 + 11881*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 22423066090*uk_47 + 244411420381*uk_48 + 44846132180*uk_49 + 20*uk_5 + 289257552561*uk_50 + 486580534153*uk_51 + 244411420381*uk_52 + 187944057*uk_53 + 29832390*uk_54 + 325173051*uk_55 + 59664780*uk_56 + 384837831*uk_57 + 647362863*uk_58 + 325173051*uk_59 + 129*uk_6 + 4735300*uk_60 + 51614770*uk_61 + 9470600*uk_62 + 61085370*uk_63 + 102756010*uk_64 + 51614770*uk_65 + 562600993*uk_66 + 103229540*uk_67 + 665830533*uk_68 + 1120040509*uk_69 + 217*uk_7 + 562600993*uk_70 + 18941200*uk_71 + 122170740*uk_72 + 205512020*uk_73 + 103229540*uk_74 + 788001273*uk_75 + 1325552529*uk_76 + 665830533*uk_77 + 2229805417*uk_78 + 1120040509*uk_79 + 109*uk_8 + 562600993*uk_80 + 250047*uk_81 + 39690*uk_82 + 432621*uk_83 + 79380*uk_84 + 512001*uk_85 + 861273*uk_86 + 432621*uk_87 + 6300*uk_88 + 68670*uk_89 + 2242306609*uk_9 + 12600*uk_90 + 81270*uk_91 + 136710*uk_92 + 68670*uk_93 + 748503*uk_94 + 137340*uk_95 + 885843*uk_96 + 1490139*uk_97 + 748503*uk_98 + 25200*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 198072*uk_100 + 328104*uk_101 + 15120*uk_102 + 1081143*uk_103 + 1790901*uk_104 + 82530*uk_105 + 2966607*uk_106 + 136710*uk_107 + 6300*uk_108 + 238328*uk_109 + 2935886*uk_11 + 38440*uk_110 + 92256*uk_111 + 503564*uk_112 + 834148*uk_113 + 38440*uk_114 + 6200*uk_115 + 14880*uk_116 + 81220*uk_117 + 134540*uk_118 + 6200*uk_119 + 473530*uk_12 + 35712*uk_120 + 194928*uk_121 + 322896*uk_122 + 14880*uk_123 + 1063982*uk_124 + 1762474*uk_125 + 81220*uk_126 + 2919518*uk_127 + 134540*uk_128 + 6200*uk_129 + 1136472*uk_13 + 1000*uk_130 + 2400*uk_131 + 13100*uk_132 + 21700*uk_133 + 1000*uk_134 + 5760*uk_135 + 31440*uk_136 + 52080*uk_137 + 2400*uk_138 + 171610*uk_139 + 6203243*uk_14 + 284270*uk_140 + 13100*uk_141 + 470890*uk_142 + 21700*uk_143 + 1000*uk_144 + 13824*uk_145 + 75456*uk_146 + 124992*uk_147 + 5760*uk_148 + 411864*uk_149 + 10275601*uk_15 + 682248*uk_150 + 31440*uk_151 + 1130136*uk_152 + 52080*uk_153 + 2400*uk_154 + 2248091*uk_155 + 3723937*uk_156 + 171610*uk_157 + 6168659*uk_158 + 284270*uk_159 + 473530*uk_16 + 13100*uk_160 + 10218313*uk_161 + 470890*uk_162 + 21700*uk_163 + 1000*uk_164 + 3969*uk_17 + 3906*uk_18 + 630*uk_19 + 63*uk_2 + 1512*uk_20 + 8253*uk_21 + 13671*uk_22 + 630*uk_23 + 3844*uk_24 + 620*uk_25 + 1488*uk_26 + 8122*uk_27 + 13454*uk_28 + 620*uk_29 + 62*uk_3 + 100*uk_30 + 240*uk_31 + 1310*uk_32 + 2170*uk_33 + 100*uk_34 + 576*uk_35 + 3144*uk_36 + 5208*uk_37 + 240*uk_38 + 17161*uk_39 + 10*uk_4 + 28427*uk_40 + 1310*uk_41 + 47089*uk_42 + 2170*uk_43 + 100*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 139023009758*uk_47 + 22423066090*uk_48 + 53815358616*uk_49 + 24*uk_5 + 293742165779*uk_50 + 486580534153*uk_51 + 22423066090*uk_52 + 187944057*uk_53 + 184960818*uk_54 + 29832390*uk_55 + 71597736*uk_56 + 390804309*uk_57 + 647362863*uk_58 + 29832390*uk_59 + 131*uk_6 + 182024932*uk_60 + 29358860*uk_61 + 70461264*uk_62 + 384601066*uk_63 + 637087262*uk_64 + 29358860*uk_65 + 4735300*uk_66 + 11364720*uk_67 + 62032430*uk_68 + 102756010*uk_69 + 217*uk_7 + 4735300*uk_70 + 27275328*uk_71 + 148877832*uk_72 + 246614424*uk_73 + 11364720*uk_74 + 812624833*uk_75 + 1346103731*uk_76 + 62032430*uk_77 + 2229805417*uk_78 + 102756010*uk_79 + 10*uk_8 + 4735300*uk_80 + 250047*uk_81 + 246078*uk_82 + 39690*uk_83 + 95256*uk_84 + 519939*uk_85 + 861273*uk_86 + 39690*uk_87 + 242172*uk_88 + 39060*uk_89 + 2242306609*uk_9 + 93744*uk_90 + 511686*uk_91 + 847602*uk_92 + 39060*uk_93 + 6300*uk_94 + 15120*uk_95 + 82530*uk_96 + 136710*uk_97 + 6300*uk_98 + 36288*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 167580*uk_100 + 273420*uk_101 + 78120*uk_102 + 1114407*uk_103 + 1818243*uk_104 + 519498*uk_105 + 2966607*uk_106 + 847602*uk_107 + 242172*uk_108 + 125*uk_109 + 236765*uk_11 + 1550*uk_110 + 500*uk_111 + 3325*uk_112 + 5425*uk_113 + 1550*uk_114 + 19220*uk_115 + 6200*uk_116 + 41230*uk_117 + 67270*uk_118 + 19220*uk_119 + 2935886*uk_12 + 2000*uk_120 + 13300*uk_121 + 21700*uk_122 + 6200*uk_123 + 88445*uk_124 + 144305*uk_125 + 41230*uk_126 + 235445*uk_127 + 67270*uk_128 + 19220*uk_129 + 947060*uk_13 + 238328*uk_130 + 76880*uk_131 + 511252*uk_132 + 834148*uk_133 + 238328*uk_134 + 24800*uk_135 + 164920*uk_136 + 269080*uk_137 + 76880*uk_138 + 1096718*uk_139 + 6297949*uk_14 + 1789382*uk_140 + 511252*uk_141 + 2919518*uk_142 + 834148*uk_143 + 238328*uk_144 + 8000*uk_145 + 53200*uk_146 + 86800*uk_147 + 24800*uk_148 + 353780*uk_149 + 10275601*uk_15 + 577220*uk_150 + 164920*uk_151 + 941780*uk_152 + 269080*uk_153 + 76880*uk_154 + 2352637*uk_155 + 3838513*uk_156 + 1096718*uk_157 + 6262837*uk_158 + 1789382*uk_159 + 2935886*uk_16 + 511252*uk_160 + 10218313*uk_161 + 2919518*uk_162 + 834148*uk_163 + 238328*uk_164 + 3969*uk_17 + 315*uk_18 + 3906*uk_19 + 63*uk_2 + 1260*uk_20 + 8379*uk_21 + 13671*uk_22 + 3906*uk_23 + 25*uk_24 + 310*uk_25 + 100*uk_26 + 665*uk_27 + 1085*uk_28 + 310*uk_29 + 5*uk_3 + 3844*uk_30 + 1240*uk_31 + 8246*uk_32 + 13454*uk_33 + 3844*uk_34 + 400*uk_35 + 2660*uk_36 + 4340*uk_37 + 1240*uk_38 + 17689*uk_39 + 62*uk_4 + 28861*uk_40 + 8246*uk_41 + 47089*uk_42 + 13454*uk_43 + 3844*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 11211533045*uk_47 + 139023009758*uk_48 + 44846132180*uk_49 + 20*uk_5 + 298226778997*uk_50 + 486580534153*uk_51 + 139023009758*uk_52 + 187944057*uk_53 + 14916195*uk_54 + 184960818*uk_55 + 59664780*uk_56 + 396770787*uk_57 + 647362863*uk_58 + 184960818*uk_59 + 133*uk_6 + 1183825*uk_60 + 14679430*uk_61 + 4735300*uk_62 + 31489745*uk_63 + 51378005*uk_64 + 14679430*uk_65 + 182024932*uk_66 + 58717720*uk_67 + 390472838*uk_68 + 637087262*uk_69 + 217*uk_7 + 182024932*uk_70 + 18941200*uk_71 + 125958980*uk_72 + 205512020*uk_73 + 58717720*uk_74 + 837627217*uk_75 + 1366654933*uk_76 + 390472838*uk_77 + 2229805417*uk_78 + 637087262*uk_79 + 62*uk_8 + 182024932*uk_80 + 250047*uk_81 + 19845*uk_82 + 246078*uk_83 + 79380*uk_84 + 527877*uk_85 + 861273*uk_86 + 246078*uk_87 + 1575*uk_88 + 19530*uk_89 + 2242306609*uk_9 + 6300*uk_90 + 41895*uk_91 + 68355*uk_92 + 19530*uk_93 + 242172*uk_94 + 78120*uk_95 + 519498*uk_96 + 847602*uk_97 + 242172*uk_98 + 25200*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 204120*uk_100 + 328104*uk_101 + 7560*uk_102 + 1148175*uk_103 + 1845585*uk_104 + 42525*uk_105 + 2966607*uk_106 + 68355*uk_107 + 1575*uk_108 + 1092727*uk_109 + 4877359*uk_11 + 53045*uk_110 + 254616*uk_111 + 1432215*uk_112 + 2302153*uk_113 + 53045*uk_114 + 2575*uk_115 + 12360*uk_116 + 69525*uk_117 + 111755*uk_118 + 2575*uk_119 + 236765*uk_12 + 59328*uk_120 + 333720*uk_121 + 536424*uk_122 + 12360*uk_123 + 1877175*uk_124 + 3017385*uk_125 + 69525*uk_126 + 4850167*uk_127 + 111755*uk_128 + 2575*uk_129 + 1136472*uk_13 + 125*uk_130 + 600*uk_131 + 3375*uk_132 + 5425*uk_133 + 125*uk_134 + 2880*uk_135 + 16200*uk_136 + 26040*uk_137 + 600*uk_138 + 91125*uk_139 + 6392655*uk_14 + 146475*uk_140 + 3375*uk_141 + 235445*uk_142 + 5425*uk_143 + 125*uk_144 + 13824*uk_145 + 77760*uk_146 + 124992*uk_147 + 2880*uk_148 + 437400*uk_149 + 10275601*uk_15 + 703080*uk_150 + 16200*uk_151 + 1130136*uk_152 + 26040*uk_153 + 600*uk_154 + 2460375*uk_155 + 3954825*uk_156 + 91125*uk_157 + 6357015*uk_158 + 146475*uk_159 + 236765*uk_16 + 3375*uk_160 + 10218313*uk_161 + 235445*uk_162 + 5425*uk_163 + 125*uk_164 + 3969*uk_17 + 6489*uk_18 + 315*uk_19 + 63*uk_2 + 1512*uk_20 + 8505*uk_21 + 13671*uk_22 + 315*uk_23 + 10609*uk_24 + 515*uk_25 + 2472*uk_26 + 13905*uk_27 + 22351*uk_28 + 515*uk_29 + 103*uk_3 + 25*uk_30 + 120*uk_31 + 675*uk_32 + 1085*uk_33 + 25*uk_34 + 576*uk_35 + 3240*uk_36 + 5208*uk_37 + 120*uk_38 + 18225*uk_39 + 5*uk_4 + 29295*uk_40 + 675*uk_41 + 47089*uk_42 + 1085*uk_43 + 25*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 230957580727*uk_47 + 11211533045*uk_48 + 53815358616*uk_49 + 24*uk_5 + 302711392215*uk_50 + 486580534153*uk_51 + 11211533045*uk_52 + 187944057*uk_53 + 307273617*uk_54 + 14916195*uk_55 + 71597736*uk_56 + 402737265*uk_57 + 647362863*uk_58 + 14916195*uk_59 + 135*uk_6 + 502367977*uk_60 + 24386795*uk_61 + 117056616*uk_62 + 658443465*uk_63 + 1058386903*uk_64 + 24386795*uk_65 + 1183825*uk_66 + 5682360*uk_67 + 31963275*uk_68 + 51378005*uk_69 + 217*uk_7 + 1183825*uk_70 + 27275328*uk_71 + 153423720*uk_72 + 246614424*uk_73 + 5682360*uk_74 + 863008425*uk_75 + 1387206135*uk_76 + 31963275*uk_77 + 2229805417*uk_78 + 51378005*uk_79 + 5*uk_8 + 1183825*uk_80 + 250047*uk_81 + 408807*uk_82 + 19845*uk_83 + 95256*uk_84 + 535815*uk_85 + 861273*uk_86 + 19845*uk_87 + 668367*uk_88 + 32445*uk_89 + 2242306609*uk_9 + 155736*uk_90 + 876015*uk_91 + 1408113*uk_92 + 32445*uk_93 + 1575*uk_94 + 7560*uk_95 + 42525*uk_96 + 68355*uk_97 + 1575*uk_98 + 36288*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 172620*uk_100 + 273420*uk_101 + 129780*uk_102 + 1182447*uk_103 + 1872927*uk_104 + 888993*uk_105 + 2966607*uk_106 + 1408113*uk_107 + 668367*uk_108 + 681472*uk_109 + 4167064*uk_11 + 797632*uk_110 + 154880*uk_111 + 1060928*uk_112 + 1680448*uk_113 + 797632*uk_114 + 933592*uk_115 + 181280*uk_116 + 1241768*uk_117 + 1966888*uk_118 + 933592*uk_119 + 4877359*uk_12 + 35200*uk_120 + 241120*uk_121 + 381920*uk_122 + 181280*uk_123 + 1651672*uk_124 + 2616152*uk_125 + 1241768*uk_126 + 4143832*uk_127 + 1966888*uk_128 + 933592*uk_129 + 947060*uk_13 + 1092727*uk_130 + 212180*uk_131 + 1453433*uk_132 + 2302153*uk_133 + 1092727*uk_134 + 41200*uk_135 + 282220*uk_136 + 447020*uk_137 + 212180*uk_138 + 1933207*uk_139 + 6487361*uk_14 + 3062087*uk_140 + 1453433*uk_141 + 4850167*uk_142 + 2302153*uk_143 + 1092727*uk_144 + 8000*uk_145 + 54800*uk_146 + 86800*uk_147 + 41200*uk_148 + 375380*uk_149 + 10275601*uk_15 + 594580*uk_150 + 282220*uk_151 + 941780*uk_152 + 447020*uk_153 + 212180*uk_154 + 2571353*uk_155 + 4072873*uk_156 + 1933207*uk_157 + 6451193*uk_158 + 3062087*uk_159 + 4877359*uk_16 + 1453433*uk_160 + 10218313*uk_161 + 4850167*uk_162 + 2302153*uk_163 + 1092727*uk_164 + 3969*uk_17 + 5544*uk_18 + 6489*uk_19 + 63*uk_2 + 1260*uk_20 + 8631*uk_21 + 13671*uk_22 + 6489*uk_23 + 7744*uk_24 + 9064*uk_25 + 1760*uk_26 + 12056*uk_27 + 19096*uk_28 + 9064*uk_29 + 88*uk_3 + 10609*uk_30 + 2060*uk_31 + 14111*uk_32 + 22351*uk_33 + 10609*uk_34 + 400*uk_35 + 2740*uk_36 + 4340*uk_37 + 2060*uk_38 + 18769*uk_39 + 103*uk_4 + 29729*uk_40 + 14111*uk_41 + 47089*uk_42 + 22351*uk_43 + 10609*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 197322981592*uk_47 + 230957580727*uk_48 + 44846132180*uk_49 + 20*uk_5 + 307196005433*uk_50 + 486580534153*uk_51 + 230957580727*uk_52 + 187944057*uk_53 + 262525032*uk_54 + 307273617*uk_55 + 59664780*uk_56 + 408703743*uk_57 + 647362863*uk_58 + 307273617*uk_59 + 137*uk_6 + 366701632*uk_60 + 429207592*uk_61 + 83341280*uk_62 + 570887768*uk_63 + 904252888*uk_64 + 429207592*uk_65 + 502367977*uk_66 + 97547180*uk_67 + 668198183*uk_68 + 1058386903*uk_69 + 217*uk_7 + 502367977*uk_70 + 18941200*uk_71 + 129747220*uk_72 + 205512020*uk_73 + 97547180*uk_74 + 888768457*uk_75 + 1407757337*uk_76 + 668198183*uk_77 + 2229805417*uk_78 + 1058386903*uk_79 + 103*uk_8 + 502367977*uk_80 + 250047*uk_81 + 349272*uk_82 + 408807*uk_83 + 79380*uk_84 + 543753*uk_85 + 861273*uk_86 + 408807*uk_87 + 487872*uk_88 + 571032*uk_89 + 2242306609*uk_9 + 110880*uk_90 + 759528*uk_91 + 1203048*uk_92 + 571032*uk_93 + 668367*uk_94 + 129780*uk_95 + 888993*uk_96 + 1408113*uk_97 + 668367*uk_98 + 25200*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 175140*uk_100 + 273420*uk_101 + 110880*uk_102 + 1217223*uk_103 + 1900269*uk_104 + 770616*uk_105 + 2966607*uk_106 + 1203048*uk_107 + 487872*uk_108 + 804357*uk_109 + 4403829*uk_11 + 761112*uk_110 + 172980*uk_111 + 1202211*uk_112 + 1876833*uk_113 + 761112*uk_114 + 720192*uk_115 + 163680*uk_116 + 1137576*uk_117 + 1775928*uk_118 + 720192*uk_119 + 4167064*uk_12 + 37200*uk_120 + 258540*uk_121 + 403620*uk_122 + 163680*uk_123 + 1796853*uk_124 + 2805159*uk_125 + 1137576*uk_126 + 4379277*uk_127 + 1775928*uk_128 + 720192*uk_129 + 947060*uk_13 + 681472*uk_130 + 154880*uk_131 + 1076416*uk_132 + 1680448*uk_133 + 681472*uk_134 + 35200*uk_135 + 244640*uk_136 + 381920*uk_137 + 154880*uk_138 + 1700248*uk_139 + 6582067*uk_14 + 2654344*uk_140 + 1076416*uk_141 + 4143832*uk_142 + 1680448*uk_143 + 681472*uk_144 + 8000*uk_145 + 55600*uk_146 + 86800*uk_147 + 35200*uk_148 + 386420*uk_149 + 10275601*uk_15 + 603260*uk_150 + 244640*uk_151 + 941780*uk_152 + 381920*uk_153 + 154880*uk_154 + 2685619*uk_155 + 4192657*uk_156 + 1700248*uk_157 + 6545371*uk_158 + 2654344*uk_159 + 4167064*uk_16 + 1076416*uk_160 + 10218313*uk_161 + 4143832*uk_162 + 1680448*uk_163 + 681472*uk_164 + 3969*uk_17 + 5859*uk_18 + 5544*uk_19 + 63*uk_2 + 1260*uk_20 + 8757*uk_21 + 13671*uk_22 + 5544*uk_23 + 8649*uk_24 + 8184*uk_25 + 1860*uk_26 + 12927*uk_27 + 20181*uk_28 + 8184*uk_29 + 93*uk_3 + 7744*uk_30 + 1760*uk_31 + 12232*uk_32 + 19096*uk_33 + 7744*uk_34 + 400*uk_35 + 2780*uk_36 + 4340*uk_37 + 1760*uk_38 + 19321*uk_39 + 88*uk_4 + 30163*uk_40 + 12232*uk_41 + 47089*uk_42 + 19096*uk_43 + 7744*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 208534514637*uk_47 + 197322981592*uk_48 + 44846132180*uk_49 + 20*uk_5 + 311680618651*uk_50 + 486580534153*uk_51 + 197322981592*uk_52 + 187944057*uk_53 + 277441227*uk_54 + 262525032*uk_55 + 59664780*uk_56 + 414670221*uk_57 + 647362863*uk_58 + 262525032*uk_59 + 139*uk_6 + 409556097*uk_60 + 387536952*uk_61 + 88076580*uk_62 + 612132231*uk_63 + 955630893*uk_64 + 387536952*uk_65 + 366701632*uk_66 + 83341280*uk_67 + 579221896*uk_68 + 904252888*uk_69 + 217*uk_7 + 366701632*uk_70 + 18941200*uk_71 + 131641340*uk_72 + 205512020*uk_73 + 83341280*uk_74 + 914907313*uk_75 + 1428308539*uk_76 + 579221896*uk_77 + 2229805417*uk_78 + 904252888*uk_79 + 88*uk_8 + 366701632*uk_80 + 250047*uk_81 + 369117*uk_82 + 349272*uk_83 + 79380*uk_84 + 551691*uk_85 + 861273*uk_86 + 349272*uk_87 + 544887*uk_88 + 515592*uk_89 + 2242306609*uk_9 + 117180*uk_90 + 814401*uk_91 + 1271403*uk_92 + 515592*uk_93 + 487872*uk_94 + 110880*uk_95 + 770616*uk_96 + 1203048*uk_97 + 487872*uk_98 + 25200*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 177660*uk_100 + 273420*uk_101 + 117180*uk_102 + 1252503*uk_103 + 1927611*uk_104 + 826119*uk_105 + 2966607*uk_106 + 1271403*uk_107 + 544887*uk_108 + 1643032*uk_109 + 5587654*uk_11 + 1294932*uk_110 + 278480*uk_111 + 1963284*uk_112 + 3021508*uk_113 + 1294932*uk_114 + 1020582*uk_115 + 219480*uk_116 + 1547334*uk_117 + 2381358*uk_118 + 1020582*uk_119 + 4403829*uk_12 + 47200*uk_120 + 332760*uk_121 + 512120*uk_122 + 219480*uk_123 + 2345958*uk_124 + 3610446*uk_125 + 1547334*uk_126 + 5556502*uk_127 + 2381358*uk_128 + 1020582*uk_129 + 947060*uk_13 + 804357*uk_130 + 172980*uk_131 + 1219509*uk_132 + 1876833*uk_133 + 804357*uk_134 + 37200*uk_135 + 262260*uk_136 + 403620*uk_137 + 172980*uk_138 + 1848933*uk_139 + 6676773*uk_14 + 2845521*uk_140 + 1219509*uk_141 + 4379277*uk_142 + 1876833*uk_143 + 804357*uk_144 + 8000*uk_145 + 56400*uk_146 + 86800*uk_147 + 37200*uk_148 + 397620*uk_149 + 10275601*uk_15 + 611940*uk_150 + 262260*uk_151 + 941780*uk_152 + 403620*uk_153 + 172980*uk_154 + 2803221*uk_155 + 4314177*uk_156 + 1848933*uk_157 + 6639549*uk_158 + 2845521*uk_159 + 4403829*uk_16 + 1219509*uk_160 + 10218313*uk_161 + 4379277*uk_162 + 1876833*uk_163 + 804357*uk_164 + 3969*uk_17 + 7434*uk_18 + 5859*uk_19 + 63*uk_2 + 1260*uk_20 + 8883*uk_21 + 13671*uk_22 + 5859*uk_23 + 13924*uk_24 + 10974*uk_25 + 2360*uk_26 + 16638*uk_27 + 25606*uk_28 + 10974*uk_29 + 118*uk_3 + 8649*uk_30 + 1860*uk_31 + 13113*uk_32 + 20181*uk_33 + 8649*uk_34 + 400*uk_35 + 2820*uk_36 + 4340*uk_37 + 1860*uk_38 + 19881*uk_39 + 93*uk_4 + 30597*uk_40 + 13113*uk_41 + 47089*uk_42 + 20181*uk_43 + 8649*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 264592179862*uk_47 + 208534514637*uk_48 + 44846132180*uk_49 + 20*uk_5 + 316165231869*uk_50 + 486580534153*uk_51 + 208534514637*uk_52 + 187944057*uk_53 + 352022202*uk_54 + 277441227*uk_55 + 59664780*uk_56 + 420636699*uk_57 + 647362863*uk_58 + 277441227*uk_59 + 141*uk_6 + 659343172*uk_60 + 519651822*uk_61 + 111753080*uk_62 + 787859214*uk_63 + 1212520918*uk_64 + 519651822*uk_65 + 409556097*uk_66 + 88076580*uk_67 + 620939889*uk_68 + 955630893*uk_69 + 217*uk_7 + 409556097*uk_70 + 18941200*uk_71 + 133535460*uk_72 + 205512020*uk_73 + 88076580*uk_74 + 941424993*uk_75 + 1448859741*uk_76 + 620939889*uk_77 + 2229805417*uk_78 + 955630893*uk_79 + 93*uk_8 + 409556097*uk_80 + 250047*uk_81 + 468342*uk_82 + 369117*uk_83 + 79380*uk_84 + 559629*uk_85 + 861273*uk_86 + 369117*uk_87 + 877212*uk_88 + 691362*uk_89 + 2242306609*uk_9 + 148680*uk_90 + 1048194*uk_91 + 1613178*uk_92 + 691362*uk_93 + 544887*uk_94 + 117180*uk_95 + 826119*uk_96 + 1271403*uk_97 + 544887*uk_98 + 25200*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 144144*uk_100 + 218736*uk_101 + 118944*uk_102 + 1288287*uk_103 + 1954953*uk_104 + 1063062*uk_105 + 2966607*uk_106 + 1613178*uk_107 + 877212*uk_108 + 8000*uk_109 + 947060*uk_11 + 47200*uk_110 + 6400*uk_111 + 57200*uk_112 + 86800*uk_113 + 47200*uk_114 + 278480*uk_115 + 37760*uk_116 + 337480*uk_117 + 512120*uk_118 + 278480*uk_119 + 5587654*uk_12 + 5120*uk_120 + 45760*uk_121 + 69440*uk_122 + 37760*uk_123 + 408980*uk_124 + 620620*uk_125 + 337480*uk_126 + 941780*uk_127 + 512120*uk_128 + 278480*uk_129 + 757648*uk_13 + 1643032*uk_130 + 222784*uk_131 + 1991132*uk_132 + 3021508*uk_133 + 1643032*uk_134 + 30208*uk_135 + 269984*uk_136 + 409696*uk_137 + 222784*uk_138 + 2412982*uk_139 + 6771479*uk_14 + 3661658*uk_140 + 1991132*uk_141 + 5556502*uk_142 + 3021508*uk_143 + 1643032*uk_144 + 4096*uk_145 + 36608*uk_146 + 55552*uk_147 + 30208*uk_148 + 327184*uk_149 + 10275601*uk_15 + 496496*uk_150 + 269984*uk_151 + 753424*uk_152 + 409696*uk_153 + 222784*uk_154 + 2924207*uk_155 + 4437433*uk_156 + 2412982*uk_157 + 6733727*uk_158 + 3661658*uk_159 + 5587654*uk_16 + 1991132*uk_160 + 10218313*uk_161 + 5556502*uk_162 + 3021508*uk_163 + 1643032*uk_164 + 3969*uk_17 + 1260*uk_18 + 7434*uk_19 + 63*uk_2 + 1008*uk_20 + 9009*uk_21 + 13671*uk_22 + 7434*uk_23 + 400*uk_24 + 2360*uk_25 + 320*uk_26 + 2860*uk_27 + 4340*uk_28 + 2360*uk_29 + 20*uk_3 + 13924*uk_30 + 1888*uk_31 + 16874*uk_32 + 25606*uk_33 + 13924*uk_34 + 256*uk_35 + 2288*uk_36 + 3472*uk_37 + 1888*uk_38 + 20449*uk_39 + 118*uk_4 + 31031*uk_40 + 16874*uk_41 + 47089*uk_42 + 25606*uk_43 + 13924*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 44846132180*uk_47 + 264592179862*uk_48 + 35876905744*uk_49 + 16*uk_5 + 320649845087*uk_50 + 486580534153*uk_51 + 264592179862*uk_52 + 187944057*uk_53 + 59664780*uk_54 + 352022202*uk_55 + 47731824*uk_56 + 426603177*uk_57 + 647362863*uk_58 + 352022202*uk_59 + 143*uk_6 + 18941200*uk_60 + 111753080*uk_61 + 15152960*uk_62 + 135429580*uk_63 + 205512020*uk_64 + 111753080*uk_65 + 659343172*uk_66 + 89402464*uk_67 + 799034522*uk_68 + 1212520918*uk_69 + 217*uk_7 + 659343172*uk_70 + 12122368*uk_71 + 108343664*uk_72 + 164409616*uk_73 + 89402464*uk_74 + 968321497*uk_75 + 1469410943*uk_76 + 799034522*uk_77 + 2229805417*uk_78 + 1212520918*uk_79 + 118*uk_8 + 659343172*uk_80 + 250047*uk_81 + 79380*uk_82 + 468342*uk_83 + 63504*uk_84 + 567567*uk_85 + 861273*uk_86 + 468342*uk_87 + 25200*uk_88 + 148680*uk_89 + 2242306609*uk_9 + 20160*uk_90 + 180180*uk_91 + 273420*uk_92 + 148680*uk_93 + 877212*uk_94 + 118944*uk_95 + 1063062*uk_96 + 1613178*uk_97 + 877212*uk_98 + 16128*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 182700*uk_100 + 273420*uk_101 + 25200*uk_102 + 1324575*uk_103 + 1982295*uk_104 + 182700*uk_105 + 2966607*uk_106 + 273420*uk_107 + 25200*uk_108 + 571787*uk_109 + 3930299*uk_11 + 137780*uk_110 + 137780*uk_111 + 998905*uk_112 + 1494913*uk_113 + 137780*uk_114 + 33200*uk_115 + 33200*uk_116 + 240700*uk_117 + 360220*uk_118 + 33200*uk_119 + 947060*uk_12 + 33200*uk_120 + 240700*uk_121 + 360220*uk_122 + 33200*uk_123 + 1745075*uk_124 + 2611595*uk_125 + 240700*uk_126 + 3908387*uk_127 + 360220*uk_128 + 33200*uk_129 + 947060*uk_13 + 8000*uk_130 + 8000*uk_131 + 58000*uk_132 + 86800*uk_133 + 8000*uk_134 + 8000*uk_135 + 58000*uk_136 + 86800*uk_137 + 8000*uk_138 + 420500*uk_139 + 6866185*uk_14 + 629300*uk_140 + 58000*uk_141 + 941780*uk_142 + 86800*uk_143 + 8000*uk_144 + 8000*uk_145 + 58000*uk_146 + 86800*uk_147 + 8000*uk_148 + 420500*uk_149 + 10275601*uk_15 + 629300*uk_150 + 58000*uk_151 + 941780*uk_152 + 86800*uk_153 + 8000*uk_154 + 3048625*uk_155 + 4562425*uk_156 + 420500*uk_157 + 6827905*uk_158 + 629300*uk_159 + 947060*uk_16 + 58000*uk_160 + 10218313*uk_161 + 941780*uk_162 + 86800*uk_163 + 8000*uk_164 + 3969*uk_17 + 5229*uk_18 + 1260*uk_19 + 63*uk_2 + 1260*uk_20 + 9135*uk_21 + 13671*uk_22 + 1260*uk_23 + 6889*uk_24 + 1660*uk_25 + 1660*uk_26 + 12035*uk_27 + 18011*uk_28 + 1660*uk_29 + 83*uk_3 + 400*uk_30 + 400*uk_31 + 2900*uk_32 + 4340*uk_33 + 400*uk_34 + 400*uk_35 + 2900*uk_36 + 4340*uk_37 + 400*uk_38 + 21025*uk_39 + 20*uk_4 + 31465*uk_40 + 2900*uk_41 + 47089*uk_42 + 4340*uk_43 + 400*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 186111448547*uk_47 + 44846132180*uk_48 + 44846132180*uk_49 + 20*uk_5 + 325134458305*uk_50 + 486580534153*uk_51 + 44846132180*uk_52 + 187944057*uk_53 + 247608837*uk_54 + 59664780*uk_55 + 59664780*uk_56 + 432569655*uk_57 + 647362863*uk_58 + 59664780*uk_59 + 145*uk_6 + 326214817*uk_60 + 78605980*uk_61 + 78605980*uk_62 + 569893355*uk_63 + 852874883*uk_64 + 78605980*uk_65 + 18941200*uk_66 + 18941200*uk_67 + 137323700*uk_68 + 205512020*uk_69 + 217*uk_7 + 18941200*uk_70 + 18941200*uk_71 + 137323700*uk_72 + 205512020*uk_73 + 18941200*uk_74 + 995596825*uk_75 + 1489962145*uk_76 + 137323700*uk_77 + 2229805417*uk_78 + 205512020*uk_79 + 20*uk_8 + 18941200*uk_80 + 250047*uk_81 + 329427*uk_82 + 79380*uk_83 + 79380*uk_84 + 575505*uk_85 + 861273*uk_86 + 79380*uk_87 + 434007*uk_88 + 104580*uk_89 + 2242306609*uk_9 + 104580*uk_90 + 758205*uk_91 + 1134693*uk_92 + 104580*uk_93 + 25200*uk_94 + 25200*uk_95 + 182700*uk_96 + 273420*uk_97 + 25200*uk_98 + 25200*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 148176*uk_100 + 218736*uk_101 + 83664*uk_102 + 1361367*uk_103 + 2009637*uk_104 + 768663*uk_105 + 2966607*uk_106 + 1134693*uk_107 + 434007*uk_108 + 6859*uk_109 + 899707*uk_11 + 29963*uk_110 + 5776*uk_111 + 53067*uk_112 + 78337*uk_113 + 29963*uk_114 + 130891*uk_115 + 25232*uk_116 + 231819*uk_117 + 342209*uk_118 + 130891*uk_119 + 3930299*uk_12 + 4864*uk_120 + 44688*uk_121 + 65968*uk_122 + 25232*uk_123 + 410571*uk_124 + 606081*uk_125 + 231819*uk_126 + 894691*uk_127 + 342209*uk_128 + 130891*uk_129 + 757648*uk_13 + 571787*uk_130 + 110224*uk_131 + 1012683*uk_132 + 1494913*uk_133 + 571787*uk_134 + 21248*uk_135 + 195216*uk_136 + 288176*uk_137 + 110224*uk_138 + 1793547*uk_139 + 6960891*uk_14 + 2647617*uk_140 + 1012683*uk_141 + 3908387*uk_142 + 1494913*uk_143 + 571787*uk_144 + 4096*uk_145 + 37632*uk_146 + 55552*uk_147 + 21248*uk_148 + 345744*uk_149 + 10275601*uk_15 + 510384*uk_150 + 195216*uk_151 + 753424*uk_152 + 288176*uk_153 + 110224*uk_154 + 3176523*uk_155 + 4689153*uk_156 + 1793547*uk_157 + 6922083*uk_158 + 2647617*uk_159 + 3930299*uk_16 + 1012683*uk_160 + 10218313*uk_161 + 3908387*uk_162 + 1494913*uk_163 + 571787*uk_164 + 3969*uk_17 + 1197*uk_18 + 5229*uk_19 + 63*uk_2 + 1008*uk_20 + 9261*uk_21 + 13671*uk_22 + 5229*uk_23 + 361*uk_24 + 1577*uk_25 + 304*uk_26 + 2793*uk_27 + 4123*uk_28 + 1577*uk_29 + 19*uk_3 + 6889*uk_30 + 1328*uk_31 + 12201*uk_32 + 18011*uk_33 + 6889*uk_34 + 256*uk_35 + 2352*uk_36 + 3472*uk_37 + 1328*uk_38 + 21609*uk_39 + 83*uk_4 + 31899*uk_40 + 12201*uk_41 + 47089*uk_42 + 18011*uk_43 + 6889*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 42603825571*uk_47 + 186111448547*uk_48 + 35876905744*uk_49 + 16*uk_5 + 329619071523*uk_50 + 486580534153*uk_51 + 186111448547*uk_52 + 187944057*uk_53 + 56681541*uk_54 + 247608837*uk_55 + 47731824*uk_56 + 438536133*uk_57 + 647362863*uk_58 + 247608837*uk_59 + 147*uk_6 + 17094433*uk_60 + 74675681*uk_61 + 14395312*uk_62 + 132256929*uk_63 + 195236419*uk_64 + 74675681*uk_65 + 326214817*uk_66 + 62884784*uk_67 + 577753953*uk_68 + 852874883*uk_69 + 217*uk_7 + 326214817*uk_70 + 12122368*uk_71 + 111374256*uk_72 + 164409616*uk_73 + 62884784*uk_74 + 1023250977*uk_75 + 1510513347*uk_76 + 577753953*uk_77 + 2229805417*uk_78 + 852874883*uk_79 + 83*uk_8 + 326214817*uk_80 + 250047*uk_81 + 75411*uk_82 + 329427*uk_83 + 63504*uk_84 + 583443*uk_85 + 861273*uk_86 + 329427*uk_87 + 22743*uk_88 + 99351*uk_89 + 2242306609*uk_9 + 19152*uk_90 + 175959*uk_91 + 259749*uk_92 + 99351*uk_93 + 434007*uk_94 + 83664*uk_95 + 768663*uk_96 + 1134693*uk_97 + 434007*uk_98 + 16128*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 187740*uk_100 + 273420*uk_101 + 23940*uk_102 + 1398663*uk_103 + 2036979*uk_104 + 178353*uk_105 + 2966607*uk_106 + 259749*uk_107 + 22743*uk_108 + 1728000*uk_109 + 5682360*uk_11 + 273600*uk_110 + 288000*uk_111 + 2145600*uk_112 + 3124800*uk_113 + 273600*uk_114 + 43320*uk_115 + 45600*uk_116 + 339720*uk_117 + 494760*uk_118 + 43320*uk_119 + 899707*uk_12 + 48000*uk_120 + 357600*uk_121 + 520800*uk_122 + 45600*uk_123 + 2664120*uk_124 + 3879960*uk_125 + 339720*uk_126 + 5650680*uk_127 + 494760*uk_128 + 43320*uk_129 + 947060*uk_13 + 6859*uk_130 + 7220*uk_131 + 53789*uk_132 + 78337*uk_133 + 6859*uk_134 + 7600*uk_135 + 56620*uk_136 + 82460*uk_137 + 7220*uk_138 + 421819*uk_139 + 7055597*uk_14 + 614327*uk_140 + 53789*uk_141 + 894691*uk_142 + 78337*uk_143 + 6859*uk_144 + 8000*uk_145 + 59600*uk_146 + 86800*uk_147 + 7600*uk_148 + 444020*uk_149 + 10275601*uk_15 + 646660*uk_150 + 56620*uk_151 + 941780*uk_152 + 82460*uk_153 + 7220*uk_154 + 3307949*uk_155 + 4817617*uk_156 + 421819*uk_157 + 7016261*uk_158 + 614327*uk_159 + 899707*uk_16 + 53789*uk_160 + 10218313*uk_161 + 894691*uk_162 + 78337*uk_163 + 6859*uk_164 + 3969*uk_17 + 7560*uk_18 + 1197*uk_19 + 63*uk_2 + 1260*uk_20 + 9387*uk_21 + 13671*uk_22 + 1197*uk_23 + 14400*uk_24 + 2280*uk_25 + 2400*uk_26 + 17880*uk_27 + 26040*uk_28 + 2280*uk_29 + 120*uk_3 + 361*uk_30 + 380*uk_31 + 2831*uk_32 + 4123*uk_33 + 361*uk_34 + 400*uk_35 + 2980*uk_36 + 4340*uk_37 + 380*uk_38 + 22201*uk_39 + 19*uk_4 + 32333*uk_40 + 2831*uk_41 + 47089*uk_42 + 4123*uk_43 + 361*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 269076793080*uk_47 + 42603825571*uk_48 + 44846132180*uk_49 + 20*uk_5 + 334103684741*uk_50 + 486580534153*uk_51 + 42603825571*uk_52 + 187944057*uk_53 + 357988680*uk_54 + 56681541*uk_55 + 59664780*uk_56 + 444502611*uk_57 + 647362863*uk_58 + 56681541*uk_59 + 149*uk_6 + 681883200*uk_60 + 107964840*uk_61 + 113647200*uk_62 + 846671640*uk_63 + 1233072120*uk_64 + 107964840*uk_65 + 17094433*uk_66 + 17994140*uk_67 + 134056343*uk_68 + 195236419*uk_69 + 217*uk_7 + 17094433*uk_70 + 18941200*uk_71 + 141111940*uk_72 + 205512020*uk_73 + 17994140*uk_74 + 1051283953*uk_75 + 1531064549*uk_76 + 134056343*uk_77 + 2229805417*uk_78 + 195236419*uk_79 + 19*uk_8 + 17094433*uk_80 + 250047*uk_81 + 476280*uk_82 + 75411*uk_83 + 79380*uk_84 + 591381*uk_85 + 861273*uk_86 + 75411*uk_87 + 907200*uk_88 + 143640*uk_89 + 2242306609*uk_9 + 151200*uk_90 + 1126440*uk_91 + 1640520*uk_92 + 143640*uk_93 + 22743*uk_94 + 23940*uk_95 + 178353*uk_96 + 259749*uk_97 + 22743*uk_98 + 25200*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 152208*uk_100 + 218736*uk_101 + 120960*uk_102 + 1436463*uk_103 + 2064321*uk_104 + 1141560*uk_105 + 2966607*uk_106 + 1640520*uk_107 + 907200*uk_108 + 729000*uk_109 + 4261770*uk_11 + 972000*uk_110 + 129600*uk_111 + 1223100*uk_112 + 1757700*uk_113 + 972000*uk_114 + 1296000*uk_115 + 172800*uk_116 + 1630800*uk_117 + 2343600*uk_118 + 1296000*uk_119 + 5682360*uk_12 + 23040*uk_120 + 217440*uk_121 + 312480*uk_122 + 172800*uk_123 + 2052090*uk_124 + 2949030*uk_125 + 1630800*uk_126 + 4238010*uk_127 + 2343600*uk_128 + 1296000*uk_129 + 757648*uk_13 + 1728000*uk_130 + 230400*uk_131 + 2174400*uk_132 + 3124800*uk_133 + 1728000*uk_134 + 30720*uk_135 + 289920*uk_136 + 416640*uk_137 + 230400*uk_138 + 2736120*uk_139 + 7150303*uk_14 + 3932040*uk_140 + 2174400*uk_141 + 5650680*uk_142 + 3124800*uk_143 + 1728000*uk_144 + 4096*uk_145 + 38656*uk_146 + 55552*uk_147 + 30720*uk_148 + 364816*uk_149 + 10275601*uk_15 + 524272*uk_150 + 289920*uk_151 + 753424*uk_152 + 416640*uk_153 + 230400*uk_154 + 3442951*uk_155 + 4947817*uk_156 + 2736120*uk_157 + 7110439*uk_158 + 3932040*uk_159 + 5682360*uk_16 + 2174400*uk_160 + 10218313*uk_161 + 5650680*uk_162 + 3124800*uk_163 + 1728000*uk_164 + 3969*uk_17 + 5670*uk_18 + 7560*uk_19 + 63*uk_2 + 1008*uk_20 + 9513*uk_21 + 13671*uk_22 + 7560*uk_23 + 8100*uk_24 + 10800*uk_25 + 1440*uk_26 + 13590*uk_27 + 19530*uk_28 + 10800*uk_29 + 90*uk_3 + 14400*uk_30 + 1920*uk_31 + 18120*uk_32 + 26040*uk_33 + 14400*uk_34 + 256*uk_35 + 2416*uk_36 + 3472*uk_37 + 1920*uk_38 + 22801*uk_39 + 120*uk_4 + 32767*uk_40 + 18120*uk_41 + 47089*uk_42 + 26040*uk_43 + 14400*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 201807594810*uk_47 + 269076793080*uk_48 + 35876905744*uk_49 + 16*uk_5 + 338588297959*uk_50 + 486580534153*uk_51 + 269076793080*uk_52 + 187944057*uk_53 + 268491510*uk_54 + 357988680*uk_55 + 47731824*uk_56 + 450469089*uk_57 + 647362863*uk_58 + 357988680*uk_59 + 151*uk_6 + 383559300*uk_60 + 511412400*uk_61 + 68188320*uk_62 + 643527270*uk_63 + 924804090*uk_64 + 511412400*uk_65 + 681883200*uk_66 + 90917760*uk_67 + 858036360*uk_68 + 1233072120*uk_69 + 217*uk_7 + 681883200*uk_70 + 12122368*uk_71 + 114404848*uk_72 + 164409616*uk_73 + 90917760*uk_74 + 1079695753*uk_75 + 1551615751*uk_76 + 858036360*uk_77 + 2229805417*uk_78 + 1233072120*uk_79 + 120*uk_8 + 681883200*uk_80 + 250047*uk_81 + 357210*uk_82 + 476280*uk_83 + 63504*uk_84 + 599319*uk_85 + 861273*uk_86 + 476280*uk_87 + 510300*uk_88 + 680400*uk_89 + 2242306609*uk_9 + 90720*uk_90 + 856170*uk_91 + 1230390*uk_92 + 680400*uk_93 + 907200*uk_94 + 120960*uk_95 + 1141560*uk_96 + 1640520*uk_97 + 907200*uk_98 + 16128*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 154224*uk_100 + 218736*uk_101 + 90720*uk_102 + 1474767*uk_103 + 2091663*uk_104 + 867510*uk_105 + 2966607*uk_106 + 1230390*uk_107 + 510300*uk_108 + 438976*uk_109 + 3598828*uk_11 + 519840*uk_110 + 92416*uk_111 + 883728*uk_112 + 1253392*uk_113 + 519840*uk_114 + 615600*uk_115 + 109440*uk_116 + 1046520*uk_117 + 1484280*uk_118 + 615600*uk_119 + 4261770*uk_12 + 19456*uk_120 + 186048*uk_121 + 263872*uk_122 + 109440*uk_123 + 1779084*uk_124 + 2523276*uk_125 + 1046520*uk_126 + 3578764*uk_127 + 1484280*uk_128 + 615600*uk_129 + 757648*uk_13 + 729000*uk_130 + 129600*uk_131 + 1239300*uk_132 + 1757700*uk_133 + 729000*uk_134 + 23040*uk_135 + 220320*uk_136 + 312480*uk_137 + 129600*uk_138 + 2106810*uk_139 + 7245009*uk_14 + 2988090*uk_140 + 1239300*uk_141 + 4238010*uk_142 + 1757700*uk_143 + 729000*uk_144 + 4096*uk_145 + 39168*uk_146 + 55552*uk_147 + 23040*uk_148 + 374544*uk_149 + 10275601*uk_15 + 531216*uk_150 + 220320*uk_151 + 753424*uk_152 + 312480*uk_153 + 129600*uk_154 + 3581577*uk_155 + 5079753*uk_156 + 2106810*uk_157 + 7204617*uk_158 + 2988090*uk_159 + 4261770*uk_16 + 1239300*uk_160 + 10218313*uk_161 + 4238010*uk_162 + 1757700*uk_163 + 729000*uk_164 + 3969*uk_17 + 4788*uk_18 + 5670*uk_19 + 63*uk_2 + 1008*uk_20 + 9639*uk_21 + 13671*uk_22 + 5670*uk_23 + 5776*uk_24 + 6840*uk_25 + 1216*uk_26 + 11628*uk_27 + 16492*uk_28 + 6840*uk_29 + 76*uk_3 + 8100*uk_30 + 1440*uk_31 + 13770*uk_32 + 19530*uk_33 + 8100*uk_34 + 256*uk_35 + 2448*uk_36 + 3472*uk_37 + 1440*uk_38 + 23409*uk_39 + 90*uk_4 + 33201*uk_40 + 13770*uk_41 + 47089*uk_42 + 19530*uk_43 + 8100*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 170415302284*uk_47 + 201807594810*uk_48 + 35876905744*uk_49 + 16*uk_5 + 343072911177*uk_50 + 486580534153*uk_51 + 201807594810*uk_52 + 187944057*uk_53 + 226726164*uk_54 + 268491510*uk_55 + 47731824*uk_56 + 456435567*uk_57 + 647362863*uk_58 + 268491510*uk_59 + 153*uk_6 + 273510928*uk_60 + 323894520*uk_61 + 57581248*uk_62 + 550620684*uk_63 + 780945676*uk_64 + 323894520*uk_65 + 383559300*uk_66 + 68188320*uk_67 + 652050810*uk_68 + 924804090*uk_69 + 217*uk_7 + 383559300*uk_70 + 12122368*uk_71 + 115920144*uk_72 + 164409616*uk_73 + 68188320*uk_74 + 1108486377*uk_75 + 1572166953*uk_76 + 652050810*uk_77 + 2229805417*uk_78 + 924804090*uk_79 + 90*uk_8 + 383559300*uk_80 + 250047*uk_81 + 301644*uk_82 + 357210*uk_83 + 63504*uk_84 + 607257*uk_85 + 861273*uk_86 + 357210*uk_87 + 363888*uk_88 + 430920*uk_89 + 2242306609*uk_9 + 76608*uk_90 + 732564*uk_91 + 1038996*uk_92 + 430920*uk_93 + 510300*uk_94 + 90720*uk_95 + 867510*uk_96 + 1230390*uk_97 + 510300*uk_98 + 16128*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 156240*uk_100 + 218736*uk_101 + 76608*uk_102 + 1513575*uk_103 + 2119005*uk_104 + 742140*uk_105 + 2966607*uk_106 + 1038996*uk_107 + 363888*uk_108 + 474552*uk_109 + 3693534*uk_11 + 462384*uk_110 + 97344*uk_111 + 943020*uk_112 + 1320228*uk_113 + 462384*uk_114 + 450528*uk_115 + 94848*uk_116 + 918840*uk_117 + 1286376*uk_118 + 450528*uk_119 + 3598828*uk_12 + 19968*uk_120 + 193440*uk_121 + 270816*uk_122 + 94848*uk_123 + 1873950*uk_124 + 2623530*uk_125 + 918840*uk_126 + 3672942*uk_127 + 1286376*uk_128 + 450528*uk_129 + 757648*uk_13 + 438976*uk_130 + 92416*uk_131 + 895280*uk_132 + 1253392*uk_133 + 438976*uk_134 + 19456*uk_135 + 188480*uk_136 + 263872*uk_137 + 92416*uk_138 + 1825900*uk_139 + 7339715*uk_14 + 2556260*uk_140 + 895280*uk_141 + 3578764*uk_142 + 1253392*uk_143 + 438976*uk_144 + 4096*uk_145 + 39680*uk_146 + 55552*uk_147 + 19456*uk_148 + 384400*uk_149 + 10275601*uk_15 + 538160*uk_150 + 188480*uk_151 + 753424*uk_152 + 263872*uk_153 + 92416*uk_154 + 3723875*uk_155 + 5213425*uk_156 + 1825900*uk_157 + 7298795*uk_158 + 2556260*uk_159 + 3598828*uk_16 + 895280*uk_160 + 10218313*uk_161 + 3578764*uk_162 + 1253392*uk_163 + 438976*uk_164 + 3969*uk_17 + 4914*uk_18 + 4788*uk_19 + 63*uk_2 + 1008*uk_20 + 9765*uk_21 + 13671*uk_22 + 4788*uk_23 + 6084*uk_24 + 5928*uk_25 + 1248*uk_26 + 12090*uk_27 + 16926*uk_28 + 5928*uk_29 + 78*uk_3 + 5776*uk_30 + 1216*uk_31 + 11780*uk_32 + 16492*uk_33 + 5776*uk_34 + 256*uk_35 + 2480*uk_36 + 3472*uk_37 + 1216*uk_38 + 24025*uk_39 + 76*uk_4 + 33635*uk_40 + 11780*uk_41 + 47089*uk_42 + 16492*uk_43 + 5776*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 174899915502*uk_47 + 170415302284*uk_48 + 35876905744*uk_49 + 16*uk_5 + 347557524395*uk_50 + 486580534153*uk_51 + 170415302284*uk_52 + 187944057*uk_53 + 232692642*uk_54 + 226726164*uk_55 + 47731824*uk_56 + 462402045*uk_57 + 647362863*uk_58 + 226726164*uk_59 + 155*uk_6 + 288095652*uk_60 + 280708584*uk_61 + 59096544*uk_62 + 572497770*uk_63 + 801496878*uk_64 + 280708584*uk_65 + 273510928*uk_66 + 57581248*uk_67 + 557818340*uk_68 + 780945676*uk_69 + 217*uk_7 + 273510928*uk_70 + 12122368*uk_71 + 117435440*uk_72 + 164409616*uk_73 + 57581248*uk_74 + 1137655825*uk_75 + 1592718155*uk_76 + 557818340*uk_77 + 2229805417*uk_78 + 780945676*uk_79 + 76*uk_8 + 273510928*uk_80 + 250047*uk_81 + 309582*uk_82 + 301644*uk_83 + 63504*uk_84 + 615195*uk_85 + 861273*uk_86 + 301644*uk_87 + 383292*uk_88 + 373464*uk_89 + 2242306609*uk_9 + 78624*uk_90 + 761670*uk_91 + 1066338*uk_92 + 373464*uk_93 + 363888*uk_94 + 76608*uk_95 + 742140*uk_96 + 1038996*uk_97 + 363888*uk_98 + 16128*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 158256*uk_100 + 218736*uk_101 + 78624*uk_102 + 1552887*uk_103 + 2146347*uk_104 + 771498*uk_105 + 2966607*uk_106 + 1066338*uk_107 + 383292*uk_108 + 884736*uk_109 + 4545888*uk_11 + 718848*uk_110 + 147456*uk_111 + 1446912*uk_112 + 1999872*uk_113 + 718848*uk_114 + 584064*uk_115 + 119808*uk_116 + 1175616*uk_117 + 1624896*uk_118 + 584064*uk_119 + 3693534*uk_12 + 24576*uk_120 + 241152*uk_121 + 333312*uk_122 + 119808*uk_123 + 2366304*uk_124 + 3270624*uk_125 + 1175616*uk_126 + 4520544*uk_127 + 1624896*uk_128 + 584064*uk_129 + 757648*uk_13 + 474552*uk_130 + 97344*uk_131 + 955188*uk_132 + 1320228*uk_133 + 474552*uk_134 + 19968*uk_135 + 195936*uk_136 + 270816*uk_137 + 97344*uk_138 + 1922622*uk_139 + 7434421*uk_14 + 2657382*uk_140 + 955188*uk_141 + 3672942*uk_142 + 1320228*uk_143 + 474552*uk_144 + 4096*uk_145 + 40192*uk_146 + 55552*uk_147 + 19968*uk_148 + 394384*uk_149 + 10275601*uk_15 + 545104*uk_150 + 195936*uk_151 + 753424*uk_152 + 270816*uk_153 + 97344*uk_154 + 3869893*uk_155 + 5348833*uk_156 + 1922622*uk_157 + 7392973*uk_158 + 2657382*uk_159 + 3693534*uk_16 + 955188*uk_160 + 10218313*uk_161 + 3672942*uk_162 + 1320228*uk_163 + 474552*uk_164 + 3969*uk_17 + 6048*uk_18 + 4914*uk_19 + 63*uk_2 + 1008*uk_20 + 9891*uk_21 + 13671*uk_22 + 4914*uk_23 + 9216*uk_24 + 7488*uk_25 + 1536*uk_26 + 15072*uk_27 + 20832*uk_28 + 7488*uk_29 + 96*uk_3 + 6084*uk_30 + 1248*uk_31 + 12246*uk_32 + 16926*uk_33 + 6084*uk_34 + 256*uk_35 + 2512*uk_36 + 3472*uk_37 + 1248*uk_38 + 24649*uk_39 + 78*uk_4 + 34069*uk_40 + 12246*uk_41 + 47089*uk_42 + 16926*uk_43 + 6084*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 215261434464*uk_47 + 174899915502*uk_48 + 35876905744*uk_49 + 16*uk_5 + 352042137613*uk_50 + 486580534153*uk_51 + 174899915502*uk_52 + 187944057*uk_53 + 286390944*uk_54 + 232692642*uk_55 + 47731824*uk_56 + 468368523*uk_57 + 647362863*uk_58 + 232692642*uk_59 + 157*uk_6 + 436405248*uk_60 + 354579264*uk_61 + 72734208*uk_62 + 713704416*uk_63 + 986457696*uk_64 + 354579264*uk_65 + 288095652*uk_66 + 59096544*uk_67 + 579884838*uk_68 + 801496878*uk_69 + 217*uk_7 + 288095652*uk_70 + 12122368*uk_71 + 118950736*uk_72 + 164409616*uk_73 + 59096544*uk_74 + 1167204097*uk_75 + 1613269357*uk_76 + 579884838*uk_77 + 2229805417*uk_78 + 801496878*uk_79 + 78*uk_8 + 288095652*uk_80 + 250047*uk_81 + 381024*uk_82 + 309582*uk_83 + 63504*uk_84 + 623133*uk_85 + 861273*uk_86 + 309582*uk_87 + 580608*uk_88 + 471744*uk_89 + 2242306609*uk_9 + 96768*uk_90 + 949536*uk_91 + 1312416*uk_92 + 471744*uk_93 + 383292*uk_94 + 78624*uk_95 + 771498*uk_96 + 1066338*uk_97 + 383292*uk_98 + 16128*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 160272*uk_100 + 218736*uk_101 + 96768*uk_102 + 1592703*uk_103 + 2173689*uk_104 + 961632*uk_105 + 2966607*uk_106 + 1312416*uk_107 + 580608*uk_108 + 2197000*uk_109 + 6155890*uk_11 + 1622400*uk_110 + 270400*uk_111 + 2687100*uk_112 + 3667300*uk_113 + 1622400*uk_114 + 1198080*uk_115 + 199680*uk_116 + 1984320*uk_117 + 2708160*uk_118 + 1198080*uk_119 + 4545888*uk_12 + 33280*uk_120 + 330720*uk_121 + 451360*uk_122 + 199680*uk_123 + 3286530*uk_124 + 4485390*uk_125 + 1984320*uk_126 + 6121570*uk_127 + 2708160*uk_128 + 1198080*uk_129 + 757648*uk_13 + 884736*uk_130 + 147456*uk_131 + 1465344*uk_132 + 1999872*uk_133 + 884736*uk_134 + 24576*uk_135 + 244224*uk_136 + 333312*uk_137 + 147456*uk_138 + 2426976*uk_139 + 7529127*uk_14 + 3312288*uk_140 + 1465344*uk_141 + 4520544*uk_142 + 1999872*uk_143 + 884736*uk_144 + 4096*uk_145 + 40704*uk_146 + 55552*uk_147 + 24576*uk_148 + 404496*uk_149 + 10275601*uk_15 + 552048*uk_150 + 244224*uk_151 + 753424*uk_152 + 333312*uk_153 + 147456*uk_154 + 4019679*uk_155 + 5485977*uk_156 + 2426976*uk_157 + 7487151*uk_158 + 3312288*uk_159 + 4545888*uk_16 + 1465344*uk_160 + 10218313*uk_161 + 4520544*uk_162 + 1999872*uk_163 + 884736*uk_164 + 3969*uk_17 + 8190*uk_18 + 6048*uk_19 + 63*uk_2 + 1008*uk_20 + 10017*uk_21 + 13671*uk_22 + 6048*uk_23 + 16900*uk_24 + 12480*uk_25 + 2080*uk_26 + 20670*uk_27 + 28210*uk_28 + 12480*uk_29 + 130*uk_3 + 9216*uk_30 + 1536*uk_31 + 15264*uk_32 + 20832*uk_33 + 9216*uk_34 + 256*uk_35 + 2544*uk_36 + 3472*uk_37 + 1536*uk_38 + 25281*uk_39 + 96*uk_4 + 34503*uk_40 + 15264*uk_41 + 47089*uk_42 + 20832*uk_43 + 9216*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 291499859170*uk_47 + 215261434464*uk_48 + 35876905744*uk_49 + 16*uk_5 + 356526750831*uk_50 + 486580534153*uk_51 + 215261434464*uk_52 + 187944057*uk_53 + 387821070*uk_54 + 286390944*uk_55 + 47731824*uk_56 + 474335001*uk_57 + 647362863*uk_58 + 286390944*uk_59 + 159*uk_6 + 800265700*uk_60 + 590965440*uk_61 + 98494240*uk_62 + 978786510*uk_63 + 1335828130*uk_64 + 590965440*uk_65 + 436405248*uk_66 + 72734208*uk_67 + 722796192*uk_68 + 986457696*uk_69 + 217*uk_7 + 436405248*uk_70 + 12122368*uk_71 + 120466032*uk_72 + 164409616*uk_73 + 72734208*uk_74 + 1197131193*uk_75 + 1633820559*uk_76 + 722796192*uk_77 + 2229805417*uk_78 + 986457696*uk_79 + 96*uk_8 + 436405248*uk_80 + 250047*uk_81 + 515970*uk_82 + 381024*uk_83 + 63504*uk_84 + 631071*uk_85 + 861273*uk_86 + 381024*uk_87 + 1064700*uk_88 + 786240*uk_89 + 2242306609*uk_9 + 131040*uk_90 + 1302210*uk_91 + 1777230*uk_92 + 786240*uk_93 + 580608*uk_94 + 96768*uk_95 + 961632*uk_96 + 1312416*uk_97 + 580608*uk_98 + 16128*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 121716*uk_100 + 164052*uk_101 + 98280*uk_102 + 1633023*uk_103 + 2201031*uk_104 + 1318590*uk_105 + 2966607*uk_106 + 1777230*uk_107 + 1064700*uk_108 + 6859*uk_109 + 899707*uk_11 + 46930*uk_110 + 4332*uk_111 + 58121*uk_112 + 78337*uk_113 + 46930*uk_114 + 321100*uk_115 + 29640*uk_116 + 397670*uk_117 + 535990*uk_118 + 321100*uk_119 + 6155890*uk_12 + 2736*uk_120 + 36708*uk_121 + 49476*uk_122 + 29640*uk_123 + 492499*uk_124 + 663803*uk_125 + 397670*uk_126 + 894691*uk_127 + 535990*uk_128 + 321100*uk_129 + 568236*uk_13 + 2197000*uk_130 + 202800*uk_131 + 2720900*uk_132 + 3667300*uk_133 + 2197000*uk_134 + 18720*uk_135 + 251160*uk_136 + 338520*uk_137 + 202800*uk_138 + 3369730*uk_139 + 7623833*uk_14 + 4541810*uk_140 + 2720900*uk_141 + 6121570*uk_142 + 3667300*uk_143 + 2197000*uk_144 + 1728*uk_145 + 23184*uk_146 + 31248*uk_147 + 18720*uk_148 + 311052*uk_149 + 10275601*uk_15 + 419244*uk_150 + 251160*uk_151 + 565068*uk_152 + 338520*uk_153 + 202800*uk_154 + 4173281*uk_155 + 5624857*uk_156 + 3369730*uk_157 + 7581329*uk_158 + 4541810*uk_159 + 6155890*uk_16 + 2720900*uk_160 + 10218313*uk_161 + 6121570*uk_162 + 3667300*uk_163 + 2197000*uk_164 + 3969*uk_17 + 1197*uk_18 + 8190*uk_19 + 63*uk_2 + 756*uk_20 + 10143*uk_21 + 13671*uk_22 + 8190*uk_23 + 361*uk_24 + 2470*uk_25 + 228*uk_26 + 3059*uk_27 + 4123*uk_28 + 2470*uk_29 + 19*uk_3 + 16900*uk_30 + 1560*uk_31 + 20930*uk_32 + 28210*uk_33 + 16900*uk_34 + 144*uk_35 + 1932*uk_36 + 2604*uk_37 + 1560*uk_38 + 25921*uk_39 + 130*uk_4 + 34937*uk_40 + 20930*uk_41 + 47089*uk_42 + 28210*uk_43 + 16900*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 42603825571*uk_47 + 291499859170*uk_48 + 26907679308*uk_49 + 12*uk_5 + 361011364049*uk_50 + 486580534153*uk_51 + 291499859170*uk_52 + 187944057*uk_53 + 56681541*uk_54 + 387821070*uk_55 + 35798868*uk_56 + 480301479*uk_57 + 647362863*uk_58 + 387821070*uk_59 + 161*uk_6 + 17094433*uk_60 + 116961910*uk_61 + 10796484*uk_62 + 144852827*uk_63 + 195236419*uk_64 + 116961910*uk_65 + 800265700*uk_66 + 73870680*uk_67 + 991098290*uk_68 + 1335828130*uk_69 + 217*uk_7 + 800265700*uk_70 + 6818832*uk_71 + 91485996*uk_72 + 123307212*uk_73 + 73870680*uk_74 + 1227437113*uk_75 + 1654371761*uk_76 + 991098290*uk_77 + 2229805417*uk_78 + 1335828130*uk_79 + 130*uk_8 + 800265700*uk_80 + 250047*uk_81 + 75411*uk_82 + 515970*uk_83 + 47628*uk_84 + 639009*uk_85 + 861273*uk_86 + 515970*uk_87 + 22743*uk_88 + 155610*uk_89 + 2242306609*uk_9 + 14364*uk_90 + 192717*uk_91 + 259749*uk_92 + 155610*uk_93 + 1064700*uk_94 + 98280*uk_95 + 1318590*uk_96 + 1777230*uk_97 + 1064700*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 164304*uk_100 + 218736*uk_101 + 19152*uk_102 + 1673847*uk_103 + 2228373*uk_104 + 195111*uk_105 + 2966607*uk_106 + 259749*uk_107 + 22743*uk_108 + 571787*uk_109 + 3930299*uk_11 + 130891*uk_110 + 110224*uk_111 + 1122907*uk_112 + 1494913*uk_113 + 130891*uk_114 + 29963*uk_115 + 25232*uk_116 + 257051*uk_117 + 342209*uk_118 + 29963*uk_119 + 899707*uk_12 + 21248*uk_120 + 216464*uk_121 + 288176*uk_122 + 25232*uk_123 + 2205227*uk_124 + 2935793*uk_125 + 257051*uk_126 + 3908387*uk_127 + 342209*uk_128 + 29963*uk_129 + 757648*uk_13 + 6859*uk_130 + 5776*uk_131 + 58843*uk_132 + 78337*uk_133 + 6859*uk_134 + 4864*uk_135 + 49552*uk_136 + 65968*uk_137 + 5776*uk_138 + 504811*uk_139 + 7718539*uk_14 + 672049*uk_140 + 58843*uk_141 + 894691*uk_142 + 78337*uk_143 + 6859*uk_144 + 4096*uk_145 + 41728*uk_146 + 55552*uk_147 + 4864*uk_148 + 425104*uk_149 + 10275601*uk_15 + 565936*uk_150 + 49552*uk_151 + 753424*uk_152 + 65968*uk_153 + 5776*uk_154 + 4330747*uk_155 + 5765473*uk_156 + 504811*uk_157 + 7675507*uk_158 + 672049*uk_159 + 899707*uk_16 + 58843*uk_160 + 10218313*uk_161 + 894691*uk_162 + 78337*uk_163 + 6859*uk_164 + 3969*uk_17 + 5229*uk_18 + 1197*uk_19 + 63*uk_2 + 1008*uk_20 + 10269*uk_21 + 13671*uk_22 + 1197*uk_23 + 6889*uk_24 + 1577*uk_25 + 1328*uk_26 + 13529*uk_27 + 18011*uk_28 + 1577*uk_29 + 83*uk_3 + 361*uk_30 + 304*uk_31 + 3097*uk_32 + 4123*uk_33 + 361*uk_34 + 256*uk_35 + 2608*uk_36 + 3472*uk_37 + 304*uk_38 + 26569*uk_39 + 19*uk_4 + 35371*uk_40 + 3097*uk_41 + 47089*uk_42 + 4123*uk_43 + 361*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 186111448547*uk_47 + 42603825571*uk_48 + 35876905744*uk_49 + 16*uk_5 + 365495977267*uk_50 + 486580534153*uk_51 + 42603825571*uk_52 + 187944057*uk_53 + 247608837*uk_54 + 56681541*uk_55 + 47731824*uk_56 + 486267957*uk_57 + 647362863*uk_58 + 56681541*uk_59 + 163*uk_6 + 326214817*uk_60 + 74675681*uk_61 + 62884784*uk_62 + 640638737*uk_63 + 852874883*uk_64 + 74675681*uk_65 + 17094433*uk_66 + 14395312*uk_67 + 146652241*uk_68 + 195236419*uk_69 + 217*uk_7 + 17094433*uk_70 + 12122368*uk_71 + 123496624*uk_72 + 164409616*uk_73 + 14395312*uk_74 + 1258121857*uk_75 + 1674922963*uk_76 + 146652241*uk_77 + 2229805417*uk_78 + 195236419*uk_79 + 19*uk_8 + 17094433*uk_80 + 250047*uk_81 + 329427*uk_82 + 75411*uk_83 + 63504*uk_84 + 646947*uk_85 + 861273*uk_86 + 75411*uk_87 + 434007*uk_88 + 99351*uk_89 + 2242306609*uk_9 + 83664*uk_90 + 852327*uk_91 + 1134693*uk_92 + 99351*uk_93 + 22743*uk_94 + 19152*uk_95 + 195111*uk_96 + 259749*uk_97 + 22743*uk_98 + 16128*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 166320*uk_100 + 218736*uk_101 + 83664*uk_102 + 1715175*uk_103 + 2255715*uk_104 + 862785*uk_105 + 2966607*uk_106 + 1134693*uk_107 + 434007*uk_108 + 4330747*uk_109 + 7718539*uk_11 + 2205227*uk_110 + 425104*uk_111 + 4383885*uk_112 + 5765473*uk_113 + 2205227*uk_114 + 1122907*uk_115 + 216464*uk_116 + 2232285*uk_117 + 2935793*uk_118 + 1122907*uk_119 + 3930299*uk_12 + 41728*uk_120 + 430320*uk_121 + 565936*uk_122 + 216464*uk_123 + 4437675*uk_124 + 5836215*uk_125 + 2232285*uk_126 + 7675507*uk_127 + 2935793*uk_128 + 1122907*uk_129 + 757648*uk_13 + 571787*uk_130 + 110224*uk_131 + 1136685*uk_132 + 1494913*uk_133 + 571787*uk_134 + 21248*uk_135 + 219120*uk_136 + 288176*uk_137 + 110224*uk_138 + 2259675*uk_139 + 7813245*uk_14 + 2971815*uk_140 + 1136685*uk_141 + 3908387*uk_142 + 1494913*uk_143 + 571787*uk_144 + 4096*uk_145 + 42240*uk_146 + 55552*uk_147 + 21248*uk_148 + 435600*uk_149 + 10275601*uk_15 + 572880*uk_150 + 219120*uk_151 + 753424*uk_152 + 288176*uk_153 + 110224*uk_154 + 4492125*uk_155 + 5907825*uk_156 + 2259675*uk_157 + 7769685*uk_158 + 2971815*uk_159 + 3930299*uk_16 + 1136685*uk_160 + 10218313*uk_161 + 3908387*uk_162 + 1494913*uk_163 + 571787*uk_164 + 3969*uk_17 + 10269*uk_18 + 5229*uk_19 + 63*uk_2 + 1008*uk_20 + 10395*uk_21 + 13671*uk_22 + 5229*uk_23 + 26569*uk_24 + 13529*uk_25 + 2608*uk_26 + 26895*uk_27 + 35371*uk_28 + 13529*uk_29 + 163*uk_3 + 6889*uk_30 + 1328*uk_31 + 13695*uk_32 + 18011*uk_33 + 6889*uk_34 + 256*uk_35 + 2640*uk_36 + 3472*uk_37 + 1328*uk_38 + 27225*uk_39 + 83*uk_4 + 35805*uk_40 + 13695*uk_41 + 47089*uk_42 + 18011*uk_43 + 6889*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 365495977267*uk_47 + 186111448547*uk_48 + 35876905744*uk_49 + 16*uk_5 + 369980590485*uk_50 + 486580534153*uk_51 + 186111448547*uk_52 + 187944057*uk_53 + 486267957*uk_54 + 247608837*uk_55 + 47731824*uk_56 + 492234435*uk_57 + 647362863*uk_58 + 247608837*uk_59 + 165*uk_6 + 1258121857*uk_60 + 640638737*uk_61 + 123496624*uk_62 + 1273558935*uk_63 + 1674922963*uk_64 + 640638737*uk_65 + 326214817*uk_66 + 62884784*uk_67 + 648499335*uk_68 + 852874883*uk_69 + 217*uk_7 + 326214817*uk_70 + 12122368*uk_71 + 125011920*uk_72 + 164409616*uk_73 + 62884784*uk_74 + 1289185425*uk_75 + 1695474165*uk_76 + 648499335*uk_77 + 2229805417*uk_78 + 852874883*uk_79 + 83*uk_8 + 326214817*uk_80 + 250047*uk_81 + 646947*uk_82 + 329427*uk_83 + 63504*uk_84 + 654885*uk_85 + 861273*uk_86 + 329427*uk_87 + 1673847*uk_88 + 852327*uk_89 + 2242306609*uk_9 + 164304*uk_90 + 1694385*uk_91 + 2228373*uk_92 + 852327*uk_93 + 434007*uk_94 + 83664*uk_95 + 862785*uk_96 + 1134693*uk_97 + 434007*uk_98 + 16128*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 126252*uk_100 + 164052*uk_101 + 123228*uk_102 + 1757007*uk_103 + 2283057*uk_104 + 1714923*uk_105 + 2966607*uk_106 + 2228373*uk_107 + 1673847*uk_108 + 778688*uk_109 + 4356476*uk_11 + 1379632*uk_110 + 101568*uk_111 + 1413488*uk_112 + 1836688*uk_113 + 1379632*uk_114 + 2444348*uk_115 + 179952*uk_116 + 2504332*uk_117 + 3254132*uk_118 + 2444348*uk_119 + 7718539*uk_12 + 13248*uk_120 + 184368*uk_121 + 239568*uk_122 + 179952*uk_123 + 2565788*uk_124 + 3333988*uk_125 + 2504332*uk_126 + 4332188*uk_127 + 3254132*uk_128 + 2444348*uk_129 + 568236*uk_13 + 4330747*uk_130 + 318828*uk_131 + 4437023*uk_132 + 5765473*uk_133 + 4330747*uk_134 + 23472*uk_135 + 326652*uk_136 + 424452*uk_137 + 318828*uk_138 + 4545907*uk_139 + 7907951*uk_14 + 5906957*uk_140 + 4437023*uk_141 + 7675507*uk_142 + 5765473*uk_143 + 4330747*uk_144 + 1728*uk_145 + 24048*uk_146 + 31248*uk_147 + 23472*uk_148 + 334668*uk_149 + 10275601*uk_15 + 434868*uk_150 + 326652*uk_151 + 565068*uk_152 + 424452*uk_153 + 318828*uk_154 + 4657463*uk_155 + 6051913*uk_156 + 4545907*uk_157 + 7863863*uk_158 + 5906957*uk_159 + 7718539*uk_16 + 4437023*uk_160 + 10218313*uk_161 + 7675507*uk_162 + 5765473*uk_163 + 4330747*uk_164 + 3969*uk_17 + 5796*uk_18 + 10269*uk_19 + 63*uk_2 + 756*uk_20 + 10521*uk_21 + 13671*uk_22 + 10269*uk_23 + 8464*uk_24 + 14996*uk_25 + 1104*uk_26 + 15364*uk_27 + 19964*uk_28 + 14996*uk_29 + 92*uk_3 + 26569*uk_30 + 1956*uk_31 + 27221*uk_32 + 35371*uk_33 + 26569*uk_34 + 144*uk_35 + 2004*uk_36 + 2604*uk_37 + 1956*uk_38 + 27889*uk_39 + 163*uk_4 + 36239*uk_40 + 27221*uk_41 + 47089*uk_42 + 35371*uk_43 + 26569*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 206292208028*uk_47 + 365495977267*uk_48 + 26907679308*uk_49 + 12*uk_5 + 374465203703*uk_50 + 486580534153*uk_51 + 365495977267*uk_52 + 187944057*uk_53 + 274457988*uk_54 + 486267957*uk_55 + 35798868*uk_56 + 498200913*uk_57 + 647362863*uk_58 + 486267957*uk_59 + 167*uk_6 + 400795792*uk_60 + 710105588*uk_61 + 52277712*uk_62 + 727531492*uk_63 + 945355292*uk_64 + 710105588*uk_65 + 1258121857*uk_66 + 92622468*uk_67 + 1288996013*uk_68 + 1674922963*uk_69 + 217*uk_7 + 1258121857*uk_70 + 6818832*uk_71 + 94895412*uk_72 + 123307212*uk_73 + 92622468*uk_74 + 1320627817*uk_75 + 1716025367*uk_76 + 1288996013*uk_77 + 2229805417*uk_78 + 1674922963*uk_79 + 163*uk_8 + 1258121857*uk_80 + 250047*uk_81 + 365148*uk_82 + 646947*uk_83 + 47628*uk_84 + 662823*uk_85 + 861273*uk_86 + 646947*uk_87 + 533232*uk_88 + 944748*uk_89 + 2242306609*uk_9 + 69552*uk_90 + 967932*uk_91 + 1257732*uk_92 + 944748*uk_93 + 1673847*uk_94 + 123228*uk_95 + 1714923*uk_96 + 2228373*uk_97 + 1673847*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 127764*uk_100 + 164052*uk_101 + 69552*uk_102 + 1799343*uk_103 + 2310399*uk_104 + 979524*uk_105 + 2966607*uk_106 + 1257732*uk_107 + 533232*uk_108 + 35937*uk_109 + 1562649*uk_11 + 100188*uk_110 + 13068*uk_111 + 184041*uk_112 + 236313*uk_113 + 100188*uk_114 + 279312*uk_115 + 36432*uk_116 + 513084*uk_117 + 658812*uk_118 + 279312*uk_119 + 4356476*uk_12 + 4752*uk_120 + 66924*uk_121 + 85932*uk_122 + 36432*uk_123 + 942513*uk_124 + 1210209*uk_125 + 513084*uk_126 + 1553937*uk_127 + 658812*uk_128 + 279312*uk_129 + 568236*uk_13 + 778688*uk_130 + 101568*uk_131 + 1430416*uk_132 + 1836688*uk_133 + 778688*uk_134 + 13248*uk_135 + 186576*uk_136 + 239568*uk_137 + 101568*uk_138 + 2627612*uk_139 + 8002657*uk_14 + 3373916*uk_140 + 1430416*uk_141 + 4332188*uk_142 + 1836688*uk_143 + 778688*uk_144 + 1728*uk_145 + 24336*uk_146 + 31248*uk_147 + 13248*uk_148 + 342732*uk_149 + 10275601*uk_15 + 440076*uk_150 + 186576*uk_151 + 565068*uk_152 + 239568*uk_153 + 101568*uk_154 + 4826809*uk_155 + 6197737*uk_156 + 2627612*uk_157 + 7958041*uk_158 + 3373916*uk_159 + 4356476*uk_16 + 1430416*uk_160 + 10218313*uk_161 + 4332188*uk_162 + 1836688*uk_163 + 778688*uk_164 + 3969*uk_17 + 2079*uk_18 + 5796*uk_19 + 63*uk_2 + 756*uk_20 + 10647*uk_21 + 13671*uk_22 + 5796*uk_23 + 1089*uk_24 + 3036*uk_25 + 396*uk_26 + 5577*uk_27 + 7161*uk_28 + 3036*uk_29 + 33*uk_3 + 8464*uk_30 + 1104*uk_31 + 15548*uk_32 + 19964*uk_33 + 8464*uk_34 + 144*uk_35 + 2028*uk_36 + 2604*uk_37 + 1104*uk_38 + 28561*uk_39 + 92*uk_4 + 36673*uk_40 + 15548*uk_41 + 47089*uk_42 + 19964*uk_43 + 8464*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 73996118097*uk_47 + 206292208028*uk_48 + 26907679308*uk_49 + 12*uk_5 + 378949816921*uk_50 + 486580534153*uk_51 + 206292208028*uk_52 + 187944057*uk_53 + 98446887*uk_54 + 274457988*uk_55 + 35798868*uk_56 + 504167391*uk_57 + 647362863*uk_58 + 274457988*uk_59 + 169*uk_6 + 51567417*uk_60 + 143763708*uk_61 + 18751788*uk_62 + 264087681*uk_63 + 339094833*uk_64 + 143763708*uk_65 + 400795792*uk_66 + 52277712*uk_67 + 736244444*uk_68 + 945355292*uk_69 + 217*uk_7 + 400795792*uk_70 + 6818832*uk_71 + 96031884*uk_72 + 123307212*uk_73 + 52277712*uk_74 + 1352449033*uk_75 + 1736576569*uk_76 + 736244444*uk_77 + 2229805417*uk_78 + 945355292*uk_79 + 92*uk_8 + 400795792*uk_80 + 250047*uk_81 + 130977*uk_82 + 365148*uk_83 + 47628*uk_84 + 670761*uk_85 + 861273*uk_86 + 365148*uk_87 + 68607*uk_88 + 191268*uk_89 + 2242306609*uk_9 + 24948*uk_90 + 351351*uk_91 + 451143*uk_92 + 191268*uk_93 + 533232*uk_94 + 69552*uk_95 + 979524*uk_96 + 1257732*uk_97 + 533232*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 172368*uk_100 + 218736*uk_101 + 33264*uk_102 + 1842183*uk_103 + 2337741*uk_104 + 355509*uk_105 + 2966607*uk_106 + 451143*uk_107 + 68607*uk_108 + 3869893*uk_109 + 7434421*uk_11 + 813417*uk_110 + 394384*uk_111 + 4214979*uk_112 + 5348833*uk_113 + 813417*uk_114 + 170973*uk_115 + 82896*uk_116 + 885951*uk_117 + 1124277*uk_118 + 170973*uk_119 + 1562649*uk_12 + 40192*uk_120 + 429552*uk_121 + 545104*uk_122 + 82896*uk_123 + 4590837*uk_124 + 5825799*uk_125 + 885951*uk_126 + 7392973*uk_127 + 1124277*uk_128 + 170973*uk_129 + 757648*uk_13 + 35937*uk_130 + 17424*uk_131 + 186219*uk_132 + 236313*uk_133 + 35937*uk_134 + 8448*uk_135 + 90288*uk_136 + 114576*uk_137 + 17424*uk_138 + 964953*uk_139 + 8097363*uk_14 + 1224531*uk_140 + 186219*uk_141 + 1553937*uk_142 + 236313*uk_143 + 35937*uk_144 + 4096*uk_145 + 43776*uk_146 + 55552*uk_147 + 8448*uk_148 + 467856*uk_149 + 10275601*uk_15 + 593712*uk_150 + 90288*uk_151 + 753424*uk_152 + 114576*uk_153 + 17424*uk_154 + 5000211*uk_155 + 6345297*uk_156 + 964953*uk_157 + 8052219*uk_158 + 1224531*uk_159 + 1562649*uk_16 + 186219*uk_160 + 10218313*uk_161 + 1553937*uk_162 + 236313*uk_163 + 35937*uk_164 + 3969*uk_17 + 9891*uk_18 + 2079*uk_19 + 63*uk_2 + 1008*uk_20 + 10773*uk_21 + 13671*uk_22 + 2079*uk_23 + 24649*uk_24 + 5181*uk_25 + 2512*uk_26 + 26847*uk_27 + 34069*uk_28 + 5181*uk_29 + 157*uk_3 + 1089*uk_30 + 528*uk_31 + 5643*uk_32 + 7161*uk_33 + 1089*uk_34 + 256*uk_35 + 2736*uk_36 + 3472*uk_37 + 528*uk_38 + 29241*uk_39 + 33*uk_4 + 37107*uk_40 + 5643*uk_41 + 47089*uk_42 + 7161*uk_43 + 1089*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 352042137613*uk_47 + 73996118097*uk_48 + 35876905744*uk_49 + 16*uk_5 + 383434430139*uk_50 + 486580534153*uk_51 + 73996118097*uk_52 + 187944057*uk_53 + 468368523*uk_54 + 98446887*uk_55 + 47731824*uk_56 + 510133869*uk_57 + 647362863*uk_58 + 98446887*uk_59 + 171*uk_6 + 1167204097*uk_60 + 245335893*uk_61 + 118950736*uk_62 + 1271285991*uk_63 + 1613269357*uk_64 + 245335893*uk_65 + 51567417*uk_66 + 25002384*uk_67 + 267212979*uk_68 + 339094833*uk_69 + 217*uk_7 + 51567417*uk_70 + 12122368*uk_71 + 129557808*uk_72 + 164409616*uk_73 + 25002384*uk_74 + 1384649073*uk_75 + 1757127771*uk_76 + 267212979*uk_77 + 2229805417*uk_78 + 339094833*uk_79 + 33*uk_8 + 51567417*uk_80 + 250047*uk_81 + 623133*uk_82 + 130977*uk_83 + 63504*uk_84 + 678699*uk_85 + 861273*uk_86 + 130977*uk_87 + 1552887*uk_88 + 326403*uk_89 + 2242306609*uk_9 + 158256*uk_90 + 1691361*uk_91 + 2146347*uk_92 + 326403*uk_93 + 68607*uk_94 + 33264*uk_95 + 355509*uk_96 + 451143*uk_97 + 68607*uk_98 + 16128*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 130788*uk_100 + 164052*uk_101 + 118692*uk_102 + 1885527*uk_103 + 2365083*uk_104 + 1711143*uk_105 + 2966607*uk_106 + 2146347*uk_107 + 1552887*uk_108 + 1906624*uk_109 + 5871772*uk_11 + 2414032*uk_110 + 184512*uk_111 + 2660048*uk_112 + 3336592*uk_113 + 2414032*uk_114 + 3056476*uk_115 + 233616*uk_116 + 3367964*uk_117 + 4224556*uk_118 + 3056476*uk_119 + 7434421*uk_12 + 17856*uk_120 + 257424*uk_121 + 322896*uk_122 + 233616*uk_123 + 3711196*uk_124 + 4655084*uk_125 + 3367964*uk_126 + 5839036*uk_127 + 4224556*uk_128 + 3056476*uk_129 + 568236*uk_13 + 3869893*uk_130 + 295788*uk_131 + 4264277*uk_132 + 5348833*uk_133 + 3869893*uk_134 + 22608*uk_135 + 325932*uk_136 + 408828*uk_137 + 295788*uk_138 + 4698853*uk_139 + 8192069*uk_14 + 5893937*uk_140 + 4264277*uk_141 + 7392973*uk_142 + 5348833*uk_143 + 3869893*uk_144 + 1728*uk_145 + 24912*uk_146 + 31248*uk_147 + 22608*uk_148 + 359148*uk_149 + 10275601*uk_15 + 450492*uk_150 + 325932*uk_151 + 565068*uk_152 + 408828*uk_153 + 295788*uk_154 + 5177717*uk_155 + 6494593*uk_156 + 4698853*uk_157 + 8146397*uk_158 + 5893937*uk_159 + 7434421*uk_16 + 4264277*uk_160 + 10218313*uk_161 + 7392973*uk_162 + 5348833*uk_163 + 3869893*uk_164 + 3969*uk_17 + 7812*uk_18 + 9891*uk_19 + 63*uk_2 + 756*uk_20 + 10899*uk_21 + 13671*uk_22 + 9891*uk_23 + 15376*uk_24 + 19468*uk_25 + 1488*uk_26 + 21452*uk_27 + 26908*uk_28 + 19468*uk_29 + 124*uk_3 + 24649*uk_30 + 1884*uk_31 + 27161*uk_32 + 34069*uk_33 + 24649*uk_34 + 144*uk_35 + 2076*uk_36 + 2604*uk_37 + 1884*uk_38 + 29929*uk_39 + 157*uk_4 + 37541*uk_40 + 27161*uk_41 + 47089*uk_42 + 34069*uk_43 + 24649*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 278046019516*uk_47 + 352042137613*uk_48 + 26907679308*uk_49 + 12*uk_5 + 387919043357*uk_50 + 486580534153*uk_51 + 352042137613*uk_52 + 187944057*uk_53 + 369921636*uk_54 + 468368523*uk_55 + 35798868*uk_56 + 516100347*uk_57 + 647362863*uk_58 + 468368523*uk_59 + 173*uk_6 + 728099728*uk_60 + 921868204*uk_61 + 70461264*uk_62 + 1015816556*uk_63 + 1274174524*uk_64 + 921868204*uk_65 + 1167204097*uk_66 + 89213052*uk_67 + 1286154833*uk_68 + 1613269357*uk_69 + 217*uk_7 + 1167204097*uk_70 + 6818832*uk_71 + 98304828*uk_72 + 123307212*uk_73 + 89213052*uk_74 + 1417227937*uk_75 + 1777678973*uk_76 + 1286154833*uk_77 + 2229805417*uk_78 + 1613269357*uk_79 + 157*uk_8 + 1167204097*uk_80 + 250047*uk_81 + 492156*uk_82 + 623133*uk_83 + 47628*uk_84 + 686637*uk_85 + 861273*uk_86 + 623133*uk_87 + 968688*uk_88 + 1226484*uk_89 + 2242306609*uk_9 + 93744*uk_90 + 1351476*uk_91 + 1695204*uk_92 + 1226484*uk_93 + 1552887*uk_94 + 118692*uk_95 + 1711143*uk_96 + 2146347*uk_97 + 1552887*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 132300*uk_100 + 164052*uk_101 + 93744*uk_102 + 1929375*uk_103 + 2392425*uk_104 + 1367100*uk_105 + 2966607*uk_106 + 1695204*uk_107 + 968688*uk_108 + 1092727*uk_109 + 4877359*uk_11 + 1315516*uk_110 + 127308*uk_111 + 1856575*uk_112 + 2302153*uk_113 + 1315516*uk_114 + 1583728*uk_115 + 153264*uk_116 + 2235100*uk_117 + 2771524*uk_118 + 1583728*uk_119 + 5871772*uk_12 + 14832*uk_120 + 216300*uk_121 + 268212*uk_122 + 153264*uk_123 + 3154375*uk_124 + 3911425*uk_125 + 2235100*uk_126 + 4850167*uk_127 + 2771524*uk_128 + 1583728*uk_129 + 568236*uk_13 + 1906624*uk_130 + 184512*uk_131 + 2690800*uk_132 + 3336592*uk_133 + 1906624*uk_134 + 17856*uk_135 + 260400*uk_136 + 322896*uk_137 + 184512*uk_138 + 3797500*uk_139 + 8286775*uk_14 + 4708900*uk_140 + 2690800*uk_141 + 5839036*uk_142 + 3336592*uk_143 + 1906624*uk_144 + 1728*uk_145 + 25200*uk_146 + 31248*uk_147 + 17856*uk_148 + 367500*uk_149 + 10275601*uk_15 + 455700*uk_150 + 260400*uk_151 + 565068*uk_152 + 322896*uk_153 + 184512*uk_154 + 5359375*uk_155 + 6645625*uk_156 + 3797500*uk_157 + 8240575*uk_158 + 4708900*uk_159 + 5871772*uk_16 + 2690800*uk_160 + 10218313*uk_161 + 5839036*uk_162 + 3336592*uk_163 + 1906624*uk_164 + 3969*uk_17 + 6489*uk_18 + 7812*uk_19 + 63*uk_2 + 756*uk_20 + 11025*uk_21 + 13671*uk_22 + 7812*uk_23 + 10609*uk_24 + 12772*uk_25 + 1236*uk_26 + 18025*uk_27 + 22351*uk_28 + 12772*uk_29 + 103*uk_3 + 15376*uk_30 + 1488*uk_31 + 21700*uk_32 + 26908*uk_33 + 15376*uk_34 + 144*uk_35 + 2100*uk_36 + 2604*uk_37 + 1488*uk_38 + 30625*uk_39 + 124*uk_4 + 37975*uk_40 + 21700*uk_41 + 47089*uk_42 + 26908*uk_43 + 15376*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 230957580727*uk_47 + 278046019516*uk_48 + 26907679308*uk_49 + 12*uk_5 + 392403656575*uk_50 + 486580534153*uk_51 + 278046019516*uk_52 + 187944057*uk_53 + 307273617*uk_54 + 369921636*uk_55 + 35798868*uk_56 + 522066825*uk_57 + 647362863*uk_58 + 369921636*uk_59 + 175*uk_6 + 502367977*uk_60 + 604792516*uk_61 + 58528308*uk_62 + 853537825*uk_63 + 1058386903*uk_64 + 604792516*uk_65 + 728099728*uk_66 + 70461264*uk_67 + 1027560100*uk_68 + 1274174524*uk_69 + 217*uk_7 + 728099728*uk_70 + 6818832*uk_71 + 99441300*uk_72 + 123307212*uk_73 + 70461264*uk_74 + 1450185625*uk_75 + 1798230175*uk_76 + 1027560100*uk_77 + 2229805417*uk_78 + 1274174524*uk_79 + 124*uk_8 + 728099728*uk_80 + 250047*uk_81 + 408807*uk_82 + 492156*uk_83 + 47628*uk_84 + 694575*uk_85 + 861273*uk_86 + 492156*uk_87 + 668367*uk_88 + 804636*uk_89 + 2242306609*uk_9 + 77868*uk_90 + 1135575*uk_91 + 1408113*uk_92 + 804636*uk_93 + 968688*uk_94 + 93744*uk_95 + 1367100*uk_96 + 1695204*uk_97 + 968688*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 133812*uk_100 + 164052*uk_101 + 77868*uk_102 + 1973727*uk_103 + 2419767*uk_104 + 1148553*uk_105 + 2966607*uk_106 + 1408113*uk_107 + 668367*uk_108 + 830584*uk_109 + 4451182*uk_11 + 910108*uk_110 + 106032*uk_111 + 1563972*uk_112 + 1917412*uk_113 + 910108*uk_114 + 997246*uk_115 + 116184*uk_116 + 1713714*uk_117 + 2100994*uk_118 + 997246*uk_119 + 4877359*uk_12 + 13536*uk_120 + 199656*uk_121 + 244776*uk_122 + 116184*uk_123 + 2944926*uk_124 + 3610446*uk_125 + 1713714*uk_126 + 4426366*uk_127 + 2100994*uk_128 + 997246*uk_129 + 568236*uk_13 + 1092727*uk_130 + 127308*uk_131 + 1877793*uk_132 + 2302153*uk_133 + 1092727*uk_134 + 14832*uk_135 + 218772*uk_136 + 268212*uk_137 + 127308*uk_138 + 3226887*uk_139 + 8381481*uk_14 + 3956127*uk_140 + 1877793*uk_141 + 4850167*uk_142 + 2302153*uk_143 + 1092727*uk_144 + 1728*uk_145 + 25488*uk_146 + 31248*uk_147 + 14832*uk_148 + 375948*uk_149 + 10275601*uk_15 + 460908*uk_150 + 218772*uk_151 + 565068*uk_152 + 268212*uk_153 + 127308*uk_154 + 5545233*uk_155 + 6798393*uk_156 + 3226887*uk_157 + 8334753*uk_158 + 3956127*uk_159 + 4877359*uk_16 + 1877793*uk_160 + 10218313*uk_161 + 4850167*uk_162 + 2302153*uk_163 + 1092727*uk_164 + 3969*uk_17 + 5922*uk_18 + 6489*uk_19 + 63*uk_2 + 756*uk_20 + 11151*uk_21 + 13671*uk_22 + 6489*uk_23 + 8836*uk_24 + 9682*uk_25 + 1128*uk_26 + 16638*uk_27 + 20398*uk_28 + 9682*uk_29 + 94*uk_3 + 10609*uk_30 + 1236*uk_31 + 18231*uk_32 + 22351*uk_33 + 10609*uk_34 + 144*uk_35 + 2124*uk_36 + 2604*uk_37 + 1236*uk_38 + 31329*uk_39 + 103*uk_4 + 38409*uk_40 + 18231*uk_41 + 47089*uk_42 + 22351*uk_43 + 10609*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 210776821246*uk_47 + 230957580727*uk_48 + 26907679308*uk_49 + 12*uk_5 + 396888269793*uk_50 + 486580534153*uk_51 + 230957580727*uk_52 + 187944057*uk_53 + 280424466*uk_54 + 307273617*uk_55 + 35798868*uk_56 + 528033303*uk_57 + 647362863*uk_58 + 307273617*uk_59 + 177*uk_6 + 418411108*uk_60 + 458471746*uk_61 + 53414184*uk_62 + 787859214*uk_63 + 965906494*uk_64 + 458471746*uk_65 + 502367977*uk_66 + 58528308*uk_67 + 863292543*uk_68 + 1058386903*uk_69 + 217*uk_7 + 502367977*uk_70 + 6818832*uk_71 + 100577772*uk_72 + 123307212*uk_73 + 58528308*uk_74 + 1483522137*uk_75 + 1818781377*uk_76 + 863292543*uk_77 + 2229805417*uk_78 + 1058386903*uk_79 + 103*uk_8 + 502367977*uk_80 + 250047*uk_81 + 373086*uk_82 + 408807*uk_83 + 47628*uk_84 + 702513*uk_85 + 861273*uk_86 + 408807*uk_87 + 556668*uk_88 + 609966*uk_89 + 2242306609*uk_9 + 71064*uk_90 + 1048194*uk_91 + 1285074*uk_92 + 609966*uk_93 + 668367*uk_94 + 77868*uk_95 + 1148553*uk_96 + 1408113*uk_97 + 668367*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 135324*uk_100 + 164052*uk_101 + 71064*uk_102 + 2018583*uk_103 + 2447109*uk_104 + 1060038*uk_105 + 2966607*uk_106 + 1285074*uk_107 + 556668*uk_108 + 912673*uk_109 + 4593241*uk_11 + 884446*uk_110 + 112908*uk_111 + 1684211*uk_112 + 2041753*uk_113 + 884446*uk_114 + 857092*uk_115 + 109416*uk_116 + 1632122*uk_117 + 1978606*uk_118 + 857092*uk_119 + 4451182*uk_12 + 13968*uk_120 + 208356*uk_121 + 252588*uk_122 + 109416*uk_123 + 3107977*uk_124 + 3767771*uk_125 + 1632122*uk_126 + 4567633*uk_127 + 1978606*uk_128 + 857092*uk_129 + 568236*uk_13 + 830584*uk_130 + 106032*uk_131 + 1581644*uk_132 + 1917412*uk_133 + 830584*uk_134 + 13536*uk_135 + 201912*uk_136 + 244776*uk_137 + 106032*uk_138 + 3011854*uk_139 + 8476187*uk_14 + 3651242*uk_140 + 1581644*uk_141 + 4426366*uk_142 + 1917412*uk_143 + 830584*uk_144 + 1728*uk_145 + 25776*uk_146 + 31248*uk_147 + 13536*uk_148 + 384492*uk_149 + 10275601*uk_15 + 466116*uk_150 + 201912*uk_151 + 565068*uk_152 + 244776*uk_153 + 106032*uk_154 + 5735339*uk_155 + 6952897*uk_156 + 3011854*uk_157 + 8428931*uk_158 + 3651242*uk_159 + 4451182*uk_16 + 1581644*uk_160 + 10218313*uk_161 + 4426366*uk_162 + 1917412*uk_163 + 830584*uk_164 + 3969*uk_17 + 6111*uk_18 + 5922*uk_19 + 63*uk_2 + 756*uk_20 + 11277*uk_21 + 13671*uk_22 + 5922*uk_23 + 9409*uk_24 + 9118*uk_25 + 1164*uk_26 + 17363*uk_27 + 21049*uk_28 + 9118*uk_29 + 97*uk_3 + 8836*uk_30 + 1128*uk_31 + 16826*uk_32 + 20398*uk_33 + 8836*uk_34 + 144*uk_35 + 2148*uk_36 + 2604*uk_37 + 1128*uk_38 + 32041*uk_39 + 94*uk_4 + 38843*uk_40 + 16826*uk_41 + 47089*uk_42 + 20398*uk_43 + 8836*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 217503741073*uk_47 + 210776821246*uk_48 + 26907679308*uk_49 + 12*uk_5 + 401372883011*uk_50 + 486580534153*uk_51 + 210776821246*uk_52 + 187944057*uk_53 + 289374183*uk_54 + 280424466*uk_55 + 35798868*uk_56 + 533999781*uk_57 + 647362863*uk_58 + 280424466*uk_59 + 179*uk_6 + 445544377*uk_60 + 431764654*uk_61 + 55118892*uk_62 + 822190139*uk_63 + 996733297*uk_64 + 431764654*uk_65 + 418411108*uk_66 + 53414184*uk_67 + 796761578*uk_68 + 965906494*uk_69 + 217*uk_7 + 418411108*uk_70 + 6818832*uk_71 + 101714244*uk_72 + 123307212*uk_73 + 53414184*uk_74 + 1517237473*uk_75 + 1839332579*uk_76 + 796761578*uk_77 + 2229805417*uk_78 + 965906494*uk_79 + 94*uk_8 + 418411108*uk_80 + 250047*uk_81 + 384993*uk_82 + 373086*uk_83 + 47628*uk_84 + 710451*uk_85 + 861273*uk_86 + 373086*uk_87 + 592767*uk_88 + 574434*uk_89 + 2242306609*uk_9 + 73332*uk_90 + 1093869*uk_91 + 1326087*uk_92 + 574434*uk_93 + 556668*uk_94 + 71064*uk_95 + 1060038*uk_96 + 1285074*uk_97 + 556668*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 136836*uk_100 + 164052*uk_101 + 73332*uk_102 + 2063943*uk_103 + 2474451*uk_104 + 1106091*uk_105 + 2966607*uk_106 + 1326087*uk_107 + 592767*uk_108 + 1404928*uk_109 + 5303536*uk_11 + 1216768*uk_110 + 150528*uk_111 + 2270464*uk_112 + 2722048*uk_113 + 1216768*uk_114 + 1053808*uk_115 + 130368*uk_116 + 1966384*uk_117 + 2357488*uk_118 + 1053808*uk_119 + 4593241*uk_12 + 16128*uk_120 + 243264*uk_121 + 291648*uk_122 + 130368*uk_123 + 3669232*uk_124 + 4399024*uk_125 + 1966384*uk_126 + 5273968*uk_127 + 2357488*uk_128 + 1053808*uk_129 + 568236*uk_13 + 912673*uk_130 + 112908*uk_131 + 1703029*uk_132 + 2041753*uk_133 + 912673*uk_134 + 13968*uk_135 + 210684*uk_136 + 252588*uk_137 + 112908*uk_138 + 3177817*uk_139 + 8570893*uk_14 + 3809869*uk_140 + 1703029*uk_141 + 4567633*uk_142 + 2041753*uk_143 + 912673*uk_144 + 1728*uk_145 + 26064*uk_146 + 31248*uk_147 + 13968*uk_148 + 393132*uk_149 + 10275601*uk_15 + 471324*uk_150 + 210684*uk_151 + 565068*uk_152 + 252588*uk_153 + 112908*uk_154 + 5929741*uk_155 + 7109137*uk_156 + 3177817*uk_157 + 8523109*uk_158 + 3809869*uk_159 + 4593241*uk_16 + 1703029*uk_160 + 10218313*uk_161 + 4567633*uk_162 + 2041753*uk_163 + 912673*uk_164 + 3969*uk_17 + 7056*uk_18 + 6111*uk_19 + 63*uk_2 + 756*uk_20 + 11403*uk_21 + 13671*uk_22 + 6111*uk_23 + 12544*uk_24 + 10864*uk_25 + 1344*uk_26 + 20272*uk_27 + 24304*uk_28 + 10864*uk_29 + 112*uk_3 + 9409*uk_30 + 1164*uk_31 + 17557*uk_32 + 21049*uk_33 + 9409*uk_34 + 144*uk_35 + 2172*uk_36 + 2604*uk_37 + 1164*uk_38 + 32761*uk_39 + 97*uk_4 + 39277*uk_40 + 17557*uk_41 + 47089*uk_42 + 21049*uk_43 + 9409*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 251138340208*uk_47 + 217503741073*uk_48 + 26907679308*uk_49 + 12*uk_5 + 405857496229*uk_50 + 486580534153*uk_51 + 217503741073*uk_52 + 187944057*uk_53 + 334122768*uk_54 + 289374183*uk_55 + 35798868*uk_56 + 539966259*uk_57 + 647362863*uk_58 + 289374183*uk_59 + 181*uk_6 + 593996032*uk_60 + 514442992*uk_61 + 63642432*uk_62 + 959940016*uk_63 + 1150867312*uk_64 + 514442992*uk_65 + 445544377*uk_66 + 55118892*uk_67 + 831376621*uk_68 + 996733297*uk_69 + 217*uk_7 + 445544377*uk_70 + 6818832*uk_71 + 102850716*uk_72 + 123307212*uk_73 + 55118892*uk_74 + 1551331633*uk_75 + 1859883781*uk_76 + 831376621*uk_77 + 2229805417*uk_78 + 996733297*uk_79 + 97*uk_8 + 445544377*uk_80 + 250047*uk_81 + 444528*uk_82 + 384993*uk_83 + 47628*uk_84 + 718389*uk_85 + 861273*uk_86 + 384993*uk_87 + 790272*uk_88 + 684432*uk_89 + 2242306609*uk_9 + 84672*uk_90 + 1277136*uk_91 + 1531152*uk_92 + 684432*uk_93 + 592767*uk_94 + 73332*uk_95 + 1106091*uk_96 + 1326087*uk_97 + 592767*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 138348*uk_100 + 164052*uk_101 + 84672*uk_102 + 2109807*uk_103 + 2501793*uk_104 + 1291248*uk_105 + 2966607*uk_106 + 1531152*uk_107 + 790272*uk_108 + 2685619*uk_109 + 6582067*uk_11 + 2163952*uk_110 + 231852*uk_111 + 3535743*uk_112 + 4192657*uk_113 + 2163952*uk_114 + 1743616*uk_115 + 186816*uk_116 + 2848944*uk_117 + 3378256*uk_118 + 1743616*uk_119 + 5303536*uk_12 + 20016*uk_120 + 305244*uk_121 + 361956*uk_122 + 186816*uk_123 + 4654971*uk_124 + 5519829*uk_125 + 2848944*uk_126 + 6545371*uk_127 + 3378256*uk_128 + 1743616*uk_129 + 568236*uk_13 + 1404928*uk_130 + 150528*uk_131 + 2295552*uk_132 + 2722048*uk_133 + 1404928*uk_134 + 16128*uk_135 + 245952*uk_136 + 291648*uk_137 + 150528*uk_138 + 3750768*uk_139 + 8665599*uk_14 + 4447632*uk_140 + 2295552*uk_141 + 5273968*uk_142 + 2722048*uk_143 + 1404928*uk_144 + 1728*uk_145 + 26352*uk_146 + 31248*uk_147 + 16128*uk_148 + 401868*uk_149 + 10275601*uk_15 + 476532*uk_150 + 245952*uk_151 + 565068*uk_152 + 291648*uk_153 + 150528*uk_154 + 6128487*uk_155 + 7267113*uk_156 + 3750768*uk_157 + 8617287*uk_158 + 4447632*uk_159 + 5303536*uk_16 + 2295552*uk_160 + 10218313*uk_161 + 5273968*uk_162 + 2722048*uk_163 + 1404928*uk_164 + 3969*uk_17 + 8757*uk_18 + 7056*uk_19 + 63*uk_2 + 756*uk_20 + 11529*uk_21 + 13671*uk_22 + 7056*uk_23 + 19321*uk_24 + 15568*uk_25 + 1668*uk_26 + 25437*uk_27 + 30163*uk_28 + 15568*uk_29 + 139*uk_3 + 12544*uk_30 + 1344*uk_31 + 20496*uk_32 + 24304*uk_33 + 12544*uk_34 + 144*uk_35 + 2196*uk_36 + 2604*uk_37 + 1344*uk_38 + 33489*uk_39 + 112*uk_4 + 39711*uk_40 + 20496*uk_41 + 47089*uk_42 + 24304*uk_43 + 12544*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 311680618651*uk_47 + 251138340208*uk_48 + 26907679308*uk_49 + 12*uk_5 + 410342109447*uk_50 + 486580534153*uk_51 + 251138340208*uk_52 + 187944057*uk_53 + 414670221*uk_54 + 334122768*uk_55 + 35798868*uk_56 + 545932737*uk_57 + 647362863*uk_58 + 334122768*uk_59 + 183*uk_6 + 914907313*uk_60 + 737191504*uk_61 + 78984804*uk_62 + 1204518261*uk_63 + 1428308539*uk_64 + 737191504*uk_65 + 593996032*uk_66 + 63642432*uk_67 + 970547088*uk_68 + 1150867312*uk_69 + 217*uk_7 + 593996032*uk_70 + 6818832*uk_71 + 103987188*uk_72 + 123307212*uk_73 + 63642432*uk_74 + 1585804617*uk_75 + 1880434983*uk_76 + 970547088*uk_77 + 2229805417*uk_78 + 1150867312*uk_79 + 112*uk_8 + 593996032*uk_80 + 250047*uk_81 + 551691*uk_82 + 444528*uk_83 + 47628*uk_84 + 726327*uk_85 + 861273*uk_86 + 444528*uk_87 + 1217223*uk_88 + 980784*uk_89 + 2242306609*uk_9 + 105084*uk_90 + 1602531*uk_91 + 1900269*uk_92 + 980784*uk_93 + 790272*uk_94 + 84672*uk_95 + 1291248*uk_96 + 1531152*uk_97 + 790272*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 139860*uk_100 + 164052*uk_101 + 105084*uk_102 + 2156175*uk_103 + 2529135*uk_104 + 1620045*uk_105 + 2966607*uk_106 + 1900269*uk_107 + 1217223*uk_108 + 5639752*uk_109 + 8428834*uk_11 + 4404076*uk_110 + 380208*uk_111 + 5861540*uk_112 + 6875428*uk_113 + 4404076*uk_114 + 3439138*uk_115 + 296904*uk_116 + 4577270*uk_117 + 5369014*uk_118 + 3439138*uk_119 + 6582067*uk_12 + 25632*uk_120 + 395160*uk_121 + 463512*uk_122 + 296904*uk_123 + 6092050*uk_124 + 7145810*uk_125 + 4577270*uk_126 + 8381842*uk_127 + 5369014*uk_128 + 3439138*uk_129 + 568236*uk_13 + 2685619*uk_130 + 231852*uk_131 + 3574385*uk_132 + 4192657*uk_133 + 2685619*uk_134 + 20016*uk_135 + 308580*uk_136 + 361956*uk_137 + 231852*uk_138 + 4757275*uk_139 + 8760305*uk_14 + 5580155*uk_140 + 3574385*uk_141 + 6545371*uk_142 + 4192657*uk_143 + 2685619*uk_144 + 1728*uk_145 + 26640*uk_146 + 31248*uk_147 + 20016*uk_148 + 410700*uk_149 + 10275601*uk_15 + 481740*uk_150 + 308580*uk_151 + 565068*uk_152 + 361956*uk_153 + 231852*uk_154 + 6331625*uk_155 + 7426825*uk_156 + 4757275*uk_157 + 8711465*uk_158 + 5580155*uk_159 + 6582067*uk_16 + 3574385*uk_160 + 10218313*uk_161 + 6545371*uk_162 + 4192657*uk_163 + 2685619*uk_164 + 3969*uk_17 + 11214*uk_18 + 8757*uk_19 + 63*uk_2 + 756*uk_20 + 11655*uk_21 + 13671*uk_22 + 8757*uk_23 + 31684*uk_24 + 24742*uk_25 + 2136*uk_26 + 32930*uk_27 + 38626*uk_28 + 24742*uk_29 + 178*uk_3 + 19321*uk_30 + 1668*uk_31 + 25715*uk_32 + 30163*uk_33 + 19321*uk_34 + 144*uk_35 + 2220*uk_36 + 2604*uk_37 + 1668*uk_38 + 34225*uk_39 + 139*uk_4 + 40145*uk_40 + 25715*uk_41 + 47089*uk_42 + 30163*uk_43 + 19321*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 399130576402*uk_47 + 311680618651*uk_48 + 26907679308*uk_49 + 12*uk_5 + 414826722665*uk_50 + 486580534153*uk_51 + 311680618651*uk_52 + 187944057*uk_53 + 531016542*uk_54 + 414670221*uk_55 + 35798868*uk_56 + 551899215*uk_57 + 647362863*uk_58 + 414670221*uk_59 + 185*uk_6 + 1500332452*uk_60 + 1171607926*uk_61 + 101146008*uk_62 + 1559334290*uk_63 + 1829056978*uk_64 + 1171607926*uk_65 + 914907313*uk_66 + 78984804*uk_67 + 1217682395*uk_68 + 1428308539*uk_69 + 217*uk_7 + 914907313*uk_70 + 6818832*uk_71 + 105123660*uk_72 + 123307212*uk_73 + 78984804*uk_74 + 1620656425*uk_75 + 1900986185*uk_76 + 1217682395*uk_77 + 2229805417*uk_78 + 1428308539*uk_79 + 139*uk_8 + 914907313*uk_80 + 250047*uk_81 + 706482*uk_82 + 551691*uk_83 + 47628*uk_84 + 734265*uk_85 + 861273*uk_86 + 551691*uk_87 + 1996092*uk_88 + 1558746*uk_89 + 2242306609*uk_9 + 134568*uk_90 + 2074590*uk_91 + 2433438*uk_92 + 1558746*uk_93 + 1217223*uk_94 + 105084*uk_95 + 1620045*uk_96 + 1900269*uk_97 + 1217223*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 94248*uk_100 + 109368*uk_101 + 89712*uk_102 + 2203047*uk_103 + 2556477*uk_104 + 2097018*uk_105 + 2966607*uk_106 + 2433438*uk_107 + 1996092*uk_108 + 74088*uk_109 + 1988826*uk_11 + 313992*uk_110 + 14112*uk_111 + 329868*uk_112 + 382788*uk_113 + 313992*uk_114 + 1330728*uk_115 + 59808*uk_116 + 1398012*uk_117 + 1622292*uk_118 + 1330728*uk_119 + 8428834*uk_12 + 2688*uk_120 + 62832*uk_121 + 72912*uk_122 + 59808*uk_123 + 1468698*uk_124 + 1704318*uk_125 + 1398012*uk_126 + 1977738*uk_127 + 1622292*uk_128 + 1330728*uk_129 + 378824*uk_13 + 5639752*uk_130 + 253472*uk_131 + 5924908*uk_132 + 6875428*uk_133 + 5639752*uk_134 + 11392*uk_135 + 266288*uk_136 + 309008*uk_137 + 253472*uk_138 + 6224482*uk_139 + 8855011*uk_14 + 7223062*uk_140 + 5924908*uk_141 + 8381842*uk_142 + 6875428*uk_143 + 5639752*uk_144 + 512*uk_145 + 11968*uk_146 + 13888*uk_147 + 11392*uk_148 + 279752*uk_149 + 10275601*uk_15 + 324632*uk_150 + 266288*uk_151 + 376712*uk_152 + 309008*uk_153 + 253472*uk_154 + 6539203*uk_155 + 7588273*uk_156 + 6224482*uk_157 + 8805643*uk_158 + 7223062*uk_159 + 8428834*uk_16 + 5924908*uk_160 + 10218313*uk_161 + 8381842*uk_162 + 6875428*uk_163 + 5639752*uk_164 + 3969*uk_17 + 2646*uk_18 + 11214*uk_19 + 63*uk_2 + 504*uk_20 + 11781*uk_21 + 13671*uk_22 + 11214*uk_23 + 1764*uk_24 + 7476*uk_25 + 336*uk_26 + 7854*uk_27 + 9114*uk_28 + 7476*uk_29 + 42*uk_3 + 31684*uk_30 + 1424*uk_31 + 33286*uk_32 + 38626*uk_33 + 31684*uk_34 + 64*uk_35 + 1496*uk_36 + 1736*uk_37 + 1424*uk_38 + 34969*uk_39 + 178*uk_4 + 40579*uk_40 + 33286*uk_41 + 47089*uk_42 + 38626*uk_43 + 31684*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 94176877578*uk_47 + 399130576402*uk_48 + 17938452872*uk_49 + 8*uk_5 + 419311335883*uk_50 + 486580534153*uk_51 + 399130576402*uk_52 + 187944057*uk_53 + 125296038*uk_54 + 531016542*uk_55 + 23865912*uk_56 + 557865693*uk_57 + 647362863*uk_58 + 531016542*uk_59 + 187*uk_6 + 83530692*uk_60 + 354011028*uk_61 + 15910608*uk_62 + 371910462*uk_63 + 431575242*uk_64 + 354011028*uk_65 + 1500332452*uk_66 + 67430672*uk_67 + 1576191958*uk_68 + 1829056978*uk_69 + 217*uk_7 + 1500332452*uk_70 + 3030592*uk_71 + 70840088*uk_72 + 82204808*uk_73 + 67430672*uk_74 + 1655887057*uk_75 + 1921537387*uk_76 + 1576191958*uk_77 + 2229805417*uk_78 + 1829056978*uk_79 + 178*uk_8 + 1500332452*uk_80 + 250047*uk_81 + 166698*uk_82 + 706482*uk_83 + 31752*uk_84 + 742203*uk_85 + 861273*uk_86 + 706482*uk_87 + 111132*uk_88 + 470988*uk_89 + 2242306609*uk_9 + 21168*uk_90 + 494802*uk_91 + 574182*uk_92 + 470988*uk_93 + 1996092*uk_94 + 89712*uk_95 + 2097018*uk_96 + 2433438*uk_97 + 1996092*uk_98 + 4032*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 142884*uk_100 + 164052*uk_101 + 31752*uk_102 + 2250423*uk_103 + 2583819*uk_104 + 500094*uk_105 + 2966607*uk_106 + 574182*uk_107 + 111132*uk_108 + 1092727*uk_109 + 4877359*uk_11 + 445578*uk_110 + 127308*uk_111 + 2005101*uk_112 + 2302153*uk_113 + 445578*uk_114 + 181692*uk_115 + 51912*uk_116 + 817614*uk_117 + 938742*uk_118 + 181692*uk_119 + 1988826*uk_12 + 14832*uk_120 + 233604*uk_121 + 268212*uk_122 + 51912*uk_123 + 3679263*uk_124 + 4224339*uk_125 + 817614*uk_126 + 4850167*uk_127 + 938742*uk_128 + 181692*uk_129 + 568236*uk_13 + 74088*uk_130 + 21168*uk_131 + 333396*uk_132 + 382788*uk_133 + 74088*uk_134 + 6048*uk_135 + 95256*uk_136 + 109368*uk_137 + 21168*uk_138 + 1500282*uk_139 + 8949717*uk_14 + 1722546*uk_140 + 333396*uk_141 + 1977738*uk_142 + 382788*uk_143 + 74088*uk_144 + 1728*uk_145 + 27216*uk_146 + 31248*uk_147 + 6048*uk_148 + 428652*uk_149 + 10275601*uk_15 + 492156*uk_150 + 95256*uk_151 + 565068*uk_152 + 109368*uk_153 + 21168*uk_154 + 6751269*uk_155 + 7751457*uk_156 + 1500282*uk_157 + 8899821*uk_158 + 1722546*uk_159 + 1988826*uk_16 + 333396*uk_160 + 10218313*uk_161 + 1977738*uk_162 + 382788*uk_163 + 74088*uk_164 + 3969*uk_17 + 6489*uk_18 + 2646*uk_19 + 63*uk_2 + 756*uk_20 + 11907*uk_21 + 13671*uk_22 + 2646*uk_23 + 10609*uk_24 + 4326*uk_25 + 1236*uk_26 + 19467*uk_27 + 22351*uk_28 + 4326*uk_29 + 103*uk_3 + 1764*uk_30 + 504*uk_31 + 7938*uk_32 + 9114*uk_33 + 1764*uk_34 + 144*uk_35 + 2268*uk_36 + 2604*uk_37 + 504*uk_38 + 35721*uk_39 + 42*uk_4 + 41013*uk_40 + 7938*uk_41 + 47089*uk_42 + 9114*uk_43 + 1764*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 230957580727*uk_47 + 94176877578*uk_48 + 26907679308*uk_49 + 12*uk_5 + 423795949101*uk_50 + 486580534153*uk_51 + 94176877578*uk_52 + 187944057*uk_53 + 307273617*uk_54 + 125296038*uk_55 + 35798868*uk_56 + 563832171*uk_57 + 647362863*uk_58 + 125296038*uk_59 + 189*uk_6 + 502367977*uk_60 + 204849078*uk_61 + 58528308*uk_62 + 921820851*uk_63 + 1058386903*uk_64 + 204849078*uk_65 + 83530692*uk_66 + 23865912*uk_67 + 375888114*uk_68 + 431575242*uk_69 + 217*uk_7 + 83530692*uk_70 + 6818832*uk_71 + 107396604*uk_72 + 123307212*uk_73 + 23865912*uk_74 + 1691496513*uk_75 + 1942088589*uk_76 + 375888114*uk_77 + 2229805417*uk_78 + 431575242*uk_79 + 42*uk_8 + 83530692*uk_80 + 250047*uk_81 + 408807*uk_82 + 166698*uk_83 + 47628*uk_84 + 750141*uk_85 + 861273*uk_86 + 166698*uk_87 + 668367*uk_88 + 272538*uk_89 + 2242306609*uk_9 + 77868*uk_90 + 1226421*uk_91 + 1408113*uk_92 + 272538*uk_93 + 111132*uk_94 + 31752*uk_95 + 500094*uk_96 + 574182*uk_97 + 111132*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 144396*uk_100 + 164052*uk_101 + 77868*uk_102 + 2298303*uk_103 + 2611161*uk_104 + 1239399*uk_105 + 2966607*uk_106 + 1408113*uk_107 + 668367*uk_108 + 5451776*uk_109 + 8334128*uk_11 + 3190528*uk_110 + 371712*uk_111 + 5916416*uk_112 + 6721792*uk_113 + 3190528*uk_114 + 1867184*uk_115 + 217536*uk_116 + 3462448*uk_117 + 3933776*uk_118 + 1867184*uk_119 + 4877359*uk_12 + 25344*uk_120 + 403392*uk_121 + 458304*uk_122 + 217536*uk_123 + 6420656*uk_124 + 7294672*uk_125 + 3462448*uk_126 + 8287664*uk_127 + 3933776*uk_128 + 1867184*uk_129 + 568236*uk_13 + 1092727*uk_130 + 127308*uk_131 + 2026319*uk_132 + 2302153*uk_133 + 1092727*uk_134 + 14832*uk_135 + 236076*uk_136 + 268212*uk_137 + 127308*uk_138 + 3757543*uk_139 + 9044423*uk_14 + 4269041*uk_140 + 2026319*uk_141 + 4850167*uk_142 + 2302153*uk_143 + 1092727*uk_144 + 1728*uk_145 + 27504*uk_146 + 31248*uk_147 + 14832*uk_148 + 437772*uk_149 + 10275601*uk_15 + 497364*uk_150 + 236076*uk_151 + 565068*uk_152 + 268212*uk_153 + 127308*uk_154 + 6967871*uk_155 + 7916377*uk_156 + 3757543*uk_157 + 8993999*uk_158 + 4269041*uk_159 + 4877359*uk_16 + 2026319*uk_160 + 10218313*uk_161 + 4850167*uk_162 + 2302153*uk_163 + 1092727*uk_164 + 3969*uk_17 + 11088*uk_18 + 6489*uk_19 + 63*uk_2 + 756*uk_20 + 12033*uk_21 + 13671*uk_22 + 6489*uk_23 + 30976*uk_24 + 18128*uk_25 + 2112*uk_26 + 33616*uk_27 + 38192*uk_28 + 18128*uk_29 + 176*uk_3 + 10609*uk_30 + 1236*uk_31 + 19673*uk_32 + 22351*uk_33 + 10609*uk_34 + 144*uk_35 + 2292*uk_36 + 2604*uk_37 + 1236*uk_38 + 36481*uk_39 + 103*uk_4 + 41447*uk_40 + 19673*uk_41 + 47089*uk_42 + 22351*uk_43 + 10609*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 394645963184*uk_47 + 230957580727*uk_48 + 26907679308*uk_49 + 12*uk_5 + 428280562319*uk_50 + 486580534153*uk_51 + 230957580727*uk_52 + 187944057*uk_53 + 525050064*uk_54 + 307273617*uk_55 + 35798868*uk_56 + 569798649*uk_57 + 647362863*uk_58 + 307273617*uk_59 + 191*uk_6 + 1466806528*uk_60 + 858415184*uk_61 + 100009536*uk_62 + 1591818448*uk_63 + 1808505776*uk_64 + 858415184*uk_65 + 502367977*uk_66 + 58528308*uk_67 + 931575569*uk_68 + 1058386903*uk_69 + 217*uk_7 + 502367977*uk_70 + 6818832*uk_71 + 108533076*uk_72 + 123307212*uk_73 + 58528308*uk_74 + 1727484793*uk_75 + 1962639791*uk_76 + 931575569*uk_77 + 2229805417*uk_78 + 1058386903*uk_79 + 103*uk_8 + 502367977*uk_80 + 250047*uk_81 + 698544*uk_82 + 408807*uk_83 + 47628*uk_84 + 758079*uk_85 + 861273*uk_86 + 408807*uk_87 + 1951488*uk_88 + 1142064*uk_89 + 2242306609*uk_9 + 133056*uk_90 + 2117808*uk_91 + 2406096*uk_92 + 1142064*uk_93 + 668367*uk_94 + 77868*uk_95 + 1239399*uk_96 + 1408113*uk_97 + 668367*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 97272*uk_100 + 109368*uk_101 + 88704*uk_102 + 2346687*uk_103 + 2638503*uk_104 + 2139984*uk_105 + 2966607*uk_106 + 2406096*uk_107 + 1951488*uk_108 + 314432*uk_109 + 3220004*uk_11 + 813824*uk_110 + 36992*uk_111 + 892432*uk_112 + 1003408*uk_113 + 813824*uk_114 + 2106368*uk_115 + 95744*uk_116 + 2309824*uk_117 + 2597056*uk_118 + 2106368*uk_119 + 8334128*uk_12 + 4352*uk_120 + 104992*uk_121 + 118048*uk_122 + 95744*uk_123 + 2532932*uk_124 + 2847908*uk_125 + 2309824*uk_126 + 3202052*uk_127 + 2597056*uk_128 + 2106368*uk_129 + 378824*uk_13 + 5451776*uk_130 + 247808*uk_131 + 5978368*uk_132 + 6721792*uk_133 + 5451776*uk_134 + 11264*uk_135 + 271744*uk_136 + 305536*uk_137 + 247808*uk_138 + 6555824*uk_139 + 9139129*uk_14 + 7371056*uk_140 + 5978368*uk_141 + 8287664*uk_142 + 6721792*uk_143 + 5451776*uk_144 + 512*uk_145 + 12352*uk_146 + 13888*uk_147 + 11264*uk_148 + 297992*uk_149 + 10275601*uk_15 + 335048*uk_150 + 271744*uk_151 + 376712*uk_152 + 305536*uk_153 + 247808*uk_154 + 7189057*uk_155 + 8083033*uk_156 + 6555824*uk_157 + 9088177*uk_158 + 7371056*uk_159 + 8334128*uk_16 + 5978368*uk_160 + 10218313*uk_161 + 8287664*uk_162 + 6721792*uk_163 + 5451776*uk_164 + 3969*uk_17 + 4284*uk_18 + 11088*uk_19 + 63*uk_2 + 504*uk_20 + 12159*uk_21 + 13671*uk_22 + 11088*uk_23 + 4624*uk_24 + 11968*uk_25 + 544*uk_26 + 13124*uk_27 + 14756*uk_28 + 11968*uk_29 + 68*uk_3 + 30976*uk_30 + 1408*uk_31 + 33968*uk_32 + 38192*uk_33 + 30976*uk_34 + 64*uk_35 + 1544*uk_36 + 1736*uk_37 + 1408*uk_38 + 37249*uk_39 + 176*uk_4 + 41881*uk_40 + 33968*uk_41 + 47089*uk_42 + 38192*uk_43 + 30976*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 152476849412*uk_47 + 394645963184*uk_48 + 17938452872*uk_49 + 8*uk_5 + 432765175537*uk_50 + 486580534153*uk_51 + 394645963184*uk_52 + 187944057*uk_53 + 202860252*uk_54 + 525050064*uk_55 + 23865912*uk_56 + 575765127*uk_57 + 647362863*uk_58 + 525050064*uk_59 + 193*uk_6 + 218960272*uk_60 + 566720704*uk_61 + 25760032*uk_62 + 621460772*uk_63 + 698740868*uk_64 + 566720704*uk_65 + 1466806528*uk_66 + 66673024*uk_67 + 1608486704*uk_68 + 1808505776*uk_69 + 217*uk_7 + 1466806528*uk_70 + 3030592*uk_71 + 73113032*uk_72 + 82204808*uk_73 + 66673024*uk_74 + 1763851897*uk_75 + 1983190993*uk_76 + 1608486704*uk_77 + 2229805417*uk_78 + 1808505776*uk_79 + 176*uk_8 + 1466806528*uk_80 + 250047*uk_81 + 269892*uk_82 + 698544*uk_83 + 31752*uk_84 + 766017*uk_85 + 861273*uk_86 + 698544*uk_87 + 291312*uk_88 + 753984*uk_89 + 2242306609*uk_9 + 34272*uk_90 + 826812*uk_91 + 929628*uk_92 + 753984*uk_93 + 1951488*uk_94 + 88704*uk_95 + 2139984*uk_96 + 2406096*uk_97 + 1951488*uk_98 + 4032*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 147420*uk_100 + 164052*uk_101 + 51408*uk_102 + 2395575*uk_103 + 2665845*uk_104 + 835380*uk_105 + 2966607*uk_106 + 929628*uk_107 + 291312*uk_108 + 4330747*uk_109 + 7718539*uk_11 + 1806692*uk_110 + 318828*uk_111 + 5180955*uk_112 + 5765473*uk_113 + 1806692*uk_114 + 753712*uk_115 + 133008*uk_116 + 2161380*uk_117 + 2405228*uk_118 + 753712*uk_119 + 3220004*uk_12 + 23472*uk_120 + 381420*uk_121 + 424452*uk_122 + 133008*uk_123 + 6198075*uk_124 + 6897345*uk_125 + 2161380*uk_126 + 7675507*uk_127 + 2405228*uk_128 + 753712*uk_129 + 568236*uk_13 + 314432*uk_130 + 55488*uk_131 + 901680*uk_132 + 1003408*uk_133 + 314432*uk_134 + 9792*uk_135 + 159120*uk_136 + 177072*uk_137 + 55488*uk_138 + 2585700*uk_139 + 9233835*uk_14 + 2877420*uk_140 + 901680*uk_141 + 3202052*uk_142 + 1003408*uk_143 + 314432*uk_144 + 1728*uk_145 + 28080*uk_146 + 31248*uk_147 + 9792*uk_148 + 456300*uk_149 + 10275601*uk_15 + 507780*uk_150 + 159120*uk_151 + 565068*uk_152 + 177072*uk_153 + 55488*uk_154 + 7414875*uk_155 + 8251425*uk_156 + 2585700*uk_157 + 9182355*uk_158 + 2877420*uk_159 + 3220004*uk_16 + 901680*uk_160 + 10218313*uk_161 + 3202052*uk_162 + 1003408*uk_163 + 314432*uk_164 + 3969*uk_17 + 10269*uk_18 + 4284*uk_19 + 63*uk_2 + 756*uk_20 + 12285*uk_21 + 13671*uk_22 + 4284*uk_23 + 26569*uk_24 + 11084*uk_25 + 1956*uk_26 + 31785*uk_27 + 35371*uk_28 + 11084*uk_29 + 163*uk_3 + 4624*uk_30 + 816*uk_31 + 13260*uk_32 + 14756*uk_33 + 4624*uk_34 + 144*uk_35 + 2340*uk_36 + 2604*uk_37 + 816*uk_38 + 38025*uk_39 + 68*uk_4 + 42315*uk_40 + 13260*uk_41 + 47089*uk_42 + 14756*uk_43 + 4624*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 365495977267*uk_47 + 152476849412*uk_48 + 26907679308*uk_49 + 12*uk_5 + 437249788755*uk_50 + 486580534153*uk_51 + 152476849412*uk_52 + 187944057*uk_53 + 486267957*uk_54 + 202860252*uk_55 + 35798868*uk_56 + 581731605*uk_57 + 647362863*uk_58 + 202860252*uk_59 + 195*uk_6 + 1258121857*uk_60 + 524860652*uk_61 + 92622468*uk_62 + 1505115105*uk_63 + 1674922963*uk_64 + 524860652*uk_65 + 218960272*uk_66 + 38640048*uk_67 + 627900780*uk_68 + 698740868*uk_69 + 217*uk_7 + 218960272*uk_70 + 6818832*uk_71 + 110806020*uk_72 + 123307212*uk_73 + 38640048*uk_74 + 1800597825*uk_75 + 2003742195*uk_76 + 627900780*uk_77 + 2229805417*uk_78 + 698740868*uk_79 + 68*uk_8 + 218960272*uk_80 + 250047*uk_81 + 646947*uk_82 + 269892*uk_83 + 47628*uk_84 + 773955*uk_85 + 861273*uk_86 + 269892*uk_87 + 1673847*uk_88 + 698292*uk_89 + 2242306609*uk_9 + 123228*uk_90 + 2002455*uk_91 + 2228373*uk_92 + 698292*uk_93 + 291312*uk_94 + 51408*uk_95 + 835380*uk_96 + 929628*uk_97 + 291312*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 99288*uk_100 + 109368*uk_101 + 82152*uk_102 + 2444967*uk_103 + 2693187*uk_104 + 2022993*uk_105 + 2966607*uk_106 + 2228373*uk_107 + 1673847*uk_108 + 389017*uk_109 + 3456769*uk_11 + 868627*uk_110 + 42632*uk_111 + 1049813*uk_112 + 1156393*uk_113 + 868627*uk_114 + 1939537*uk_115 + 95192*uk_116 + 2344103*uk_117 + 2582083*uk_118 + 1939537*uk_119 + 7718539*uk_12 + 4672*uk_120 + 115048*uk_121 + 126728*uk_122 + 95192*uk_123 + 2833057*uk_124 + 3120677*uk_125 + 2344103*uk_126 + 3437497*uk_127 + 2582083*uk_128 + 1939537*uk_129 + 378824*uk_13 + 4330747*uk_130 + 212552*uk_131 + 5234093*uk_132 + 5765473*uk_133 + 4330747*uk_134 + 10432*uk_135 + 256888*uk_136 + 282968*uk_137 + 212552*uk_138 + 6325867*uk_139 + 9328541*uk_14 + 6968087*uk_140 + 5234093*uk_141 + 7675507*uk_142 + 5765473*uk_143 + 4330747*uk_144 + 512*uk_145 + 12608*uk_146 + 13888*uk_147 + 10432*uk_148 + 310472*uk_149 + 10275601*uk_15 + 341992*uk_150 + 256888*uk_151 + 376712*uk_152 + 282968*uk_153 + 212552*uk_154 + 7645373*uk_155 + 8421553*uk_156 + 6325867*uk_157 + 9276533*uk_158 + 6968087*uk_159 + 7718539*uk_16 + 5234093*uk_160 + 10218313*uk_161 + 7675507*uk_162 + 5765473*uk_163 + 4330747*uk_164 + 3969*uk_17 + 4599*uk_18 + 10269*uk_19 + 63*uk_2 + 504*uk_20 + 12411*uk_21 + 13671*uk_22 + 10269*uk_23 + 5329*uk_24 + 11899*uk_25 + 584*uk_26 + 14381*uk_27 + 15841*uk_28 + 11899*uk_29 + 73*uk_3 + 26569*uk_30 + 1304*uk_31 + 32111*uk_32 + 35371*uk_33 + 26569*uk_34 + 64*uk_35 + 1576*uk_36 + 1736*uk_37 + 1304*uk_38 + 38809*uk_39 + 163*uk_4 + 42749*uk_40 + 32111*uk_41 + 47089*uk_42 + 35371*uk_43 + 26569*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 163688382457*uk_47 + 365495977267*uk_48 + 17938452872*uk_49 + 8*uk_5 + 441734401973*uk_50 + 486580534153*uk_51 + 365495977267*uk_52 + 187944057*uk_53 + 217776447*uk_54 + 486267957*uk_55 + 23865912*uk_56 + 587698083*uk_57 + 647362863*uk_58 + 486267957*uk_59 + 197*uk_6 + 252344137*uk_60 + 563453347*uk_61 + 27654152*uk_62 + 680983493*uk_63 + 750118873*uk_64 + 563453347*uk_65 + 1258121857*uk_66 + 61748312*uk_67 + 1520552183*uk_68 + 1674922963*uk_69 + 217*uk_7 + 1258121857*uk_70 + 3030592*uk_71 + 74628328*uk_72 + 82204808*uk_73 + 61748312*uk_74 + 1837722577*uk_75 + 2024293397*uk_76 + 1520552183*uk_77 + 2229805417*uk_78 + 1674922963*uk_79 + 163*uk_8 + 1258121857*uk_80 + 250047*uk_81 + 289737*uk_82 + 646947*uk_83 + 31752*uk_84 + 781893*uk_85 + 861273*uk_86 + 646947*uk_87 + 335727*uk_88 + 749637*uk_89 + 2242306609*uk_9 + 36792*uk_90 + 906003*uk_91 + 997983*uk_92 + 749637*uk_93 + 1673847*uk_94 + 82152*uk_95 + 2022993*uk_96 + 2228373*uk_97 + 1673847*uk_98 + 4032*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 150444*uk_100 + 164052*uk_101 + 55188*uk_102 + 2494863*uk_103 + 2720529*uk_104 + 915201*uk_105 + 2966607*uk_106 + 997983*uk_107 + 335727*uk_108 + 6859000*uk_109 + 8997070*uk_11 + 2635300*uk_110 + 433200*uk_111 + 7183900*uk_112 + 7833700*uk_113 + 2635300*uk_114 + 1012510*uk_115 + 166440*uk_116 + 2760130*uk_117 + 3009790*uk_118 + 1012510*uk_119 + 3456769*uk_12 + 27360*uk_120 + 453720*uk_121 + 494760*uk_122 + 166440*uk_123 + 7524190*uk_124 + 8204770*uk_125 + 2760130*uk_126 + 8946910*uk_127 + 3009790*uk_128 + 1012510*uk_129 + 568236*uk_13 + 389017*uk_130 + 63948*uk_131 + 1060471*uk_132 + 1156393*uk_133 + 389017*uk_134 + 10512*uk_135 + 174324*uk_136 + 190092*uk_137 + 63948*uk_138 + 2890873*uk_139 + 9423247*uk_14 + 3152359*uk_140 + 1060471*uk_141 + 3437497*uk_142 + 1156393*uk_143 + 389017*uk_144 + 1728*uk_145 + 28656*uk_146 + 31248*uk_147 + 10512*uk_148 + 475212*uk_149 + 10275601*uk_15 + 518196*uk_150 + 174324*uk_151 + 565068*uk_152 + 190092*uk_153 + 63948*uk_154 + 7880599*uk_155 + 8593417*uk_156 + 2890873*uk_157 + 9370711*uk_158 + 3152359*uk_159 + 3456769*uk_16 + 1060471*uk_160 + 10218313*uk_161 + 3437497*uk_162 + 1156393*uk_163 + 389017*uk_164 + 3969*uk_17 + 11970*uk_18 + 4599*uk_19 + 63*uk_2 + 756*uk_20 + 12537*uk_21 + 13671*uk_22 + 4599*uk_23 + 36100*uk_24 + 13870*uk_25 + 2280*uk_26 + 37810*uk_27 + 41230*uk_28 + 13870*uk_29 + 190*uk_3 + 5329*uk_30 + 876*uk_31 + 14527*uk_32 + 15841*uk_33 + 5329*uk_34 + 144*uk_35 + 2388*uk_36 + 2604*uk_37 + 876*uk_38 + 39601*uk_39 + 73*uk_4 + 43183*uk_40 + 14527*uk_41 + 47089*uk_42 + 15841*uk_43 + 5329*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 426038255710*uk_47 + 163688382457*uk_48 + 26907679308*uk_49 + 12*uk_5 + 446219015191*uk_50 + 486580534153*uk_51 + 163688382457*uk_52 + 187944057*uk_53 + 566815410*uk_54 + 217776447*uk_55 + 35798868*uk_56 + 593664561*uk_57 + 647362863*uk_58 + 217776447*uk_59 + 199*uk_6 + 1709443300*uk_60 + 656786110*uk_61 + 107964840*uk_62 + 1790416930*uk_63 + 1952364190*uk_64 + 656786110*uk_65 + 252344137*uk_66 + 41481228*uk_67 + 687897031*uk_68 + 750118873*uk_69 + 217*uk_7 + 252344137*uk_70 + 6818832*uk_71 + 113078964*uk_72 + 123307212*uk_73 + 41481228*uk_74 + 1875226153*uk_75 + 2044844599*uk_76 + 687897031*uk_77 + 2229805417*uk_78 + 750118873*uk_79 + 73*uk_8 + 252344137*uk_80 + 250047*uk_81 + 754110*uk_82 + 289737*uk_83 + 47628*uk_84 + 789831*uk_85 + 861273*uk_86 + 289737*uk_87 + 2274300*uk_88 + 873810*uk_89 + 2242306609*uk_9 + 143640*uk_90 + 2382030*uk_91 + 2597490*uk_92 + 873810*uk_93 + 335727*uk_94 + 55188*uk_95 + 915201*uk_96 + 997983*uk_97 + 335727*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 101304*uk_100 + 109368*uk_101 + 95760*uk_102 + 2545263*uk_103 + 2747871*uk_104 + 2405970*uk_105 + 2966607*uk_106 + 2597490*uk_107 + 2274300*uk_108 + 1643032*uk_109 + 5587654*uk_11 + 2645560*uk_110 + 111392*uk_111 + 2798724*uk_112 + 3021508*uk_113 + 2645560*uk_114 + 4259800*uk_115 + 179360*uk_116 + 4506420*uk_117 + 4865140*uk_118 + 4259800*uk_119 + 8997070*uk_12 + 7552*uk_120 + 189744*uk_121 + 204848*uk_122 + 179360*uk_123 + 4767318*uk_124 + 5146806*uk_125 + 4506420*uk_126 + 5556502*uk_127 + 4865140*uk_128 + 4259800*uk_129 + 378824*uk_13 + 6859000*uk_130 + 288800*uk_131 + 7256100*uk_132 + 7833700*uk_133 + 6859000*uk_134 + 12160*uk_135 + 305520*uk_136 + 329840*uk_137 + 288800*uk_138 + 7676190*uk_139 + 9517953*uk_14 + 8287230*uk_140 + 7256100*uk_141 + 8946910*uk_142 + 7833700*uk_143 + 6859000*uk_144 + 512*uk_145 + 12864*uk_146 + 13888*uk_147 + 12160*uk_148 + 323208*uk_149 + 10275601*uk_15 + 348936*uk_150 + 305520*uk_151 + 376712*uk_152 + 329840*uk_153 + 288800*uk_154 + 8120601*uk_155 + 8767017*uk_156 + 7676190*uk_157 + 9464889*uk_158 + 8287230*uk_159 + 8997070*uk_16 + 7256100*uk_160 + 10218313*uk_161 + 8946910*uk_162 + 7833700*uk_163 + 6859000*uk_164 + 3969*uk_17 + 7434*uk_18 + 11970*uk_19 + 63*uk_2 + 504*uk_20 + 12663*uk_21 + 13671*uk_22 + 11970*uk_23 + 13924*uk_24 + 22420*uk_25 + 944*uk_26 + 23718*uk_27 + 25606*uk_28 + 22420*uk_29 + 118*uk_3 + 36100*uk_30 + 1520*uk_31 + 38190*uk_32 + 41230*uk_33 + 36100*uk_34 + 64*uk_35 + 1608*uk_36 + 1736*uk_37 + 1520*uk_38 + 40401*uk_39 + 190*uk_4 + 43617*uk_40 + 38190*uk_41 + 47089*uk_42 + 41230*uk_43 + 36100*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 264592179862*uk_47 + 426038255710*uk_48 + 17938452872*uk_49 + 8*uk_5 + 450703628409*uk_50 + 486580534153*uk_51 + 426038255710*uk_52 + 187944057*uk_53 + 352022202*uk_54 + 566815410*uk_55 + 23865912*uk_56 + 599631039*uk_57 + 647362863*uk_58 + 566815410*uk_59 + 201*uk_6 + 659343172*uk_60 + 1061654260*uk_61 + 44701232*uk_62 + 1123118454*uk_63 + 1212520918*uk_64 + 1061654260*uk_65 + 1709443300*uk_66 + 71976560*uk_67 + 1808411070*uk_68 + 1952364190*uk_69 + 217*uk_7 + 1709443300*uk_70 + 3030592*uk_71 + 76143624*uk_72 + 82204808*uk_73 + 71976560*uk_74 + 1913108553*uk_75 + 2065395801*uk_76 + 1808411070*uk_77 + 2229805417*uk_78 + 1952364190*uk_79 + 190*uk_8 + 1709443300*uk_80 + 250047*uk_81 + 468342*uk_82 + 754110*uk_83 + 31752*uk_84 + 797769*uk_85 + 861273*uk_86 + 754110*uk_87 + 877212*uk_88 + 1412460*uk_89 + 2242306609*uk_9 + 59472*uk_90 + 1494234*uk_91 + 1613178*uk_92 + 1412460*uk_93 + 2274300*uk_94 + 95760*uk_95 + 2405970*uk_96 + 2597490*uk_97 + 2274300*uk_98 + 4032*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 102312*uk_100 + 109368*uk_101 + 59472*uk_102 + 2596167*uk_103 + 2775213*uk_104 + 1509102*uk_105 + 2966607*uk_106 + 1613178*uk_107 + 877212*uk_108 + 157464*uk_109 + 2557062*uk_11 + 344088*uk_110 + 23328*uk_111 + 591948*uk_112 + 632772*uk_113 + 344088*uk_114 + 751896*uk_115 + 50976*uk_116 + 1293516*uk_117 + 1382724*uk_118 + 751896*uk_119 + 5587654*uk_12 + 3456*uk_120 + 87696*uk_121 + 93744*uk_122 + 50976*uk_123 + 2225286*uk_124 + 2378754*uk_125 + 1293516*uk_126 + 2542806*uk_127 + 1382724*uk_128 + 751896*uk_129 + 378824*uk_13 + 1643032*uk_130 + 111392*uk_131 + 2826572*uk_132 + 3021508*uk_133 + 1643032*uk_134 + 7552*uk_135 + 191632*uk_136 + 204848*uk_137 + 111392*uk_138 + 4862662*uk_139 + 9612659*uk_14 + 5198018*uk_140 + 2826572*uk_141 + 5556502*uk_142 + 3021508*uk_143 + 1643032*uk_144 + 512*uk_145 + 12992*uk_146 + 13888*uk_147 + 7552*uk_148 + 329672*uk_149 + 10275601*uk_15 + 352408*uk_150 + 191632*uk_151 + 376712*uk_152 + 204848*uk_153 + 111392*uk_154 + 8365427*uk_155 + 8942353*uk_156 + 4862662*uk_157 + 9559067*uk_158 + 5198018*uk_159 + 5587654*uk_16 + 2826572*uk_160 + 10218313*uk_161 + 5556502*uk_162 + 3021508*uk_163 + 1643032*uk_164 + 3969*uk_17 + 3402*uk_18 + 7434*uk_19 + 63*uk_2 + 504*uk_20 + 12789*uk_21 + 13671*uk_22 + 7434*uk_23 + 2916*uk_24 + 6372*uk_25 + 432*uk_26 + 10962*uk_27 + 11718*uk_28 + 6372*uk_29 + 54*uk_3 + 13924*uk_30 + 944*uk_31 + 23954*uk_32 + 25606*uk_33 + 13924*uk_34 + 64*uk_35 + 1624*uk_36 + 1736*uk_37 + 944*uk_38 + 41209*uk_39 + 118*uk_4 + 44051*uk_40 + 23954*uk_41 + 47089*uk_42 + 25606*uk_43 + 13924*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 121084556886*uk_47 + 264592179862*uk_48 + 17938452872*uk_49 + 8*uk_5 + 455188241627*uk_50 + 486580534153*uk_51 + 264592179862*uk_52 + 187944057*uk_53 + 161094906*uk_54 + 352022202*uk_55 + 23865912*uk_56 + 605597517*uk_57 + 647362863*uk_58 + 352022202*uk_59 + 203*uk_6 + 138081348*uk_60 + 301733316*uk_61 + 20456496*uk_62 + 519083586*uk_63 + 554882454*uk_64 + 301733316*uk_65 + 659343172*uk_66 + 44701232*uk_67 + 1134293762*uk_68 + 1212520918*uk_69 + 217*uk_7 + 659343172*uk_70 + 3030592*uk_71 + 76901272*uk_72 + 82204808*uk_73 + 44701232*uk_74 + 1951369777*uk_75 + 2085947003*uk_76 + 1134293762*uk_77 + 2229805417*uk_78 + 1212520918*uk_79 + 118*uk_8 + 659343172*uk_80 + 250047*uk_81 + 214326*uk_82 + 468342*uk_83 + 31752*uk_84 + 805707*uk_85 + 861273*uk_86 + 468342*uk_87 + 183708*uk_88 + 401436*uk_89 + 2242306609*uk_9 + 27216*uk_90 + 690606*uk_91 + 738234*uk_92 + 401436*uk_93 + 877212*uk_94 + 59472*uk_95 + 1509102*uk_96 + 1613178*uk_97 + 877212*uk_98 + 4032*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 154980*uk_100 + 164052*uk_101 + 40824*uk_102 + 2647575*uk_103 + 2802555*uk_104 + 697410*uk_105 + 2966607*uk_106 + 738234*uk_107 + 183708*uk_108 + 8365427*uk_109 + 9612659*uk_11 + 2225286*uk_110 + 494508*uk_111 + 8447845*uk_112 + 8942353*uk_113 + 2225286*uk_114 + 591948*uk_115 + 131544*uk_116 + 2247210*uk_117 + 2378754*uk_118 + 591948*uk_119 + 2557062*uk_12 + 29232*uk_120 + 499380*uk_121 + 528612*uk_122 + 131544*uk_123 + 8531075*uk_124 + 9030455*uk_125 + 2247210*uk_126 + 9559067*uk_127 + 2378754*uk_128 + 591948*uk_129 + 568236*uk_13 + 157464*uk_130 + 34992*uk_131 + 597780*uk_132 + 632772*uk_133 + 157464*uk_134 + 7776*uk_135 + 132840*uk_136 + 140616*uk_137 + 34992*uk_138 + 2269350*uk_139 + 9707365*uk_14 + 2402190*uk_140 + 597780*uk_141 + 2542806*uk_142 + 632772*uk_143 + 157464*uk_144 + 1728*uk_145 + 29520*uk_146 + 31248*uk_147 + 7776*uk_148 + 504300*uk_149 + 10275601*uk_15 + 533820*uk_150 + 132840*uk_151 + 565068*uk_152 + 140616*uk_153 + 34992*uk_154 + 8615125*uk_155 + 9119425*uk_156 + 2269350*uk_157 + 9653245*uk_158 + 2402190*uk_159 + 2557062*uk_16 + 597780*uk_160 + 10218313*uk_161 + 2542806*uk_162 + 632772*uk_163 + 157464*uk_164 + 3969*uk_17 + 12789*uk_18 + 3402*uk_19 + 63*uk_2 + 756*uk_20 + 12915*uk_21 + 13671*uk_22 + 3402*uk_23 + 41209*uk_24 + 10962*uk_25 + 2436*uk_26 + 41615*uk_27 + 44051*uk_28 + 10962*uk_29 + 203*uk_3 + 2916*uk_30 + 648*uk_31 + 11070*uk_32 + 11718*uk_33 + 2916*uk_34 + 144*uk_35 + 2460*uk_36 + 2604*uk_37 + 648*uk_38 + 42025*uk_39 + 54*uk_4 + 44485*uk_40 + 11070*uk_41 + 47089*uk_42 + 11718*uk_43 + 2916*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 455188241627*uk_47 + 121084556886*uk_48 + 26907679308*uk_49 + 12*uk_5 + 459672854845*uk_50 + 486580534153*uk_51 + 121084556886*uk_52 + 187944057*uk_53 + 605597517*uk_54 + 161094906*uk_55 + 35798868*uk_56 + 611563995*uk_57 + 647362863*uk_58 + 161094906*uk_59 + 205*uk_6 + 1951369777*uk_60 + 519083586*uk_61 + 115351908*uk_62 + 1970595095*uk_63 + 2085947003*uk_64 + 519083586*uk_65 + 138081348*uk_66 + 30684744*uk_67 + 524197710*uk_68 + 554882454*uk_69 + 217*uk_7 + 138081348*uk_70 + 6818832*uk_71 + 116488380*uk_72 + 123307212*uk_73 + 30684744*uk_74 + 1990009825*uk_75 + 2106498205*uk_76 + 524197710*uk_77 + 2229805417*uk_78 + 554882454*uk_79 + 54*uk_8 + 138081348*uk_80 + 250047*uk_81 + 805707*uk_82 + 214326*uk_83 + 47628*uk_84 + 813645*uk_85 + 861273*uk_86 + 214326*uk_87 + 2596167*uk_88 + 690606*uk_89 + 2242306609*uk_9 + 153468*uk_90 + 2621745*uk_91 + 2775213*uk_92 + 690606*uk_93 + 183708*uk_94 + 40824*uk_95 + 697410*uk_96 + 738234*uk_97 + 183708*uk_98 + 9072*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 104328*uk_100 + 109368*uk_101 + 102312*uk_102 + 2699487*uk_103 + 2829897*uk_104 + 2647323*uk_105 + 2966607*uk_106 + 2775213*uk_107 + 2596167*uk_108 + 3869893*uk_109 + 7434421*uk_11 + 5003747*uk_110 + 197192*uk_111 + 5102343*uk_112 + 5348833*uk_113 + 5003747*uk_114 + 6469813*uk_115 + 254968*uk_116 + 6597297*uk_117 + 6916007*uk_118 + 6469813*uk_119 + 9612659*uk_12 + 10048*uk_120 + 259992*uk_121 + 272552*uk_122 + 254968*uk_123 + 6727293*uk_124 + 7052283*uk_125 + 6597297*uk_126 + 7392973*uk_127 + 6916007*uk_128 + 6469813*uk_129 + 378824*uk_13 + 8365427*uk_130 + 329672*uk_131 + 8530263*uk_132 + 8942353*uk_133 + 8365427*uk_134 + 12992*uk_135 + 336168*uk_136 + 352408*uk_137 + 329672*uk_138 + 8698347*uk_139 + 9802071*uk_14 + 9118557*uk_140 + 8530263*uk_141 + 9559067*uk_142 + 8942353*uk_143 + 8365427*uk_144 + 512*uk_145 + 13248*uk_146 + 13888*uk_147 + 12992*uk_148 + 342792*uk_149 + 10275601*uk_15 + 359352*uk_150 + 336168*uk_151 + 376712*uk_152 + 352408*uk_153 + 329672*uk_154 + 8869743*uk_155 + 9298233*uk_156 + 8698347*uk_157 + 9747423*uk_158 + 9118557*uk_159 + 9612659*uk_16 + 8530263*uk_160 + 10218313*uk_161 + 9559067*uk_162 + 8942353*uk_163 + 8365427*uk_164 + 3969*uk_17 + 9891*uk_18 + 12789*uk_19 + 63*uk_2 + 504*uk_20 + 13041*uk_21 + 13671*uk_22 + 12789*uk_23 + 24649*uk_24 + 31871*uk_25 + 1256*uk_26 + 32499*uk_27 + 34069*uk_28 + 31871*uk_29 + 157*uk_3 + 41209*uk_30 + 1624*uk_31 + 42021*uk_32 + 44051*uk_33 + 41209*uk_34 + 64*uk_35 + 1656*uk_36 + 1736*uk_37 + 1624*uk_38 + 42849*uk_39 + 203*uk_4 + 44919*uk_40 + 42021*uk_41 + 47089*uk_42 + 44051*uk_43 + 41209*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 352042137613*uk_47 + 455188241627*uk_48 + 17938452872*uk_49 + 8*uk_5 + 464157468063*uk_50 + 486580534153*uk_51 + 455188241627*uk_52 + 187944057*uk_53 + 468368523*uk_54 + 605597517*uk_55 + 23865912*uk_56 + 617530473*uk_57 + 647362863*uk_58 + 605597517*uk_59 + 207*uk_6 + 1167204097*uk_60 + 1509187463*uk_61 + 59475368*uk_62 + 1538925147*uk_63 + 1613269357*uk_64 + 1509187463*uk_65 + 1951369777*uk_66 + 76901272*uk_67 + 1989820413*uk_68 + 2085947003*uk_69 + 217*uk_7 + 1951369777*uk_70 + 3030592*uk_71 + 78416568*uk_72 + 82204808*uk_73 + 76901272*uk_74 + 2029028697*uk_75 + 2127049407*uk_76 + 1989820413*uk_77 + 2229805417*uk_78 + 2085947003*uk_79 + 203*uk_8 + 1951369777*uk_80 + 250047*uk_81 + 623133*uk_82 + 805707*uk_83 + 31752*uk_84 + 821583*uk_85 + 861273*uk_86 + 805707*uk_87 + 1552887*uk_88 + 2007873*uk_89 + 2242306609*uk_9 + 79128*uk_90 + 2047437*uk_91 + 2146347*uk_92 + 2007873*uk_93 + 2596167*uk_94 + 102312*uk_95 + 2647323*uk_96 + 2775213*uk_97 + 2596167*uk_98 + 4032*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 105336*uk_100 + 109368*uk_101 + 79128*uk_102 + 2751903*uk_103 + 2857239*uk_104 + 2067219*uk_105 + 2966607*uk_106 + 2146347*uk_107 + 1552887*uk_108 + 1685159*uk_109 + 5635007*uk_11 + 2223277*uk_110 + 113288*uk_111 + 2959649*uk_112 + 3072937*uk_113 + 2223277*uk_114 + 2933231*uk_115 + 149464*uk_116 + 3904747*uk_117 + 4054211*uk_118 + 2933231*uk_119 + 7434421*uk_12 + 7616*uk_120 + 198968*uk_121 + 206584*uk_122 + 149464*uk_123 + 5198039*uk_124 + 5397007*uk_125 + 3904747*uk_126 + 5603591*uk_127 + 4054211*uk_128 + 2933231*uk_129 + 378824*uk_13 + 3869893*uk_130 + 197192*uk_131 + 5151641*uk_132 + 5348833*uk_133 + 3869893*uk_134 + 10048*uk_135 + 262504*uk_136 + 272552*uk_137 + 197192*uk_138 + 6857917*uk_139 + 9896777*uk_14 + 7120421*uk_140 + 5151641*uk_141 + 7392973*uk_142 + 5348833*uk_143 + 3869893*uk_144 + 512*uk_145 + 13376*uk_146 + 13888*uk_147 + 10048*uk_148 + 349448*uk_149 + 10275601*uk_15 + 362824*uk_150 + 262504*uk_151 + 376712*uk_152 + 272552*uk_153 + 197192*uk_154 + 9129329*uk_155 + 9478777*uk_156 + 6857917*uk_157 + 9841601*uk_158 + 7120421*uk_159 + 7434421*uk_16 + 5151641*uk_160 + 10218313*uk_161 + 7392973*uk_162 + 5348833*uk_163 + 3869893*uk_164 + 3969*uk_17 + 7497*uk_18 + 9891*uk_19 + 63*uk_2 + 504*uk_20 + 13167*uk_21 + 13671*uk_22 + 9891*uk_23 + 14161*uk_24 + 18683*uk_25 + 952*uk_26 + 24871*uk_27 + 25823*uk_28 + 18683*uk_29 + 119*uk_3 + 24649*uk_30 + 1256*uk_31 + 32813*uk_32 + 34069*uk_33 + 24649*uk_34 + 64*uk_35 + 1672*uk_36 + 1736*uk_37 + 1256*uk_38 + 43681*uk_39 + 157*uk_4 + 45353*uk_40 + 32813*uk_41 + 47089*uk_42 + 34069*uk_43 + 24649*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 266834486471*uk_47 + 352042137613*uk_48 + 17938452872*uk_49 + 8*uk_5 + 468642081281*uk_50 + 486580534153*uk_51 + 352042137613*uk_52 + 187944057*uk_53 + 355005441*uk_54 + 468368523*uk_55 + 23865912*uk_56 + 623496951*uk_57 + 647362863*uk_58 + 468368523*uk_59 + 209*uk_6 + 670565833*uk_60 + 884696099*uk_61 + 45080056*uk_62 + 1177716463*uk_63 + 1222796519*uk_64 + 884696099*uk_65 + 1167204097*uk_66 + 59475368*uk_67 + 1553793989*uk_68 + 1613269357*uk_69 + 217*uk_7 + 1167204097*uk_70 + 3030592*uk_71 + 79174216*uk_72 + 82204808*uk_73 + 59475368*uk_74 + 2068426393*uk_75 + 2147600609*uk_76 + 1553793989*uk_77 + 2229805417*uk_78 + 1613269357*uk_79 + 157*uk_8 + 1167204097*uk_80 + 250047*uk_81 + 472311*uk_82 + 623133*uk_83 + 31752*uk_84 + 829521*uk_85 + 861273*uk_86 + 623133*uk_87 + 892143*uk_88 + 1177029*uk_89 + 2242306609*uk_9 + 59976*uk_90 + 1566873*uk_91 + 1626849*uk_92 + 1177029*uk_93 + 1552887*uk_94 + 79128*uk_95 + 2067219*uk_96 + 2146347*uk_97 + 1552887*uk_98 + 4032*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 106344*uk_100 + 109368*uk_101 + 59976*uk_102 + 2804823*uk_103 + 2884581*uk_104 + 1581867*uk_105 + 2966607*uk_106 + 1626849*uk_107 + 892143*uk_108 + 704969*uk_109 + 4214417*uk_11 + 942599*uk_110 + 63368*uk_111 + 1671331*uk_112 + 1718857*uk_113 + 942599*uk_114 + 1260329*uk_115 + 84728*uk_116 + 2234701*uk_117 + 2298247*uk_118 + 1260329*uk_119 + 5635007*uk_12 + 5696*uk_120 + 150232*uk_121 + 154504*uk_122 + 84728*uk_123 + 3962369*uk_124 + 4075043*uk_125 + 2234701*uk_126 + 4190921*uk_127 + 2298247*uk_128 + 1260329*uk_129 + 378824*uk_13 + 1685159*uk_130 + 113288*uk_131 + 2987971*uk_132 + 3072937*uk_133 + 1685159*uk_134 + 7616*uk_135 + 200872*uk_136 + 206584*uk_137 + 113288*uk_138 + 5297999*uk_139 + 9991483*uk_14 + 5448653*uk_140 + 2987971*uk_141 + 5603591*uk_142 + 3072937*uk_143 + 1685159*uk_144 + 512*uk_145 + 13504*uk_146 + 13888*uk_147 + 7616*uk_148 + 356168*uk_149 + 10275601*uk_15 + 366296*uk_150 + 200872*uk_151 + 376712*uk_152 + 206584*uk_153 + 113288*uk_154 + 9393931*uk_155 + 9661057*uk_156 + 5297999*uk_157 + 9935779*uk_158 + 5448653*uk_159 + 5635007*uk_16 + 2987971*uk_160 + 10218313*uk_161 + 5603591*uk_162 + 3072937*uk_163 + 1685159*uk_164 + 3969*uk_17 + 5607*uk_18 + 7497*uk_19 + 63*uk_2 + 504*uk_20 + 13293*uk_21 + 13671*uk_22 + 7497*uk_23 + 7921*uk_24 + 10591*uk_25 + 712*uk_26 + 18779*uk_27 + 19313*uk_28 + 10591*uk_29 + 89*uk_3 + 14161*uk_30 + 952*uk_31 + 25109*uk_32 + 25823*uk_33 + 14161*uk_34 + 64*uk_35 + 1688*uk_36 + 1736*uk_37 + 952*uk_38 + 44521*uk_39 + 119*uk_4 + 45787*uk_40 + 25109*uk_41 + 47089*uk_42 + 25823*uk_43 + 14161*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 199565288201*uk_47 + 266834486471*uk_48 + 17938452872*uk_49 + 8*uk_5 + 473126694499*uk_50 + 486580534153*uk_51 + 266834486471*uk_52 + 187944057*uk_53 + 265508271*uk_54 + 355005441*uk_55 + 23865912*uk_56 + 629463429*uk_57 + 647362863*uk_58 + 355005441*uk_59 + 211*uk_6 + 375083113*uk_60 + 501515623*uk_61 + 33715336*uk_62 + 889241987*uk_63 + 914528489*uk_64 + 501515623*uk_65 + 670565833*uk_66 + 45080056*uk_67 + 1188986477*uk_68 + 1222796519*uk_69 + 217*uk_7 + 670565833*uk_70 + 3030592*uk_71 + 79931864*uk_72 + 82204808*uk_73 + 45080056*uk_74 + 2108202913*uk_75 + 2168151811*uk_76 + 1188986477*uk_77 + 2229805417*uk_78 + 1222796519*uk_79 + 119*uk_8 + 670565833*uk_80 + 250047*uk_81 + 353241*uk_82 + 472311*uk_83 + 31752*uk_84 + 837459*uk_85 + 861273*uk_86 + 472311*uk_87 + 499023*uk_88 + 667233*uk_89 + 2242306609*uk_9 + 44856*uk_90 + 1183077*uk_91 + 1216719*uk_92 + 667233*uk_93 + 892143*uk_94 + 59976*uk_95 + 1581867*uk_96 + 1626849*uk_97 + 892143*uk_98 + 4032*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 107352*uk_100 + 109368*uk_101 + 44856*uk_102 + 2858247*uk_103 + 2911923*uk_104 + 1194291*uk_105 + 2966607*uk_106 + 1216719*uk_107 + 499023*uk_108 + 300763*uk_109 + 3172651*uk_11 + 399521*uk_110 + 35912*uk_111 + 956157*uk_112 + 974113*uk_113 + 399521*uk_114 + 530707*uk_115 + 47704*uk_116 + 1270119*uk_117 + 1293971*uk_118 + 530707*uk_119 + 4214417*uk_12 + 4288*uk_120 + 114168*uk_121 + 116312*uk_122 + 47704*uk_123 + 3039723*uk_124 + 3096807*uk_125 + 1270119*uk_126 + 3154963*uk_127 + 1293971*uk_128 + 530707*uk_129 + 378824*uk_13 + 704969*uk_130 + 63368*uk_131 + 1687173*uk_132 + 1718857*uk_133 + 704969*uk_134 + 5696*uk_135 + 151656*uk_136 + 154504*uk_137 + 63368*uk_138 + 4037841*uk_139 + 10086189*uk_14 + 4113669*uk_140 + 1687173*uk_141 + 4190921*uk_142 + 1718857*uk_143 + 704969*uk_144 + 512*uk_145 + 13632*uk_146 + 13888*uk_147 + 5696*uk_148 + 362952*uk_149 + 10275601*uk_15 + 369768*uk_150 + 151656*uk_151 + 376712*uk_152 + 154504*uk_153 + 63368*uk_154 + 9663597*uk_155 + 9845073*uk_156 + 4037841*uk_157 + 10029957*uk_158 + 4113669*uk_159 + 4214417*uk_16 + 1687173*uk_160 + 10218313*uk_161 + 4190921*uk_162 + 1718857*uk_163 + 704969*uk_164 + 3969*uk_17 + 4221*uk_18 + 5607*uk_19 + 63*uk_2 + 504*uk_20 + 13419*uk_21 + 13671*uk_22 + 5607*uk_23 + 4489*uk_24 + 5963*uk_25 + 536*uk_26 + 14271*uk_27 + 14539*uk_28 + 5963*uk_29 + 67*uk_3 + 7921*uk_30 + 712*uk_31 + 18957*uk_32 + 19313*uk_33 + 7921*uk_34 + 64*uk_35 + 1704*uk_36 + 1736*uk_37 + 712*uk_38 + 45369*uk_39 + 89*uk_4 + 46221*uk_40 + 18957*uk_41 + 47089*uk_42 + 19313*uk_43 + 7921*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 150234542803*uk_47 + 199565288201*uk_48 + 17938452872*uk_49 + 8*uk_5 + 477611307717*uk_50 + 486580534153*uk_51 + 199565288201*uk_52 + 187944057*uk_53 + 199877013*uk_54 + 265508271*uk_55 + 23865912*uk_56 + 635429907*uk_57 + 647362863*uk_58 + 265508271*uk_59 + 213*uk_6 + 212567617*uk_60 + 282365939*uk_61 + 25381208*uk_62 + 675774663*uk_63 + 688465267*uk_64 + 282365939*uk_65 + 375083113*uk_66 + 33715336*uk_67 + 897670821*uk_68 + 914528489*uk_69 + 217*uk_7 + 375083113*uk_70 + 3030592*uk_71 + 80689512*uk_72 + 82204808*uk_73 + 33715336*uk_74 + 2148358257*uk_75 + 2188703013*uk_76 + 897670821*uk_77 + 2229805417*uk_78 + 914528489*uk_79 + 89*uk_8 + 375083113*uk_80 + 250047*uk_81 + 265923*uk_82 + 353241*uk_83 + 31752*uk_84 + 845397*uk_85 + 861273*uk_86 + 353241*uk_87 + 282807*uk_88 + 375669*uk_89 + 2242306609*uk_9 + 33768*uk_90 + 899073*uk_91 + 915957*uk_92 + 375669*uk_93 + 499023*uk_94 + 44856*uk_95 + 1194291*uk_96 + 1216719*uk_97 + 499023*uk_98 + 4032*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 108360*uk_100 + 109368*uk_101 + 33768*uk_102 + 2912175*uk_103 + 2939265*uk_104 + 907515*uk_105 + 2966607*uk_106 + 915957*uk_107 + 282807*uk_108 + 148877*uk_109 + 2509709*uk_11 + 188203*uk_110 + 22472*uk_111 + 603935*uk_112 + 609553*uk_113 + 188203*uk_114 + 237917*uk_115 + 28408*uk_116 + 763465*uk_117 + 770567*uk_118 + 237917*uk_119 + 3172651*uk_12 + 3392*uk_120 + 91160*uk_121 + 92008*uk_122 + 28408*uk_123 + 2449925*uk_124 + 2472715*uk_125 + 763465*uk_126 + 2495717*uk_127 + 770567*uk_128 + 237917*uk_129 + 378824*uk_13 + 300763*uk_130 + 35912*uk_131 + 965135*uk_132 + 974113*uk_133 + 300763*uk_134 + 4288*uk_135 + 115240*uk_136 + 116312*uk_137 + 35912*uk_138 + 3097075*uk_139 + 10180895*uk_14 + 3125885*uk_140 + 965135*uk_141 + 3154963*uk_142 + 974113*uk_143 + 300763*uk_144 + 512*uk_145 + 13760*uk_146 + 13888*uk_147 + 4288*uk_148 + 369800*uk_149 + 10275601*uk_15 + 373240*uk_150 + 115240*uk_151 + 376712*uk_152 + 116312*uk_153 + 35912*uk_154 + 9938375*uk_155 + 10030825*uk_156 + 3097075*uk_157 + 10124135*uk_158 + 3125885*uk_159 + 3172651*uk_16 + 965135*uk_160 + 10218313*uk_161 + 3154963*uk_162 + 974113*uk_163 + 300763*uk_164 + 3969*uk_17 + 3339*uk_18 + 4221*uk_19 + 63*uk_2 + 504*uk_20 + 13545*uk_21 + 13671*uk_22 + 4221*uk_23 + 2809*uk_24 + 3551*uk_25 + 424*uk_26 + 11395*uk_27 + 11501*uk_28 + 3551*uk_29 + 53*uk_3 + 4489*uk_30 + 536*uk_31 + 14405*uk_32 + 14539*uk_33 + 4489*uk_34 + 64*uk_35 + 1720*uk_36 + 1736*uk_37 + 536*uk_38 + 46225*uk_39 + 67*uk_4 + 46655*uk_40 + 14405*uk_41 + 47089*uk_42 + 14539*uk_43 + 4489*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 118842250277*uk_47 + 150234542803*uk_48 + 17938452872*uk_49 + 8*uk_5 + 482095920935*uk_50 + 486580534153*uk_51 + 150234542803*uk_52 + 187944057*uk_53 + 158111667*uk_54 + 199877013*uk_55 + 23865912*uk_56 + 641396385*uk_57 + 647362863*uk_58 + 199877013*uk_59 + 215*uk_6 + 133014577*uk_60 + 168150503*uk_61 + 20077672*uk_62 + 539587435*uk_63 + 544606853*uk_64 + 168150503*uk_65 + 212567617*uk_66 + 25381208*uk_67 + 682119965*uk_68 + 688465267*uk_69 + 217*uk_7 + 212567617*uk_70 + 3030592*uk_71 + 81447160*uk_72 + 82204808*uk_73 + 25381208*uk_74 + 2188892425*uk_75 + 2209254215*uk_76 + 682119965*uk_77 + 2229805417*uk_78 + 688465267*uk_79 + 67*uk_8 + 212567617*uk_80 + 250047*uk_81 + 210357*uk_82 + 265923*uk_83 + 31752*uk_84 + 853335*uk_85 + 861273*uk_86 + 265923*uk_87 + 176967*uk_88 + 223713*uk_89 + 2242306609*uk_9 + 26712*uk_90 + 717885*uk_91 + 724563*uk_92 + 223713*uk_93 + 282807*uk_94 + 33768*uk_95 + 907515*uk_96 + 915957*uk_97 + 282807*uk_98 + 4032*uk_99, + uk_0 + 47353*uk_1 + 2983239*uk_10 + 109368*uk_100 + 109368*uk_101 + 26712*uk_102 + 2966607*uk_103 + 2966607*uk_104 + 724563*uk_105 + 2966607*uk_106 + 724563*uk_107 + 176967*uk_108 + 103823*uk_109 + 2225591*uk_11 + 117077*uk_110 + 17672*uk_111 + 479353*uk_112 + 479353*uk_113 + 117077*uk_114 + 132023*uk_115 + 19928*uk_116 + 540547*uk_117 + 540547*uk_118 + 132023*uk_119 + 2509709*uk_12 + 3008*uk_120 + 81592*uk_121 + 81592*uk_122 + 19928*uk_123 + 2213183*uk_124 + 2213183*uk_125 + 540547*uk_126 + 2213183*uk_127 + 540547*uk_128 + 132023*uk_129 + 378824*uk_13 + 148877*uk_130 + 22472*uk_131 + 609553*uk_132 + 609553*uk_133 + 148877*uk_134 + 3392*uk_135 + 92008*uk_136 + 92008*uk_137 + 22472*uk_138 + 2495717*uk_139 + 10275601*uk_14 + 2495717*uk_140 + 609553*uk_141 + 2495717*uk_142 + 609553*uk_143 + 148877*uk_144 + 512*uk_145 + 13888*uk_146 + 13888*uk_147 + 3392*uk_148 + 376712*uk_149 + 10275601*uk_15 + 376712*uk_150 + 92008*uk_151 + 376712*uk_152 + 92008*uk_153 + 22472*uk_154 + 10218313*uk_155 + 10218313*uk_156 + 2495717*uk_157 + 10218313*uk_158 + 2495717*uk_159 + 2509709*uk_16 + 609553*uk_160 + 10218313*uk_161 + 2495717*uk_162 + 609553*uk_163 + 148877*uk_164 + 3969*uk_17 + 2961*uk_18 + 3339*uk_19 + 63*uk_2 + 504*uk_20 + 13671*uk_21 + 13671*uk_22 + 3339*uk_23 + 2209*uk_24 + 2491*uk_25 + 376*uk_26 + 10199*uk_27 + 10199*uk_28 + 2491*uk_29 + 47*uk_3 + 2809*uk_30 + 424*uk_31 + 11501*uk_32 + 11501*uk_33 + 2809*uk_34 + 64*uk_35 + 1736*uk_36 + 1736*uk_37 + 424*uk_38 + 47089*uk_39 + 53*uk_4 + 47089*uk_40 + 11501*uk_41 + 47089*uk_42 + 11501*uk_43 + 2809*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 105388410623*uk_47 + 118842250277*uk_48 + 17938452872*uk_49 + 8*uk_5 + 486580534153*uk_50 + 486580534153*uk_51 + 118842250277*uk_52 + 187944057*uk_53 + 140212233*uk_54 + 158111667*uk_55 + 23865912*uk_56 + 647362863*uk_57 + 647362863*uk_58 + 158111667*uk_59 + 217*uk_6 + 104602777*uk_60 + 117956323*uk_61 + 17804728*uk_62 + 482953247*uk_63 + 482953247*uk_64 + 117956323*uk_65 + 133014577*uk_66 + 20077672*uk_67 + 544606853*uk_68 + 544606853*uk_69 + 217*uk_7 + 133014577*uk_70 + 3030592*uk_71 + 82204808*uk_72 + 82204808*uk_73 + 20077672*uk_74 + 2229805417*uk_75 + 2229805417*uk_76 + 544606853*uk_77 + 2229805417*uk_78 + 544606853*uk_79 + 53*uk_8 + 133014577*uk_80 + 250047*uk_81 + 186543*uk_82 + 210357*uk_83 + 31752*uk_84 + 861273*uk_85 + 861273*uk_86 + 210357*uk_87 + 139167*uk_88 + 156933*uk_89 + 2242306609*uk_9 + 23688*uk_90 + 642537*uk_91 + 642537*uk_92 + 156933*uk_93 + 176967*uk_94 + 26712*uk_95 + 724563*uk_96 + 724563*uk_97 + 176967*uk_98 + 4032*uk_99, + ] + +def sol_165x165(): + return { + uk_0: -QQ(295441,1683)*uk_2 - QQ(175799,1683)*uk_7 + QQ(2401696807,1)*uk_9 - QQ(9606787228,1683)*uk_10 + QQ(9606787228,1683)*uk_15 - QQ(29030443,1683)*uk_17 - QQ(5965893,187)*uk_22 + QQ(262901,99)*uk_42 + QQ(235539209256104,1)*uk_45 - QQ(232597130667529,1683)*uk_46 + QQ(1364372733998209,1683)*uk_51 - QQ(1133600892904,1683)*uk_53 - QQ(172922170104,187)*uk_58 + QQ(249776467928,99)*uk_78 - QQ(2401889209,1683)*uk_81 - QQ(636292759,187)*uk_86 - QQ(1034157281,187)*uk_106 + QQ(10558824289,1683)*uk_161, + uk_1: QQ(4,1683)*uk_2 - QQ(4,1683)*uk_7 - QQ(98072,1)*uk_9 + QQ(96847,1683)*uk_10 - QQ(568087,1683)*uk_15 + QQ(472,1683)*uk_17 + QQ(72,187)*uk_22 - QQ(104,99)*uk_42 - QQ(7216420377,1)*uk_45 - QQ(108808244,1683)*uk_46 - QQ(46106641036,1683)*uk_51 + QQ(17259541,1683)*uk_53 + QQ(1095291,187)*uk_58 - QQ(9936587,99)*uk_78 + QQ(41836,1683)*uk_81 + QQ(10036,187)*uk_86 + QQ(10124,187)*uk_106 - QQ(8,1)*uk_149 - QQ(586156,1683)*uk_161, + uk_3: -QQ(295441,1683)*uk_18 - QQ(175799,1683)*uk_28 + QQ(2401696807,1)*uk_47 - QQ(9606787228,1683)*uk_54 + QQ(9606787228,1683)*uk_64 - QQ(29030443,1683)*uk_82 - QQ(5965893,187)*uk_92 + QQ(262901,99)*uk_127 + QQ(8,1)*uk_149, + uk_4: -QQ(295441,1683)*uk_19 + QQ(1602583,3366)*uk_29 - QQ(175799,1683)*uk_33 - QQ(45670,99)*uk_34 - QQ(76006,187)*uk_38 + QQ(295441,1683)*uk_41 - QQ(45670,99)*uk_44 + QQ(2401696807,1)*uk_48 - QQ(9606787228,1683)*uk_55 + QQ(74452601017,3366)*uk_65 + QQ(9606787228,1683)*uk_69 - QQ(2401696807,99)*uk_70 - QQ(4803393614,187)*uk_74 + QQ(9606787228,1683)*uk_77 - QQ(2401696807,99)*uk_80 - QQ(29030443,1683)*uk_83 + QQ(11596905,374)*uk_93 - QQ(5965893,187)*uk_97 - QQ(769658,33)*uk_98 - QQ(17335370,1683)*uk_102 + QQ(29030443,1683)*uk_105 - QQ(769658,33)*uk_108 + QQ(77314807,3366)*uk_114 + QQ(750229,198)*uk_119 + QQ(72457964,1683)*uk_123 + QQ(11596905,374)*uk_126 + QQ(31304645,306)*uk_128 + QQ(750229,198)*uk_129 - QQ(3191393,99)*uk_134 - QQ(647642,9)*uk_138 - QQ(769658,33)*uk_141 + QQ(262901,99)*uk_142 - QQ(10478626,99)*uk_143 - QQ(3191393,99)*uk_144 - QQ(20480616,187)*uk_148 - QQ(17335370,1683)*uk_151 - QQ(174199750,1683)*uk_153 - QQ(647642,9)*uk_154 + QQ(29030443,1683)*uk_157 + QQ(5965893,187)*uk_159 - QQ(769658,33)*uk_160 - QQ(10478626,99)*uk_163 - QQ(3191393,99)*uk_164, + uk_5: -QQ(295441,1683)*uk_20 - QQ(175799,1683)*uk_37 + QQ(2401696807,1)*uk_49 - QQ(9606787228,1683)*uk_56 + QQ(9606787228,1683)*uk_73 - QQ(29030443,1683)*uk_84 - QQ(5965893,187)*uk_101 + QQ(262901,99)*uk_152, + uk_6: -QQ(295441,1683)*uk_21 - QQ(175799,1683)*uk_40 + QQ(2401696807,1)*uk_50 - QQ(9606787228,1683)*uk_57 + QQ(9606787228,1683)*uk_76 - QQ(29030443,1683)*uk_85 - QQ(5965893,187)*uk_104 + QQ(262901,99)*uk_158, + uk_8: -QQ(295441,1683)*uk_23 - QQ(1602583,3366)*uk_29 + QQ(45670,99)*uk_34 + QQ(76006,187)*uk_38 - QQ(295441,1683)*uk_41 - QQ(175799,1683)*uk_43 + QQ(45670,99)*uk_44 + QQ(2401696807,1)*uk_52 - QQ(9606787228,1683)*uk_59 - QQ(74452601017,3366)*uk_65 + QQ(2401696807,99)*uk_70 + QQ(4803393614,187)*uk_74 - QQ(9606787228,1683)*uk_77 + QQ(9606787228,1683)*uk_79 + QQ(2401696807,99)*uk_80 - QQ(29030443,1683)*uk_87 - QQ(11596905,374)*uk_93 + QQ(769658,33)*uk_98 + QQ(17335370,1683)*uk_102 - QQ(29030443,1683)*uk_105 - QQ(5965893,187)*uk_107 + QQ(769658,33)*uk_108 - QQ(77314807,3366)*uk_114 - QQ(750229,198)*uk_119 - QQ(72457964,1683)*uk_123 - QQ(11596905,374)*uk_126 - QQ(31304645,306)*uk_128 - QQ(750229,198)*uk_129 + QQ(3191393,99)*uk_134 + QQ(647642,9)*uk_138 + QQ(769658,33)*uk_141 + QQ(10478626,99)*uk_143 + QQ(3191393,99)*uk_144 + QQ(20480616,187)*uk_148 + QQ(17335370,1683)*uk_151 + QQ(174199750,1683)*uk_153 + QQ(647642,9)*uk_154 - QQ(29030443,1683)*uk_157 - QQ(5965893,187)*uk_159 + QQ(769658,33)*uk_160 + QQ(262901,99)*uk_162 + QQ(10478626,99)*uk_163 + QQ(3191393,99)*uk_164, + uk_11: QQ(4,1683)*uk_18 - QQ(4,1683)*uk_28 - QQ(98072,1)*uk_47 + QQ(96847,1683)*uk_54 - QQ(568087,1683)*uk_64 + QQ(472,1683)*uk_82 + QQ(72,187)*uk_92 - QQ(104,99)*uk_127, + uk_12: QQ(4,1683)*uk_19 - QQ(31,3366)*uk_29 - QQ(4,1683)*uk_33 + QQ(1,99)*uk_34 + QQ(2,187)*uk_38 - QQ(4,1683)*uk_41 + QQ(1,99)*uk_44 - QQ(98072,1)*uk_48 + QQ(96847,1683)*uk_55 - QQ(1437649,3366)*uk_65 - QQ(568087,1683)*uk_69 + QQ(52402,99)*uk_70 + QQ(120138,187)*uk_74 - QQ(96847,1683)*uk_77 + QQ(52402,99)*uk_80 + QQ(472,1683)*uk_83 - QQ(225,374)*uk_93 + QQ(72,187)*uk_97 + QQ(17,33)*uk_98 + QQ(590,1683)*uk_102 - QQ(472,1683)*uk_105 + QQ(17,33)*uk_108 - QQ(1519,3366)*uk_114 - QQ(13,198)*uk_119 - QQ(1388,1683)*uk_123 - QQ(225,374)*uk_126 - QQ(605,306)*uk_128 - QQ(13,198)*uk_129 + QQ(68,99)*uk_134 + QQ(14,9)*uk_138 + QQ(17,33)*uk_141 - QQ(104,99)*uk_142 + QQ(229,99)*uk_143 + QQ(68,99)*uk_144 + QQ(472,187)*uk_148 + QQ(590,1683)*uk_151 + QQ(4450,1683)*uk_153 + QQ(14,9)*uk_154 - QQ(472,1683)*uk_157 - QQ(72,187)*uk_159 + QQ(17,33)*uk_160 + QQ(229,99)*uk_163 + QQ(68,99)*uk_164, + uk_13: QQ(4,1683)*uk_20 - QQ(4,1683)*uk_37 - QQ(98072,1)*uk_49 + QQ(96847,1683)*uk_56 - QQ(568087,1683)*uk_73 + QQ(472,1683)*uk_84 + QQ(72,187)*uk_101 - QQ(104,99)*uk_152, + uk_14: QQ(4,1683)*uk_21 - QQ(4,1683)*uk_40 - QQ(98072,1)*uk_50 + QQ(96847,1683)*uk_57 - QQ(568087,1683)*uk_76 + QQ(472,1683)*uk_85 + QQ(72,187)*uk_104 - QQ(104,99)*uk_158, + uk_16: QQ(4,1683)*uk_23 + QQ(31,3366)*uk_29 - QQ(1,99)*uk_34 - QQ(2,187)*uk_38 + QQ(4,1683)*uk_41 - QQ(4,1683)*uk_43 - QQ(1,99)*uk_44 - QQ(98072,1)*uk_52 + QQ(96847,1683)*uk_59 + QQ(1437649,3366)*uk_65 - QQ(52402,99)*uk_70 - QQ(120138,187)*uk_74 + QQ(96847,1683)*uk_77 - QQ(568087,1683)*uk_79 - QQ(52402,99)*uk_80 + QQ(472,1683)*uk_87 + QQ(225,374)*uk_93 - QQ(17,33)*uk_98 - QQ(590,1683)*uk_102 + QQ(472,1683)*uk_105 + QQ(72,187)*uk_107 - QQ(17,33)*uk_108 + QQ(1519,3366)*uk_114 + QQ(13,198)*uk_119 + QQ(1388,1683)*uk_123 + QQ(225,374)*uk_126 + QQ(605,306)*uk_128 + QQ(13,198)*uk_129 - QQ(68,99)*uk_134 - QQ(14,9)*uk_138 - QQ(17,33)*uk_141 - QQ(229,99)*uk_143 - QQ(68,99)*uk_144 - QQ(472,187)*uk_148 - QQ(590,1683)*uk_151 - QQ(4450,1683)*uk_153 - QQ(14,9)*uk_154 + QQ(472,1683)*uk_157 + QQ(72,187)*uk_159 - QQ(17,33)*uk_160 - QQ(104,99)*uk_162 - QQ(229,99)*uk_163 - QQ(68,99)*uk_164, + uk_24: -QQ(295441,1683)*uk_88 - QQ(175799,1683)*uk_113, + uk_26: -QQ(295441,1683)*uk_90 - QQ(175799,1683)*uk_122, uk_25: -uk_29 - QQ(295441,1683)*uk_89 - QQ(295441,1683)*uk_93 - QQ(175799,1683)*uk_118 - QQ(175799,1683)*uk_128, + uk_27: -QQ(295441,1683)*uk_91 - QQ(175799,1683)*uk_125 - QQ(4,1)*uk_149, + uk_30: -uk_34 - uk_44 - QQ(295441,1683)*uk_94 - QQ(295441,1683)*uk_98 - QQ(295441,1683)*uk_108 - QQ(175799,1683)*uk_133 - QQ(175799,1683)*uk_143 - QQ(175799,1683)*uk_163, + uk_31: -uk_38 - QQ(295441,1683)*uk_95 - QQ(295441,1683)*uk_102 - QQ(175799,1683)*uk_137 - QQ(175799,1683)*uk_153, + uk_32: -uk_41 - QQ(295441,1683)*uk_96 - QQ(295441,1683)*uk_105 - QQ(175799,1683)*uk_140 + QQ(4,1)*uk_149 - QQ(175799,1683)*uk_159, + uk_35: -QQ(295441,1683)*uk_99 - QQ(175799,1683)*uk_147, + uk_36: -QQ(295441,1683)*uk_100 - QQ(2,1)*uk_149 - QQ(175799,1683)*uk_150, + uk_39: -QQ(295441,1683)*uk_103 - QQ(175799,1683)*uk_156, + uk_60: QQ(4,1683)*uk_88 - QQ(4,1683)*uk_113, + uk_61: -uk_65 + QQ(4,1683)*uk_89 + QQ(4,1683)*uk_93 - QQ(4,1683)*uk_118 - QQ(4,1683)*uk_128, + uk_62: QQ(4,1683)*uk_90 - QQ(4,1683)*uk_122, + uk_63: QQ(4,1683)*uk_91 - QQ(4,1683)*uk_125, + uk_66: -uk_70 - uk_80 + QQ(4,1683)*uk_94 + QQ(4,1683)*uk_98 + QQ(4,1683)*uk_108 - QQ(4,1683)*uk_133 - QQ(4,1683)*uk_143 - QQ(4,1683)*uk_163, + uk_67: -uk_74 + QQ(4,1683)*uk_95 + QQ(4,1683)*uk_102 - QQ(4,1683)*uk_137 - QQ(4,1683)*uk_153, + uk_68: -uk_77 + QQ(4,1683)*uk_96 + QQ(4,1683)*uk_105 - QQ(4,1683)*uk_140 - QQ(4,1683)*uk_159, + uk_71: QQ(4,1683)*uk_99 - QQ(4,1683)*uk_147, + uk_72: QQ(4,1683)*uk_100 - QQ(4,1683)*uk_150, + uk_75: QQ(4,1683)*uk_103 - QQ(4,1683)*uk_156, + uk_109: 0, + uk_110: -uk_114, + uk_111: 0, + uk_112: 0, + uk_115: -uk_119 - uk_129, + uk_116: -uk_123, + uk_117: -uk_126, + uk_120: 0, + uk_121: 0, + uk_124: 0, + uk_130: -uk_134 - uk_144 - uk_164, + uk_131: -uk_138 - uk_154, + uk_132: -uk_141 - uk_160, + uk_135: -uk_148, + uk_136: -uk_151, + uk_139: -uk_157, + uk_145: 0, + uk_146: 0, + uk_155: 0, + } + +def time_eqs_165x165(): + if len(eqs_165x165()) != 165: + raise ValueError("length should be 165") + +def time_solve_lin_sys_165x165(): + eqs = eqs_165x165() + sol = solve_lin_sys(eqs, R_165) + if sol != sol_165x165(): + raise ValueError("Value should be equal") + +def time_verify_sol_165x165(): + eqs = eqs_165x165() + sol = sol_165x165() + zeros = [ eq.compose(sol) for eq in eqs ] + if not all(zero == 0 for zero in zeros): + raise ValueError("All should be 0") + +def time_to_expr_eqs_165x165(): + eqs = eqs_165x165() + assert [ R_165.from_expr(eq.as_expr()) for eq in eqs ] == eqs + +# Benchmark R_49: shows how fast are arithmetics in rational function fields. +F_abc, a, b, c = field("a,b,c", ZZ) +R_49, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49 = ring("k1:50", F_abc) + +def eqs_189x49(): + return [ + -b*k8/a+c*k8/a, + -b*k11/a+c*k11/a, + -b*k10/a+c*k10/a+k2, + -k3-b*k9/a+c*k9/a, + -b*k14/a+c*k14/a, + -b*k15/a+c*k15/a, + -b*k18/a+c*k18/a-k2, + -b*k17/a+c*k17/a, + -b*k16/a+c*k16/a+k4, + -b*k13/a+c*k13/a-b*k21/a+c*k21/a+b*k5/a-c*k5/a, + b*k44/a-c*k44/a, + -b*k45/a+c*k45/a, + -b*k20/a+c*k20/a, + -b*k44/a+c*k44/a, + b*k46/a-c*k46/a, + b**2*k47/a**2-2*b*c*k47/a**2+c**2*k47/a**2, + k3, + -k4, + -b*k12/a+c*k12/a-a*k6/b+c*k6/b, + -b*k19/a+c*k19/a+a*k7/c-b*k7/c, + b*k45/a-c*k45/a, + -b*k46/a+c*k46/a, + -k48+c*k48/a+c*k48/b-c**2*k48/(a*b), + -k49+b*k49/a+b*k49/c-b**2*k49/(a*c), + a*k1/b-c*k1/b, + a*k4/b-c*k4/b, + a*k3/b-c*k3/b+k9, + -k10+a*k2/b-c*k2/b, + a*k7/b-c*k7/b, + -k9, + k11, + b*k12/a-c*k12/a+a*k6/b-c*k6/b, + a*k15/b-c*k15/b, + k10+a*k18/b-c*k18/b, + -k11+a*k17/b-c*k17/b, + a*k16/b-c*k16/b, + -a*k13/b+c*k13/b+a*k21/b-c*k21/b+a*k5/b-c*k5/b, + -a*k44/b+c*k44/b, + a*k45/b-c*k45/b, + a*k14/c-b*k14/c+a*k20/b-c*k20/b, + a*k44/b-c*k44/b, + -a*k46/b+c*k46/b, + -k47+c*k47/a+c*k47/b-c**2*k47/(a*b), + a*k19/b-c*k19/b, + -a*k45/b+c*k45/b, + a*k46/b-c*k46/b, + a**2*k48/b**2-2*a*c*k48/b**2+c**2*k48/b**2, + -k49+a*k49/b+a*k49/c-a**2*k49/(b*c), + k16, + -k17, + -a*k1/c+b*k1/c, + -k16-a*k4/c+b*k4/c, + -a*k3/c+b*k3/c, + k18-a*k2/c+b*k2/c, + b*k19/a-c*k19/a-a*k7/c+b*k7/c, + -a*k6/c+b*k6/c, + -a*k8/c+b*k8/c, + -a*k11/c+b*k11/c+k17, + -a*k10/c+b*k10/c-k18, + -a*k9/c+b*k9/c, + -a*k14/c+b*k14/c-a*k20/b+c*k20/b, + -a*k13/c+b*k13/c+a*k21/c-b*k21/c-a*k5/c+b*k5/c, + a*k44/c-b*k44/c, + -a*k45/c+b*k45/c, + -a*k44/c+b*k44/c, + a*k46/c-b*k46/c, + -k47+b*k47/a+b*k47/c-b**2*k47/(a*c), + -a*k12/c+b*k12/c, + a*k45/c-b*k45/c, + -a*k46/c+b*k46/c, + -k48+a*k48/b+a*k48/c-a**2*k48/(b*c), + a**2*k49/c**2-2*a*b*k49/c**2+b**2*k49/c**2, + k8, + k11, + -k15, + k10-k18, + -k17, + k9, + -k16, + -k29, + k14-k32, + -k21+k23-k31, + -k24-k30, + -k35, + k44, + -k45, + k36, + k13-k23+k39, + -k20+k38, + k25+k37, + b*k26/a-c*k26/a-k34+k42, + -2*k44, + k45, + k46, + b*k47/a-c*k47/a, + k41, + k44, + -k46, + -b*k47/a+c*k47/a, + k12+k24, + -k19-k25, + -a*k27/b+c*k27/b-k33, + k45, + -k46, + -a*k48/b+c*k48/b, + a*k28/c-b*k28/c+k40, + -k45, + k46, + a*k48/b-c*k48/b, + a*k49/c-b*k49/c, + -a*k49/c+b*k49/c, + -k1, + -k4, + -k3, + k15, + k18-k2, + k17, + k16, + k22, + k25-k7, + k24+k30, + k21+k23-k31, + k28, + -k44, + k45, + -k30-k6, + k20+k32, + k27+b*k33/a-c*k33/a, + k44, + -k46, + -b*k47/a+c*k47/a, + -k36, + k31-k39-k5, + -k32-k38, + k19-k37, + k26-a*k34/b+c*k34/b-k42, + k44, + -2*k45, + k46, + a*k48/b-c*k48/b, + a*k35/c-b*k35/c-k41, + -k44, + k46, + b*k47/a-c*k47/a, + -a*k49/c+b*k49/c, + -k40, + k45, + -k46, + -a*k48/b+c*k48/b, + a*k49/c-b*k49/c, + k1, + k4, + k3, + -k8, + -k11, + -k10+k2, + -k9, + k37+k7, + -k14-k38, + -k22, + -k25-k37, + -k24+k6, + -k13-k23+k39, + -k28+b*k40/a-c*k40/a, + k44, + -k45, + -k27, + -k44, + k46, + b*k47/a-c*k47/a, + k29, + k32+k38, + k31-k39+k5, + -k12+k30, + k35-a*k41/b+c*k41/b, + -k44, + k45, + -k26+k34+a*k42/c-b*k42/c, + k44, + k45, + -2*k46, + -b*k47/a+c*k47/a, + -a*k48/b+c*k48/b, + a*k49/c-b*k49/c, + k33, + -k45, + k46, + a*k48/b-c*k48/b, + -a*k49/c+b*k49/c, + ] + +def sol_189x49(): + return { + k49: 0, k48: 0, k47: 0, k46: 0, k45: 0, k44: 0, k41: 0, k40: 0, + k38: 0, k37: 0, k36: 0, k35: 0, k33: 0, k32: 0, k30: 0, k29: 0, + k28: 0, k27: 0, k25: 0, k24: 0, k22: 0, k21: 0, k20: 0, k19: 0, + k18: 0, k17: 0, k16: 0, k15: 0, k14: 0, k13: 0, k12: 0, k11: 0, + k10: 0, k9: 0, k8: 0, k7: 0, k6: 0, k5: 0, k4: 0, k3: 0, + k2: 0, k1: 0, + k34: b/c*k42, + k31: k39, + k26: a/c*k42, + k23: k39, + } + +def time_eqs_189x49(): + if len(eqs_189x49()) != 189: + raise ValueError("Length should be equal to 189") + +def time_solve_lin_sys_189x49(): + eqs = eqs_189x49() + sol = solve_lin_sys(eqs, R_49) + if sol != sol_189x49(): + raise ValueError("Values should be equal") + +def time_verify_sol_189x49(): + eqs = eqs_189x49() + sol = sol_189x49() + zeros = [ eq.compose(sol) for eq in eqs ] + assert all(zero == 0 for zero in zeros) + +def time_to_expr_eqs_189x49(): + eqs = eqs_189x49() + assert [ R_49.from_expr(eq.as_expr()) for eq in eqs ] == eqs + +# Benchmark R_8: shows how fast polynomial GCDs are computed. + +F_a5_5, a_11, a_12, a_13, a_14, a_21, a_22, a_23, a_24, a_31, a_32, a_33, a_34, a_41, a_42, a_43, a_44 = field("a_(1:5)(1:5)", ZZ) +R_8, x0, x1, x2, x3, x4, x5, x6, x7 = ring("x:8", F_a5_5) + +def eqs_10x8(): + return [ + (a_33*a_34 + a_33*a_44 + a_43*a_44)*x3 + (a_33*a_34 + a_33*a_44 + a_43*a_44)*x4 + (a_12*a_34 + a_12*a_44 + a_22*a_34 + a_22*a_44)*x5 + (a_12*a_44 + a_22*a_44)*x6 + (a_12*a_33 + a_22*a_33)*x7 - a_12*a_33 - a_12*a_43 - a_22*a_33 - a_22*a_43, + (a_33 + a_34 + a_43 + a_44)*x3 + (a_33 + a_34 + a_43 + a_44)*x4 + (a_12 + a_22 + a_34 + a_44)*x5 + (a_12 + a_22 + a_44)*x6 + (a_12 + a_22 + a_33)*x7 - a_12 - a_22 - a_33 - a_43, + x3 + x4 + x5 + x6 + x7 - 1, + (a_12*a_33*a_34 + a_12*a_33*a_44 + a_12*a_43*a_44 + a_22*a_33*a_34 + a_22*a_33*a_44 + a_22*a_43*a_44)*x0 + (a_22*a_33*a_34 + a_22*a_33*a_44 + a_22*a_43*a_44)*x1 + (a_12*a_33*a_34 + a_12*a_33*a_44 + a_12*a_43*a_44 + a_22*a_33*a_34 + a_22*a_33*a_44 + a_22*a_43*a_44)*x2 + (a_11*a_33*a_34 + a_11*a_33*a_44 + a_11*a_43*a_44 + a_31*a_33*a_34 + a_31*a_33*a_44 + a_31*a_43*a_44)*x3 + (a_11*a_33*a_34 + a_11*a_33*a_44 + a_11*a_43*a_44 + a_21*a_33*a_34 + a_21*a_33*a_44 + a_21*a_43*a_44 + a_31*a_33*a_34 + a_31*a_33*a_44 + a_31*a_43*a_44)*x4 + (a_11*a_12*a_34 + a_11*a_12*a_44 + a_11*a_22*a_34 + a_11*a_22*a_44 + a_12*a_31*a_34 + a_12*a_31*a_44 + a_21*a_22*a_34 + a_21*a_22*a_44 + a_22*a_31*a_34 + a_22*a_31*a_44)*x5 + (a_11*a_12*a_44 + a_11*a_22*a_44 + a_12*a_31*a_44 + a_21*a_22*a_44 + a_22*a_31*a_44)*x6 + (a_11*a_12*a_33 + a_11*a_22*a_33 + a_12*a_31*a_33 + a_21*a_22*a_33 + a_22*a_31*a_33)*x7 - a_11*a_12*a_33 - a_11*a_12*a_43 - a_11*a_22*a_33 - a_11*a_22*a_43 - a_12*a_31*a_33 - a_12*a_31*a_43 - a_21*a_22*a_33 - a_21*a_22*a_43 - a_22*a_31*a_33 - a_22*a_31*a_43, + (a_12*a_33 + a_12*a_34 + a_12*a_43 + a_12*a_44 + a_22*a_33 + a_22*a_34 + a_22*a_43 + a_22*a_44 + a_33*a_34 + a_33*a_44 + a_43*a_44)*x0 + (a_22*a_33 + a_22*a_34 + a_22*a_43 + a_22*a_44 + a_33*a_34 + a_33*a_44 + a_43*a_44)*x1 + (a_12*a_33 + a_12*a_34 + a_12*a_43 + a_12*a_44 + a_22*a_33 + a_22*a_34 + a_22*a_43 + a_22*a_44 + a_33*a_34 + a_33*a_44 + a_43*a_44)*x2 + (a_11*a_33 + a_11*a_34 + a_11*a_43 + a_11*a_44 + a_31*a_33 + a_31*a_34 + a_31*a_43 + a_31*a_44 + a_33*a_34 + a_33*a_44 + a_43*a_44)*x3 + (a_11*a_33 + a_11*a_34 + a_11*a_43 + a_11*a_44 + a_21*a_33 + a_21*a_34 + a_21*a_43 + a_21*a_44 + a_31*a_33 + a_31*a_34 + a_31*a_43 + a_31*a_44 + a_33*a_34 + a_33*a_44 + a_43*a_44)*x4 + (a_11*a_12 + a_11*a_22 + a_11*a_34 + a_11*a_44 + a_12*a_31 + a_12*a_34 + a_12*a_44 + a_21*a_22 + a_21*a_34 + a_21*a_44 + a_22*a_31 + a_22*a_34 + a_22*a_44 + a_31*a_34 + a_31*a_44)*x5 + (a_11*a_12 + a_11*a_22 + a_11*a_44 + a_12*a_31 + a_12*a_44 + a_21*a_22 + a_21*a_44 + a_22*a_31 + a_22*a_44 + a_31*a_44)*x6 + (a_11*a_12 + a_11*a_22 + a_11*a_33 + a_12*a_31 + a_12*a_33 + a_21*a_22 + a_21*a_33 + a_22*a_31 + a_22*a_33 + a_31*a_33)*x7 - a_11*a_12 - a_11*a_22 - a_11*a_33 - a_11*a_43 - a_12*a_31 - a_12*a_33 - a_12*a_43 - a_21*a_22 - a_21*a_33 - a_21*a_43 - a_22*a_31 - a_22*a_33 - a_22*a_43 - a_31*a_33 - a_31*a_43, + (a_12 + a_22 + a_33 + a_34 + a_43 + a_44)*x0 + (a_22 + a_33 + a_34 + a_43 + a_44)*x1 + (a_12 + a_22 + a_33 + a_34 + a_43 + a_44)*x2 + (a_11 + a_31 + a_33 + a_34 + a_43 + a_44)*x3 + (a_11 + a_21 + a_31 + a_33 + a_34 + a_43 + a_44)*x4 + (a_11 + a_12 + a_21 + a_22 + a_31 + a_34 + a_44)*x5 + (a_11 + a_12 + a_21 + a_22 + a_31 + a_44)*x6 + (a_11 + a_12 + a_21 + a_22 + a_31 + a_33)*x7 - a_11 - a_12 - a_21 - a_22 - a_31 - a_33 - a_43, + x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 - 1, + (a_12*a_34 + a_12*a_44 + a_22*a_34 + a_22*a_44)*x2 + (a_31*a_34 + a_31*a_44)*x3 + (a_31*a_34 + a_31*a_44)*x4 + (a_12*a_31 + a_22*a_31)*x7 - a_12*a_31 - a_22*a_31, + (a_12 + a_22 + a_34 + a_44)*x2 + a_31*x3 + a_31*x4 + a_31*x7 - a_31, + x2, + ] + +def sol_10x8(): + return { + x0: -a_21/a_12*x4, + x1: a_21/a_12*x4, + x2: 0, + x3: -x4, + x5: a_43/a_34, + x6: -a_43/a_34, + x7: 1, + } + +def time_eqs_10x8(): + if len(eqs_10x8()) != 10: + raise ValueError("Value should be equal to 10") + +def time_solve_lin_sys_10x8(): + eqs = eqs_10x8() + sol = solve_lin_sys(eqs, R_8) + if sol != sol_10x8(): + raise ValueError("Values should be equal") + +def time_verify_sol_10x8(): + eqs = eqs_10x8() + sol = sol_10x8() + zeros = [ eq.compose(sol) for eq in eqs ] + if not all(zero == 0 for zero in zeros): + raise ValueError("All values in zero should be 0") + +def time_to_expr_eqs_10x8(): + eqs = eqs_10x8() + assert [ R_8.from_expr(eq.as_expr()) for eq in eqs ] == eqs diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c6839b4494afd0ee0c0ecd9ddee65d1afbdc6b53 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__init__.py @@ -0,0 +1,57 @@ +"""Implementation of mathematical domains. """ + +__all__ = [ + 'Domain', 'FiniteField', 'IntegerRing', 'RationalField', 'RealField', + 'ComplexField', 'AlgebraicField', 'PolynomialRing', 'FractionField', + 'ExpressionDomain', 'PythonRational', + + 'GF', 'FF', 'ZZ', 'QQ', 'ZZ_I', 'QQ_I', 'RR', 'CC', 'EX', 'EXRAW', +] + +from .domain import Domain +from .finitefield import FiniteField, FF, GF +from .integerring import IntegerRing, ZZ +from .rationalfield import RationalField, QQ +from .algebraicfield import AlgebraicField +from .gaussiandomains import ZZ_I, QQ_I +from .realfield import RealField, RR +from .complexfield import ComplexField, CC +from .polynomialring import PolynomialRing +from .fractionfield import FractionField +from .expressiondomain import ExpressionDomain, EX +from .expressionrawdomain import EXRAW +from .pythonrational import PythonRational + + +# This is imported purely for backwards compatibility because some parts of +# the codebase used to import this from here and it's possible that downstream +# does as well: +from sympy.external.gmpy import GROUND_TYPES # noqa: F401 + +# +# The rest of these are obsolete and provided only for backwards +# compatibility: +# + +from .pythonfinitefield import PythonFiniteField +from .gmpyfinitefield import GMPYFiniteField +from .pythonintegerring import PythonIntegerRing +from .gmpyintegerring import GMPYIntegerRing +from .pythonrationalfield import PythonRationalField +from .gmpyrationalfield import GMPYRationalField + +FF_python = PythonFiniteField +FF_gmpy = GMPYFiniteField + +ZZ_python = PythonIntegerRing +ZZ_gmpy = GMPYIntegerRing + +QQ_python = PythonRationalField +QQ_gmpy = GMPYRationalField + +__all__.extend(( + 'PythonFiniteField', 'GMPYFiniteField', 'PythonIntegerRing', + 'GMPYIntegerRing', 'PythonRational', 'GMPYRationalField', + + 'FF_python', 'FF_gmpy', 'ZZ_python', 'ZZ_gmpy', 'QQ_python', 'QQ_gmpy', +)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/domainelement.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/domainelement.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e067f096acbd0e010ec0044e30b0e215cc71e5d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/domainelement.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/field.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/field.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..464c4e3ea43f55e0bb4c3d7f99dc96e98b9371b3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/field.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/finitefield.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/finitefield.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..247c576690de55b97bc6b38996812385fa77e73f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/finitefield.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gaussiandomains.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gaussiandomains.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c06871d84a37a0ce330bbd6ba74d484280341e75 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gaussiandomains.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gmpyrationalfield.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gmpyrationalfield.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa4279d8e1fc5e42d3f4a57c83485f965dcec728 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/gmpyrationalfield.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/groundtypes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/groundtypes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e30541bd6e511e45c6cb187e883bd6715ec83c4a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/groundtypes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/ring.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/ring.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a8e21d4bd9fb102abef0520acc85185104f5835f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/__pycache__/ring.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/algebraicfield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/algebraicfield.py new file mode 100644 index 0000000000000000000000000000000000000000..3ee3f10d90fc4a3331471ea9a24589d65654d1cd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/algebraicfield.py @@ -0,0 +1,638 @@ +"""Implementation of :class:`AlgebraicField` class. """ + + +from sympy.core.add import Add +from sympy.core.mul import Mul +from sympy.core.singleton import S +from sympy.core.symbol import Dummy, symbols +from sympy.polys.domains.characteristiczero import CharacteristicZero +from sympy.polys.domains.field import Field +from sympy.polys.domains.simpledomain import SimpleDomain +from sympy.polys.polyclasses import ANP +from sympy.polys.polyerrors import CoercionFailed, DomainError, NotAlgebraic, IsomorphismFailed +from sympy.utilities import public + +@public +class AlgebraicField(Field, CharacteristicZero, SimpleDomain): + r"""Algebraic number field :ref:`QQ(a)` + + A :ref:`QQ(a)` domain represents an `algebraic number field`_ + `\mathbb{Q}(a)` as a :py:class:`~.Domain` in the domain system (see + :ref:`polys-domainsintro`). + + A :py:class:`~.Poly` created from an expression involving `algebraic + numbers`_ will treat the algebraic numbers as generators if the generators + argument is not specified. + + >>> from sympy import Poly, Symbol, sqrt + >>> x = Symbol('x') + >>> Poly(x**2 + sqrt(2)) + Poly(x**2 + (sqrt(2)), x, sqrt(2), domain='ZZ') + + That is a multivariate polynomial with ``sqrt(2)`` treated as one of the + generators (variables). If the generators are explicitly specified then + ``sqrt(2)`` will be considered to be a coefficient but by default the + :ref:`EX` domain is used. To make a :py:class:`~.Poly` with a :ref:`QQ(a)` + domain the argument ``extension=True`` can be given. + + >>> Poly(x**2 + sqrt(2), x) + Poly(x**2 + sqrt(2), x, domain='EX') + >>> Poly(x**2 + sqrt(2), x, extension=True) + Poly(x**2 + sqrt(2), x, domain='QQ') + + A generator of the algebraic field extension can also be specified + explicitly which is particularly useful if the coefficients are all + rational but an extension field is needed (e.g. to factor the + polynomial). + + >>> Poly(x**2 + 1) + Poly(x**2 + 1, x, domain='ZZ') + >>> Poly(x**2 + 1, extension=sqrt(2)) + Poly(x**2 + 1, x, domain='QQ') + + It is possible to factorise a polynomial over a :ref:`QQ(a)` domain using + the ``extension`` argument to :py:func:`~.factor` or by specifying the domain + explicitly. + + >>> from sympy import factor, QQ + >>> factor(x**2 - 2) + x**2 - 2 + >>> factor(x**2 - 2, extension=sqrt(2)) + (x - sqrt(2))*(x + sqrt(2)) + >>> factor(x**2 - 2, domain='QQ') + (x - sqrt(2))*(x + sqrt(2)) + >>> factor(x**2 - 2, domain=QQ.algebraic_field(sqrt(2))) + (x - sqrt(2))*(x + sqrt(2)) + + The ``extension=True`` argument can be used but will only create an + extension that contains the coefficients which is usually not enough to + factorise the polynomial. + + >>> p = x**3 + sqrt(2)*x**2 - 2*x - 2*sqrt(2) + >>> factor(p) # treats sqrt(2) as a symbol + (x + sqrt(2))*(x**2 - 2) + >>> factor(p, extension=True) + (x - sqrt(2))*(x + sqrt(2))**2 + >>> factor(x**2 - 2, extension=True) # all rational coefficients + x**2 - 2 + + It is also possible to use :ref:`QQ(a)` with the :py:func:`~.cancel` + and :py:func:`~.gcd` functions. + + >>> from sympy import cancel, gcd + >>> cancel((x**2 - 2)/(x - sqrt(2))) + (x**2 - 2)/(x - sqrt(2)) + >>> cancel((x**2 - 2)/(x - sqrt(2)), extension=sqrt(2)) + x + sqrt(2) + >>> gcd(x**2 - 2, x - sqrt(2)) + 1 + >>> gcd(x**2 - 2, x - sqrt(2), extension=sqrt(2)) + x - sqrt(2) + + When using the domain directly :ref:`QQ(a)` can be used as a constructor + to create instances which then support the operations ``+,-,*,**,/``. The + :py:meth:`~.Domain.algebraic_field` method is used to construct a + particular :ref:`QQ(a)` domain. The :py:meth:`~.Domain.from_sympy` method + can be used to create domain elements from normal SymPy expressions. + + >>> K = QQ.algebraic_field(sqrt(2)) + >>> K + QQ + >>> xk = K.from_sympy(3 + 4*sqrt(2)) + >>> xk # doctest: +SKIP + ANP([4, 3], [1, 0, -2], QQ) + + Elements of :ref:`QQ(a)` are instances of :py:class:`~.ANP` which have + limited printing support. The raw display shows the internal + representation of the element as the list ``[4, 3]`` representing the + coefficients of ``1`` and ``sqrt(2)`` for this element in the form + ``a * sqrt(2) + b * 1`` where ``a`` and ``b`` are elements of :ref:`QQ`. + The minimal polynomial for the generator ``(x**2 - 2)`` is also shown in + the :ref:`dup-representation` as the list ``[1, 0, -2]``. We can use + :py:meth:`~.Domain.to_sympy` to get a better printed form for the + elements and to see the results of operations. + + >>> xk = K.from_sympy(3 + 4*sqrt(2)) + >>> yk = K.from_sympy(2 + 3*sqrt(2)) + >>> xk * yk # doctest: +SKIP + ANP([17, 30], [1, 0, -2], QQ) + >>> K.to_sympy(xk * yk) + 17*sqrt(2) + 30 + >>> K.to_sympy(xk + yk) + 5 + 7*sqrt(2) + >>> K.to_sympy(xk ** 2) + 24*sqrt(2) + 41 + >>> K.to_sympy(xk / yk) + sqrt(2)/14 + 9/7 + + Any expression representing an algebraic number can be used to generate + a :ref:`QQ(a)` domain provided its `minimal polynomial`_ can be computed. + The function :py:func:`~.minpoly` function is used for this. + + >>> from sympy import exp, I, pi, minpoly + >>> g = exp(2*I*pi/3) + >>> g + exp(2*I*pi/3) + >>> g.is_algebraic + True + >>> minpoly(g, x) + x**2 + x + 1 + >>> factor(x**3 - 1, extension=g) + (x - 1)*(x - exp(2*I*pi/3))*(x + 1 + exp(2*I*pi/3)) + + It is also possible to make an algebraic field from multiple extension + elements. + + >>> K = QQ.algebraic_field(sqrt(2), sqrt(3)) + >>> K + QQ + >>> p = x**4 - 5*x**2 + 6 + >>> factor(p) + (x**2 - 3)*(x**2 - 2) + >>> factor(p, domain=K) + (x - sqrt(2))*(x + sqrt(2))*(x - sqrt(3))*(x + sqrt(3)) + >>> factor(p, extension=[sqrt(2), sqrt(3)]) + (x - sqrt(2))*(x + sqrt(2))*(x - sqrt(3))*(x + sqrt(3)) + + Multiple extension elements are always combined together to make a single + `primitive element`_. In the case of ``[sqrt(2), sqrt(3)]`` the primitive + element chosen is ``sqrt(2) + sqrt(3)`` which is why the domain displays + as ``QQ``. The minimal polynomial for the primitive + element is computed using the :py:func:`~.primitive_element` function. + + >>> from sympy import primitive_element + >>> primitive_element([sqrt(2), sqrt(3)], x) + (x**4 - 10*x**2 + 1, [1, 1]) + >>> minpoly(sqrt(2) + sqrt(3), x) + x**4 - 10*x**2 + 1 + + The extension elements that generate the domain can be accessed from the + domain using the :py:attr:`~.ext` and :py:attr:`~.orig_ext` attributes as + instances of :py:class:`~.AlgebraicNumber`. The minimal polynomial for + the primitive element as a :py:class:`~.DMP` instance is available as + :py:attr:`~.mod`. + + >>> K = QQ.algebraic_field(sqrt(2), sqrt(3)) + >>> K + QQ + >>> K.ext + sqrt(2) + sqrt(3) + >>> K.orig_ext + (sqrt(2), sqrt(3)) + >>> K.mod # doctest: +SKIP + DMP_Python([1, 0, -10, 0, 1], QQ) + + The `discriminant`_ of the field can be obtained from the + :py:meth:`~.discriminant` method, and an `integral basis`_ from the + :py:meth:`~.integral_basis` method. The latter returns a list of + :py:class:`~.ANP` instances by default, but can be made to return instances + of :py:class:`~.Expr` or :py:class:`~.AlgebraicNumber` by passing a ``fmt`` + argument. The maximal order, or ring of integers, of the field can also be + obtained from the :py:meth:`~.maximal_order` method, as a + :py:class:`~sympy.polys.numberfields.modules.Submodule`. + + >>> zeta5 = exp(2*I*pi/5) + >>> K = QQ.algebraic_field(zeta5) + >>> K + QQ + >>> K.discriminant() + 125 + >>> K = QQ.algebraic_field(sqrt(5)) + >>> K + QQ + >>> K.integral_basis(fmt='sympy') + [1, 1/2 + sqrt(5)/2] + >>> K.maximal_order() + Submodule[[2, 0], [1, 1]]/2 + + The factorization of a rational prime into prime ideals of the field is + computed by the :py:meth:`~.primes_above` method, which returns a list + of :py:class:`~sympy.polys.numberfields.primes.PrimeIdeal` instances. + + >>> zeta7 = exp(2*I*pi/7) + >>> K = QQ.algebraic_field(zeta7) + >>> K + QQ + >>> K.primes_above(11) + [(11, _x**3 + 5*_x**2 + 4*_x - 1), (11, _x**3 - 4*_x**2 - 5*_x - 1)] + + The Galois group of the Galois closure of the field can be computed (when + the minimal polynomial of the field is of sufficiently small degree). + + >>> K.galois_group(by_name=True)[0] + S6TransitiveSubgroups.C6 + + Notes + ===== + + It is not currently possible to generate an algebraic extension over any + domain other than :ref:`QQ`. Ideally it would be possible to generate + extensions like ``QQ(x)(sqrt(x**2 - 2))``. This is equivalent to the + quotient ring ``QQ(x)[y]/(y**2 - x**2 + 2)`` and there are two + implementations of this kind of quotient ring/extension in the + :py:class:`~.QuotientRing` and :py:class:`~.MonogenicFiniteExtension` + classes. Each of those implementations needs some work to make them fully + usable though. + + .. _algebraic number field: https://en.wikipedia.org/wiki/Algebraic_number_field + .. _algebraic numbers: https://en.wikipedia.org/wiki/Algebraic_number + .. _discriminant: https://en.wikipedia.org/wiki/Discriminant_of_an_algebraic_number_field + .. _integral basis: https://en.wikipedia.org/wiki/Algebraic_number_field#Integral_basis + .. _minimal polynomial: https://en.wikipedia.org/wiki/Minimal_polynomial_(field_theory) + .. _primitive element: https://en.wikipedia.org/wiki/Primitive_element_theorem + """ + + dtype = ANP + + is_AlgebraicField = is_Algebraic = True + is_Numerical = True + + has_assoc_Ring = False + has_assoc_Field = True + + def __init__(self, dom, *ext, alias=None): + r""" + Parameters + ========== + + dom : :py:class:`~.Domain` + The base field over which this is an extension field. + Currently only :ref:`QQ` is accepted. + + *ext : One or more :py:class:`~.Expr` + Generators of the extension. These should be expressions that are + algebraic over `\mathbb{Q}`. + + alias : str, :py:class:`~.Symbol`, None, optional (default=None) + If provided, this will be used as the alias symbol for the + primitive element of the :py:class:`~.AlgebraicField`. + If ``None``, while ``ext`` consists of exactly one + :py:class:`~.AlgebraicNumber`, its alias (if any) will be used. + """ + if not dom.is_QQ: + raise DomainError("ground domain must be a rational field") + + from sympy.polys.numberfields import to_number_field + if len(ext) == 1 and isinstance(ext[0], tuple): + orig_ext = ext[0][1:] + else: + orig_ext = ext + + if alias is None and len(ext) == 1: + alias = getattr(ext[0], 'alias', None) + + self.orig_ext = orig_ext + """ + Original elements given to generate the extension. + + >>> from sympy import QQ, sqrt + >>> K = QQ.algebraic_field(sqrt(2), sqrt(3)) + >>> K.orig_ext + (sqrt(2), sqrt(3)) + """ + + self.ext = to_number_field(ext, alias=alias) + """ + Primitive element used for the extension. + + >>> from sympy import QQ, sqrt + >>> K = QQ.algebraic_field(sqrt(2), sqrt(3)) + >>> K.ext + sqrt(2) + sqrt(3) + """ + + self.mod = self.ext.minpoly.rep + """ + Minimal polynomial for the primitive element of the extension. + + >>> from sympy import QQ, sqrt + >>> K = QQ.algebraic_field(sqrt(2)) + >>> K.mod + DMP([1, 0, -2], QQ) + """ + + self.domain = self.dom = dom + + self.ngens = 1 + self.symbols = self.gens = (self.ext,) + self.unit = self([dom(1), dom(0)]) + + self.zero = self.dtype.zero(self.mod.to_list(), dom) + self.one = self.dtype.one(self.mod.to_list(), dom) + + self._maximal_order = None + self._discriminant = None + self._nilradicals_mod_p = {} + + def new(self, element): + return self.dtype(element, self.mod.to_list(), self.dom) + + def __str__(self): + return str(self.dom) + '<' + str(self.ext) + '>' + + def __hash__(self): + return hash((self.__class__.__name__, self.dtype, self.dom, self.ext)) + + def __eq__(self, other): + """Returns ``True`` if two domains are equivalent. """ + if isinstance(other, AlgebraicField): + return self.dtype == other.dtype and self.ext == other.ext + else: + return NotImplemented + + def algebraic_field(self, *extension, alias=None): + r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \ldots)`. """ + return AlgebraicField(self.dom, *((self.ext,) + extension), alias=alias) + + def to_alg_num(self, a): + """Convert ``a`` of ``dtype`` to an :py:class:`~.AlgebraicNumber`. """ + return self.ext.field_element(a) + + def to_sympy(self, a): + """Convert ``a`` of ``dtype`` to a SymPy object. """ + # Precompute a converter to be reused: + if not hasattr(self, '_converter'): + self._converter = _make_converter(self) + + return self._converter(a) + + def from_sympy(self, a): + """Convert SymPy's expression to ``dtype``. """ + try: + return self([self.dom.from_sympy(a)]) + except CoercionFailed: + pass + + from sympy.polys.numberfields import to_number_field + + 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)) + + def from_ZZ(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return K1(K1.dom.convert(a, K0)) + + def from_ZZ_python(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return K1(K1.dom.convert(a, K0)) + + def from_QQ(K1, a, K0): + """Convert a Python ``Fraction`` 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_RealField(K1, a, K0): + """Convert a mpmath ``mpf`` object to ``dtype``. """ + return K1(K1.dom.convert(a, K0)) + + def get_ring(self): + """Returns a ring associated with ``self``. """ + raise DomainError('there is no ring associated with %s' % self) + + def is_positive(self, a): + """Returns True if ``a`` is positive. """ + return self.dom.is_positive(a.LC()) + + def is_negative(self, a): + """Returns True if ``a`` is negative. """ + return self.dom.is_negative(a.LC()) + + def is_nonpositive(self, a): + """Returns True if ``a`` is non-positive. """ + return self.dom.is_nonpositive(a.LC()) + + def is_nonnegative(self, a): + """Returns True if ``a`` is non-negative. """ + return self.dom.is_nonnegative(a.LC()) + + def numer(self, a): + """Returns numerator of ``a``. """ + return a + + def denom(self, a): + """Returns denominator of ``a``. """ + return self.one + + def from_AlgebraicField(K1, a, K0): + """Convert AlgebraicField element 'a' to another AlgebraicField """ + return K1.from_sympy(K0.to_sympy(a)) + + def from_GaussianIntegerRing(K1, a, K0): + """Convert a GaussianInteger element 'a' to ``dtype``. """ + return K1.from_sympy(K0.to_sympy(a)) + + def from_GaussianRationalField(K1, a, K0): + """Convert a GaussianRational element 'a' to ``dtype``. """ + return K1.from_sympy(K0.to_sympy(a)) + + def _do_round_two(self): + from sympy.polys.numberfields.basis import round_two + ZK, dK = round_two(self, radicals=self._nilradicals_mod_p) + self._maximal_order = ZK + self._discriminant = dK + + def maximal_order(self): + """ + Compute the maximal order, or ring of integers, of the field. + + Returns + ======= + + :py:class:`~sympy.polys.numberfields.modules.Submodule`. + + See Also + ======== + + integral_basis + + """ + if self._maximal_order is None: + self._do_round_two() + return self._maximal_order + + def integral_basis(self, fmt=None): + r""" + Get an integral basis for the field. + + Parameters + ========== + + fmt : str, None, optional (default=None) + If ``None``, return a list of :py:class:`~.ANP` instances. + If ``"sympy"``, convert each element of the list to an + :py:class:`~.Expr`, using ``self.to_sympy()``. + If ``"alg"``, convert each element of the list to an + :py:class:`~.AlgebraicNumber`, using ``self.to_alg_num()``. + + Examples + ======== + + >>> from sympy import QQ, AlgebraicNumber, sqrt + >>> alpha = AlgebraicNumber(sqrt(5), alias='alpha') + >>> k = QQ.algebraic_field(alpha) + >>> B0 = k.integral_basis() + >>> B1 = k.integral_basis(fmt='sympy') + >>> B2 = k.integral_basis(fmt='alg') + >>> print(B0[1]) # doctest: +SKIP + ANP([mpq(1,2), mpq(1,2)], [mpq(1,1), mpq(0,1), mpq(-5,1)], QQ) + >>> print(B1[1]) + 1/2 + alpha/2 + >>> print(B2[1]) + alpha/2 + 1/2 + + In the last two cases we get legible expressions, which print somewhat + differently because of the different types involved: + + >>> print(type(B1[1])) + + >>> print(type(B2[1])) + + + See Also + ======== + + to_sympy + to_alg_num + maximal_order + """ + ZK = self.maximal_order() + M = ZK.QQ_matrix + n = M.shape[1] + B = [self.new(list(reversed(M[:, j].flat()))) for j in range(n)] + if fmt == 'sympy': + return [self.to_sympy(b) for b in B] + elif fmt == 'alg': + return [self.to_alg_num(b) for b in B] + return B + + def discriminant(self): + """Get the discriminant of the field.""" + if self._discriminant is None: + self._do_round_two() + return self._discriminant + + def primes_above(self, p): + """Compute the prime ideals lying above a given rational prime *p*.""" + from sympy.polys.numberfields.primes import prime_decomp + ZK = self.maximal_order() + dK = self.discriminant() + rad = self._nilradicals_mod_p.get(p) + return prime_decomp(p, ZK=ZK, dK=dK, radical=rad) + + def galois_group(self, by_name=False, max_tries=30, randomize=False): + """ + Compute the Galois group of the Galois closure of this field. + + Examples + ======== + + If the field is Galois, the order of the group will equal the degree + of the field: + + >>> from sympy import QQ + >>> from sympy.abc import x + >>> k = QQ.alg_field_from_poly(x**4 + 1) + >>> G, _ = k.galois_group() + >>> G.order() + 4 + + If the field is not Galois, then its Galois closure is a proper + extension, and the order of the Galois group will be greater than the + degree of the field: + + >>> k = QQ.alg_field_from_poly(x**4 - 2) + >>> G, _ = k.galois_group() + >>> G.order() + 8 + + See Also + ======== + + sympy.polys.numberfields.galoisgroups.galois_group + + """ + return self.ext.minpoly_of_element().galois_group( + by_name=by_name, max_tries=max_tries, randomize=randomize) + + +def _make_converter(K): + """Construct the converter to convert back to Expr""" + # Precompute the effect of converting to SymPy and expanding expressions + # like (sqrt(2) + sqrt(3))**2. Asking Expr to do the expansion on every + # conversion from K to Expr is slow. Here we compute the expansions for + # each power of the generator and collect together the resulting algebraic + # terms and the rational coefficients into a matrix. + + ext = K.ext.as_expr() + todom = K.dom.from_sympy + toexpr = K.dom.to_sympy + + if not ext.is_Add: + powers = [ext**n for n in range(K.mod.degree())] + else: + # primitive_element generates a QQ-linear combination of lower degree + # algebraic numbers to generate the higher degree extension e.g. + # QQ That means that we end up having high powers of low + # degree algebraic numbers that can be reduced. Here we will use the + # minimal polynomials of the algebraic numbers to reduce those powers + # before converting to Expr. + from sympy.polys.numberfields.minpoly import minpoly + + # Decompose ext as a linear combination of gens and make a symbol for + # each gen. + gens, coeffs = zip(*ext.as_coefficients_dict().items()) + syms = symbols(f'a:{len(gens)}', cls=Dummy) + sym2gen = dict(zip(syms, gens)) + + # Make a polynomial ring that can express ext and minpolys of all gens + # in terms of syms. + R = K.dom[syms] + monoms = [R.ring.monomial_basis(i) for i in range(R.ngens)] + ext_dict = {m: todom(c) for m, c in zip(monoms, coeffs)} + ext_poly = R.ring.from_dict(ext_dict) + minpolys = [R.from_sympy(minpoly(g, s)) for s, g in sym2gen.items()] + + # Compute all powers of ext_poly reduced modulo minpolys + powers = [R.one, ext_poly] + for n in range(2, K.mod.degree()): + ext_poly_n = (powers[-1] * ext_poly).rem(minpolys) + powers.append(ext_poly_n) + + # Convert the powers back to Expr. This will recombine some things like + # sqrt(2)*sqrt(3) -> sqrt(6). + powers = [p.as_expr().xreplace(sym2gen) for p in powers] + + # This also expands some rational powers + powers = [p.expand() for p in powers] + + # Collect the rational coefficients and algebraic Expr that can + # map the ANP coefficients into an expanded SymPy expression + terms = [dict(t.as_coeff_Mul()[::-1] for t in Add.make_args(p)) for p in powers] + algebraics = set().union(*terms) + matrix = [[todom(t.get(a, S.Zero)) for t in terms] for a in algebraics] + + # Create a function to do the conversion efficiently: + + def converter(a): + """Convert a to Expr using converter""" + ai = a.to_list()[::-1] + coeffs_dom = [sum(mij*aj for mij, aj in zip(mi, ai)) for mi in matrix] + coeffs_sympy = [toexpr(c) for c in coeffs_dom] + res = Add(*(Mul(c, a) for c, a in zip(coeffs_sympy, algebraics))) + return res + + return converter diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/characteristiczero.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/characteristiczero.py new file mode 100644 index 0000000000000000000000000000000000000000..755a354bea9594b9e8f73256c448b3debae037b2 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/characteristiczero.py @@ -0,0 +1,15 @@ +"""Implementation of :class:`CharacteristicZero` class. """ + + +from sympy.polys.domains.domain import Domain +from sympy.utilities import public + +@public +class CharacteristicZero(Domain): + """Domain that has infinite number of elements. """ + + has_CharacteristicZero = True + + def characteristic(self): + """Return the characteristic of this domain. """ + return 0 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/complexfield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/complexfield.py new file mode 100644 index 0000000000000000000000000000000000000000..69f0bff2c1b311a150add88d5a1f146ea7b1726a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/complexfield.py @@ -0,0 +1,198 @@ +"""Implementation of :class:`ComplexField` class. """ + + +from sympy.external.gmpy import SYMPY_INTS +from sympy.core.numbers import Float, I +from sympy.polys.domains.characteristiczero import CharacteristicZero +from sympy.polys.domains.field import Field +from sympy.polys.domains.gaussiandomains import QQ_I +from sympy.polys.domains.simpledomain import SimpleDomain +from sympy.polys.polyerrors import DomainError, CoercionFailed +from sympy.utilities import public + +from mpmath import MPContext + + +@public +class ComplexField(Field, CharacteristicZero, SimpleDomain): + """Complex numbers up to the given precision. """ + + rep = 'CC' + + is_ComplexField = is_CC = True + + is_Exact = False + is_Numerical = True + + has_assoc_Ring = False + has_assoc_Field = True + + _default_precision = 53 + + @property + def has_default_precision(self): + return self.precision == self._default_precision + + @property + def precision(self): + return self._context.prec + + @property + def dps(self): + return self._context.dps + + @property + def tolerance(self): + return self._tolerance + + def __init__(self, prec=None, dps=None, tol=None): + # XXX: The tolerance parameter is ignored but is kept for backward + # compatibility for now. + + context = MPContext() + + if prec is None and dps is None: + context.prec = self._default_precision + elif dps is None: + context.prec = prec + elif prec is None: + context.dps = dps + else: + raise TypeError("Cannot set both prec and dps") + + self._context = context + + self._dtype = context.mpc + self.zero = self.dtype(0) + self.one = self.dtype(1) + + # XXX: Neither of these is actually used anywhere. + self._max_denom = max(2**context.prec // 200, 99) + self._tolerance = self.one / self._max_denom + + @property + def tp(self): + # XXX: Domain treats tp as an alias of dtype. Here we need two separate + # things: dtype is a callable to make/convert instances. We use tp with + # isinstance to check if an object is an instance of the domain + # already. + return self._dtype + + def dtype(self, x, y=0): + # XXX: This is needed because mpmath does not recognise fmpz. + # It might be better to add conversion routines to mpmath and if that + # happens then this can be removed. + if isinstance(x, SYMPY_INTS): + x = int(x) + if isinstance(y, SYMPY_INTS): + y = int(y) + return self._dtype(x, y) + + def __eq__(self, other): + return isinstance(other, ComplexField) and self.precision == other.precision + + def __hash__(self): + return hash((self.__class__.__name__, self._dtype, self.precision)) + + def to_sympy(self, element): + """Convert ``element`` to SymPy number. """ + return Float(element.real, self.dps) + I*Float(element.imag, self.dps) + + def from_sympy(self, expr): + """Convert SymPy's number to ``dtype``. """ + number = expr.evalf(n=self.dps) + real, imag = number.as_real_imag() + + if real.is_Number and imag.is_Number: + return self.dtype(real, imag) + else: + raise CoercionFailed("expected complex number, got %s" % expr) + + def from_ZZ(self, element, base): + return self.dtype(element) + + def from_ZZ_gmpy(self, element, base): + return self.dtype(int(element)) + + def from_ZZ_python(self, element, base): + return self.dtype(element) + + def from_QQ(self, element, base): + return self.dtype(int(element.numerator)) / int(element.denominator) + + def from_QQ_python(self, element, base): + return self.dtype(element.numerator) / element.denominator + + def from_QQ_gmpy(self, element, base): + return self.dtype(int(element.numerator)) / int(element.denominator) + + def from_GaussianIntegerRing(self, element, base): + return self.dtype(int(element.x), int(element.y)) + + def from_GaussianRationalField(self, element, base): + x = element.x + y = element.y + return (self.dtype(int(x.numerator)) / int(x.denominator) + + self.dtype(0, int(y.numerator)) / int(y.denominator)) + + def from_AlgebraicField(self, element, base): + return self.from_sympy(base.to_sympy(element).evalf(self.dps)) + + def from_RealField(self, element, base): + return self.dtype(element) + + def from_ComplexField(self, element, base): + return self.dtype(element) + + def get_ring(self): + """Returns a ring associated with ``self``. """ + raise DomainError("there is no ring associated with %s" % self) + + def get_exact(self): + """Returns an exact domain associated with ``self``. """ + return QQ_I + + def is_negative(self, element): + """Returns ``False`` for any ``ComplexElement``. """ + return False + + def is_positive(self, element): + """Returns ``False`` for any ``ComplexElement``. """ + return False + + def is_nonnegative(self, element): + """Returns ``False`` for any ``ComplexElement``. """ + return False + + def is_nonpositive(self, element): + """Returns ``False`` for any ``ComplexElement``. """ + return False + + def gcd(self, a, b): + """Returns GCD of ``a`` and ``b``. """ + return self.one + + def lcm(self, a, b): + """Returns LCM of ``a`` and ``b``. """ + return a*b + + def almosteq(self, a, b, tolerance=None): + """Check if ``a`` and ``b`` are almost equal. """ + return self._context.almosteq(a, b, tolerance) + + def is_square(self, a): + """Returns ``True``. Every complex number has a complex square root.""" + return True + + def exsqrt(self, a): + r"""Returns the principal complex square root of ``a``. + + Explanation + =========== + The argument of the principal square root is always within + $(-\frac{\pi}{2}, \frac{\pi}{2}]$. The square root may be + slightly inaccurate due to floating point rounding error. + """ + return a ** 0.5 + +CC = ComplexField() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/compositedomain.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/compositedomain.py new file mode 100644 index 0000000000000000000000000000000000000000..a8f63ba7bb86b1d69493b77bfa8c7f33652adbbf --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/compositedomain.py @@ -0,0 +1,52 @@ +"""Implementation of :class:`CompositeDomain` class. """ + + +from sympy.polys.domains.domain import Domain +from sympy.polys.polyerrors import GeneratorsError + +from sympy.utilities import public + +@public +class CompositeDomain(Domain): + """Base class for composite domains, e.g. ZZ[x], ZZ(X). """ + + is_Composite = True + + gens, ngens, symbols, domain = [None]*4 + + def inject(self, *symbols): + """Inject generators into this domain. """ + if not (set(self.symbols) & set(symbols)): + return self.__class__(self.domain, self.symbols + symbols, self.order) + else: + raise GeneratorsError("common generators in %s and %s" % (self.symbols, symbols)) + + def drop(self, *symbols): + """Drop generators from this domain. """ + symset = set(symbols) + newsyms = tuple(s for s in self.symbols if s not in symset) + domain = self.domain.drop(*symbols) + if not newsyms: + return domain + else: + return self.__class__(domain, newsyms, self.order) + + def set_domain(self, domain): + """Set the ground domain of this domain. """ + return self.__class__(domain, self.symbols, self.order) + + @property + def is_Exact(self): + """Returns ``True`` if this domain is exact. """ + return self.domain.is_Exact + + def get_exact(self): + """Returns an exact version of this domain. """ + return self.set_domain(self.domain.get_exact()) + + @property + def has_CharacteristicZero(self): + return self.domain.has_CharacteristicZero + + def characteristic(self): + return self.domain.characteristic() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/domain.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/domain.py new file mode 100644 index 0000000000000000000000000000000000000000..1d7fc1eac6184601c199fb6724a11e92346789f1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/domain.py @@ -0,0 +1,1382 @@ +"""Implementation of :class:`Domain` class. """ + +from __future__ import annotations +from typing import Any + +from sympy.core.numbers import AlgebraicNumber +from sympy.core import Basic, sympify +from sympy.core.sorting import ordered +from sympy.external.gmpy import GROUND_TYPES +from sympy.polys.domains.domainelement import DomainElement +from sympy.polys.orderings import lex +from sympy.polys.polyerrors import UnificationFailed, CoercionFailed, DomainError +from sympy.polys.polyutils import _unify_gens, _not_a_coeff +from sympy.utilities import public +from sympy.utilities.iterables import is_sequence + + +@public +class Domain: + """Superclass for all domains in the polys domains system. + + See :ref:`polys-domainsintro` for an introductory explanation of the + domains system. + + The :py:class:`~.Domain` class is an abstract base class for all of the + concrete domain types. There are many different :py:class:`~.Domain` + subclasses each of which has an associated ``dtype`` which is a class + representing the elements of the domain. The coefficients of a + :py:class:`~.Poly` are elements of a domain which must be a subclass of + :py:class:`~.Domain`. + + Examples + ======== + + The most common example domains are the integers :ref:`ZZ` and the + rationals :ref:`QQ`. + + >>> from sympy import Poly, symbols, Domain + >>> x, y = symbols('x, y') + >>> p = Poly(x**2 + y) + >>> p + Poly(x**2 + y, x, y, domain='ZZ') + >>> p.domain + ZZ + >>> isinstance(p.domain, Domain) + True + >>> Poly(x**2 + y/2) + Poly(x**2 + 1/2*y, x, y, domain='QQ') + + The domains can be used directly in which case the domain object e.g. + (:ref:`ZZ` or :ref:`QQ`) can be used as a constructor for elements of + ``dtype``. + + >>> from sympy import ZZ, QQ + >>> ZZ(2) + 2 + >>> ZZ.dtype # doctest: +SKIP + + >>> type(ZZ(2)) # doctest: +SKIP + + >>> QQ(1, 2) + 1/2 + >>> type(QQ(1, 2)) # doctest: +SKIP + + + The corresponding domain elements can be used with the arithmetic + operations ``+,-,*,**`` and depending on the domain some combination of + ``/,//,%`` might be usable. For example in :ref:`ZZ` both ``//`` (floor + division) and ``%`` (modulo division) can be used but ``/`` (true + division) cannot. Since :ref:`QQ` is a :py:class:`~.Field` its elements + can be used with ``/`` but ``//`` and ``%`` should not be used. Some + domains have a :py:meth:`~.Domain.gcd` method. + + >>> ZZ(2) + ZZ(3) + 5 + >>> ZZ(5) // ZZ(2) + 2 + >>> ZZ(5) % ZZ(2) + 1 + >>> QQ(1, 2) / QQ(2, 3) + 3/4 + >>> ZZ.gcd(ZZ(4), ZZ(2)) + 2 + >>> QQ.gcd(QQ(2,7), QQ(5,3)) + 1/21 + >>> ZZ.is_Field + False + >>> QQ.is_Field + True + + There are also many other domains including: + + 1. :ref:`GF(p)` for finite fields of prime order. + 2. :ref:`RR` for real (floating point) numbers. + 3. :ref:`CC` for complex (floating point) numbers. + 4. :ref:`QQ(a)` for algebraic number fields. + 5. :ref:`K[x]` for polynomial rings. + 6. :ref:`K(x)` for rational function fields. + 7. :ref:`EX` for arbitrary expressions. + + Each domain is represented by a domain object and also an implementation + class (``dtype``) for the elements of the domain. For example the + :ref:`K[x]` domains are represented by a domain object which is an + instance of :py:class:`~.PolynomialRing` and the elements are always + instances of :py:class:`~.PolyElement`. The implementation class + represents particular types of mathematical expressions in a way that is + more efficient than a normal SymPy expression which is of type + :py:class:`~.Expr`. The domain methods :py:meth:`~.Domain.from_sympy` and + :py:meth:`~.Domain.to_sympy` are used to convert from :py:class:`~.Expr` + to a domain element and vice versa. + + >>> from sympy import Symbol, ZZ, Expr + >>> x = Symbol('x') + >>> K = ZZ[x] # polynomial ring domain + >>> K + ZZ[x] + >>> type(K) # class of the domain + + >>> K.dtype # doctest: +SKIP + + >>> p_expr = x**2 + 1 # Expr + >>> p_expr + x**2 + 1 + >>> type(p_expr) + + >>> isinstance(p_expr, Expr) + True + >>> p_domain = K.from_sympy(p_expr) + >>> p_domain # domain element + x**2 + 1 + >>> type(p_domain) + + >>> K.to_sympy(p_domain) == p_expr + True + + The :py:meth:`~.Domain.convert_from` method is used to convert domain + elements from one domain to another. + + >>> from sympy import ZZ, QQ + >>> ez = ZZ(2) + >>> eq = QQ.convert_from(ez, ZZ) + >>> type(ez) # doctest: +SKIP + + >>> type(eq) # doctest: +SKIP + + + Elements from different domains should not be mixed in arithmetic or other + operations: they should be converted to a common domain first. The domain + method :py:meth:`~.Domain.unify` is used to find a domain that can + represent all the elements of two given domains. + + >>> from sympy import ZZ, QQ, symbols + >>> x, y = symbols('x, y') + >>> ZZ.unify(QQ) + QQ + >>> ZZ[x].unify(QQ) + QQ[x] + >>> ZZ[x].unify(QQ[y]) + QQ[x,y] + + If a domain is a :py:class:`~.Ring` then is might have an associated + :py:class:`~.Field` and vice versa. The :py:meth:`~.Domain.get_field` and + :py:meth:`~.Domain.get_ring` methods will find or create the associated + domain. + + >>> from sympy import ZZ, QQ, Symbol + >>> x = Symbol('x') + >>> ZZ.has_assoc_Field + True + >>> ZZ.get_field() + QQ + >>> QQ.has_assoc_Ring + True + >>> QQ.get_ring() + ZZ + >>> K = QQ[x] + >>> K + QQ[x] + >>> K.get_field() + QQ(x) + + See also + ======== + + DomainElement: abstract base class for domain elements + construct_domain: construct a minimal domain for some expressions + + """ + + dtype: type | None = None + """The type (class) of the elements of this :py:class:`~.Domain`: + + >>> from sympy import ZZ, QQ, Symbol + >>> ZZ.dtype + + >>> z = ZZ(2) + >>> z + 2 + >>> type(z) + + >>> type(z) == ZZ.dtype + True + + Every domain has an associated **dtype** ("datatype") which is the + class of the associated domain elements. + + See also + ======== + + of_type + """ + + zero: Any = None + """The zero element of the :py:class:`~.Domain`: + + >>> from sympy import QQ + >>> QQ.zero + 0 + >>> QQ.of_type(QQ.zero) + True + + See also + ======== + + of_type + one + """ + + one: Any = None + """The one element of the :py:class:`~.Domain`: + + >>> from sympy import QQ + >>> QQ.one + 1 + >>> QQ.of_type(QQ.one) + True + + See also + ======== + + of_type + zero + """ + + is_Ring = False + """Boolean flag indicating if the domain is a :py:class:`~.Ring`. + + >>> from sympy import ZZ + >>> ZZ.is_Ring + True + + Basically every :py:class:`~.Domain` represents a ring so this flag is + not that useful. + + See also + ======== + + is_PID + is_Field + get_ring + has_assoc_Ring + """ + + is_Field = False + """Boolean flag indicating if the domain is a :py:class:`~.Field`. + + >>> from sympy import ZZ, QQ + >>> ZZ.is_Field + False + >>> QQ.is_Field + True + + See also + ======== + + is_PID + is_Ring + get_field + has_assoc_Field + """ + + has_assoc_Ring = False + """Boolean flag indicating if the domain has an associated + :py:class:`~.Ring`. + + >>> from sympy import QQ + >>> QQ.has_assoc_Ring + True + >>> QQ.get_ring() + ZZ + + See also + ======== + + is_Field + get_ring + """ + + has_assoc_Field = False + """Boolean flag indicating if the domain has an associated + :py:class:`~.Field`. + + >>> from sympy import ZZ + >>> ZZ.has_assoc_Field + True + >>> ZZ.get_field() + QQ + + See also + ======== + + is_Field + get_field + """ + + is_FiniteField = is_FF = False + is_IntegerRing = is_ZZ = False + is_RationalField = is_QQ = False + is_GaussianRing = is_ZZ_I = False + is_GaussianField = is_QQ_I = False + is_RealField = is_RR = False + is_ComplexField = is_CC = False + is_AlgebraicField = is_Algebraic = False + is_PolynomialRing = is_Poly = False + is_FractionField = is_Frac = False + is_SymbolicDomain = is_EX = False + is_SymbolicRawDomain = is_EXRAW = False + is_FiniteExtension = False + + is_Exact = True + is_Numerical = False + + is_Simple = False + is_Composite = False + + is_PID = False + """Boolean flag indicating if the domain is a `principal ideal domain`_. + + >>> from sympy import ZZ + >>> ZZ.has_assoc_Field + True + >>> ZZ.get_field() + QQ + + .. _principal ideal domain: https://en.wikipedia.org/wiki/Principal_ideal_domain + + See also + ======== + + is_Field + get_field + """ + + has_CharacteristicZero = False + + rep: str | None = None + alias: str | None = None + + def __init__(self): + raise NotImplementedError + + def __str__(self): + return self.rep + + def __repr__(self): + return str(self) + + def __hash__(self): + return hash((self.__class__.__name__, self.dtype)) + + def new(self, *args): + return self.dtype(*args) + + @property + def tp(self): + """Alias for :py:attr:`~.Domain.dtype`""" + return self.dtype + + def __call__(self, *args): + """Construct an element of ``self`` domain from ``args``. """ + return self.new(*args) + + def normal(self, *args): + return self.dtype(*args) + + 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(self, method) + + if _convert is not None: + result = _convert(element, base) + + if result is not None: + return result + + raise CoercionFailed("Cannot 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: + if _not_a_coeff(element): + raise CoercionFailed('%s is not in any domain' % element) + return self.convert_from(element, base) + + if self.of_type(element): + return element + + if _not_a_coeff(element): + raise CoercionFailed('%s is not in any domain' % element) + + from sympy.polys.domains import ZZ, QQ, RealField, ComplexField + + if ZZ.of_type(element): + return self.convert_from(element, ZZ) + + if isinstance(element, int): + return self.convert_from(ZZ(element), ZZ) + + if GROUND_TYPES != 'python': + if isinstance(element, ZZ.tp): + return self.convert_from(element, ZZ) + if isinstance(element, QQ.tp): + return self.convert_from(element, QQ) + + if isinstance(element, float): + parent = RealField() + return self.convert_from(parent(element), parent) + + if isinstance(element, complex): + parent = ComplexField() + return self.convert_from(parent(element), parent) + + if type(element).__name__ == 'mpf': + parent = RealField() + return self.convert_from(parent(element), parent) + + if type(element).__name__ == 'mpc': + parent = ComplexField() + return self.convert_from(parent(element), parent) + + if isinstance(element, DomainElement): + return self.convert_from(element, element.parent()) + + # TODO: implement this in from_ methods + if self.is_Numerical and getattr(element, 'is_ground', False): + return self.convert(element.LC()) + + if isinstance(element, Basic): + try: + return self.from_sympy(element) + except (TypeError, ValueError): + pass + else: # TODO: remove this branch + if not is_sequence(element): + try: + element = sympify(element, strict=True) + if isinstance(element, Basic): + return self.from_sympy(element) + except (TypeError, ValueError): + pass + + raise CoercionFailed("Cannot convert %s of type %s to %s" % (element, type(element), self)) + + def of_type(self, element): + """Check if ``a`` is of type ``dtype``. """ + return isinstance(element, self.tp) + + def __contains__(self, a): + """Check if ``a`` belongs to this domain. """ + try: + if _not_a_coeff(a): + raise CoercionFailed + self.convert(a) # this might raise, too + except CoercionFailed: + return False + + return True + + def to_sympy(self, a): + """Convert domain element *a* to a SymPy expression (Expr). + + Explanation + =========== + + Convert a :py:class:`~.Domain` element *a* to :py:class:`~.Expr`. Most + public SymPy functions work with objects of type :py:class:`~.Expr`. + The elements of a :py:class:`~.Domain` have a different internal + representation. It is not possible to mix domain elements with + :py:class:`~.Expr` so each domain has :py:meth:`~.Domain.to_sympy` and + :py:meth:`~.Domain.from_sympy` methods to convert its domain elements + to and from :py:class:`~.Expr`. + + Parameters + ========== + + a: domain element + An element of this :py:class:`~.Domain`. + + Returns + ======= + + expr: Expr + A normal SymPy expression of type :py:class:`~.Expr`. + + Examples + ======== + + Construct an element of the :ref:`QQ` domain and then convert it to + :py:class:`~.Expr`. + + >>> from sympy import QQ, Expr + >>> q_domain = QQ(2) + >>> q_domain + 2 + >>> q_expr = QQ.to_sympy(q_domain) + >>> q_expr + 2 + + Although the printed forms look similar these objects are not of the + same type. + + >>> isinstance(q_domain, Expr) + False + >>> isinstance(q_expr, Expr) + True + + Construct an element of :ref:`K[x]` and convert to + :py:class:`~.Expr`. + + >>> from sympy import Symbol + >>> x = Symbol('x') + >>> K = QQ[x] + >>> x_domain = K.gens[0] # generator x as a domain element + >>> p_domain = x_domain**2/3 + 1 + >>> p_domain + 1/3*x**2 + 1 + >>> p_expr = K.to_sympy(p_domain) + >>> p_expr + x**2/3 + 1 + + The :py:meth:`~.Domain.from_sympy` method is used for the opposite + conversion from a normal SymPy expression to a domain element. + + >>> p_domain == p_expr + False + >>> K.from_sympy(p_expr) == p_domain + True + >>> K.to_sympy(p_domain) == p_expr + True + >>> K.from_sympy(K.to_sympy(p_domain)) == p_domain + True + >>> K.to_sympy(K.from_sympy(p_expr)) == p_expr + True + + The :py:meth:`~.Domain.from_sympy` method makes it easier to construct + domain elements interactively. + + >>> from sympy import Symbol + >>> x = Symbol('x') + >>> K = QQ[x] + >>> K.from_sympy(x**2/3 + 1) + 1/3*x**2 + 1 + + See also + ======== + + from_sympy + convert_from + """ + raise NotImplementedError + + def from_sympy(self, a): + """Convert a SymPy expression to an element of this domain. + + Explanation + =========== + + See :py:meth:`~.Domain.to_sympy` for explanation and examples. + + Parameters + ========== + + expr: Expr + A normal SymPy expression of type :py:class:`~.Expr`. + + Returns + ======= + + a: domain element + An element of this :py:class:`~.Domain`. + + See also + ======== + + to_sympy + convert_from + """ + raise NotImplementedError + + def sum(self, args): + return sum(args, start=self.zero) + + def from_FF(K1, a, K0): + """Convert ``ModularInteger(int)`` to ``dtype``. """ + return None + + def from_FF_python(K1, a, K0): + """Convert ``ModularInteger(int)`` to ``dtype``. """ + return None + + def from_ZZ_python(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return None + + def from_QQ_python(K1, a, K0): + """Convert a Python ``Fraction`` object to ``dtype``. """ + return None + + def from_FF_gmpy(K1, a, K0): + """Convert ``ModularInteger(mpz)`` to ``dtype``. """ + return None + + def from_ZZ_gmpy(K1, a, K0): + """Convert a GMPY ``mpz`` object to ``dtype``. """ + return None + + def from_QQ_gmpy(K1, a, K0): + """Convert a GMPY ``mpq`` object to ``dtype``. """ + return None + + def from_RealField(K1, a, K0): + """Convert a real element object to ``dtype``. """ + return None + + def from_ComplexField(K1, a, K0): + """Convert a complex element to ``dtype``. """ + return None + + def from_AlgebraicField(K1, a, K0): + """Convert an algebraic number to ``dtype``. """ + return None + + 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 rational function to ``dtype``. """ + return None + + def from_MonogenicFiniteExtension(K1, a, K0): + """Convert an ``ExtensionElement`` to ``dtype``. """ + return K1.convert_from(a.rep, K0.ring) + + def from_ExpressionDomain(K1, a, K0): + """Convert a ``EX`` object to ``dtype``. """ + return K1.from_sympy(a.ex) + + def from_ExpressionRawDomain(K1, a, K0): + """Convert a ``EX`` object to ``dtype``. """ + return K1.from_sympy(a) + + 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) + + def unify_with_symbols(K0, K1, symbols): + if (K0.is_Composite and (set(K0.symbols) & set(symbols))) or (K1.is_Composite and (set(K1.symbols) & set(symbols))): + raise UnificationFailed("Cannot unify %s with %s, given %s generators" % (K0, K1, tuple(symbols))) + + return K0.unify(K1) + + def unify_composite(K0, K1): + """Unify two domains where at least one is composite.""" + K0_ground = K0.dom if K0.is_Composite else K0 + K1_ground = K1.dom if K1.is_Composite else K1 + + K0_symbols = K0.symbols if K0.is_Composite else () + K1_symbols = K1.symbols if K1.is_Composite else () + + domain = K0_ground.unify(K1_ground) + symbols = _unify_gens(K0_symbols, K1_symbols) + order = K0.order if K0.is_Composite else K1.order + + # E.g. ZZ[x].unify(QQ.frac_field(x)) -> ZZ.frac_field(x) + if ((K0.is_FractionField and K1.is_PolynomialRing or + K1.is_FractionField and K0.is_PolynomialRing) and + (not K0_ground.is_Field or not K1_ground.is_Field) and domain.is_Field + and domain.has_assoc_Ring): + domain = domain.get_ring() + + if K0.is_Composite and (not K1.is_Composite or K0.is_FractionField or K1.is_PolynomialRing): + cls = K0.__class__ + else: + cls = K1.__class__ + + # Here cls might be PolynomialRing, FractionField, GlobalPolynomialRing + # (dense/old Polynomialring) or dense/old FractionField. + + from sympy.polys.domains.old_polynomialring import GlobalPolynomialRing + if cls == GlobalPolynomialRing: + return cls(domain, symbols) + + return cls(domain, symbols, order) + + def unify(K0, K1, symbols=None): + """ + Construct a minimal domain that contains elements of ``K0`` and ``K1``. + + Known domains (from smallest to largest): + + - ``GF(p)`` + - ``ZZ`` + - ``QQ`` + - ``RR(prec, tol)`` + - ``CC(prec, tol)`` + - ``ALG(a, b, c)`` + - ``K[x, y, z]`` + - ``K(x, y, z)`` + - ``EX`` + + """ + if symbols is not None: + return K0.unify_with_symbols(K1, symbols) + + if K0 == K1: + return K0 + + if not (K0.has_CharacteristicZero and K1.has_CharacteristicZero): + # Reject unification of domains with different characteristics. + if K0.characteristic() != K1.characteristic(): + raise UnificationFailed("Cannot unify %s with %s" % (K0, K1)) + + # We do not get here if K0 == K1. The two domains have the same + # characteristic but are unequal so at least one is composite and + # we are unifying something like GF(3).unify(GF(3)[x]). + return K0.unify_composite(K1) + + # From here we know both domains have characteristic zero and it can be + # acceptable to fall back on EX. + + if K0.is_EXRAW: + return K0 + if K1.is_EXRAW: + return K1 + + if K0.is_EX: + return K0 + if K1.is_EX: + return K1 + + if K0.is_FiniteExtension or K1.is_FiniteExtension: + if K1.is_FiniteExtension: + K0, K1 = K1, K0 + if K1.is_FiniteExtension: + # Unifying two extensions. + # Try to ensure that K0.unify(K1) == K1.unify(K0) + if list(ordered([K0.modulus, K1.modulus]))[1] == K0.modulus: + K0, K1 = K1, K0 + return K1.set_domain(K0) + else: + # Drop the generator from other and unify with the base domain + K1 = K1.drop(K0.symbol) + K1 = K0.domain.unify(K1) + return K0.set_domain(K1) + + if K0.is_Composite or K1.is_Composite: + return K0.unify_composite(K1) + + if K1.is_ComplexField: + K0, K1 = K1, K0 + if K0.is_ComplexField: + if K1.is_ComplexField or K1.is_RealField: + if K0.precision >= K1.precision: + return K0 + else: + from sympy.polys.domains.complexfield import ComplexField + return ComplexField(prec=K1.precision) + else: + return K0 + + if K1.is_RealField: + K0, K1 = K1, K0 + if K0.is_RealField: + if K1.is_RealField: + if K0.precision >= K1.precision: + return K0 + else: + return K1 + elif K1.is_GaussianRing or K1.is_GaussianField: + from sympy.polys.domains.complexfield import ComplexField + return ComplexField(prec=K0.precision) + else: + return K0 + + if K1.is_AlgebraicField: + K0, K1 = K1, K0 + if K0.is_AlgebraicField: + if K1.is_GaussianRing: + K1 = K1.get_field() + if K1.is_GaussianField: + K1 = K1.as_AlgebraicField() + if K1.is_AlgebraicField: + return K0.__class__(K0.dom.unify(K1.dom), *_unify_gens(K0.orig_ext, K1.orig_ext)) + else: + return K0 + + if K0.is_GaussianField: + return K0 + if K1.is_GaussianField: + return K1 + + if K0.is_GaussianRing: + if K1.is_RationalField: + K0 = K0.get_field() + return K0 + if K1.is_GaussianRing: + if K0.is_RationalField: + K1 = K1.get_field() + return K1 + + if K0.is_RationalField: + return K0 + if K1.is_RationalField: + return K1 + + if K0.is_IntegerRing: + return K0 + if K1.is_IntegerRing: + return K1 + + from sympy.polys.domains import EX + return EX + + def __eq__(self, other): + """Returns ``True`` if two domains are equivalent. """ + # XXX: Remove this. + return isinstance(other, Domain) and self.dtype == other.dtype + + def __ne__(self, other): + """Returns ``False`` if two domains are equivalent. """ + return not self == other + + def map(self, seq): + """Rersively apply ``self`` to all elements of ``seq``. """ + result = [] + + for elt in seq: + if isinstance(elt, list): + result.append(self.map(elt)) + else: + result.append(self(elt)) + + return result + + def get_ring(self): + """Returns a ring associated with ``self``. """ + raise DomainError('there is no ring associated with %s' % self) + + def get_field(self): + """Returns a field associated with ``self``. """ + raise DomainError('there is no field associated with %s' % self) + + def get_exact(self): + """Returns an exact domain associated with ``self``. """ + return self + + def __getitem__(self, symbols): + """The mathematical way to make a polynomial ring. """ + if hasattr(symbols, '__iter__'): + return self.poly_ring(*symbols) + else: + return self.poly_ring(symbols) + + def poly_ring(self, *symbols, order=lex): + """Returns a polynomial ring, i.e. `K[X]`. """ + from sympy.polys.domains.polynomialring import PolynomialRing + return PolynomialRing(self, symbols, order) + + def frac_field(self, *symbols, order=lex): + """Returns a fraction field, i.e. `K(X)`. """ + from sympy.polys.domains.fractionfield import FractionField + return FractionField(self, symbols, order) + + def old_poly_ring(self, *symbols, **kwargs): + """Returns a polynomial ring, i.e. `K[X]`. """ + from sympy.polys.domains.old_polynomialring import PolynomialRing + return PolynomialRing(self, *symbols, **kwargs) + + def old_frac_field(self, *symbols, **kwargs): + """Returns a fraction field, i.e. `K(X)`. """ + from sympy.polys.domains.old_fractionfield import FractionField + return FractionField(self, *symbols, **kwargs) + + def algebraic_field(self, *extension, alias=None): + r"""Returns an algebraic field, i.e. `K(\alpha, \ldots)`. """ + raise DomainError("Cannot create algebraic field over %s" % self) + + def alg_field_from_poly(self, poly, alias=None, root_index=-1): + r""" + Convenience method to construct an algebraic extension on a root of a + polynomial, chosen by root index. + + Parameters + ========== + + poly : :py:class:`~.Poly` + The polynomial whose root generates the extension. + alias : str, optional (default=None) + Symbol name for the generator of the extension. + E.g. "alpha" or "theta". + root_index : int, optional (default=-1) + Specifies which root of the polynomial is desired. The ordering is + as defined by the :py:class:`~.ComplexRootOf` class. The default of + ``-1`` selects the most natural choice in the common cases of + quadratic and cyclotomic fields (the square root on the positive + real or imaginary axis, resp. $\mathrm{e}^{2\pi i/n}$). + + Examples + ======== + + >>> from sympy import QQ, Poly + >>> from sympy.abc import x + >>> f = Poly(x**2 - 2) + >>> K = QQ.alg_field_from_poly(f) + >>> K.ext.minpoly == f + True + >>> g = Poly(8*x**3 - 6*x - 1) + >>> L = QQ.alg_field_from_poly(g, "alpha") + >>> L.ext.minpoly == g + True + >>> L.to_sympy(L([1, 1, 1])) + alpha**2 + alpha + 1 + + """ + from sympy.polys.rootoftools import CRootOf + root = CRootOf(poly, root_index) + alpha = AlgebraicNumber(root, alias=alias) + return self.algebraic_field(alpha, alias=alias) + + def cyclotomic_field(self, n, ss=False, alias="zeta", gen=None, root_index=-1): + r""" + Convenience method to construct a cyclotomic field. + + Parameters + ========== + + n : int + Construct the nth cyclotomic field. + ss : boolean, optional (default=False) + If True, append *n* as a subscript on the alias string. + alias : str, optional (default="zeta") + Symbol name for the generator. + gen : :py:class:`~.Symbol`, optional (default=None) + Desired variable for the cyclotomic polynomial that defines the + field. If ``None``, a dummy variable will be used. + root_index : int, optional (default=-1) + Specifies which root of the polynomial is desired. The ordering is + as defined by the :py:class:`~.ComplexRootOf` class. The default of + ``-1`` selects the root $\mathrm{e}^{2\pi i/n}$. + + Examples + ======== + + >>> from sympy import QQ, latex + >>> K = QQ.cyclotomic_field(5) + >>> K.to_sympy(K([-1, 1])) + 1 - zeta + >>> L = QQ.cyclotomic_field(7, True) + >>> a = L.to_sympy(L([-1, 1])) + >>> print(a) + 1 - zeta7 + >>> print(latex(a)) + 1 - \zeta_{7} + + """ + from sympy.polys.specialpolys import cyclotomic_poly + if ss: + alias += str(n) + return self.alg_field_from_poly(cyclotomic_poly(n, gen), alias=alias, + root_index=root_index) + + def inject(self, *symbols): + """Inject generators into this domain. """ + raise NotImplementedError + + def drop(self, *symbols): + """Drop generators from this domain. """ + if self.is_Simple: + return self + raise NotImplementedError # pragma: no cover + + def is_zero(self, a): + """Returns True if ``a`` is zero. """ + return not a + + def is_one(self, a): + """Returns True if ``a`` is one. """ + return a == self.one + + def is_positive(self, a): + """Returns True if ``a`` is positive. """ + return a > 0 + + def is_negative(self, a): + """Returns True if ``a`` is negative. """ + return a < 0 + + def is_nonpositive(self, a): + """Returns True if ``a`` is non-positive. """ + return a <= 0 + + def is_nonnegative(self, a): + """Returns True if ``a`` is non-negative. """ + return a >= 0 + + def canonical_unit(self, a): + if self.is_negative(a): + return -self.one + else: + return self.one + + def abs(self, a): + """Absolute value of ``a``, implies ``__abs__``. """ + return abs(a) + + def neg(self, a): + """Returns ``a`` negated, implies ``__neg__``. """ + return -a + + def pos(self, a): + """Returns ``a`` positive, implies ``__pos__``. """ + return +a + + def add(self, a, b): + """Sum of ``a`` and ``b``, implies ``__add__``. """ + return a + b + + def sub(self, a, b): + """Difference of ``a`` and ``b``, implies ``__sub__``. """ + return a - b + + def mul(self, a, b): + """Product of ``a`` and ``b``, implies ``__mul__``. """ + return a * b + + def pow(self, a, b): + """Raise ``a`` to power ``b``, implies ``__pow__``. """ + return a ** b + + def exquo(self, a, b): + """Exact quotient of *a* and *b*. Analogue of ``a / b``. + + Explanation + =========== + + This is essentially the same as ``a / b`` except that an error will be + raised if the division is inexact (if there is any remainder) and the + result will always be a domain element. When working in a + :py:class:`~.Domain` that is not a :py:class:`~.Field` (e.g. :ref:`ZZ` + or :ref:`K[x]`) ``exquo`` should be used instead of ``/``. + + The key invariant is that if ``q = K.exquo(a, b)`` (and ``exquo`` does + not raise an exception) then ``a == b*q``. + + Examples + ======== + + We can use ``K.exquo`` instead of ``/`` for exact division. + + >>> from sympy import ZZ + >>> ZZ.exquo(ZZ(4), ZZ(2)) + 2 + >>> ZZ.exquo(ZZ(5), ZZ(2)) + Traceback (most recent call last): + ... + ExactQuotientFailed: 2 does not divide 5 in ZZ + + Over a :py:class:`~.Field` such as :ref:`QQ`, division (with nonzero + divisor) is always exact so in that case ``/`` can be used instead of + :py:meth:`~.Domain.exquo`. + + >>> from sympy import QQ + >>> QQ.exquo(QQ(5), QQ(2)) + 5/2 + >>> QQ(5) / QQ(2) + 5/2 + + Parameters + ========== + + a: domain element + The dividend + b: domain element + The divisor + + Returns + ======= + + q: domain element + The exact quotient + + Raises + ====== + + ExactQuotientFailed: if exact division is not possible. + ZeroDivisionError: when the divisor is zero. + + See also + ======== + + quo: Analogue of ``a // b`` + rem: Analogue of ``a % b`` + div: Analogue of ``divmod(a, b)`` + + Notes + ===== + + Since the default :py:attr:`~.Domain.dtype` for :ref:`ZZ` is ``int`` + (or ``mpz``) division as ``a / b`` should not be used as it would give + a ``float`` which is not a domain element. + + >>> ZZ(4) / ZZ(2) # doctest: +SKIP + 2.0 + >>> ZZ(5) / ZZ(2) # doctest: +SKIP + 2.5 + + On the other hand with `SYMPY_GROUND_TYPES=flint` elements of :ref:`ZZ` + are ``flint.fmpz`` and division would raise an exception: + + >>> ZZ(4) / ZZ(2) # doctest: +SKIP + Traceback (most recent call last): + ... + TypeError: unsupported operand type(s) for /: 'fmpz' and 'fmpz' + + Using ``/`` with :ref:`ZZ` will lead to incorrect results so + :py:meth:`~.Domain.exquo` should be used instead. + + """ + raise NotImplementedError + + def quo(self, a, b): + """Quotient of *a* and *b*. Analogue of ``a // b``. + + ``K.quo(a, b)`` is equivalent to ``K.div(a, b)[0]``. See + :py:meth:`~.Domain.div` for more explanation. + + See also + ======== + + rem: Analogue of ``a % b`` + div: Analogue of ``divmod(a, b)`` + exquo: Analogue of ``a / b`` + """ + raise NotImplementedError + + def rem(self, a, b): + """Modulo division of *a* and *b*. Analogue of ``a % b``. + + ``K.rem(a, b)`` is equivalent to ``K.div(a, b)[1]``. See + :py:meth:`~.Domain.div` for more explanation. + + See also + ======== + + quo: Analogue of ``a // b`` + div: Analogue of ``divmod(a, b)`` + exquo: Analogue of ``a / b`` + """ + raise NotImplementedError + + def div(self, a, b): + """Quotient and remainder for *a* and *b*. Analogue of ``divmod(a, b)`` + + Explanation + =========== + + This is essentially the same as ``divmod(a, b)`` except that is more + consistent when working over some :py:class:`~.Field` domains such as + :ref:`QQ`. When working over an arbitrary :py:class:`~.Domain` the + :py:meth:`~.Domain.div` method should be used instead of ``divmod``. + + The key invariant is that if ``q, r = K.div(a, b)`` then + ``a == b*q + r``. + + The result of ``K.div(a, b)`` is the same as the tuple + ``(K.quo(a, b), K.rem(a, b))`` except that if both quotient and + remainder are needed then it is more efficient to use + :py:meth:`~.Domain.div`. + + Examples + ======== + + We can use ``K.div`` instead of ``divmod`` for floor division and + remainder. + + >>> from sympy import ZZ, QQ + >>> ZZ.div(ZZ(5), ZZ(2)) + (2, 1) + + If ``K`` is a :py:class:`~.Field` then the division is always exact + with a remainder of :py:attr:`~.Domain.zero`. + + >>> QQ.div(QQ(5), QQ(2)) + (5/2, 0) + + Parameters + ========== + + a: domain element + The dividend + b: domain element + The divisor + + Returns + ======= + + (q, r): tuple of domain elements + The quotient and remainder + + Raises + ====== + + ZeroDivisionError: when the divisor is zero. + + See also + ======== + + quo: Analogue of ``a // b`` + rem: Analogue of ``a % b`` + exquo: Analogue of ``a / b`` + + Notes + ===== + + If ``gmpy`` is installed then the ``gmpy.mpq`` type will be used as + the :py:attr:`~.Domain.dtype` for :ref:`QQ`. The ``gmpy.mpq`` type + defines ``divmod`` in a way that is undesirable so + :py:meth:`~.Domain.div` should be used instead of ``divmod``. + + >>> a = QQ(1) + >>> b = QQ(3, 2) + >>> a # doctest: +SKIP + mpq(1,1) + >>> b # doctest: +SKIP + mpq(3,2) + >>> divmod(a, b) # doctest: +SKIP + (mpz(0), mpq(1,1)) + >>> QQ.div(a, b) # doctest: +SKIP + (mpq(2,3), mpq(0,1)) + + Using ``//`` or ``%`` with :ref:`QQ` will lead to incorrect results so + :py:meth:`~.Domain.div` should be used instead. + + """ + raise NotImplementedError + + def invert(self, a, b): + """Returns inversion of ``a mod b``, implies something. """ + raise NotImplementedError + + def revert(self, a): + """Returns ``a**(-1)`` if possible. """ + raise NotImplementedError + + def numer(self, a): + """Returns numerator of ``a``. """ + raise NotImplementedError + + def denom(self, a): + """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 + + def lcm(self, a, b): + """Returns LCM of ``a`` and ``b``. """ + raise NotImplementedError + + def log(self, a, b): + """Returns b-base logarithm of ``a``. """ + raise NotImplementedError + + def sqrt(self, a): + """Returns a (possibly inexact) square root of ``a``. + + Explanation + =========== + There is no universal definition of "inexact square root" for all + domains. It is not recommended to implement this method for domains + other then :ref:`ZZ`. + + See also + ======== + exsqrt + """ + raise NotImplementedError + + def is_square(self, a): + """Returns whether ``a`` is a square in the domain. + + Explanation + =========== + Returns ``True`` if there is an element ``b`` in the domain such that + ``b * b == a``, otherwise returns ``False``. For inexact domains like + :ref:`RR` and :ref:`CC`, a tiny difference in this equality can be + tolerated. + + See also + ======== + exsqrt + """ + raise NotImplementedError + + def exsqrt(self, a): + """Principal square root of a within the domain if ``a`` is square. + + Explanation + =========== + The implementation of this method should return an element ``b`` in the + domain such that ``b * b == a``, or ``None`` if there is no such ``b``. + For inexact domains like :ref:`RR` and :ref:`CC`, a tiny difference in + this equality can be tolerated. The choice of a "principal" square root + should follow a consistent rule whenever possible. + + See also + ======== + sqrt, is_square + """ + raise NotImplementedError + + def evalf(self, a, prec=None, **options): + """Returns numerical approximation of ``a``. """ + return self.to_sympy(a).evalf(prec, **options) + + n = evalf + + def real(self, a): + return a + + def imag(self, a): + return self.zero + + def almosteq(self, a, b, tolerance=None): + """Check if ``a`` and ``b`` are almost equal. """ + return a == b + + def characteristic(self): + """Return the characteristic of this domain. """ + raise NotImplementedError('characteristic()') + + +__all__ = ['Domain'] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/domainelement.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/domainelement.py new file mode 100644 index 0000000000000000000000000000000000000000..b1033e86a7edcbffa633efd65ca7ced48f3b1f1a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/domainelement.py @@ -0,0 +1,38 @@ +"""Trait for implementing domain elements. """ + + +from sympy.utilities import public + +@public +class DomainElement: + """ + Represents an element of a domain. + + Mix in this trait into a class whose instances should be recognized as + elements of a domain. Method ``parent()`` gives that domain. + """ + + __slots__ = () + + def parent(self): + """Get the domain associated with ``self`` + + Examples + ======== + + >>> from sympy import ZZ, symbols + >>> x, y = symbols('x, y') + >>> K = ZZ[x,y] + >>> p = K(x)**2 + K(y)**2 + >>> p + x**2 + y**2 + >>> p.parent() + ZZ[x,y] + + Notes + ===== + + This is used by :py:meth:`~.Domain.convert` to identify the domain + associated with a domain element. + """ + raise NotImplementedError("abstract method") diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/expressiondomain.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/expressiondomain.py new file mode 100644 index 0000000000000000000000000000000000000000..26cd5aa5bf34985f885093be227df6aa9b35d36c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/expressiondomain.py @@ -0,0 +1,278 @@ +"""Implementation of :class:`ExpressionDomain` class. """ + + +from sympy.core import sympify, SympifyError +from sympy.polys.domains.domainelement import DomainElement +from sympy.polys.domains.characteristiczero import CharacteristicZero +from sympy.polys.domains.field import Field +from sympy.polys.domains.simpledomain import SimpleDomain +from sympy.polys.polyutils import PicklableWithSlots +from sympy.utilities import public + +eflags = {"deep": False, "mul": True, "power_exp": False, "power_base": False, + "basic": False, "multinomial": False, "log": False} + +@public +class ExpressionDomain(Field, CharacteristicZero, SimpleDomain): + """A class for arbitrary expressions. """ + + is_SymbolicDomain = is_EX = True + + class Expression(DomainElement, PicklableWithSlots): + """An arbitrary expression. """ + + __slots__ = ('ex',) + + def __init__(self, ex): + if not isinstance(ex, self.__class__): + self.ex = sympify(ex) + else: + self.ex = ex.ex + + def __repr__(f): + return 'EX(%s)' % repr(f.ex) + + def __str__(f): + return 'EX(%s)' % str(f.ex) + + def __hash__(self): + return hash((self.__class__.__name__, self.ex)) + + def parent(self): + return EX + + def as_expr(f): + return f.ex + + def numer(f): + return f.__class__(f.ex.as_numer_denom()[0]) + + def denom(f): + return f.__class__(f.ex.as_numer_denom()[1]) + + def simplify(f, ex): + return f.__class__(ex.cancel().expand(**eflags)) + + def __abs__(f): + return f.__class__(abs(f.ex)) + + def __neg__(f): + return f.__class__(-f.ex) + + def _to_ex(f, g): + try: + return f.__class__(g) + except SympifyError: + return None + + def __lt__(f, g): + return f.ex.sort_key() < g.ex.sort_key() + + def __add__(f, g): + g = f._to_ex(g) + + if g is None: + return NotImplemented + elif g == EX.zero: + return f + elif f == EX.zero: + return g + else: + return f.simplify(f.ex + g.ex) + + def __radd__(f, g): + return f.simplify(f.__class__(g).ex + f.ex) + + def __sub__(f, g): + g = f._to_ex(g) + + if g is None: + return NotImplemented + elif g == EX.zero: + return f + elif f == EX.zero: + return -g + else: + return f.simplify(f.ex - g.ex) + + def __rsub__(f, g): + return f.simplify(f.__class__(g).ex - f.ex) + + def __mul__(f, g): + g = f._to_ex(g) + + if g is None: + return NotImplemented + + if EX.zero in (f, g): + return EX.zero + elif f.ex.is_Number and g.ex.is_Number: + return f.__class__(f.ex*g.ex) + + return f.simplify(f.ex*g.ex) + + def __rmul__(f, g): + return f.simplify(f.__class__(g).ex*f.ex) + + def __pow__(f, n): + n = f._to_ex(n) + + if n is not None: + return f.simplify(f.ex**n.ex) + else: + return NotImplemented + + def __truediv__(f, g): + g = f._to_ex(g) + + if g is not None: + return f.simplify(f.ex/g.ex) + else: + return NotImplemented + + def __rtruediv__(f, g): + return f.simplify(f.__class__(g).ex/f.ex) + + def __eq__(f, g): + return f.ex == f.__class__(g).ex + + def __ne__(f, g): + return not f == g + + def __bool__(f): + return not f.ex.is_zero + + 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) + + rep = 'EX' + + has_assoc_Ring = False + has_assoc_Field = True + + def __init__(self): + pass + + def __eq__(self, other): + if isinstance(other, ExpressionDomain): + return True + else: + return NotImplemented + + def __hash__(self): + return hash("EX") + + 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.dtype(a) + + def from_ZZ(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return K1(K0.to_sympy(a)) + + def from_ZZ_python(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return K1(K0.to_sympy(a)) + + def from_QQ(K1, a, K0): + """Convert a Python ``Fraction`` object to ``dtype``. """ + return K1(K0.to_sympy(a)) + + def from_QQ_python(K1, a, K0): + """Convert a Python ``Fraction`` 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)) + + def from_QQ_gmpy(K1, a, K0): + """Convert a GMPY ``mpq`` object to ``dtype``. """ + return K1(K0.to_sympy(a)) + + def from_GaussianIntegerRing(K1, a, K0): + """Convert a ``GaussianRational`` object to ``dtype``. """ + return K1(K0.to_sympy(a)) + + def from_GaussianRationalField(K1, a, K0): + """Convert a ``GaussianRational`` object to ``dtype``. """ + return K1(K0.to_sympy(a)) + + def from_AlgebraicField(K1, a, K0): + """Convert an ``ANP`` object to ``dtype``. """ + return K1(K0.to_sympy(a)) + + def from_RealField(K1, a, K0): + """Convert a mpmath ``mpf`` object to ``dtype``. """ + return K1(K0.to_sympy(a)) + + def from_ComplexField(K1, a, K0): + """Convert a mpmath ``mpc`` object to ``dtype``. """ + return K1(K0.to_sympy(a)) + + def from_PolynomialRing(K1, a, K0): + """Convert a ``DMP`` object to ``dtype``. """ + return K1(K0.to_sympy(a)) + + def from_FractionField(K1, a, K0): + """Convert a ``DMF`` object to ``dtype``. """ + return K1(K0.to_sympy(a)) + + def from_ExpressionDomain(K1, a, K0): + """Convert a ``EX`` object to ``dtype``. """ + return a + + def get_ring(self): + """Returns a ring associated with ``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``. """ + return self + + def is_positive(self, a): + """Returns True if ``a`` is positive. """ + return a.ex.as_coeff_mul()[0].is_positive + + def is_negative(self, a): + """Returns True if ``a`` is negative. """ + return a.ex.could_extract_minus_sign() + + def is_nonpositive(self, a): + """Returns True if ``a`` is non-positive. """ + return a.ex.as_coeff_mul()[0].is_nonpositive + + def is_nonnegative(self, a): + """Returns True if ``a`` is non-negative. """ + return a.ex.as_coeff_mul()[0].is_nonnegative + + def numer(self, a): + """Returns numerator of ``a``. """ + return a.numer() + + def denom(self, a): + """Returns denominator of ``a``. """ + return a.denom() + + def gcd(self, a, b): + return self(1) + + def lcm(self, a, b): + return a.lcm(b) + + +EX = ExpressionDomain() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/expressionrawdomain.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/expressionrawdomain.py new file mode 100644 index 0000000000000000000000000000000000000000..9811ca26c965197a13f56ab8266ad744e4571560 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/expressionrawdomain.py @@ -0,0 +1,57 @@ +"""Implementation of :class:`ExpressionRawDomain` class. """ + + +from sympy.core import Expr, S, sympify, Add +from sympy.polys.domains.characteristiczero import CharacteristicZero +from sympy.polys.domains.field import Field +from sympy.polys.domains.simpledomain import SimpleDomain +from sympy.polys.polyerrors import CoercionFailed +from sympy.utilities import public + + +@public +class ExpressionRawDomain(Field, CharacteristicZero, SimpleDomain): + """A class for arbitrary expressions but without automatic simplification. """ + + is_SymbolicRawDomain = is_EXRAW = True + + dtype = Expr + + zero = S.Zero + one = S.One + + rep = 'EXRAW' + + has_assoc_Ring = False + has_assoc_Field = True + + def __init__(self): + pass + + @classmethod + def new(self, a): + return sympify(a) + + def to_sympy(self, a): + """Convert ``a`` to a SymPy object. """ + return a + + def from_sympy(self, a): + """Convert SymPy's expression to ``dtype``. """ + if not isinstance(a, Expr): + raise CoercionFailed(f"Expecting an Expr instance but found: {type(a).__name__}") + return a + + def convert_from(self, a, K): + """Convert a domain element from another domain to EXRAW""" + return K.to_sympy(a) + + def get_field(self): + """Returns a field associated with ``self``. """ + return self + + def sum(self, items): + return Add(*items) + + +EXRAW = ExpressionRawDomain() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/field.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/field.py new file mode 100644 index 0000000000000000000000000000000000000000..a6370294365a38dee1b2eda9942a66aeef8fdae9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/field.py @@ -0,0 +1,118 @@ +"""Implementation of :class:`Field` class. """ + + +from sympy.polys.domains.ring import Ring +from sympy.polys.polyerrors import NotReversible, DomainError +from sympy.utilities import public + +@public +class Field(Ring): + """Represents a field domain. """ + + is_Field = True + is_PID = True + + def get_ring(self): + """Returns a ring associated with ``self``. """ + raise DomainError('there is no ring associated with %s' % self) + + def get_field(self): + """Returns a field associated with ``self``. """ + return self + + def exquo(self, a, b): + """Exact quotient of ``a`` and ``b``, implies ``__truediv__``. """ + return a / b + + def quo(self, a, b): + """Quotient of ``a`` and ``b``, implies ``__truediv__``. """ + return a / b + + def rem(self, a, b): + """Remainder of ``a`` and ``b``, implies nothing. """ + return self.zero + + def div(self, a, b): + """Division of ``a`` and ``b``, implies ``__truediv__``. """ + return a / b, self.zero + + def gcd(self, a, b): + """ + Returns GCD of ``a`` and ``b``. + + This definition of GCD over fields allows to clear denominators + in `primitive()`. + + Examples + ======== + + >>> from sympy.polys.domains import QQ + >>> from sympy import S, gcd, primitive + >>> from sympy.abc import x + + >>> QQ.gcd(QQ(2, 3), QQ(4, 9)) + 2/9 + >>> gcd(S(2)/3, S(4)/9) + 2/9 + >>> primitive(2*x/3 + S(4)/9) + (2/9, 3*x + 2) + + """ + try: + ring = self.get_ring() + except DomainError: + return self.one + + p = ring.gcd(self.numer(a), self.numer(b)) + q = ring.lcm(self.denom(a), self.denom(b)) + + return self.convert(p, ring)/q + + def gcdex(self, a, b): + """ + Returns x, y, g such that a * x + b * y == g == gcd(a, b) + """ + d = self.gcd(a, b) + + if a == self.zero: + if b == self.zero: + return self.zero, self.one, self.zero + else: + return self.zero, d/b, d + else: + return d/a, self.zero, d + + def lcm(self, a, b): + """ + Returns LCM of ``a`` and ``b``. + + >>> from sympy.polys.domains import QQ + >>> from sympy import S, lcm + + >>> QQ.lcm(QQ(2, 3), QQ(4, 9)) + 4/3 + >>> lcm(S(2)/3, S(4)/9) + 4/3 + + """ + + try: + ring = self.get_ring() + except DomainError: + return a*b + + p = ring.lcm(self.numer(a), self.numer(b)) + q = ring.gcd(self.denom(a), self.denom(b)) + + return self.convert(p, ring)/q + + def revert(self, a): + """Returns ``a**(-1)`` if possible. """ + if a: + return 1/a + else: + raise NotReversible('zero is not reversible') + + def is_unit(self, a): + """Return true if ``a`` is a invertible""" + return bool(a) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/finitefield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/finitefield.py new file mode 100644 index 0000000000000000000000000000000000000000..d3c48ac07f63aefb9a58c83bb95c5261e67e6a9e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/finitefield.py @@ -0,0 +1,368 @@ +"""Implementation of :class:`FiniteField` class. """ + +import operator + +from sympy.external.gmpy import GROUND_TYPES +from sympy.utilities.decorator import doctest_depends_on + +from sympy.core.numbers import int_valued +from sympy.polys.domains.field import Field + +from sympy.polys.domains.modularinteger import ModularIntegerFactory +from sympy.polys.domains.simpledomain import SimpleDomain +from sympy.polys.galoistools import gf_zassenhaus, gf_irred_p_rabin +from sympy.polys.polyerrors import CoercionFailed +from sympy.utilities import public +from sympy.polys.domains.groundtypes import SymPyInteger + + +if GROUND_TYPES == 'flint': + __doctest_skip__ = ['FiniteField'] + + +if GROUND_TYPES == 'flint': + import flint + # Don't use python-flint < 0.5.0 because nmod was missing some features in + # previous versions of python-flint and fmpz_mod was not yet added. + _major, _minor, *_ = flint.__version__.split('.') + if (int(_major), int(_minor)) < (0, 5): + flint = None +else: + flint = None + + +def _modular_int_factory_nmod(mod): + # nmod only recognises int + index = operator.index + mod = index(mod) + nmod = flint.nmod + nmod_poly = flint.nmod_poly + + # flint's nmod is only for moduli up to 2^64-1 (on a 64-bit machine) + try: + nmod(0, mod) + except OverflowError: + return None, None + + def ctx(x): + try: + return nmod(x, mod) + except TypeError: + return nmod(index(x), mod) + + def poly_ctx(cs): + return nmod_poly(cs, mod) + + return ctx, poly_ctx + + +def _modular_int_factory_fmpz_mod(mod): + index = operator.index + fctx = flint.fmpz_mod_ctx(mod) + fctx_poly = flint.fmpz_mod_poly_ctx(mod) + fmpz_mod_poly = flint.fmpz_mod_poly + + def ctx(x): + try: + return fctx(x) + except TypeError: + # x might be Integer + return fctx(index(x)) + + def poly_ctx(cs): + return fmpz_mod_poly(cs, fctx_poly) + + return ctx, poly_ctx + + +def _modular_int_factory(mod, dom, symmetric, self): + # Convert the modulus to ZZ + try: + mod = dom.convert(mod) + except CoercionFailed: + raise ValueError('modulus must be an integer, got %s' % mod) + + ctx, poly_ctx, is_flint = None, None, False + + # Don't use flint if the modulus is not prime as it often crashes. + if flint is not None and mod.is_prime(): + + is_flint = True + + # Try to use flint's nmod first + ctx, poly_ctx = _modular_int_factory_nmod(mod) + + if ctx is None: + # Use fmpz_mod for larger moduli + ctx, poly_ctx = _modular_int_factory_fmpz_mod(mod) + + if ctx is None: + # Use the Python implementation if flint is not available or the + # modulus is not prime. + ctx = ModularIntegerFactory(mod, dom, symmetric, self) + poly_ctx = None # not used + + return ctx, poly_ctx, is_flint + + +@public +@doctest_depends_on(modules=['python', 'gmpy']) +class FiniteField(Field, SimpleDomain): + r"""Finite field of prime order :ref:`GF(p)` + + A :ref:`GF(p)` domain represents a `finite field`_ `\mathbb{F}_p` of prime + order as :py:class:`~.Domain` in the domain system (see + :ref:`polys-domainsintro`). + + A :py:class:`~.Poly` created from an expression with integer + coefficients will have the domain :ref:`ZZ`. However, if the ``modulus=p`` + option is given then the domain will be a finite field instead. + + >>> from sympy import Poly, Symbol + >>> x = Symbol('x') + >>> p = Poly(x**2 + 1) + >>> p + Poly(x**2 + 1, x, domain='ZZ') + >>> p.domain + ZZ + >>> p2 = Poly(x**2 + 1, modulus=2) + >>> p2 + Poly(x**2 + 1, x, modulus=2) + >>> p2.domain + GF(2) + + It is possible to factorise a polynomial over :ref:`GF(p)` using the + modulus argument to :py:func:`~.factor` or by specifying the domain + explicitly. The domain can also be given as a string. + + >>> from sympy import factor, GF + >>> factor(x**2 + 1) + x**2 + 1 + >>> factor(x**2 + 1, modulus=2) + (x + 1)**2 + >>> factor(x**2 + 1, domain=GF(2)) + (x + 1)**2 + >>> factor(x**2 + 1, domain='GF(2)') + (x + 1)**2 + + It is also possible to use :ref:`GF(p)` with the :py:func:`~.cancel` + and :py:func:`~.gcd` functions. + + >>> from sympy import cancel, gcd + >>> cancel((x**2 + 1)/(x + 1)) + (x**2 + 1)/(x + 1) + >>> cancel((x**2 + 1)/(x + 1), domain=GF(2)) + x + 1 + >>> gcd(x**2 + 1, x + 1) + 1 + >>> gcd(x**2 + 1, x + 1, domain=GF(2)) + x + 1 + + When using the domain directly :ref:`GF(p)` can be used as a constructor + to create instances which then support the operations ``+,-,*,**,/`` + + >>> from sympy import GF + >>> K = GF(5) + >>> K + GF(5) + >>> x = K(3) + >>> y = K(2) + >>> x + 3 mod 5 + >>> y + 2 mod 5 + >>> x * y + 1 mod 5 + >>> x / y + 4 mod 5 + + Notes + ===== + + It is also possible to create a :ref:`GF(p)` domain of **non-prime** + order but the resulting ring is **not** a field: it is just the ring of + the integers modulo ``n``. + + >>> K = GF(9) + >>> z = K(3) + >>> z + 3 mod 9 + >>> z**2 + 0 mod 9 + + It would be good to have a proper implementation of prime power fields + (``GF(p**n)``) but these are not yet implemented in SymPY. + + .. _finite field: https://en.wikipedia.org/wiki/Finite_field + """ + + rep = 'FF' + alias = 'FF' + + is_FiniteField = is_FF = True + is_Numerical = True + + has_assoc_Ring = False + has_assoc_Field = True + + dom = None + mod = None + + def __init__(self, mod, symmetric=True): + from sympy.polys.domains import ZZ + dom = ZZ + + if mod <= 0: + raise ValueError('modulus must be a positive integer, got %s' % mod) + + ctx, poly_ctx, is_flint = _modular_int_factory(mod, dom, symmetric, self) + + self.dtype = ctx + self._poly_ctx = poly_ctx + self._is_flint = is_flint + + self.zero = self.dtype(0) + self.one = self.dtype(1) + self.dom = dom + self.mod = mod + self.sym = symmetric + self._tp = type(self.zero) + + @property + def tp(self): + return self._tp + + @property + def is_Field(self): + is_field = getattr(self, '_is_field', None) + if is_field is None: + from sympy.ntheory.primetest import isprime + self._is_field = is_field = isprime(self.mod) + return is_field + + def __str__(self): + return 'GF(%s)' % self.mod + + def __hash__(self): + return hash((self.__class__.__name__, self.dtype, self.mod, self.dom)) + + def __eq__(self, other): + """Returns ``True`` if two domains are equivalent. """ + return isinstance(other, FiniteField) and \ + self.mod == other.mod and self.dom == other.dom + + def characteristic(self): + """Return the characteristic of this domain. """ + return self.mod + + def get_field(self): + """Returns a field associated with ``self``. """ + return self + + def to_sympy(self, a): + """Convert ``a`` to a SymPy object. """ + return SymPyInteger(self.to_int(a)) + + def from_sympy(self, a): + """Convert SymPy's Integer to SymPy's ``Integer``. """ + if a.is_Integer: + return self.dtype(self.dom.dtype(int(a))) + elif int_valued(a): + return self.dtype(self.dom.dtype(int(a))) + else: + raise CoercionFailed("expected an integer, got %s" % a) + + def to_int(self, a): + """Convert ``val`` to a Python ``int`` object. """ + aval = int(a) + if self.sym and aval > self.mod // 2: + aval -= self.mod + return aval + + def is_positive(self, a): + """Returns True if ``a`` is positive. """ + return bool(a) + + def is_nonnegative(self, a): + """Returns True if ``a`` is non-negative. """ + return True + + def is_negative(self, a): + """Returns True if ``a`` is negative. """ + return False + + def is_nonpositive(self, a): + """Returns True if ``a`` is non-positive. """ + return not a + + def from_FF(K1, a, K0=None): + """Convert ``ModularInteger(int)`` to ``dtype``. """ + return K1.dtype(K1.dom.from_ZZ(int(a), K0.dom)) + + def from_FF_python(K1, a, K0=None): + """Convert ``ModularInteger(int)`` to ``dtype``. """ + return K1.dtype(K1.dom.from_ZZ_python(int(a), K0.dom)) + + def from_ZZ(K1, a, K0=None): + """Convert Python's ``int`` to ``dtype``. """ + return K1.dtype(K1.dom.from_ZZ_python(a, K0)) + + def from_ZZ_python(K1, a, K0=None): + """Convert Python's ``int`` to ``dtype``. """ + return K1.dtype(K1.dom.from_ZZ_python(a, K0)) + + def from_QQ(K1, a, K0=None): + """Convert Python's ``Fraction`` to ``dtype``. """ + if a.denominator == 1: + return K1.from_ZZ_python(a.numerator) + + def from_QQ_python(K1, a, K0=None): + """Convert Python's ``Fraction`` to ``dtype``. """ + if a.denominator == 1: + return K1.from_ZZ_python(a.numerator) + + 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)) + + def from_ZZ_gmpy(K1, a, K0=None): + """Convert GMPY's ``mpz`` to ``dtype``. """ + return K1.dtype(K1.dom.from_ZZ_gmpy(a, K0)) + + def from_QQ_gmpy(K1, a, K0=None): + """Convert GMPY's ``mpq`` to ``dtype``. """ + if a.denominator == 1: + return K1.from_ZZ_gmpy(a.numerator) + + def from_RealField(K1, a, K0): + """Convert mpmath's ``mpf`` to ``dtype``. """ + p, q = K0.to_rational(a) + + if q == 1: + return K1.dtype(K1.dom.dtype(p)) + + def is_square(self, a): + """Returns True if ``a`` is a quadratic residue modulo p. """ + # a is not a square <=> x**2-a is irreducible + poly = [int(x) for x in [self.one, self.zero, -a]] + return not gf_irred_p_rabin(poly, self.mod, self.dom) + + def exsqrt(self, a): + """Square root modulo p of ``a`` if it is a quadratic residue. + + Explanation + =========== + Always returns the square root that is no larger than ``p // 2``. + """ + # x**2-a is not square-free if a=0 or the field is characteristic 2 + if self.mod == 2 or a == 0: + return a + # Otherwise, use square-free factorization routine to factorize x**2-a + poly = [int(x) for x in [self.one, self.zero, -a]] + for factor in gf_zassenhaus(poly, self.mod, self.dom): + if len(factor) == 2 and factor[1] <= self.mod // 2: + return self.dtype(factor[1]) + return None + + +FF = GF = FiniteField diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/fractionfield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/fractionfield.py new file mode 100644 index 0000000000000000000000000000000000000000..78f5054ddd5480fe6f77442f7a25f22603a4d90d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/fractionfield.py @@ -0,0 +1,181 @@ +"""Implementation of :class:`FractionField` class. """ + + +from sympy.polys.domains.compositedomain import CompositeDomain +from sympy.polys.domains.field import Field +from sympy.polys.polyerrors import CoercionFailed, GeneratorsError +from sympy.utilities import public + +@public +class FractionField(Field, CompositeDomain): + """A class for representing multivariate rational function fields. """ + + is_FractionField = is_Frac = True + + has_assoc_Ring = True + has_assoc_Field = True + + def __init__(self, domain_or_field, symbols=None, order=None): + from sympy.polys.fields import FracField + + if isinstance(domain_or_field, FracField) and symbols is None and order is None: + field = domain_or_field + else: + field = FracField(symbols, domain_or_field, order) + + self.field = field + self.dtype = field.dtype + + self.gens = field.gens + self.ngens = field.ngens + self.symbols = field.symbols + self.domain = field.domain + + # TODO: remove this + self.dom = self.domain + + def new(self, element): + return self.field.field_new(element) + + def of_type(self, element): + """Check if ``a`` is of type ``dtype``. """ + return self.field.is_element(element) + + @property + def zero(self): + return self.field.zero + + @property + def one(self): + return self.field.one + + @property + def order(self): + return self.field.order + + def __str__(self): + return str(self.domain) + '(' + ','.join(map(str, self.symbols)) + ')' + + def __hash__(self): + return hash((self.__class__.__name__, self.field, self.domain, self.symbols)) + + def __eq__(self, other): + """Returns ``True`` if two domains are equivalent. """ + if not isinstance(other, FractionField): + return NotImplemented + return self.field == other.field + + 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.field.from_expr(a) + + def from_ZZ(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return K1(K1.domain.convert(a, K0)) + + def from_ZZ_python(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return K1(K1.domain.convert(a, K0)) + + def from_QQ(K1, a, K0): + """Convert a Python ``Fraction`` object to ``dtype``. """ + dom = K1.domain + conv = dom.convert_from + if dom.is_ZZ: + return K1(conv(K0.numer(a), K0)) / K1(conv(K0.denom(a), K0)) + else: + return K1(conv(a, K0)) + + def from_QQ_python(K1, a, K0): + """Convert a Python ``Fraction`` object to ``dtype``. """ + return K1(K1.domain.convert(a, K0)) + + def from_ZZ_gmpy(K1, a, K0): + """Convert a GMPY ``mpz`` object to ``dtype``. """ + return K1(K1.domain.convert(a, K0)) + + def from_QQ_gmpy(K1, a, K0): + """Convert a GMPY ``mpq`` object to ``dtype``. """ + return K1(K1.domain.convert(a, K0)) + + def from_GaussianRationalField(K1, a, K0): + """Convert a ``GaussianRational`` object to ``dtype``. """ + return K1(K1.domain.convert(a, K0)) + + def from_GaussianIntegerRing(K1, a, K0): + """Convert a ``GaussianInteger`` object to ``dtype``. """ + return K1(K1.domain.convert(a, K0)) + + def from_RealField(K1, a, K0): + """Convert a mpmath ``mpf`` object to ``dtype``. """ + return K1(K1.domain.convert(a, K0)) + + def from_ComplexField(K1, a, K0): + """Convert a mpmath ``mpf`` object to ``dtype``. """ + return K1(K1.domain.convert(a, K0)) + + def from_AlgebraicField(K1, a, K0): + """Convert an algebraic number to ``dtype``. """ + if K1.domain != K0: + a = K1.domain.convert_from(a, K0) + if a is not None: + return K1.new(a) + + def from_PolynomialRing(K1, a, K0): + """Convert a polynomial to ``dtype``. """ + if a.is_ground: + return K1.convert_from(a.coeff(1), K0.domain) + try: + return K1.new(a.set_ring(K1.field.ring)) + except (CoercionFailed, GeneratorsError): + # XXX: We get here if K1=ZZ(x,y) and K0=QQ[x,y] + # and the poly a in K0 has non-integer coefficients. + # It seems that K1.new can handle this but K1.new doesn't work + # when K0.domain is an algebraic field... + try: + return K1.new(a) + except (CoercionFailed, GeneratorsError): + return None + + def from_FractionField(K1, a, K0): + """Convert a rational function to ``dtype``. """ + try: + return a.set_field(K1.field) + except (CoercionFailed, GeneratorsError): + return None + + def get_ring(self): + """Returns a field associated with ``self``. """ + return self.field.to_ring().to_domain() + + def is_positive(self, a): + """Returns True if ``LC(a)`` is positive. """ + return self.domain.is_positive(a.numer.LC) + + def is_negative(self, a): + """Returns True if ``LC(a)`` is negative. """ + return self.domain.is_negative(a.numer.LC) + + def is_nonpositive(self, a): + """Returns True if ``LC(a)`` is non-positive. """ + return self.domain.is_nonpositive(a.numer.LC) + + def is_nonnegative(self, a): + """Returns True if ``LC(a)`` is non-negative. """ + return self.domain.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.domain.factorial(a)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gaussiandomains.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gaussiandomains.py new file mode 100644 index 0000000000000000000000000000000000000000..a96bed78e29445c90c53605a85faa4df16bf807c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gaussiandomains.py @@ -0,0 +1,706 @@ +"""Domains of Gaussian type.""" + +from __future__ import annotations +from sympy.core.numbers import I +from sympy.polys.polyclasses import DMP +from sympy.polys.polyerrors import CoercionFailed +from sympy.polys.domains.integerring import ZZ +from sympy.polys.domains.rationalfield import QQ +from sympy.polys.domains.algebraicfield import AlgebraicField +from sympy.polys.domains.domain import Domain +from sympy.polys.domains.domainelement import DomainElement +from sympy.polys.domains.field import Field +from sympy.polys.domains.ring import Ring + + +class GaussianElement(DomainElement): + """Base class for elements of Gaussian type domains.""" + base: Domain + _parent: Domain + + __slots__ = ('x', 'y') + + def __new__(cls, x, y=0): + conv = cls.base.convert + return cls.new(conv(x), conv(y)) + + @classmethod + def new(cls, x, y): + """Create a new GaussianElement of the same domain.""" + obj = super().__new__(cls) + obj.x = x + obj.y = y + return obj + + def parent(self): + """The domain that this is an element of (ZZ_I or QQ_I)""" + return self._parent + + def __hash__(self): + return hash((self.x, self.y)) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.x == other.x and self.y == other.y + else: + return NotImplemented + + def __lt__(self, other): + if not isinstance(other, GaussianElement): + return NotImplemented + return [self.y, self.x] < [other.y, other.x] + + def __pos__(self): + return self + + def __neg__(self): + return self.new(-self.x, -self.y) + + def __repr__(self): + return "%s(%s, %s)" % (self._parent.rep, self.x, self.y) + + def __str__(self): + return str(self._parent.to_sympy(self)) + + @classmethod + def _get_xy(cls, other): + if not isinstance(other, cls): + try: + other = cls._parent.convert(other) + except CoercionFailed: + return None, None + return other.x, other.y + + def __add__(self, other): + x, y = self._get_xy(other) + if x is not None: + return self.new(self.x + x, self.y + y) + else: + return NotImplemented + + __radd__ = __add__ + + def __sub__(self, other): + x, y = self._get_xy(other) + if x is not None: + return self.new(self.x - x, self.y - y) + else: + return NotImplemented + + def __rsub__(self, other): + x, y = self._get_xy(other) + if x is not None: + return self.new(x - self.x, y - self.y) + else: + return NotImplemented + + def __mul__(self, other): + x, y = self._get_xy(other) + if x is not None: + return self.new(self.x*x - self.y*y, self.x*y + self.y*x) + else: + return NotImplemented + + __rmul__ = __mul__ + + def __pow__(self, exp): + if exp == 0: + return self.new(1, 0) + if exp < 0: + self, exp = 1/self, -exp + if exp == 1: + return self + pow2 = self + prod = self if exp % 2 else self._parent.one + exp //= 2 + while exp: + pow2 *= pow2 + if exp % 2: + prod *= pow2 + exp //= 2 + return prod + + def __bool__(self): + return bool(self.x) or bool(self.y) + + def quadrant(self): + """Return quadrant index 0-3. + + 0 is included in quadrant 0. + """ + if self.y > 0: + return 0 if self.x > 0 else 1 + elif self.y < 0: + return 2 if self.x < 0 else 3 + else: + return 0 if self.x >= 0 else 2 + + def __rdivmod__(self, other): + try: + other = self._parent.convert(other) + except CoercionFailed: + return NotImplemented + else: + return other.__divmod__(self) + + def __rtruediv__(self, other): + try: + other = QQ_I.convert(other) + except CoercionFailed: + return NotImplemented + else: + return other.__truediv__(self) + + def __floordiv__(self, other): + qr = self.__divmod__(other) + return qr if qr is NotImplemented else qr[0] + + def __rfloordiv__(self, other): + qr = self.__rdivmod__(other) + return qr if qr is NotImplemented else qr[0] + + def __mod__(self, other): + qr = self.__divmod__(other) + return qr if qr is NotImplemented else qr[1] + + def __rmod__(self, other): + qr = self.__rdivmod__(other) + return qr if qr is NotImplemented else qr[1] + + +class GaussianInteger(GaussianElement): + """Gaussian integer: domain element for :ref:`ZZ_I` + + >>> from sympy import ZZ_I + >>> z = ZZ_I(2, 3) + >>> z + (2 + 3*I) + >>> type(z) + + """ + base = ZZ + + def __truediv__(self, other): + """Return a Gaussian rational.""" + return QQ_I.convert(self)/other + + def __divmod__(self, other): + if not other: + raise ZeroDivisionError('divmod({}, 0)'.format(self)) + x, y = self._get_xy(other) + if x is None: + return NotImplemented + + # multiply self and other by x - I*y + # self/other == (a + I*b)/c + a, b = self.x*x + self.y*y, -self.x*y + self.y*x + c = x*x + y*y + + # find integers qx and qy such that + # |a - qx*c| <= c/2 and |b - qy*c| <= c/2 + qx = (2*a + c) // (2*c) # -c <= 2*a - qx*2*c < c + qy = (2*b + c) // (2*c) + + q = GaussianInteger(qx, qy) + # |self/other - q| < 1 since + # |a/c - qx|**2 + |b/c - qy|**2 <= 1/4 + 1/4 < 1 + + return q, self - q*other # |r| < |other| + + +class GaussianRational(GaussianElement): + """Gaussian rational: domain element for :ref:`QQ_I` + + >>> from sympy import QQ_I, QQ + >>> z = QQ_I(QQ(2, 3), QQ(4, 5)) + >>> z + (2/3 + 4/5*I) + >>> type(z) + + """ + base = QQ + + def __truediv__(self, other): + """Return a Gaussian rational.""" + if not other: + raise ZeroDivisionError('{} / 0'.format(self)) + x, y = self._get_xy(other) + if x is None: + return NotImplemented + c = x*x + y*y + + return GaussianRational((self.x*x + self.y*y)/c, + (-self.x*y + self.y*x)/c) + + def __divmod__(self, other): + try: + other = self._parent.convert(other) + except CoercionFailed: + return NotImplemented + if not other: + raise ZeroDivisionError('{} % 0'.format(self)) + else: + return self/other, QQ_I.zero + + +class GaussianDomain(): + """Base class for Gaussian domains.""" + dom: Domain + + is_Numerical = True + is_Exact = True + + has_assoc_Ring = True + has_assoc_Field = True + + def to_sympy(self, a): + """Convert ``a`` to a SymPy object. """ + conv = self.dom.to_sympy + return conv(a.x) + I*conv(a.y) + + def from_sympy(self, a): + """Convert a SymPy object to ``self.dtype``.""" + r, b = a.as_coeff_Add() + x = self.dom.from_sympy(r) # may raise CoercionFailed + if not b: + return self.new(x, 0) + r, b = b.as_coeff_Mul() + y = self.dom.from_sympy(r) + if b is I: + return self.new(x, y) + else: + raise CoercionFailed("{} is not Gaussian".format(a)) + + def inject(self, *gens): + """Inject generators into this domain. """ + return self.poly_ring(*gens) + + def canonical_unit(self, d): + unit = self.units[-d.quadrant()] # - for inverse power + return unit + + def is_negative(self, element): + """Returns ``False`` for any ``GaussianElement``. """ + return False + + def is_positive(self, element): + """Returns ``False`` for any ``GaussianElement``. """ + return False + + def is_nonnegative(self, element): + """Returns ``False`` for any ``GaussianElement``. """ + return False + + def is_nonpositive(self, element): + """Returns ``False`` for any ``GaussianElement``. """ + return False + + def from_ZZ_gmpy(K1, a, K0): + """Convert a GMPY mpz to ``self.dtype``.""" + return K1(a) + + def from_ZZ(K1, a, K0): + """Convert a ZZ_python element to ``self.dtype``.""" + return K1(a) + + def from_ZZ_python(K1, a, K0): + """Convert a ZZ_python element to ``self.dtype``.""" + return K1(a) + + def from_QQ(K1, a, K0): + """Convert a GMPY mpq to ``self.dtype``.""" + return K1(a) + + def from_QQ_gmpy(K1, a, K0): + """Convert a GMPY mpq to ``self.dtype``.""" + return K1(a) + + def from_QQ_python(K1, a, K0): + """Convert a QQ_python element to ``self.dtype``.""" + return K1(a) + + def from_AlgebraicField(K1, a, K0): + """Convert an element from ZZ or QQ to ``self.dtype``.""" + if K0.ext.args[0] == I: + return K1.from_sympy(K0.to_sympy(a)) + + +class GaussianIntegerRing(GaussianDomain, Ring): + r"""Ring of Gaussian integers ``ZZ_I`` + + The :ref:`ZZ_I` domain represents the `Gaussian integers`_ `\mathbb{Z}[i]` + as a :py:class:`~.Domain` in the domain system (see + :ref:`polys-domainsintro`). + + By default a :py:class:`~.Poly` created from an expression with + coefficients that are combinations of integers and ``I`` (`\sqrt{-1}`) + will have the domain :ref:`ZZ_I`. + + >>> from sympy import Poly, Symbol, I + >>> x = Symbol('x') + >>> p = Poly(x**2 + I) + >>> p + Poly(x**2 + I, x, domain='ZZ_I') + >>> p.domain + ZZ_I + + The :ref:`ZZ_I` domain can be used to factorise polynomials that are + reducible over the Gaussian integers. + + >>> from sympy import factor + >>> factor(x**2 + 1) + x**2 + 1 + >>> factor(x**2 + 1, domain='ZZ_I') + (x - I)*(x + I) + + The corresponding `field of fractions`_ is the domain of the Gaussian + rationals :ref:`QQ_I`. Conversely :ref:`ZZ_I` is the `ring of integers`_ + of :ref:`QQ_I`. + + >>> from sympy import ZZ_I, QQ_I + >>> ZZ_I.get_field() + QQ_I + >>> QQ_I.get_ring() + ZZ_I + + When using the domain directly :ref:`ZZ_I` can be used as a constructor. + + >>> ZZ_I(3, 4) + (3 + 4*I) + >>> ZZ_I(5) + (5 + 0*I) + + The domain elements of :ref:`ZZ_I` are instances of + :py:class:`~.GaussianInteger` which support the rings operations + ``+,-,*,**``. + + >>> z1 = ZZ_I(5, 1) + >>> z2 = ZZ_I(2, 3) + >>> z1 + (5 + 1*I) + >>> z2 + (2 + 3*I) + >>> z1 + z2 + (7 + 4*I) + >>> z1 * z2 + (7 + 17*I) + >>> z1 ** 2 + (24 + 10*I) + + Both floor (``//``) and modulo (``%``) division work with + :py:class:`~.GaussianInteger` (see the :py:meth:`~.Domain.div` method). + + >>> z3, z4 = ZZ_I(5), ZZ_I(1, 3) + >>> z3 // z4 # floor division + (1 + -1*I) + >>> z3 % z4 # modulo division (remainder) + (1 + -2*I) + >>> (z3//z4)*z4 + z3%z4 == z3 + True + + True division (``/``) in :ref:`ZZ_I` gives an element of :ref:`QQ_I`. The + :py:meth:`~.Domain.exquo` method can be used to divide in :ref:`ZZ_I` when + exact division is possible. + + >>> z1 / z2 + (1 + -1*I) + >>> ZZ_I.exquo(z1, z2) + (1 + -1*I) + >>> z3 / z4 + (1/2 + -3/2*I) + >>> ZZ_I.exquo(z3, z4) + Traceback (most recent call last): + ... + ExactQuotientFailed: (1 + 3*I) does not divide (5 + 0*I) in ZZ_I + + The :py:meth:`~.Domain.gcd` method can be used to compute the `gcd`_ of any + two elements. + + >>> ZZ_I.gcd(ZZ_I(10), ZZ_I(2)) + (2 + 0*I) + >>> ZZ_I.gcd(ZZ_I(5), ZZ_I(2, 1)) + (2 + 1*I) + + .. _Gaussian integers: https://en.wikipedia.org/wiki/Gaussian_integer + .. _gcd: https://en.wikipedia.org/wiki/Greatest_common_divisor + + """ + dom = ZZ + mod = DMP([ZZ.one, ZZ.zero, ZZ.one], ZZ) + dtype = GaussianInteger + zero = dtype(ZZ(0), ZZ(0)) + one = dtype(ZZ(1), ZZ(0)) + imag_unit = dtype(ZZ(0), ZZ(1)) + units = (one, imag_unit, -one, -imag_unit) # powers of i + + rep = 'ZZ_I' + + is_GaussianRing = True + is_ZZ_I = True + is_PID = True + + def __init__(self): # override Domain.__init__ + """For constructing ZZ_I.""" + + def __eq__(self, other): + """Returns ``True`` if two domains are equivalent. """ + if isinstance(other, GaussianIntegerRing): + return True + else: + return NotImplemented + + def __hash__(self): + """Compute hash code of ``self``. """ + return hash('ZZ_I') + + @property + def has_CharacteristicZero(self): + return True + + def characteristic(self): + return 0 + + def get_ring(self): + """Returns a ring associated with ``self``. """ + return self + + def get_field(self): + """Returns a field associated with ``self``. """ + return QQ_I + + def normalize(self, d, *args): + """Return first quadrant element associated with ``d``. + + Also multiply the other arguments by the same power of i. + """ + unit = self.canonical_unit(d) + d *= unit + args = tuple(a*unit for a in args) + return (d,) + args if args else d + + def gcd(self, a, b): + """Greatest common divisor of a and b over ZZ_I.""" + while b: + a, b = b, a % b + return self.normalize(a) + + def gcdex(self, a, b): + """Return x, y, g such that x * a + y * b = g = gcd(a, b)""" + x_a = self.one + x_b = self.zero + y_a = self.zero + y_b = self.one + while b: + q = a // b + a, b = b, a - q * b + x_a, x_b = x_b, x_a - q * x_b + y_a, y_b = y_b, y_a - q * y_b + + a, x_a, y_a = self.normalize(a, x_a, y_a) + return x_a, y_a, a + + def lcm(self, a, b): + """Least common multiple of a and b over ZZ_I.""" + return (a * b) // self.gcd(a, b) + + def from_GaussianIntegerRing(K1, a, K0): + """Convert a ZZ_I element to ZZ_I.""" + return a + + def from_GaussianRationalField(K1, a, K0): + """Convert a QQ_I element to ZZ_I.""" + return K1.new(ZZ.convert(a.x), ZZ.convert(a.y)) + +ZZ_I = GaussianInteger._parent = GaussianIntegerRing() + + +class GaussianRationalField(GaussianDomain, Field): + r"""Field of Gaussian rationals ``QQ_I`` + + The :ref:`QQ_I` domain represents the `Gaussian rationals`_ `\mathbb{Q}(i)` + as a :py:class:`~.Domain` in the domain system (see + :ref:`polys-domainsintro`). + + By default a :py:class:`~.Poly` created from an expression with + coefficients that are combinations of rationals and ``I`` (`\sqrt{-1}`) + will have the domain :ref:`QQ_I`. + + >>> from sympy import Poly, Symbol, I + >>> x = Symbol('x') + >>> p = Poly(x**2 + I/2) + >>> p + Poly(x**2 + I/2, x, domain='QQ_I') + >>> p.domain + QQ_I + + The polys option ``gaussian=True`` can be used to specify that the domain + should be :ref:`QQ_I` even if the coefficients do not contain ``I`` or are + all integers. + + >>> Poly(x**2) + Poly(x**2, x, domain='ZZ') + >>> Poly(x**2 + I) + Poly(x**2 + I, x, domain='ZZ_I') + >>> Poly(x**2/2) + Poly(1/2*x**2, x, domain='QQ') + >>> Poly(x**2, gaussian=True) + Poly(x**2, x, domain='QQ_I') + >>> Poly(x**2 + I, gaussian=True) + Poly(x**2 + I, x, domain='QQ_I') + >>> Poly(x**2/2, gaussian=True) + Poly(1/2*x**2, x, domain='QQ_I') + + The :ref:`QQ_I` domain can be used to factorise polynomials that are + reducible over the Gaussian rationals. + + >>> from sympy import factor, QQ_I + >>> factor(x**2/4 + 1) + (x**2 + 4)/4 + >>> factor(x**2/4 + 1, domain='QQ_I') + (x - 2*I)*(x + 2*I)/4 + >>> factor(x**2/4 + 1, domain=QQ_I) + (x - 2*I)*(x + 2*I)/4 + + It is also possible to specify the :ref:`QQ_I` domain explicitly with + polys functions like :py:func:`~.apart`. + + >>> from sympy import apart + >>> apart(1/(1 + x**2)) + 1/(x**2 + 1) + >>> apart(1/(1 + x**2), domain=QQ_I) + I/(2*(x + I)) - I/(2*(x - I)) + + The corresponding `ring of integers`_ is the domain of the Gaussian + integers :ref:`ZZ_I`. Conversely :ref:`QQ_I` is the `field of fractions`_ + of :ref:`ZZ_I`. + + >>> from sympy import ZZ_I, QQ_I, QQ + >>> ZZ_I.get_field() + QQ_I + >>> QQ_I.get_ring() + ZZ_I + + When using the domain directly :ref:`QQ_I` can be used as a constructor. + + >>> QQ_I(3, 4) + (3 + 4*I) + >>> QQ_I(5) + (5 + 0*I) + >>> QQ_I(QQ(2, 3), QQ(4, 5)) + (2/3 + 4/5*I) + + The domain elements of :ref:`QQ_I` are instances of + :py:class:`~.GaussianRational` which support the field operations + ``+,-,*,**,/``. + + >>> z1 = QQ_I(5, 1) + >>> z2 = QQ_I(2, QQ(1, 2)) + >>> z1 + (5 + 1*I) + >>> z2 + (2 + 1/2*I) + >>> z1 + z2 + (7 + 3/2*I) + >>> z1 * z2 + (19/2 + 9/2*I) + >>> z2 ** 2 + (15/4 + 2*I) + + True division (``/``) in :ref:`QQ_I` gives an element of :ref:`QQ_I` and + is always exact. + + >>> z1 / z2 + (42/17 + -2/17*I) + >>> QQ_I.exquo(z1, z2) + (42/17 + -2/17*I) + >>> z1 == (z1/z2)*z2 + True + + Both floor (``//``) and modulo (``%``) division can be used with + :py:class:`~.GaussianRational` (see :py:meth:`~.Domain.div`) + but division is always exact so there is no remainder. + + >>> z1 // z2 + (42/17 + -2/17*I) + >>> z1 % z2 + (0 + 0*I) + >>> QQ_I.div(z1, z2) + ((42/17 + -2/17*I), (0 + 0*I)) + >>> (z1//z2)*z2 + z1%z2 == z1 + True + + .. _Gaussian rationals: https://en.wikipedia.org/wiki/Gaussian_rational + """ + dom = QQ + mod = DMP([QQ.one, QQ.zero, QQ.one], QQ) + dtype = GaussianRational + zero = dtype(QQ(0), QQ(0)) + one = dtype(QQ(1), QQ(0)) + imag_unit = dtype(QQ(0), QQ(1)) + units = (one, imag_unit, -one, -imag_unit) # powers of i + + rep = 'QQ_I' + + is_GaussianField = True + is_QQ_I = True + + def __init__(self): # override Domain.__init__ + """For constructing QQ_I.""" + + def __eq__(self, other): + """Returns ``True`` if two domains are equivalent. """ + if isinstance(other, GaussianRationalField): + return True + else: + return NotImplemented + + def __hash__(self): + """Compute hash code of ``self``. """ + return hash('QQ_I') + + @property + def has_CharacteristicZero(self): + return True + + def characteristic(self): + return 0 + + def get_ring(self): + """Returns a ring associated with ``self``. """ + return ZZ_I + + def get_field(self): + """Returns a field associated with ``self``. """ + return self + + def as_AlgebraicField(self): + """Get equivalent domain as an ``AlgebraicField``. """ + return AlgebraicField(self.dom, I) + + def numer(self, a): + """Get the numerator of ``a``.""" + ZZ_I = self.get_ring() + return ZZ_I.convert(a * self.denom(a)) + + def denom(self, a): + """Get the denominator of ``a``.""" + ZZ = self.dom.get_ring() + QQ = self.dom + ZZ_I = self.get_ring() + denom_ZZ = ZZ.lcm(QQ.denom(a.x), QQ.denom(a.y)) + return ZZ_I(denom_ZZ, ZZ.zero) + + def from_GaussianIntegerRing(K1, a, K0): + """Convert a ZZ_I element to QQ_I.""" + return K1.new(a.x, a.y) + + def from_GaussianRationalField(K1, a, K0): + """Convert a QQ_I element to QQ_I.""" + return a + + def from_ComplexField(K1, a, K0): + """Convert a ComplexField element to QQ_I.""" + return K1.new(QQ.convert(a.real), QQ.convert(a.imag)) + + +QQ_I = GaussianRational._parent = GaussianRationalField() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gmpyfinitefield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gmpyfinitefield.py new file mode 100644 index 0000000000000000000000000000000000000000..2e8315a29eca8160102d66b83d953caf998b0fd7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gmpyfinitefield.py @@ -0,0 +1,16 @@ +"""Implementation of :class:`GMPYFiniteField` class. """ + + +from sympy.polys.domains.finitefield import FiniteField +from sympy.polys.domains.gmpyintegerring import GMPYIntegerRing + +from sympy.utilities import public + +@public +class GMPYFiniteField(FiniteField): + """Finite field based on GMPY integers. """ + + alias = 'FF_gmpy' + + def __init__(self, mod, symmetric=True): + super().__init__(mod, GMPYIntegerRing(), symmetric) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gmpyintegerring.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gmpyintegerring.py new file mode 100644 index 0000000000000000000000000000000000000000..f132bbe5aff7a4164a09b9b90f00ae5f140cbd03 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gmpyintegerring.py @@ -0,0 +1,105 @@ +"""Implementation of :class:`GMPYIntegerRing` class. """ + + +from sympy.polys.domains.groundtypes import ( + GMPYInteger, SymPyInteger, + factorial as gmpy_factorial, + gmpy_gcdex, gmpy_gcd, gmpy_lcm, sqrt as gmpy_sqrt, +) +from sympy.core.numbers import int_valued +from sympy.polys.domains.integerring import IntegerRing +from sympy.polys.polyerrors import CoercionFailed +from sympy.utilities import public + +@public +class GMPYIntegerRing(IntegerRing): + """Integer ring based on GMPY's ``mpz`` type. + + This will be the implementation of :ref:`ZZ` if ``gmpy`` or ``gmpy2`` is + installed. Elements will be of type ``gmpy.mpz``. + """ + + dtype = GMPYInteger + zero = dtype(0) + one = dtype(1) + tp = type(one) + alias = 'ZZ_gmpy' + + def __init__(self): + """Allow instantiation of this domain. """ + + def to_sympy(self, a): + """Convert ``a`` to a SymPy object. """ + return SymPyInteger(int(a)) + + def from_sympy(self, a): + """Convert SymPy's Integer to ``dtype``. """ + if a.is_Integer: + return GMPYInteger(a.p) + elif int_valued(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 K0.to_int(a) + + def from_ZZ_python(K1, a, K0): + """Convert Python's ``int`` to GMPY's ``mpz``. """ + return GMPYInteger(a) + + def from_QQ(K1, a, K0): + """Convert Python's ``Fraction`` to GMPY's ``mpz``. """ + if a.denominator == 1: + return GMPYInteger(a.numerator) + + def from_QQ_python(K1, a, K0): + """Convert Python's ``Fraction`` to GMPY's ``mpz``. """ + if a.denominator == 1: + return GMPYInteger(a.numerator) + + def from_FF_gmpy(K1, a, K0): + """Convert ``ModularInteger(mpz)`` to GMPY's ``mpz``. """ + return K0.to_int(a) + + def from_ZZ_gmpy(K1, a, K0): + """Convert GMPY's ``mpz`` to GMPY's ``mpz``. """ + return a + + def from_QQ_gmpy(K1, a, K0): + """Convert GMPY ``mpq`` to GMPY's ``mpz``. """ + if a.denominator == 1: + return a.numerator + + def from_RealField(K1, a, K0): + """Convert mpmath's ``mpf`` to GMPY's ``mpz``. """ + p, q = K0.to_rational(a) + + if q == 1: + return GMPYInteger(p) + + def from_GaussianIntegerRing(K1, a, K0): + if a.y == 0: + return a.x + + def gcdex(self, a, b): + """Compute extended GCD of ``a`` and ``b``. """ + h, s, t = gmpy_gcdex(a, b) + return s, t, h + + def gcd(self, a, b): + """Compute GCD of ``a`` and ``b``. """ + return gmpy_gcd(a, b) + + def lcm(self, a, b): + """Compute LCM of ``a`` and ``b``. """ + return gmpy_lcm(a, b) + + def sqrt(self, a): + """Compute square root of ``a``. """ + return gmpy_sqrt(a) + + def factorial(self, a): + """Compute factorial of ``a``. """ + return gmpy_factorial(a) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gmpyrationalfield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gmpyrationalfield.py new file mode 100644 index 0000000000000000000000000000000000000000..10bae5b2b7b476f96ba06f637c549ee4afff4c6d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/gmpyrationalfield.py @@ -0,0 +1,100 @@ +"""Implementation of :class:`GMPYRationalField` class. """ + + +from sympy.polys.domains.groundtypes import ( + GMPYRational, SymPyRational, + gmpy_numer, gmpy_denom, factorial as gmpy_factorial, +) +from sympy.polys.domains.rationalfield import RationalField +from sympy.polys.polyerrors import CoercionFailed +from sympy.utilities import public + +@public +class GMPYRationalField(RationalField): + """Rational field based on GMPY's ``mpq`` type. + + This will be the implementation of :ref:`QQ` if ``gmpy`` or ``gmpy2`` is + installed. Elements will be of type ``gmpy.mpq``. + """ + + dtype = GMPYRational + zero = dtype(0) + one = dtype(1) + tp = type(one) + 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 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 GMPYRational(a.p, a.q) + elif a.is_Float: + from sympy.polys.domains import RR + return GMPYRational(*map(int, RR.to_rational(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 GMPYRational(a) + + def from_QQ_python(K1, a, K0): + """Convert a Python ``Fraction`` object to ``dtype``. """ + return GMPYRational(a.numerator, a.denominator) + + def from_ZZ_gmpy(K1, a, K0): + """Convert a GMPY ``mpz`` object to ``dtype``. """ + return GMPYRational(a) + + def from_QQ_gmpy(K1, a, K0): + """Convert a GMPY ``mpq`` object to ``dtype``. """ + return a + + def from_GaussianRationalField(K1, a, K0): + """Convert a ``GaussianElement`` object to ``dtype``. """ + if a.y == 0: + return GMPYRational(a.x) + + def from_RealField(K1, a, K0): + """Convert a mpmath ``mpf`` object to ``dtype``. """ + return GMPYRational(*map(int, K0.to_rational(a))) + + def exquo(self, a, b): + """Exact quotient of ``a`` and ``b``, implies ``__truediv__``. """ + return GMPYRational(a) / GMPYRational(b) + + def quo(self, a, b): + """Quotient of ``a`` and ``b``, implies ``__truediv__``. """ + return GMPYRational(a) / GMPYRational(b) + + def rem(self, a, b): + """Remainder of ``a`` and ``b``, implies nothing. """ + return self.zero + + def div(self, a, b): + """Division of ``a`` and ``b``, implies ``__truediv__``. """ + return GMPYRational(a) / GMPYRational(b), self.zero + + def numer(self, a): + """Returns numerator of ``a``. """ + return a.numerator + + def denom(self, a): + """Returns denominator of ``a``. """ + return a.denominator + + def factorial(self, a): + """Returns factorial of ``a``. """ + return GMPYRational(gmpy_factorial(int(a))) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/groundtypes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/groundtypes.py new file mode 100644 index 0000000000000000000000000000000000000000..1d50cf912a998767c4a52c5a2f3aab825e072aec --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/groundtypes.py @@ -0,0 +1,99 @@ +"""Ground types for various mathematical domains in SymPy. """ + +import builtins +from sympy.external.gmpy import GROUND_TYPES, factorial, sqrt, is_square, sqrtrem + +PythonInteger = builtins.int +PythonReal = builtins.float +PythonComplex = builtins.complex + +from .pythonrational import PythonRational + +from sympy.core.intfunc import ( + igcdex as python_gcdex, + igcd2 as python_gcd, + ilcm as python_lcm, +) + +from sympy.core.numbers import (Float as SymPyReal, Integer as SymPyInteger, Rational as SymPyRational) + + +class _GMPYInteger: + def __init__(self, obj): + pass + +class _GMPYRational: + def __init__(self, obj): + pass + + +if GROUND_TYPES == 'gmpy': + + from gmpy2 import ( + mpz as GMPYInteger, + mpq as GMPYRational, + numer as gmpy_numer, + denom as gmpy_denom, + gcdext as gmpy_gcdex, + gcd as gmpy_gcd, + lcm as gmpy_lcm, + qdiv as gmpy_qdiv, + ) + gcdex = gmpy_gcdex + gcd = gmpy_gcd + lcm = gmpy_lcm + +elif GROUND_TYPES == 'flint': + + from flint import fmpz as _fmpz + + GMPYInteger = _GMPYInteger + GMPYRational = _GMPYRational + gmpy_numer = None + gmpy_denom = None + gmpy_gcdex = None + gmpy_gcd = None + gmpy_lcm = None + gmpy_qdiv = None + + def gcd(a, b): + return a.gcd(b) + + def gcdex(a, b): + x, y, g = python_gcdex(a, b) + return _fmpz(x), _fmpz(y), _fmpz(g) + + def lcm(a, b): + return a.lcm(b) + +else: + GMPYInteger = _GMPYInteger + GMPYRational = _GMPYRational + gmpy_numer = None + gmpy_denom = None + gmpy_gcdex = None + gmpy_gcd = None + gmpy_lcm = None + gmpy_qdiv = None + gcdex = python_gcdex + gcd = python_gcd + lcm = python_lcm + + +__all__ = [ + 'PythonInteger', 'PythonReal', 'PythonComplex', + + 'PythonRational', + + 'python_gcdex', 'python_gcd', 'python_lcm', + + 'SymPyReal', 'SymPyInteger', 'SymPyRational', + + 'GMPYInteger', 'GMPYRational', 'gmpy_numer', + 'gmpy_denom', 'gmpy_gcdex', 'gmpy_gcd', 'gmpy_lcm', + 'gmpy_qdiv', + + 'factorial', 'sqrt', 'is_square', 'sqrtrem', + + 'GMPYInteger', 'GMPYRational', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/integerring.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/integerring.py new file mode 100644 index 0000000000000000000000000000000000000000..65eaa9631cfdf138997a4ebdb362c4233fb098fb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/integerring.py @@ -0,0 +1,276 @@ +"""Implementation of :class:`IntegerRing` class. """ + +from sympy.external.gmpy import MPZ, GROUND_TYPES + +from sympy.core.numbers import int_valued +from sympy.polys.domains.groundtypes import ( + SymPyInteger, + factorial, + gcdex, gcd, lcm, sqrt, is_square, sqrtrem, +) + +from sympy.polys.domains.characteristiczero import CharacteristicZero +from sympy.polys.domains.ring import Ring +from sympy.polys.domains.simpledomain import SimpleDomain +from sympy.polys.polyerrors import CoercionFailed +from sympy.utilities import public + +import math + +@public +class IntegerRing(Ring, CharacteristicZero, SimpleDomain): + r"""The domain ``ZZ`` representing the integers `\mathbb{Z}`. + + The :py:class:`IntegerRing` class represents the ring of integers as a + :py:class:`~.Domain` in the domain system. :py:class:`IntegerRing` is a + super class of :py:class:`PythonIntegerRing` and + :py:class:`GMPYIntegerRing` one of which will be the implementation for + :ref:`ZZ` depending on whether or not ``gmpy`` or ``gmpy2`` is installed. + + See also + ======== + + Domain + """ + + rep = 'ZZ' + alias = 'ZZ' + dtype = MPZ + zero = dtype(0) + one = dtype(1) + tp = type(one) + + + is_IntegerRing = is_ZZ = True + is_Numerical = True + is_PID = True + + has_assoc_Ring = True + has_assoc_Field = True + + def __init__(self): + """Allow instantiation of this domain. """ + + def __eq__(self, other): + """Returns ``True`` if two domains are equivalent. """ + if isinstance(other, IntegerRing): + return True + else: + return NotImplemented + + def __hash__(self): + """Compute a hash value for this domain. """ + return hash('ZZ') + + def to_sympy(self, a): + """Convert ``a`` to a SymPy object. """ + return SymPyInteger(int(a)) + + def from_sympy(self, a): + """Convert SymPy's Integer to ``dtype``. """ + if a.is_Integer: + return MPZ(a.p) + elif int_valued(a): + return MPZ(int(a)) + else: + raise CoercionFailed("expected an integer, got %s" % a) + + def get_field(self): + r"""Return the associated field of fractions :ref:`QQ` + + Returns + ======= + + :ref:`QQ`: + The associated field of fractions :ref:`QQ`, a + :py:class:`~.Domain` representing the rational numbers + `\mathbb{Q}`. + + Examples + ======== + + >>> from sympy import ZZ + >>> ZZ.get_field() + QQ + """ + from sympy.polys.domains import QQ + return QQ + + def algebraic_field(self, *extension, alias=None): + r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \ldots)`. + + Parameters + ========== + + *extension : One or more :py:class:`~.Expr`. + Generators of the extension. These should be expressions that are + algebraic over `\mathbb{Q}`. + + alias : str, :py:class:`~.Symbol`, None, optional (default=None) + If provided, this will be used as the alias symbol for the + primitive element of the returned :py:class:`~.AlgebraicField`. + + Returns + ======= + + :py:class:`~.AlgebraicField` + A :py:class:`~.Domain` representing the algebraic field extension. + + Examples + ======== + + >>> from sympy import ZZ, sqrt + >>> ZZ.algebraic_field(sqrt(2)) + QQ + """ + return self.get_field().algebraic_field(*extension, alias=alias) + + def from_AlgebraicField(K1, a, K0): + """Convert a :py:class:`~.ANP` object to :ref:`ZZ`. + + See :py:meth:`~.Domain.convert`. + """ + if a.is_ground: + return K1.convert(a.LC(), K0.dom) + + def log(self, a, b): + r"""Logarithm of *a* to the base *b*. + + Parameters + ========== + + a: number + b: number + + Returns + ======= + + $\\lfloor\log(a, b)\\rfloor$: + Floor of the logarithm of *a* to the base *b* + + Examples + ======== + + >>> from sympy import ZZ + >>> ZZ.log(ZZ(8), ZZ(2)) + 3 + >>> ZZ.log(ZZ(9), ZZ(2)) + 3 + + Notes + ===== + + This function uses ``math.log`` which is based on ``float`` so it will + fail for large integer arguments. + """ + return self.dtype(int(math.log(int(a), b))) + + def from_FF(K1, a, K0): + """Convert ``ModularInteger(int)`` to GMPY's ``mpz``. """ + return MPZ(K0.to_int(a)) + + def from_FF_python(K1, a, K0): + """Convert ``ModularInteger(int)`` to GMPY's ``mpz``. """ + return MPZ(K0.to_int(a)) + + def from_ZZ(K1, a, K0): + """Convert Python's ``int`` to GMPY's ``mpz``. """ + return MPZ(a) + + def from_ZZ_python(K1, a, K0): + """Convert Python's ``int`` to GMPY's ``mpz``. """ + return MPZ(a) + + def from_QQ(K1, a, K0): + """Convert Python's ``Fraction`` to GMPY's ``mpz``. """ + if a.denominator == 1: + return MPZ(a.numerator) + + def from_QQ_python(K1, a, K0): + """Convert Python's ``Fraction`` to GMPY's ``mpz``. """ + if a.denominator == 1: + return MPZ(a.numerator) + + def from_FF_gmpy(K1, a, K0): + """Convert ``ModularInteger(mpz)`` to GMPY's ``mpz``. """ + return MPZ(K0.to_int(a)) + + def from_ZZ_gmpy(K1, a, K0): + """Convert GMPY's ``mpz`` to GMPY's ``mpz``. """ + return a + + def from_QQ_gmpy(K1, a, K0): + """Convert GMPY ``mpq`` to GMPY's ``mpz``. """ + if a.denominator == 1: + return a.numerator + + def from_RealField(K1, a, K0): + """Convert mpmath's ``mpf`` to GMPY's ``mpz``. """ + p, q = K0.to_rational(a) + + if q == 1: + # XXX: If MPZ is flint.fmpz and p is a gmpy2.mpz, then we need + # to convert via int because fmpz and mpz do not know about each + # other. + return MPZ(int(p)) + + def from_GaussianIntegerRing(K1, a, K0): + if a.y == 0: + return a.x + + def from_EX(K1, a, K0): + """Convert ``Expression`` to GMPY's ``mpz``. """ + if a.is_Integer: + return K1.from_sympy(a) + + def gcdex(self, a, b): + """Compute extended GCD of ``a`` and ``b``. """ + h, s, t = gcdex(a, b) + # XXX: This conditional logic should be handled somewhere else. + if GROUND_TYPES == 'gmpy': + return s, t, h + else: + return h, s, t + + def gcd(self, a, b): + """Compute GCD of ``a`` and ``b``. """ + return gcd(a, b) + + def lcm(self, a, b): + """Compute LCM of ``a`` and ``b``. """ + return lcm(a, b) + + def sqrt(self, a): + """Compute square root of ``a``. """ + return sqrt(a) + + def is_square(self, a): + """Return ``True`` if ``a`` is a square. + + Explanation + =========== + An integer is a square if and only if there exists an integer + ``b`` such that ``b * b == a``. + """ + return is_square(a) + + def exsqrt(self, a): + """Non-negative square root of ``a`` if ``a`` is a square. + + See also + ======== + is_square + """ + if a < 0: + return None + root, rem = sqrtrem(a) + if rem != 0: + return None + return root + + def factorial(self, a): + """Compute factorial of ``a``. """ + return factorial(a) + + +ZZ = IntegerRing() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/modularinteger.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/modularinteger.py new file mode 100644 index 0000000000000000000000000000000000000000..39a0237563c69a77e4736466d1ebcaa7ca39485f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/modularinteger.py @@ -0,0 +1,237 @@ +"""Implementation of :class:`ModularInteger` class. """ + +from __future__ import annotations +from typing import Any + +import operator + +from sympy.polys.polyutils import PicklableWithSlots +from sympy.polys.polyerrors import CoercionFailed +from sympy.polys.domains.domainelement import DomainElement + +from sympy.utilities import public +from sympy.utilities.exceptions import sympy_deprecation_warning + +@public +class ModularInteger(PicklableWithSlots, DomainElement): + """A class representing a modular integer. """ + + mod, dom, sym, _parent = None, None, None, None + + __slots__ = ('val',) + + def parent(self): + return self._parent + + def __init__(self, val): + if isinstance(val, self.__class__): + self.val = val.val % self.mod + else: + self.val = self.dom.convert(val) % self.mod + + def modulus(self): + return self.mod + + def __hash__(self): + return hash((self.val, self.mod)) + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, self.val) + + def __str__(self): + return "%s mod %s" % (self.val, self.mod) + + def __int__(self): + return int(self.val) + + def to_int(self): + + sympy_deprecation_warning( + """ModularInteger.to_int() is deprecated. + + Use int(a) or K = GF(p) and K.to_int(a) instead of a.to_int(). + """, + deprecated_since_version="1.13", + active_deprecations_target="modularinteger-to-int", + ) + + if self.sym: + if self.val <= self.mod // 2: + return self.val + else: + return self.val - self.mod + else: + return self.val + + def __pos__(self): + return self + + def __neg__(self): + return self.__class__(-self.val) + + @classmethod + def _get_val(cls, other): + if isinstance(other, cls): + return other.val + else: + try: + return cls.dom.convert(other) + except CoercionFailed: + return None + + def __add__(self, other): + val = self._get_val(other) + + if val is not None: + return self.__class__(self.val + val) + else: + return NotImplemented + + def __radd__(self, other): + return self.__add__(other) + + def __sub__(self, other): + val = self._get_val(other) + + if val is not None: + return self.__class__(self.val - val) + else: + return NotImplemented + + def __rsub__(self, other): + return (-self).__add__(other) + + def __mul__(self, other): + val = self._get_val(other) + + if val is not None: + return self.__class__(self.val * val) + else: + return NotImplemented + + def __rmul__(self, other): + return self.__mul__(other) + + def __truediv__(self, other): + val = self._get_val(other) + + if val is not None: + return self.__class__(self.val * self._invert(val)) + else: + return NotImplemented + + def __rtruediv__(self, other): + return self.invert().__mul__(other) + + def __mod__(self, other): + val = self._get_val(other) + + if val is not None: + return self.__class__(self.val % val) + else: + return NotImplemented + + def __rmod__(self, other): + val = self._get_val(other) + + if val is not None: + return self.__class__(val % self.val) + else: + return NotImplemented + + def __pow__(self, exp): + if not exp: + return self.__class__(self.dom.one) + + if exp < 0: + val, exp = self.invert().val, -exp + else: + val = self.val + + return self.__class__(pow(val, int(exp), self.mod)) + + def _compare(self, other, op): + val = self._get_val(other) + + if val is None: + return NotImplemented + + return op(self.val, val % self.mod) + + def _compare_deprecated(self, other, op): + val = self._get_val(other) + + if val is None: + return NotImplemented + + sympy_deprecation_warning( + """Ordered comparisons with modular integers are deprecated. + + Use e.g. int(a) < int(b) instead of a < b. + """, + deprecated_since_version="1.13", + active_deprecations_target="modularinteger-compare", + stacklevel=4, + ) + + return op(self.val, val % self.mod) + + def __eq__(self, other): + return self._compare(other, operator.eq) + + def __ne__(self, other): + return self._compare(other, operator.ne) + + def __lt__(self, other): + return self._compare_deprecated(other, operator.lt) + + def __le__(self, other): + return self._compare_deprecated(other, operator.le) + + def __gt__(self, other): + return self._compare_deprecated(other, operator.gt) + + def __ge__(self, other): + return self._compare_deprecated(other, operator.ge) + + def __bool__(self): + return bool(self.val) + + @classmethod + def _invert(cls, value): + return cls.dom.invert(value, cls.mod) + + def invert(self): + return self.__class__(self._invert(self.val)) + +_modular_integer_cache: dict[tuple[Any, Any, Any], type[ModularInteger]] = {} + +def ModularIntegerFactory(_mod, _dom, _sym, parent): + """Create custom class for specific integer modulus.""" + try: + _mod = _dom.convert(_mod) + except CoercionFailed: + ok = False + else: + ok = True + + if not ok or _mod < 1: + raise ValueError("modulus must be a positive integer, got %s" % _mod) + + key = _mod, _dom, _sym + + try: + cls = _modular_integer_cache[key] + except KeyError: + class cls(ModularInteger): + mod, dom, sym = _mod, _dom, _sym + _parent = parent + + if _sym: + cls.__name__ = "SymmetricModularIntegerMod%s" % _mod + else: + cls.__name__ = "ModularIntegerMod%s" % _mod + + _modular_integer_cache[key] = cls + + return cls diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/mpelements.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/mpelements.py new file mode 100644 index 0000000000000000000000000000000000000000..04ae8eaddcbb7fd8fae684374d9d2c05e79f6c7a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/mpelements.py @@ -0,0 +1,181 @@ +# +# This module is deprecated and should not be used any more. The actual +# implementation of RR and CC now uses mpmath's mpf and mpc types directly. +# +"""Real and complex elements. """ + + +from sympy.external.gmpy import MPQ +from sympy.polys.domains.domainelement import DomainElement +from sympy.utilities import public + +from mpmath.ctx_mp_python import PythonMPContext, _mpf, _mpc, _constant +from mpmath.libmp import (MPZ_ONE, fzero, fone, finf, fninf, fnan, + round_nearest, mpf_mul, repr_dps, int_types, + from_int, from_float, from_str, to_rational) + + +@public +class RealElement(_mpf, DomainElement): + """An element of a real domain. """ + + __slots__ = ('__mpf__',) + + def _set_mpf(self, val): + self.__mpf__ = val + + _mpf_ = property(lambda self: self.__mpf__, _set_mpf) + + def parent(self): + return self.context._parent + +@public +class ComplexElement(_mpc, DomainElement): + """An element of a complex domain. """ + + __slots__ = ('__mpc__',) + + def _set_mpc(self, val): + self.__mpc__ = val + + _mpc_ = property(lambda self: self.__mpc__, _set_mpc) + + def parent(self): + return self.context._parent + +new = object.__new__ + +@public +class MPContext(PythonMPContext): + + def __init__(ctx, prec=53, dps=None, tol=None, real=False): + ctx._prec_rounding = [prec, round_nearest] + + if dps is None: + ctx._set_prec(prec) + else: + ctx._set_dps(dps) + + ctx.mpf = RealElement + ctx.mpc = ComplexElement + ctx.mpf._ctxdata = [ctx.mpf, new, ctx._prec_rounding] + ctx.mpc._ctxdata = [ctx.mpc, new, ctx._prec_rounding] + + if real: + ctx.mpf.context = ctx + else: + ctx.mpc.context = ctx + + ctx.constant = _constant + ctx.constant._ctxdata = [ctx.mpf, new, ctx._prec_rounding] + ctx.constant.context = ctx + + ctx.types = [ctx.mpf, ctx.mpc, ctx.constant] + ctx.trap_complex = True + ctx.pretty = True + + if tol is None: + ctx.tol = ctx._make_tol() + elif tol is False: + ctx.tol = fzero + else: + ctx.tol = ctx._convert_tol(tol) + + ctx.tolerance = ctx.make_mpf(ctx.tol) + + if not ctx.tolerance: + ctx.max_denom = 1000000 + else: + ctx.max_denom = int(1/ctx.tolerance) + + ctx.zero = ctx.make_mpf(fzero) + ctx.one = ctx.make_mpf(fone) + ctx.j = ctx.make_mpc((fzero, fone)) + ctx.inf = ctx.make_mpf(finf) + ctx.ninf = ctx.make_mpf(fninf) + ctx.nan = ctx.make_mpf(fnan) + + def _make_tol(ctx): + hundred = (0, 25, 2, 5) + eps = (0, MPZ_ONE, 1-ctx.prec, 1) + return mpf_mul(hundred, eps) + + def make_tol(ctx): + return ctx.make_mpf(ctx._make_tol()) + + def _convert_tol(ctx, tol): + if isinstance(tol, int_types): + return from_int(tol) + if isinstance(tol, float): + return from_float(tol) + if hasattr(tol, "_mpf_"): + return tol._mpf_ + prec, rounding = ctx._prec_rounding + if isinstance(tol, str): + return from_str(tol, prec, rounding) + raise ValueError("expected a real number, got %s" % tol) + + def _convert_fallback(ctx, x, strings): + raise TypeError("cannot create mpf from " + repr(x)) + + @property + def _repr_digits(ctx): + return repr_dps(ctx._prec) + + @property + def _str_digits(ctx): + return ctx._dps + + def to_rational(ctx, s, limit=True): + p, q = to_rational(s._mpf_) + + # Needed for GROUND_TYPES=flint if gmpy2 is installed because mpmath's + # to_rational() function returns a gmpy2.mpz instance and if MPQ is + # flint.fmpq then MPQ(p, q) will fail. + p = int(p) + + if not limit or q <= ctx.max_denom: + return p, q + + p0, q0, p1, q1 = 0, 1, 1, 0 + n, d = p, q + + while True: + a = n//d + q2 = q0 + a*q1 + if q2 > ctx.max_denom: + break + p0, q0, p1, q1 = p1, q1, p0 + a*p1, q2 + n, d = d, n - a*d + + k = (ctx.max_denom - q0)//q1 + + number = MPQ(p, q) + bound1 = MPQ(p0 + k*p1, q0 + k*q1) + bound2 = MPQ(p1, q1) + + if not bound2 or not bound1: + return p, q + elif abs(bound2 - number) <= abs(bound1 - number): + return bound2.numerator, bound2.denominator + else: + return bound1.numerator, bound1.denominator + + def almosteq(ctx, s, t, rel_eps=None, abs_eps=None): + t = ctx.convert(t) + if abs_eps is None and rel_eps is None: + rel_eps = abs_eps = ctx.tolerance or ctx.make_tol() + if abs_eps is None: + abs_eps = ctx.convert(rel_eps) + elif rel_eps is None: + rel_eps = ctx.convert(abs_eps) + diff = abs(s-t) + if diff <= abs_eps: + return True + abss = abs(s) + abst = abs(t) + if abss < abst: + err = diff/abst + else: + err = diff/abss + return err <= rel_eps diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/old_fractionfield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/old_fractionfield.py new file mode 100644 index 0000000000000000000000000000000000000000..25d849c39e45259728479ab0305d4956053ae743 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/old_fractionfield.py @@ -0,0 +1,188 @@ +"""Implementation of :class:`FractionField` class. """ + + +from sympy.polys.domains.field import Field +from sympy.polys.domains.compositedomain import CompositeDomain +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 +from sympy.utilities import public + +@public +class FractionField(Field, CompositeDomain): + """A class for representing rational function fields. """ + + dtype = DMF + is_FractionField = 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.ngens = len(gens) + + self.zero = self.dtype.zero(lev, dom) + self.one = self.dtype.one(lev, dom) + + self.domain = self.dom = dom + self.symbols = self.gens = gens + + def set_domain(self, dom): + """Make a new fraction field with given domain. """ + return self.__class__(dom, *self.gens) + + def new(self, element): + return self.dtype(element, self.dom, len(self.gens) - 1) + + 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(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return K1(K1.dom.convert(a, K0)) + + 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_RealField(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.to_list()) + else: + return K1(a.convert(K1.dom).to_list()) + 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(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.old_frac_field(x) + >>> ZZx = ZZ.old_frac_field(x) + + >>> QQx.from_FractionField(f, ZZx) + DMF([1, 2], [1, 1], QQ) + + """ + if K1.gens == K0.gens: + if K1.dom == K0.dom: + return a + else: + return K1((a.numer().convert(K1.dom).to_list(), + a.denom().convert(K1.dom).to_list())) + 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(zip(nmonoms, ncoeffs)), dict(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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/old_polynomialring.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/old_polynomialring.py new file mode 100644 index 0000000000000000000000000000000000000000..c29a4529aac3c64b29d8c670ac45b6c100294ced --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/old_polynomialring.py @@ -0,0 +1,490 @@ +"""Implementation of :class:`PolynomialRing` class. """ + + +from sympy.polys.agca.modules import FreeModulePolyRing +from sympy.polys.domains.compositedomain import CompositeDomain +from sympy.polys.domains.old_fractionfield import FractionField +from sympy.polys.domains.ring import Ring +from sympy.polys.orderings import monomial_key, build_product_order +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.utilities import public +from sympy.utilities.iterables import iterable + + +@public +class PolynomialRingBase(Ring, 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.ngens = len(gens) + + self.zero = self.dtype.zero(lev, dom) + self.one = self.dtype.one(lev, dom) + + self.domain = self.dom = dom + self.symbols = 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 set_domain(self, dom): + """Return a new polynomial ring with given domain. """ + return self.__class__(dom, *self.gens, order=self.order) + + def new(self, element): + return self.dtype(element, self.dom, len(self.gens) - 1) + + def _ground_new(self, element): + return self.one.ground_new(element) + + def _from_dict(self, element): + return DMP.from_dict(element, len(self.gens) - 1, self.dom) + + 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(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return K1._ground_new(K1.dom.convert(a, K0)) + + def from_ZZ_python(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return K1._ground_new(K1.dom.convert(a, K0)) + + def from_QQ(K1, a, K0): + """Convert a Python ``Fraction`` object to ``dtype``. """ + return K1._ground_new(K1.dom.convert(a, K0)) + + def from_QQ_python(K1, a, K0): + """Convert a Python ``Fraction`` object to ``dtype``. """ + return K1._ground_new(K1.dom.convert(a, K0)) + + def from_ZZ_gmpy(K1, a, K0): + """Convert a GMPY ``mpz`` object to ``dtype``. """ + return K1._ground_new(K1.dom.convert(a, K0)) + + def from_QQ_gmpy(K1, a, K0): + """Convert a GMPY ``mpq`` object to ``dtype``. """ + return K1._ground_new(K1.dom.convert(a, K0)) + + def from_RealField(K1, a, K0): + """Convert a mpmath ``mpf`` object to ``dtype``. """ + return K1._ground_new(K1.dom.convert(a, K0)) + + def from_AlgebraicField(K1, a, K0): + """Convert a ``ANP`` object to ``dtype``. """ + if K1.dom == K0: + return K1._ground_new(a) + + def from_PolynomialRing(K1, a, K0): + """Convert a ``PolyElement`` object to ``dtype``. """ + if K1.gens == K0.symbols: + if K1.dom == K0.dom: + return K1(dict(a)) # set the correct ring + else: + convert_dom = lambda c: K1.dom.convert_from(c, K0.dom) + return K1._from_dict({m: convert_dom(c) for m, c in a.items()}) + else: + monoms, coeffs = _dict_reorder(a.to_dict(), K0.symbols, K1.gens) + + if K1.dom != K0.dom: + coeffs = [ K1.dom.convert(c, K0.dom) for c in coeffs ] + + return K1._from_dict(dict(zip(monoms, coeffs))) + + def from_GlobalPolynomialRing(K1, a, K0): + """Convert a ``DMP`` object to ``dtype``. """ + if K1.gens == K0.gens: + if K1.dom != K0.dom: + a = a.convert(K1.dom) + return K1(a.to_list()) + 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(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 self.exquo(self.one, 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``. + + Examples + ======== + + >>> from sympy import QQ, ilex + >>> from sympy.abc import x, y + >>> R = QQ.old_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) + [DMF([[1], [2, 0]], [[1]], QQ), DMF([[1, 0], []], [[1]], QQ)] + """ + 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``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(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) + + +@public +class GlobalPolynomialRing(PolynomialRingBase): + """A true polynomial ring, with objects DMP. """ + + is_PolynomialRing = is_Poly = True + dtype = DMP + + def new(self, element): + if isinstance(element, dict): + return DMP.from_dict(element, len(self.gens) - 1, self.dom) + elif element in self.dom: + return self._ground_new(self.dom.convert(element)) + else: + return self.dtype(element, self.dom, len(self.gens) - 1) + + 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.old_frac_field(x) + + >>> F = ZZ.old_poly_ring(x).from_FractionField(f, K) + + >>> F == DMP([ZZ(1), ZZ(1)], ZZ) + True + >>> type(F) # doctest: +SKIP + + + """ + 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("Cannot convert %s to type %s" % (a, self)) + + for k, v in rep.items(): + rep[k] = self.dom.from_sympy(v) + + return DMP.from_dict(rep, self.ngens - 1, self.dom) + + 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): + """ + Examples + ======== + + >>> from sympy import lex, QQ + >>> from sympy.abc import x, y + >>> R = QQ.old_poly_ring(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) + + # 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 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 exquo(self, a, b): + """Exact quotient of ``a`` and ``b``. """ + # Elements are DMF that will always divide (except 0). The result is + # not guaranteed to be in this ring, so we have to check that. + r = a / b + + try: + r = self.new((r.num, r.den)) + except CoercionFailed: + raise ExactQuotientFailed(a, b, self) + + return r + + def from_FractionField(K1, a, K0): + dmf = K1.get_field().from_FractionField(a, K0) + return K1((dmf.num, dmf.den)) + + 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. + + Examples + ======== + + >>> from sympy import ilex, QQ + >>> from sympy.abc import x, y + >>> R = QQ.old_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) + + +@public +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, \ldots, 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, \ldots, 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, \ldots, x_n] | LM(f) = 1\}`. The generalized + polynomial ring corresponding to the monomial order is + `R = S^{-1}K[x_1, \ldots, 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, \ldots, 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.old_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.old_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.old_poly_ring(x, y, order=o1) + >>> R4 = QQ.old_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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/polynomialring.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/polynomialring.py new file mode 100644 index 0000000000000000000000000000000000000000..daccdcdede4d409e995a79540b0c3f9e8017d2d9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/polynomialring.py @@ -0,0 +1,203 @@ +"""Implementation of :class:`PolynomialRing` class. """ + + +from sympy.polys.domains.ring import Ring +from sympy.polys.domains.compositedomain import CompositeDomain + +from sympy.polys.polyerrors import CoercionFailed, GeneratorsError +from sympy.utilities import public + +@public +class PolynomialRing(Ring, CompositeDomain): + """A class for representing multivariate polynomial rings. """ + + is_PolynomialRing = is_Poly = True + + has_assoc_Ring = True + has_assoc_Field = True + + def __init__(self, domain_or_ring, symbols=None, order=None): + from sympy.polys.rings import PolyRing + + if isinstance(domain_or_ring, PolyRing) and symbols is None and order is None: + ring = domain_or_ring + else: + ring = PolyRing(symbols, domain_or_ring, order) + + self.ring = ring + self.dtype = ring.dtype + + self.gens = ring.gens + self.ngens = ring.ngens + self.symbols = ring.symbols + self.domain = ring.domain + + + if symbols: + if ring.domain.is_Field and ring.domain.is_Exact and len(symbols)==1: + self.is_PID = True + + # TODO: remove this + self.dom = self.domain + + def new(self, element): + return self.ring.ring_new(element) + + def of_type(self, element): + """Check if ``a`` is of type ``dtype``. """ + return self.ring.is_element(element) + + @property + def zero(self): + return self.ring.zero + + @property + def one(self): + return self.ring.one + + @property + def order(self): + return self.ring.order + + def __str__(self): + return str(self.domain) + '[' + ','.join(map(str, self.symbols)) + ']' + + def __hash__(self): + return hash((self.__class__.__name__, self.ring, self.domain, self.symbols)) + + def __eq__(self, other): + """Returns `True` if two domains are equivalent. """ + if not isinstance(other, PolynomialRing): + return NotImplemented + return self.ring == other.ring + + def is_unit(self, a): + """Returns ``True`` if ``a`` is a unit of ``self``""" + if not a.is_ground: + return False + K = self.domain + return K.is_unit(K.convert_from(a, self)) + + def canonical_unit(self, a): + u = self.domain.canonical_unit(a.LC) + return self.ring.ground_new(u) + + 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(K1, a, K0): + """Convert a Python `int` object to `dtype`. """ + return K1(K1.domain.convert(a, K0)) + + def from_ZZ_python(K1, a, K0): + """Convert a Python `int` object to `dtype`. """ + return K1(K1.domain.convert(a, K0)) + + def from_QQ(K1, a, K0): + """Convert a Python `Fraction` object to `dtype`. """ + return K1(K1.domain.convert(a, K0)) + + def from_QQ_python(K1, a, K0): + """Convert a Python `Fraction` object to `dtype`. """ + return K1(K1.domain.convert(a, K0)) + + def from_ZZ_gmpy(K1, a, K0): + """Convert a GMPY `mpz` object to `dtype`. """ + return K1(K1.domain.convert(a, K0)) + + def from_QQ_gmpy(K1, a, K0): + """Convert a GMPY `mpq` object to `dtype`. """ + return K1(K1.domain.convert(a, K0)) + + def from_GaussianIntegerRing(K1, a, K0): + """Convert a `GaussianInteger` object to `dtype`. """ + return K1(K1.domain.convert(a, K0)) + + def from_GaussianRationalField(K1, a, K0): + """Convert a `GaussianRational` object to `dtype`. """ + return K1(K1.domain.convert(a, K0)) + + def from_RealField(K1, a, K0): + """Convert a mpmath `mpf` object to `dtype`. """ + return K1(K1.domain.convert(a, K0)) + + def from_ComplexField(K1, a, K0): + """Convert a mpmath `mpf` object to `dtype`. """ + return K1(K1.domain.convert(a, K0)) + + def from_AlgebraicField(K1, a, K0): + """Convert an algebraic number to ``dtype``. """ + if K1.domain != K0: + a = K1.domain.convert_from(a, K0) + if a is not None: + return K1.new(a) + + def from_PolynomialRing(K1, a, K0): + """Convert a polynomial to ``dtype``. """ + try: + return a.set_ring(K1.ring) + except (CoercionFailed, GeneratorsError): + return None + + def from_FractionField(K1, a, K0): + """Convert a rational function to ``dtype``. """ + if K1.domain == K0: + return K1.ring.from_list([a]) + + q, r = K0.numer(a).div(K0.denom(a)) + + if r.is_zero: + return K1.from_PolynomialRing(q, K0.field.ring.to_domain()) + else: + return None + + def from_GlobalPolynomialRing(K1, a, K0): + """Convert from old poly ring to ``dtype``. """ + if K1.symbols == K0.gens: + ad = a.to_dict() + if K1.domain != K0.domain: + ad = {m: K1.domain.convert(c) for m, c in ad.items()} + return K1(ad) + elif a.is_ground and K0.domain == K1: + return K1.convert_from(a.to_list()[0], K0.domain) + + def get_field(self): + """Returns a field associated with `self`. """ + return self.ring.to_field().to_domain() + + def is_positive(self, a): + """Returns True if `LC(a)` is positive. """ + return self.domain.is_positive(a.LC) + + def is_negative(self, a): + """Returns True if `LC(a)` is negative. """ + return self.domain.is_negative(a.LC) + + def is_nonpositive(self, a): + """Returns True if `LC(a)` is non-positive. """ + return self.domain.is_nonpositive(a.LC) + + def is_nonnegative(self, a): + """Returns True if `LC(a)` is non-negative. """ + return self.domain.is_nonnegative(a.LC) + + 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.domain.factorial(a)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonfinitefield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonfinitefield.py new file mode 100644 index 0000000000000000000000000000000000000000..44baa4f6d1b43317283041206eaa43e06a5cc8db --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonfinitefield.py @@ -0,0 +1,16 @@ +"""Implementation of :class:`PythonFiniteField` class. """ + + +from sympy.polys.domains.finitefield import FiniteField +from sympy.polys.domains.pythonintegerring import PythonIntegerRing + +from sympy.utilities import public + +@public +class PythonFiniteField(FiniteField): + """Finite field based on Python's integers. """ + + alias = 'FF_python' + + def __init__(self, mod, symmetric=True): + super().__init__(mod, PythonIntegerRing(), symmetric) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonintegerring.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonintegerring.py new file mode 100644 index 0000000000000000000000000000000000000000..81ee9637a4ebcfaf3c5f11d12c18265305984c25 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonintegerring.py @@ -0,0 +1,98 @@ +"""Implementation of :class:`PythonIntegerRing` class. """ + + +from sympy.core.numbers import int_valued +from sympy.polys.domains.groundtypes import ( + PythonInteger, SymPyInteger, sqrt as python_sqrt, + factorial as python_factorial, python_gcdex, python_gcd, python_lcm, +) +from sympy.polys.domains.integerring import IntegerRing +from sympy.polys.polyerrors import CoercionFailed +from sympy.utilities import public + +@public +class PythonIntegerRing(IntegerRing): + """Integer ring based on Python's ``int`` type. + + This will be used as :ref:`ZZ` if ``gmpy`` and ``gmpy2`` are not + installed. Elements are instances of the standard Python ``int`` type. + """ + + dtype = PythonInteger + zero = dtype(0) + one = dtype(1) + alias = 'ZZ_python' + + def __init__(self): + """Allow instantiation of this domain. """ + + def to_sympy(self, a): + """Convert ``a`` to a SymPy object. """ + return SymPyInteger(a) + + def from_sympy(self, a): + """Convert SymPy's Integer to ``dtype``. """ + if a.is_Integer: + return PythonInteger(a.p) + elif int_valued(a): + return PythonInteger(int(a)) + else: + raise CoercionFailed("expected an integer, got %s" % a) + + def from_FF_python(K1, a, K0): + """Convert ``ModularInteger(int)`` to Python's ``int``. """ + return K0.to_int(a) + + def from_ZZ_python(K1, a, K0): + """Convert Python's ``int`` to Python's ``int``. """ + return a + + def from_QQ(K1, a, K0): + """Convert Python's ``Fraction`` to Python's ``int``. """ + if a.denominator == 1: + return a.numerator + + def from_QQ_python(K1, a, K0): + """Convert Python's ``Fraction`` to Python's ``int``. """ + if a.denominator == 1: + return a.numerator + + def from_FF_gmpy(K1, a, K0): + """Convert ``ModularInteger(mpz)`` to Python's ``int``. """ + return PythonInteger(K0.to_int(a)) + + def from_ZZ_gmpy(K1, a, K0): + """Convert GMPY's ``mpz`` to Python's ``int``. """ + return PythonInteger(a) + + def from_QQ_gmpy(K1, a, K0): + """Convert GMPY's ``mpq`` to Python's ``int``. """ + if a.denom() == 1: + return PythonInteger(a.numer()) + + def from_RealField(K1, a, K0): + """Convert mpmath's ``mpf`` to Python's ``int``. """ + p, q = K0.to_rational(a) + + if q == 1: + return PythonInteger(p) + + def gcdex(self, a, b): + """Compute extended GCD of ``a`` and ``b``. """ + return python_gcdex(a, b) + + def gcd(self, a, b): + """Compute GCD of ``a`` and ``b``. """ + return python_gcd(a, b) + + def lcm(self, a, b): + """Compute LCM of ``a`` and ``b``. """ + return python_lcm(a, b) + + def sqrt(self, a): + """Compute square root of ``a``. """ + return python_sqrt(a) + + def factorial(self, a): + """Compute factorial of ``a``. """ + return python_factorial(a) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonrational.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonrational.py new file mode 100644 index 0000000000000000000000000000000000000000..87b56d6c929c3ce3ce153dce7b3c210821d706a0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonrational.py @@ -0,0 +1,22 @@ +""" +Rational number type based on Python integers. + +The PythonRational class from here has been moved to +sympy.external.pythonmpq + +This module is just left here for backwards compatibility. +""" + + +from sympy.core.numbers import Rational +from sympy.core.sympify import _sympy_converter +from sympy.utilities import public +from sympy.external.pythonmpq import PythonMPQ + + +PythonRational = public(PythonMPQ) + + +def sympify_pythonrational(arg): + return Rational(arg.numerator, arg.denominator) +_sympy_converter[PythonRational] = sympify_pythonrational diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonrationalfield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonrationalfield.py new file mode 100644 index 0000000000000000000000000000000000000000..51afaef636f000855d51a69fb93eb416ae1e5347 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/pythonrationalfield.py @@ -0,0 +1,73 @@ +"""Implementation of :class:`PythonRationalField` class. """ + + +from sympy.polys.domains.groundtypes import PythonInteger, PythonRational, SymPyRational +from sympy.polys.domains.rationalfield import RationalField +from sympy.polys.polyerrors import CoercionFailed +from sympy.utilities import public + +@public +class PythonRationalField(RationalField): + """Rational field based on :ref:`MPQ`. + + This will be used as :ref:`QQ` if ``gmpy`` and ``gmpy2`` are not + installed. Elements are instances of :ref:`MPQ`. + """ + + 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 SymPyRational(a.numerator, a.denominator) + + def from_sympy(self, a): + """Convert SymPy's Rational to `dtype`. """ + if a.is_Rational: + return PythonRational(a.p, a.q) + elif a.is_Float: + from sympy.polys.domains import RR + p, q = RR.to_rational(a) + return PythonRational(int(p), int(q)) + else: + raise CoercionFailed("expected `Rational` object, got %s" % a) + + def from_ZZ_python(K1, a, K0): + """Convert a Python `int` object to `dtype`. """ + return PythonRational(a) + + def from_QQ_python(K1, a, K0): + """Convert a Python `Fraction` object to `dtype`. """ + return a + + def from_ZZ_gmpy(K1, a, K0): + """Convert a GMPY `mpz` object to `dtype`. """ + return PythonRational(PythonInteger(a)) + + def from_QQ_gmpy(K1, a, K0): + """Convert a GMPY `mpq` object to `dtype`. """ + return PythonRational(PythonInteger(a.numer()), + PythonInteger(a.denom())) + + def from_RealField(K1, a, K0): + """Convert a mpmath `mpf` object to `dtype`. """ + p, q = K0.to_rational(a) + return PythonRational(int(p), int(q)) + + def numer(self, a): + """Returns numerator of `a`. """ + return a.numerator + + def denom(self, a): + """Returns denominator of `a`. """ + return a.denominator diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/quotientring.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/quotientring.py new file mode 100644 index 0000000000000000000000000000000000000000..7e8abf6b210a5627c9c139e41248637c9b88931f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/quotientring.py @@ -0,0 +1,202 @@ +"""Implementation of :class:`QuotientRing` class.""" + + +from sympy.polys.agca.modules import FreeModuleQuotientRing +from sympy.polys.domains.ring import Ring +from sympy.polys.polyerrors import NotReversible, CoercionFailed +from sympy.utilities import public + +# TODO +# - successive quotients (when quotient ideals are implemented) +# - poly rings over quotients? +# - division by non-units in integral domains? + +@public +class QuotientRingElement: + """ + Class representing elements of (commutative) quotient rings. + + Attributes: + + - ring - containing ring + - data - element of ring.ring (i.e. base ring) representing self + """ + + def __init__(self, ring, data): + self.ring = ring + self.data = data + + def __str__(self): + from sympy.printing.str import sstr + data = self.ring.ring.to_sympy(self.data) + return sstr(data) + " + " + str(self.ring.base_ideal) + + __repr__ = __str__ + + def __bool__(self): + return not self.ring.is_zero(self) + + def __add__(self, om): + if not isinstance(om, self.__class__) or om.ring != self.ring: + try: + om = self.ring.convert(om) + except (NotImplementedError, CoercionFailed): + return NotImplemented + return self.ring(self.data + om.data) + + __radd__ = __add__ + + def __neg__(self): + return self.ring(self.data*self.ring.ring.convert(-1)) + + def __sub__(self, om): + return self.__add__(-om) + + def __rsub__(self, om): + return (-self).__add__(om) + + def __mul__(self, o): + if not isinstance(o, self.__class__): + try: + o = self.ring.convert(o) + except (NotImplementedError, CoercionFailed): + return NotImplemented + return self.ring(self.data*o.data) + + __rmul__ = __mul__ + + def __rtruediv__(self, o): + return self.ring.revert(self)*o + + def __truediv__(self, o): + if not isinstance(o, self.__class__): + try: + o = self.ring.convert(o) + except (NotImplementedError, CoercionFailed): + return NotImplemented + return self.ring.revert(o)*self + + def __pow__(self, oth): + if oth < 0: + return self.ring.revert(self) ** -oth + return self.ring(self.data ** oth) + + def __eq__(self, om): + if not isinstance(om, self.__class__) or om.ring != self.ring: + return False + return self.ring.is_zero(self - om) + + def __ne__(self, om): + return not self == om + + +class QuotientRing(Ring): + """ + Class representing (commutative) quotient rings. + + 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 + >>> I = QQ.old_poly_ring(x).ideal(x**3 + 1) + >>> QQ.old_poly_ring(x).quotient_ring(I) + QQ[x]/ + + Shorter versions are possible: + + >>> QQ.old_poly_ring(x)/I + QQ[x]/ + + >>> QQ.old_poly_ring(x)/[x**3 + 1] + QQ[x]/ + + Attributes: + + - ring - the base ring + - base_ideal - the ideal used to form the quotient + """ + + has_assoc_Ring = True + has_assoc_Field = False + dtype = QuotientRingElement + + def __init__(self, ring, ideal): + if not ideal.ring == ring: + raise ValueError('Ideal must belong to %s, got %s' % (ring, ideal)) + self.ring = ring + self.base_ideal = ideal + self.zero = self(self.ring.zero) + self.one = self(self.ring.one) + + def __str__(self): + return str(self.ring) + "/" + str(self.base_ideal) + + def __hash__(self): + return hash((self.__class__.__name__, self.dtype, self.ring, self.base_ideal)) + + def new(self, a): + """Construct an element of ``self`` domain from ``a``. """ + if not isinstance(a, self.ring.dtype): + a = self.ring(a) + # TODO optionally disable reduction? + return self.dtype(self, self.base_ideal.reduce_element(a)) + + def __eq__(self, other): + """Returns ``True`` if two domains are equivalent. """ + return isinstance(other, QuotientRing) and \ + self.ring == other.ring and self.base_ideal == other.base_ideal + + def from_ZZ(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return K1(K1.ring.convert(a, K0)) + + from_ZZ_python = from_ZZ + from_QQ_python = from_ZZ_python + from_ZZ_gmpy = from_ZZ_python + from_QQ_gmpy = from_ZZ_python + from_RealField = from_ZZ_python + from_GlobalPolynomialRing = from_ZZ_python + from_FractionField = from_ZZ_python + + def from_sympy(self, a): + return self(self.ring.from_sympy(a)) + + def to_sympy(self, a): + return self.ring.to_sympy(a.data) + + def from_QuotientRing(self, a, K0): + if K0 == self: + return a + + 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): + """ + Compute a**(-1), if possible. + """ + 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 + raise NotReversible('%s not a unit in %r' % (a, self)) + + def is_zero(self, a): + return self.base_ideal.contains(a.data) + + def free_module(self, rank): + """ + Generate a free module of rank ``rank`` over ``self``. + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> (QQ.old_poly_ring(x)/[x**2 + 1]).free_module(2) + (QQ[x]/)**2 + """ + return FreeModuleQuotientRing(self, rank) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/rationalfield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/rationalfield.py new file mode 100644 index 0000000000000000000000000000000000000000..6da570332de8a6d39a21bb3d57447670c7a98441 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/rationalfield.py @@ -0,0 +1,200 @@ +"""Implementation of :class:`RationalField` class. """ + + +from sympy.external.gmpy import MPQ + +from sympy.polys.domains.groundtypes import SymPyRational, is_square, sqrtrem + +from sympy.polys.domains.characteristiczero import CharacteristicZero +from sympy.polys.domains.field import Field +from sympy.polys.domains.simpledomain import SimpleDomain +from sympy.polys.polyerrors import CoercionFailed +from sympy.utilities import public + +@public +class RationalField(Field, CharacteristicZero, SimpleDomain): + r"""Abstract base class for the domain :ref:`QQ`. + + The :py:class:`RationalField` class represents the field of rational + numbers $\mathbb{Q}$ as a :py:class:`~.Domain` in the domain system. + :py:class:`RationalField` is a superclass of + :py:class:`PythonRationalField` and :py:class:`GMPYRationalField` one of + which will be the implementation for :ref:`QQ` depending on whether either + of ``gmpy`` or ``gmpy2`` is installed or not. + + See also + ======== + + Domain + """ + + rep = 'QQ' + alias = 'QQ' + + is_RationalField = is_QQ = True + is_Numerical = True + + has_assoc_Ring = True + has_assoc_Field = True + + dtype = MPQ + zero = dtype(0) + one = dtype(1) + tp = type(one) + + def __init__(self): + pass + + def __eq__(self, other): + """Returns ``True`` if two domains are equivalent. """ + if isinstance(other, RationalField): + return True + else: + return NotImplemented + + def __hash__(self): + """Returns hash code of ``self``. """ + return hash('QQ') + + def get_ring(self): + """Returns ring associated with ``self``. """ + from sympy.polys.domains import ZZ + return ZZ + + def to_sympy(self, a): + """Convert ``a`` to a SymPy object. """ + return SymPyRational(int(a.numerator), int(a.denominator)) + + def from_sympy(self, a): + """Convert SymPy's Integer to ``dtype``. """ + if a.is_Rational: + return MPQ(a.p, a.q) + elif a.is_Float: + from sympy.polys.domains import RR + return MPQ(*map(int, RR.to_rational(a))) + else: + raise CoercionFailed("expected `Rational` object, got %s" % a) + + def algebraic_field(self, *extension, alias=None): + r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \ldots)`. + + Parameters + ========== + + *extension : One or more :py:class:`~.Expr` + Generators of the extension. These should be expressions that are + algebraic over `\mathbb{Q}`. + + alias : str, :py:class:`~.Symbol`, None, optional (default=None) + If provided, this will be used as the alias symbol for the + primitive element of the returned :py:class:`~.AlgebraicField`. + + Returns + ======= + + :py:class:`~.AlgebraicField` + A :py:class:`~.Domain` representing the algebraic field extension. + + Examples + ======== + + >>> from sympy import QQ, sqrt + >>> QQ.algebraic_field(sqrt(2)) + QQ + """ + from sympy.polys.domains import AlgebraicField + return AlgebraicField(self, *extension, alias=alias) + + def from_AlgebraicField(K1, a, K0): + """Convert a :py:class:`~.ANP` object to :ref:`QQ`. + + See :py:meth:`~.Domain.convert` + """ + if a.is_ground: + return K1.convert(a.LC(), K0.dom) + + def from_ZZ(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return MPQ(a) + + def from_ZZ_python(K1, a, K0): + """Convert a Python ``int`` object to ``dtype``. """ + return MPQ(a) + + def from_QQ(K1, a, K0): + """Convert a Python ``Fraction`` object to ``dtype``. """ + return MPQ(a.numerator, a.denominator) + + def from_QQ_python(K1, a, K0): + """Convert a Python ``Fraction`` object to ``dtype``. """ + return MPQ(a.numerator, a.denominator) + + def from_ZZ_gmpy(K1, a, K0): + """Convert a GMPY ``mpz`` object to ``dtype``. """ + return MPQ(a) + + def from_QQ_gmpy(K1, a, K0): + """Convert a GMPY ``mpq`` object to ``dtype``. """ + return a + + def from_GaussianRationalField(K1, a, K0): + """Convert a ``GaussianElement`` object to ``dtype``. """ + if a.y == 0: + return MPQ(a.x) + + def from_RealField(K1, a, K0): + """Convert a mpmath ``mpf`` object to ``dtype``. """ + return MPQ(*map(int, K0.to_rational(a))) + + def exquo(self, a, b): + """Exact quotient of ``a`` and ``b``, implies ``__truediv__``. """ + return MPQ(a) / MPQ(b) + + def quo(self, a, b): + """Quotient of ``a`` and ``b``, implies ``__truediv__``. """ + return MPQ(a) / MPQ(b) + + def rem(self, a, b): + """Remainder of ``a`` and ``b``, implies nothing. """ + return self.zero + + def div(self, a, b): + """Division of ``a`` and ``b``, implies ``__truediv__``. """ + return MPQ(a) / MPQ(b), self.zero + + def numer(self, a): + """Returns numerator of ``a``. """ + return a.numerator + + def denom(self, a): + """Returns denominator of ``a``. """ + return a.denominator + + def is_square(self, a): + """Return ``True`` if ``a`` is a square. + + Explanation + =========== + A rational number is a square if and only if there exists + a rational number ``b`` such that ``b * b == a``. + """ + return is_square(a.numerator) and is_square(a.denominator) + + def exsqrt(self, a): + """Non-negative square root of ``a`` if ``a`` is a square. + + See also + ======== + is_square + """ + if a.numerator < 0: # denominator is always positive + return None + p_sqrt, p_rem = sqrtrem(a.numerator) + if p_rem != 0: + return None + q_sqrt, q_rem = sqrtrem(a.denominator) + if q_rem != 0: + return None + return MPQ(p_sqrt, q_sqrt) + +QQ = RationalField() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/realfield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/realfield.py new file mode 100644 index 0000000000000000000000000000000000000000..12f543b2619aa238969ecbe20215d6fd59792904 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/realfield.py @@ -0,0 +1,220 @@ +"""Implementation of :class:`RealField` class. """ + + +from sympy.external.gmpy import SYMPY_INTS, MPQ +from sympy.core.numbers import Float +from sympy.polys.domains.field import Field +from sympy.polys.domains.simpledomain import SimpleDomain +from sympy.polys.domains.characteristiczero import CharacteristicZero +from sympy.polys.polyerrors import CoercionFailed +from sympy.utilities import public + +from mpmath import MPContext +from mpmath.libmp import to_rational as _mpmath_to_rational + + +def to_rational(s, max_denom, limit=True): + + p, q = _mpmath_to_rational(s._mpf_) + + # Needed for GROUND_TYPES=flint if gmpy2 is installed because mpmath's + # to_rational() function returns a gmpy2.mpz instance and if MPQ is + # flint.fmpq then MPQ(p, q) will fail. + p = int(p) + q = int(q) + + if not limit or q <= max_denom: + return p, q + + p0, q0, p1, q1 = 0, 1, 1, 0 + n, d = p, q + + while True: + a = n//d + q2 = q0 + a*q1 + if q2 > max_denom: + break + p0, q0, p1, q1 = p1, q1, p0 + a*p1, q2 + n, d = d, n - a*d + + k = (max_denom - q0)//q1 + + number = MPQ(p, q) + bound1 = MPQ(p0 + k*p1, q0 + k*q1) + bound2 = MPQ(p1, q1) + + if not bound2 or not bound1: + return p, q + elif abs(bound2 - number) <= abs(bound1 - number): + return bound2.numerator, bound2.denominator + else: + return bound1.numerator, bound1.denominator + + +@public +class RealField(Field, CharacteristicZero, SimpleDomain): + """Real numbers up to the given precision. """ + + rep = 'RR' + + is_RealField = is_RR = True + + is_Exact = False + is_Numerical = True + is_PID = False + + has_assoc_Ring = False + has_assoc_Field = True + + _default_precision = 53 + + @property + def has_default_precision(self): + return self.precision == self._default_precision + + @property + def precision(self): + return self._context.prec + + @property + def dps(self): + return self._context.dps + + @property + def tolerance(self): + return self._tolerance + + def __init__(self, prec=None, dps=None, tol=None): + # XXX: The tol parameter is ignored but is kept for now for backwards + # compatibility. + + context = MPContext() + + if prec is None and dps is None: + context.prec = self._default_precision + elif dps is None: + context.prec = prec + elif prec is None: + context.dps = dps + else: + raise TypeError("Cannot set both prec and dps") + + self._context = context + + self._dtype = context.mpf + self.zero = self.dtype(0) + self.one = self.dtype(1) + + # Only max_denom here is used for anything and is only used for + # to_rational. + self._max_denom = max(2**context.prec // 200, 99) + self._tolerance = self.one / self._max_denom + + @property + def tp(self): + # XXX: Domain treats tp as an alias of dtype. Here we need to two + # separate things: dtype is a callable to make/convert instances. + # We use tp with isinstance to check if an object is an instance + # of the domain already. + return self._dtype + + def dtype(self, arg): + # XXX: This is needed because mpmath does not recognise fmpz. + # It might be better to add conversion routines to mpmath and if that + # happens then this can be removed. + if isinstance(arg, SYMPY_INTS): + arg = int(arg) + return self._dtype(arg) + + def __eq__(self, other): + return isinstance(other, RealField) and self.precision == other.precision + + def __hash__(self): + return hash((self.__class__.__name__, self._dtype, self.precision)) + + def to_sympy(self, element): + """Convert ``element`` to SymPy number. """ + return Float(element, self.dps) + + def from_sympy(self, expr): + """Convert SymPy's number to ``dtype``. """ + number = expr.evalf(n=self.dps) + + if number.is_Number: + return self.dtype(number) + else: + raise CoercionFailed("expected real number, got %s" % expr) + + def from_ZZ(self, element, base): + return self.dtype(element) + + def from_ZZ_python(self, element, base): + return self.dtype(element) + + def from_ZZ_gmpy(self, element, base): + return self.dtype(int(element)) + + # XXX: We need to convert the denominators to int here because mpmath does + # not recognise mpz. Ideally mpmath would handle this and if it changed to + # do so then the calls to int here could be removed. + + def from_QQ(self, element, base): + return self.dtype(element.numerator) / int(element.denominator) + + def from_QQ_python(self, element, base): + return self.dtype(element.numerator) / int(element.denominator) + + def from_QQ_gmpy(self, element, base): + return self.dtype(int(element.numerator)) / int(element.denominator) + + def from_AlgebraicField(self, element, base): + return self.from_sympy(base.to_sympy(element).evalf(self.dps)) + + def from_RealField(self, element, base): + return self.dtype(element) + + def from_ComplexField(self, element, base): + if not element.imag: + return self.dtype(element.real) + + def to_rational(self, element, limit=True): + """Convert a real number to rational number. """ + return to_rational(element, self._max_denom, limit=limit) + + def get_ring(self): + """Returns a ring associated with ``self``. """ + return self + + def get_exact(self): + """Returns an exact domain associated with ``self``. """ + from sympy.polys.domains import QQ + return QQ + + def gcd(self, a, b): + """Returns GCD of ``a`` and ``b``. """ + return self.one + + def lcm(self, a, b): + """Returns LCM of ``a`` and ``b``. """ + return a*b + + def almosteq(self, a, b, tolerance=None): + """Check if ``a`` and ``b`` are almost equal. """ + return self._context.almosteq(a, b, tolerance) + + def is_square(self, a): + """Returns ``True`` if ``a >= 0`` and ``False`` otherwise. """ + return a >= 0 + + def exsqrt(self, a): + """Non-negative square root for ``a >= 0`` and ``None`` otherwise. + + Explanation + =========== + The square root may be slightly inaccurate due to floating point + rounding error. + """ + return a ** 0.5 if a >= 0 else None + + +RR = RealField() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/ring.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/ring.py new file mode 100644 index 0000000000000000000000000000000000000000..c69e6944d8f51e4b319609368a476e6e847ae126 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/ring.py @@ -0,0 +1,118 @@ +"""Implementation of :class:`Ring` class. """ + + +from sympy.polys.domains.domain import Domain +from sympy.polys.polyerrors import ExactQuotientFailed, NotInvertible, NotReversible + +from sympy.utilities import public + +@public +class Ring(Domain): + """Represents a ring domain. """ + + is_Ring = True + + def get_ring(self): + """Returns a ring associated with ``self``. """ + return self + + def exquo(self, a, b): + """Exact quotient of ``a`` and ``b``, implies ``__floordiv__``. """ + if a % b: + raise ExactQuotientFailed(a, b, self) + else: + return a // b + + def quo(self, a, b): + """Quotient of ``a`` and ``b``, implies ``__floordiv__``. """ + return a // b + + def rem(self, a, b): + """Remainder of ``a`` and ``b``, implies ``__mod__``. """ + return a % b + + def div(self, a, b): + """Division of ``a`` and ``b``, implies ``__divmod__``. """ + return divmod(a, b) + + def invert(self, a, b): + """Returns inversion of ``a mod b``. """ + s, t, h = self.gcdex(a, b) + + if self.is_one(h): + return s % b + else: + raise NotInvertible("zero divisor") + + def revert(self, a): + """Returns ``a**(-1)`` if possible. """ + if self.is_one(a) or self.is_one(-a): + return a + else: + raise NotReversible('only units are reversible in a ring') + + def is_unit(self, a): + try: + self.revert(a) + return True + except NotReversible: + return False + + def numer(self, a): + """Returns numerator of ``a``. """ + return a + + def denom(self, a): + """Returns denominator of `a`. """ + return self.one + + def free_module(self, rank): + """ + Generate a free module of rank ``rank`` over self. + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).free_module(2) + QQ[x]**2 + """ + raise NotImplementedError + + def ideal(self, *gens): + """ + Generate an ideal of ``self``. + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).ideal(x**2) + + """ + from sympy.polys.agca.ideals import ModuleImplementedIdeal + return ModuleImplementedIdeal(self, self.free_module(1).submodule( + *[[x] for x in gens])) + + def quotient_ring(self, e): + """ + Form a quotient ring of ``self``. + + Here ``e`` can be an ideal or an iterable. + + >>> from sympy.abc import x + >>> from sympy import QQ + >>> QQ.old_poly_ring(x).quotient_ring(QQ.old_poly_ring(x).ideal(x**2)) + QQ[x]/ + >>> QQ.old_poly_ring(x).quotient_ring([x**2]) + QQ[x]/ + + The division operator has been overloaded for this: + + >>> QQ.old_poly_ring(x)/[x**2] + QQ[x]/ + """ + from sympy.polys.agca.ideals import Ideal + from sympy.polys.domains.quotientring import QuotientRing + if not isinstance(e, Ideal): + e = self.ideal(*e) + return QuotientRing(self, e) + + def __truediv__(self, e): + return self.quotient_ring(e) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/simpledomain.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/simpledomain.py new file mode 100644 index 0000000000000000000000000000000000000000..88cf634555d8bd9229d7fc511af3cf96fececbb8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/simpledomain.py @@ -0,0 +1,15 @@ +"""Implementation of :class:`SimpleDomain` class. """ + + +from sympy.polys.domains.domain import Domain +from sympy.utilities import public + +@public +class SimpleDomain(Domain): + """Base class for simple domains, e.g. ZZ, QQ. """ + + is_Simple = True + + def inject(self, *gens): + """Inject generators into this domain. """ + return self.poly_ring(*gens) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/tests/test_domains.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/tests/test_domains.py new file mode 100644 index 0000000000000000000000000000000000000000..403cb37a4f093517183345f0b53fc5253f6756bd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/tests/test_domains.py @@ -0,0 +1,1434 @@ +"""Tests for classes defining properties of ground domains, e.g. ZZ, QQ, ZZ[x] ... """ + +from sympy.external.gmpy import GROUND_TYPES + +from sympy.core.numbers import (AlgebraicNumber, E, Float, I, Integer, + Rational, oo, pi, _illegal) +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin +from sympy.polys.polytools import Poly +from sympy.abc import x, y, z + +from sympy.polys.domains import (ZZ, QQ, RR, CC, FF, GF, EX, EXRAW, ZZ_gmpy, + ZZ_python, QQ_gmpy, QQ_python) +from sympy.polys.domains.algebraicfield import AlgebraicField +from sympy.polys.domains.gaussiandomains import ZZ_I, QQ_I +from sympy.polys.domains.polynomialring import PolynomialRing +from sympy.polys.domains.realfield import RealField + +from sympy.polys.numberfields.subfield import field_isomorphism +from sympy.polys.rings import ring, PolyElement +from sympy.polys.specialpolys import cyclotomic_poly +from sympy.polys.fields import field, FracElement + +from sympy.polys.agca.extensions import FiniteExtension + +from sympy.polys.polyerrors import ( + UnificationFailed, + GeneratorsError, + CoercionFailed, + NotInvertible, + DomainError) + +from sympy.testing.pytest import raises, warns_deprecated_sympy + +from itertools import product + +ALG = QQ.algebraic_field(sqrt(2), sqrt(3)) + +def unify(K0, K1): + return K0.unify(K1) + +def test_Domain_unify(): + F3 = GF(3) + F5 = GF(5) + + assert unify(F3, F3) == F3 + raises(UnificationFailed, lambda: unify(F3, ZZ)) + raises(UnificationFailed, lambda: unify(F3, QQ)) + raises(UnificationFailed, lambda: unify(F3, ZZ_I)) + raises(UnificationFailed, lambda: unify(F3, QQ_I)) + raises(UnificationFailed, lambda: unify(F3, ALG)) + raises(UnificationFailed, lambda: unify(F3, RR)) + raises(UnificationFailed, lambda: unify(F3, CC)) + raises(UnificationFailed, lambda: unify(F3, ZZ[x])) + raises(UnificationFailed, lambda: unify(F3, ZZ.frac_field(x))) + raises(UnificationFailed, lambda: unify(F3, EX)) + + assert unify(F5, F5) == F5 + raises(UnificationFailed, lambda: unify(F5, F3)) + raises(UnificationFailed, lambda: unify(F5, F3[x])) + raises(UnificationFailed, lambda: unify(F5, F3.frac_field(x))) + + raises(UnificationFailed, lambda: unify(ZZ, F3)) + assert unify(ZZ, ZZ) == ZZ + assert unify(ZZ, QQ) == QQ + assert unify(ZZ, ALG) == ALG + assert unify(ZZ, RR) == RR + assert unify(ZZ, CC) == CC + assert unify(ZZ, ZZ[x]) == ZZ[x] + assert unify(ZZ, ZZ.frac_field(x)) == ZZ.frac_field(x) + assert unify(ZZ, EX) == EX + + raises(UnificationFailed, lambda: unify(QQ, F3)) + assert unify(QQ, ZZ) == QQ + assert unify(QQ, QQ) == QQ + assert unify(QQ, ALG) == ALG + assert unify(QQ, RR) == RR + assert unify(QQ, CC) == CC + assert unify(QQ, ZZ[x]) == QQ[x] + assert unify(QQ, ZZ.frac_field(x)) == QQ.frac_field(x) + assert unify(QQ, EX) == EX + + raises(UnificationFailed, lambda: unify(ZZ_I, F3)) + assert unify(ZZ_I, ZZ) == ZZ_I + assert unify(ZZ_I, ZZ_I) == ZZ_I + assert unify(ZZ_I, QQ) == QQ_I + assert unify(ZZ_I, ALG) == QQ.algebraic_field(I, sqrt(2), sqrt(3)) + assert unify(ZZ_I, RR) == CC + assert unify(ZZ_I, CC) == CC + assert unify(ZZ_I, ZZ[x]) == ZZ_I[x] + assert unify(ZZ_I, ZZ_I[x]) == ZZ_I[x] + assert unify(ZZ_I, ZZ.frac_field(x)) == ZZ_I.frac_field(x) + assert unify(ZZ_I, ZZ_I.frac_field(x)) == ZZ_I.frac_field(x) + assert unify(ZZ_I, EX) == EX + + raises(UnificationFailed, lambda: unify(QQ_I, F3)) + assert unify(QQ_I, ZZ) == QQ_I + assert unify(QQ_I, ZZ_I) == QQ_I + assert unify(QQ_I, QQ) == QQ_I + assert unify(QQ_I, ALG) == QQ.algebraic_field(I, sqrt(2), sqrt(3)) + assert unify(QQ_I, RR) == CC + assert unify(QQ_I, CC) == CC + assert unify(QQ_I, ZZ[x]) == QQ_I[x] + assert unify(QQ_I, ZZ_I[x]) == QQ_I[x] + assert unify(QQ_I, QQ[x]) == QQ_I[x] + assert unify(QQ_I, QQ_I[x]) == QQ_I[x] + assert unify(QQ_I, ZZ.frac_field(x)) == QQ_I.frac_field(x) + assert unify(QQ_I, ZZ_I.frac_field(x)) == QQ_I.frac_field(x) + assert unify(QQ_I, QQ.frac_field(x)) == QQ_I.frac_field(x) + assert unify(QQ_I, QQ_I.frac_field(x)) == QQ_I.frac_field(x) + assert unify(QQ_I, EX) == EX + + raises(UnificationFailed, lambda: unify(RR, F3)) + assert unify(RR, ZZ) == RR + assert unify(RR, QQ) == RR + assert unify(RR, ALG) == RR + assert unify(RR, RR) == RR + assert unify(RR, CC) == CC + assert unify(RR, ZZ[x]) == RR[x] + assert unify(RR, ZZ.frac_field(x)) == RR.frac_field(x) + assert unify(RR, EX) == EX + assert RR[x].unify(ZZ.frac_field(y)) == RR.frac_field(x, y) + + raises(UnificationFailed, lambda: unify(CC, F3)) + assert unify(CC, ZZ) == CC + assert unify(CC, QQ) == CC + assert unify(CC, ALG) == CC + assert unify(CC, RR) == CC + assert unify(CC, CC) == CC + assert unify(CC, ZZ[x]) == CC[x] + assert unify(CC, ZZ.frac_field(x)) == CC.frac_field(x) + assert unify(CC, EX) == EX + + raises(UnificationFailed, lambda: unify(ZZ[x], F3)) + assert unify(ZZ[x], ZZ) == ZZ[x] + assert unify(ZZ[x], QQ) == QQ[x] + assert unify(ZZ[x], ALG) == ALG[x] + assert unify(ZZ[x], RR) == RR[x] + assert unify(ZZ[x], CC) == CC[x] + assert unify(ZZ[x], ZZ[x]) == ZZ[x] + assert unify(ZZ[x], ZZ.frac_field(x)) == ZZ.frac_field(x) + assert unify(ZZ[x], EX) == EX + + raises(UnificationFailed, lambda: unify(ZZ.frac_field(x), F3)) + assert unify(ZZ.frac_field(x), ZZ) == ZZ.frac_field(x) + assert unify(ZZ.frac_field(x), QQ) == QQ.frac_field(x) + assert unify(ZZ.frac_field(x), ALG) == ALG.frac_field(x) + assert unify(ZZ.frac_field(x), RR) == RR.frac_field(x) + assert unify(ZZ.frac_field(x), CC) == CC.frac_field(x) + assert unify(ZZ.frac_field(x), ZZ[x]) == ZZ.frac_field(x) + assert unify(ZZ.frac_field(x), ZZ.frac_field(x)) == ZZ.frac_field(x) + assert unify(ZZ.frac_field(x), EX) == EX + + raises(UnificationFailed, lambda: unify(EX, F3)) + assert unify(EX, ZZ) == EX + assert unify(EX, QQ) == EX + assert unify(EX, ALG) == EX + assert unify(EX, RR) == EX + assert unify(EX, CC) == EX + assert unify(EX, ZZ[x]) == EX + assert unify(EX, ZZ.frac_field(x)) == EX + assert unify(EX, EX) == EX + +def test_Domain_unify_composite(): + assert unify(ZZ.poly_ring(x), ZZ) == ZZ.poly_ring(x) + assert unify(ZZ.poly_ring(x), QQ) == QQ.poly_ring(x) + assert unify(QQ.poly_ring(x), ZZ) == QQ.poly_ring(x) + assert unify(QQ.poly_ring(x), QQ) == QQ.poly_ring(x) + + assert unify(ZZ, ZZ.poly_ring(x)) == ZZ.poly_ring(x) + assert unify(QQ, ZZ.poly_ring(x)) == QQ.poly_ring(x) + assert unify(ZZ, QQ.poly_ring(x)) == QQ.poly_ring(x) + assert unify(QQ, QQ.poly_ring(x)) == QQ.poly_ring(x) + + assert unify(ZZ.poly_ring(x, y), ZZ) == ZZ.poly_ring(x, y) + assert unify(ZZ.poly_ring(x, y), QQ) == QQ.poly_ring(x, y) + assert unify(QQ.poly_ring(x, y), ZZ) == QQ.poly_ring(x, y) + assert unify(QQ.poly_ring(x, y), QQ) == QQ.poly_ring(x, y) + + assert unify(ZZ, ZZ.poly_ring(x, y)) == ZZ.poly_ring(x, y) + assert unify(QQ, ZZ.poly_ring(x, y)) == QQ.poly_ring(x, y) + assert unify(ZZ, QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) + assert unify(QQ, QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) + + assert unify(ZZ.frac_field(x), ZZ) == ZZ.frac_field(x) + assert unify(ZZ.frac_field(x), QQ) == QQ.frac_field(x) + assert unify(QQ.frac_field(x), ZZ) == QQ.frac_field(x) + assert unify(QQ.frac_field(x), QQ) == QQ.frac_field(x) + + assert unify(ZZ, ZZ.frac_field(x)) == ZZ.frac_field(x) + assert unify(QQ, ZZ.frac_field(x)) == QQ.frac_field(x) + assert unify(ZZ, QQ.frac_field(x)) == QQ.frac_field(x) + assert unify(QQ, QQ.frac_field(x)) == QQ.frac_field(x) + + assert unify(ZZ.frac_field(x, y), ZZ) == ZZ.frac_field(x, y) + assert unify(ZZ.frac_field(x, y), QQ) == QQ.frac_field(x, y) + assert unify(QQ.frac_field(x, y), ZZ) == QQ.frac_field(x, y) + assert unify(QQ.frac_field(x, y), QQ) == QQ.frac_field(x, y) + + assert unify(ZZ, ZZ.frac_field(x, y)) == ZZ.frac_field(x, y) + assert unify(QQ, ZZ.frac_field(x, y)) == QQ.frac_field(x, y) + assert unify(ZZ, QQ.frac_field(x, y)) == QQ.frac_field(x, y) + assert unify(QQ, QQ.frac_field(x, y)) == QQ.frac_field(x, y) + + assert unify(ZZ.poly_ring(x), ZZ.poly_ring(x)) == ZZ.poly_ring(x) + assert unify(ZZ.poly_ring(x), QQ.poly_ring(x)) == QQ.poly_ring(x) + assert unify(QQ.poly_ring(x), ZZ.poly_ring(x)) == QQ.poly_ring(x) + assert unify(QQ.poly_ring(x), QQ.poly_ring(x)) == QQ.poly_ring(x) + + assert unify(ZZ.poly_ring(x, y), ZZ.poly_ring(x)) == ZZ.poly_ring(x, y) + assert unify(ZZ.poly_ring(x, y), QQ.poly_ring(x)) == QQ.poly_ring(x, y) + assert unify(QQ.poly_ring(x, y), ZZ.poly_ring(x)) == QQ.poly_ring(x, y) + assert unify(QQ.poly_ring(x, y), QQ.poly_ring(x)) == QQ.poly_ring(x, y) + + assert unify(ZZ.poly_ring(x), ZZ.poly_ring(x, y)) == ZZ.poly_ring(x, y) + assert unify(ZZ.poly_ring(x), QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) + assert unify(QQ.poly_ring(x), ZZ.poly_ring(x, y)) == QQ.poly_ring(x, y) + assert unify(QQ.poly_ring(x), QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) + + assert unify(ZZ.poly_ring(x, y), ZZ.poly_ring(x, z)) == ZZ.poly_ring(x, y, z) + assert unify(ZZ.poly_ring(x, y), QQ.poly_ring(x, z)) == QQ.poly_ring(x, y, z) + assert unify(QQ.poly_ring(x, y), ZZ.poly_ring(x, z)) == QQ.poly_ring(x, y, z) + assert unify(QQ.poly_ring(x, y), QQ.poly_ring(x, z)) == QQ.poly_ring(x, y, z) + + assert unify(ZZ.frac_field(x), ZZ.frac_field(x)) == ZZ.frac_field(x) + assert unify(ZZ.frac_field(x), QQ.frac_field(x)) == QQ.frac_field(x) + assert unify(QQ.frac_field(x), ZZ.frac_field(x)) == QQ.frac_field(x) + assert unify(QQ.frac_field(x), QQ.frac_field(x)) == QQ.frac_field(x) + + assert unify(ZZ.frac_field(x, y), ZZ.frac_field(x)) == ZZ.frac_field(x, y) + assert unify(ZZ.frac_field(x, y), QQ.frac_field(x)) == QQ.frac_field(x, y) + assert unify(QQ.frac_field(x, y), ZZ.frac_field(x)) == QQ.frac_field(x, y) + assert unify(QQ.frac_field(x, y), QQ.frac_field(x)) == QQ.frac_field(x, y) + + assert unify(ZZ.frac_field(x), ZZ.frac_field(x, y)) == ZZ.frac_field(x, y) + assert unify(ZZ.frac_field(x), QQ.frac_field(x, y)) == QQ.frac_field(x, y) + assert unify(QQ.frac_field(x), ZZ.frac_field(x, y)) == QQ.frac_field(x, y) + assert unify(QQ.frac_field(x), QQ.frac_field(x, y)) == QQ.frac_field(x, y) + + assert unify(ZZ.frac_field(x, y), ZZ.frac_field(x, z)) == ZZ.frac_field(x, y, z) + assert unify(ZZ.frac_field(x, y), QQ.frac_field(x, z)) == QQ.frac_field(x, y, z) + assert unify(QQ.frac_field(x, y), ZZ.frac_field(x, z)) == QQ.frac_field(x, y, z) + assert unify(QQ.frac_field(x, y), QQ.frac_field(x, z)) == QQ.frac_field(x, y, z) + + assert unify(ZZ.poly_ring(x), ZZ.frac_field(x)) == ZZ.frac_field(x) + assert unify(ZZ.poly_ring(x), QQ.frac_field(x)) == ZZ.frac_field(x) + assert unify(QQ.poly_ring(x), ZZ.frac_field(x)) == ZZ.frac_field(x) + assert unify(QQ.poly_ring(x), QQ.frac_field(x)) == QQ.frac_field(x) + + assert unify(ZZ.poly_ring(x, y), ZZ.frac_field(x)) == ZZ.frac_field(x, y) + assert unify(ZZ.poly_ring(x, y), QQ.frac_field(x)) == ZZ.frac_field(x, y) + assert unify(QQ.poly_ring(x, y), ZZ.frac_field(x)) == ZZ.frac_field(x, y) + assert unify(QQ.poly_ring(x, y), QQ.frac_field(x)) == QQ.frac_field(x, y) + + assert unify(ZZ.poly_ring(x), ZZ.frac_field(x, y)) == ZZ.frac_field(x, y) + assert unify(ZZ.poly_ring(x), QQ.frac_field(x, y)) == ZZ.frac_field(x, y) + assert unify(QQ.poly_ring(x), ZZ.frac_field(x, y)) == ZZ.frac_field(x, y) + assert unify(QQ.poly_ring(x), QQ.frac_field(x, y)) == QQ.frac_field(x, y) + + assert unify(ZZ.poly_ring(x, y), ZZ.frac_field(x, z)) == ZZ.frac_field(x, y, z) + assert unify(ZZ.poly_ring(x, y), QQ.frac_field(x, z)) == ZZ.frac_field(x, y, z) + assert unify(QQ.poly_ring(x, y), ZZ.frac_field(x, z)) == ZZ.frac_field(x, y, z) + assert unify(QQ.poly_ring(x, y), QQ.frac_field(x, z)) == QQ.frac_field(x, y, z) + + assert unify(ZZ.frac_field(x), ZZ.poly_ring(x)) == ZZ.frac_field(x) + assert unify(ZZ.frac_field(x), QQ.poly_ring(x)) == ZZ.frac_field(x) + assert unify(QQ.frac_field(x), ZZ.poly_ring(x)) == ZZ.frac_field(x) + assert unify(QQ.frac_field(x), QQ.poly_ring(x)) == QQ.frac_field(x) + + assert unify(ZZ.frac_field(x, y), ZZ.poly_ring(x)) == ZZ.frac_field(x, y) + assert unify(ZZ.frac_field(x, y), QQ.poly_ring(x)) == ZZ.frac_field(x, y) + assert unify(QQ.frac_field(x, y), ZZ.poly_ring(x)) == ZZ.frac_field(x, y) + assert unify(QQ.frac_field(x, y), QQ.poly_ring(x)) == QQ.frac_field(x, y) + + assert unify(ZZ.frac_field(x), ZZ.poly_ring(x, y)) == ZZ.frac_field(x, y) + assert unify(ZZ.frac_field(x), QQ.poly_ring(x, y)) == ZZ.frac_field(x, y) + assert unify(QQ.frac_field(x), ZZ.poly_ring(x, y)) == ZZ.frac_field(x, y) + assert unify(QQ.frac_field(x), QQ.poly_ring(x, y)) == QQ.frac_field(x, y) + + assert unify(ZZ.frac_field(x, y), ZZ.poly_ring(x, z)) == ZZ.frac_field(x, y, z) + assert unify(ZZ.frac_field(x, y), QQ.poly_ring(x, z)) == ZZ.frac_field(x, y, z) + assert unify(QQ.frac_field(x, y), ZZ.poly_ring(x, z)) == ZZ.frac_field(x, y, z) + assert unify(QQ.frac_field(x, y), QQ.poly_ring(x, z)) == QQ.frac_field(x, y, z) + +def test_Domain_unify_algebraic(): + sqrt5 = QQ.algebraic_field(sqrt(5)) + sqrt7 = QQ.algebraic_field(sqrt(7)) + sqrt57 = QQ.algebraic_field(sqrt(5), sqrt(7)) + + assert sqrt5.unify(sqrt7) == sqrt57 + + assert sqrt5.unify(sqrt5[x, y]) == sqrt5[x, y] + assert sqrt5[x, y].unify(sqrt5) == sqrt5[x, y] + + assert sqrt5.unify(sqrt5.frac_field(x, y)) == sqrt5.frac_field(x, y) + assert sqrt5.frac_field(x, y).unify(sqrt5) == sqrt5.frac_field(x, y) + + assert sqrt5.unify(sqrt7[x, y]) == sqrt57[x, y] + assert sqrt5[x, y].unify(sqrt7) == sqrt57[x, y] + + assert sqrt5.unify(sqrt7.frac_field(x, y)) == sqrt57.frac_field(x, y) + assert sqrt5.frac_field(x, y).unify(sqrt7) == sqrt57.frac_field(x, y) + +def test_Domain_unify_FiniteExtension(): + KxZZ = FiniteExtension(Poly(x**2 - 2, x, domain=ZZ)) + KxQQ = FiniteExtension(Poly(x**2 - 2, x, domain=QQ)) + KxZZy = FiniteExtension(Poly(x**2 - 2, x, domain=ZZ[y])) + KxQQy = FiniteExtension(Poly(x**2 - 2, x, domain=QQ[y])) + + assert KxZZ.unify(KxZZ) == KxZZ + assert KxQQ.unify(KxQQ) == KxQQ + assert KxZZy.unify(KxZZy) == KxZZy + assert KxQQy.unify(KxQQy) == KxQQy + + assert KxZZ.unify(ZZ) == KxZZ + assert KxZZ.unify(QQ) == KxQQ + assert KxQQ.unify(ZZ) == KxQQ + assert KxQQ.unify(QQ) == KxQQ + + assert KxZZ.unify(ZZ[y]) == KxZZy + assert KxZZ.unify(QQ[y]) == KxQQy + assert KxQQ.unify(ZZ[y]) == KxQQy + assert KxQQ.unify(QQ[y]) == KxQQy + + assert KxZZy.unify(ZZ) == KxZZy + assert KxZZy.unify(QQ) == KxQQy + assert KxQQy.unify(ZZ) == KxQQy + assert KxQQy.unify(QQ) == KxQQy + + assert KxZZy.unify(ZZ[y]) == KxZZy + assert KxZZy.unify(QQ[y]) == KxQQy + assert KxQQy.unify(ZZ[y]) == KxQQy + assert KxQQy.unify(QQ[y]) == KxQQy + + K = FiniteExtension(Poly(x**2 - 2, x, domain=ZZ[y])) + assert K.unify(ZZ) == K + assert K.unify(ZZ[x]) == K + assert K.unify(ZZ[y]) == K + assert K.unify(ZZ[x, y]) == K + + Kz = FiniteExtension(Poly(x**2 - 2, x, domain=ZZ[y, z])) + assert K.unify(ZZ[z]) == Kz + assert K.unify(ZZ[x, z]) == Kz + assert K.unify(ZZ[y, z]) == Kz + assert K.unify(ZZ[x, y, z]) == Kz + + Kx = FiniteExtension(Poly(x**2 - 2, x, domain=ZZ)) + Ky = FiniteExtension(Poly(y**2 - 2, y, domain=ZZ)) + Kxy = FiniteExtension(Poly(y**2 - 2, y, domain=Kx)) + assert Kx.unify(Kx) == Kx + assert Ky.unify(Ky) == Ky + assert Kx.unify(Ky) == Kxy + assert Ky.unify(Kx) == Kxy + +def test_Domain_unify_with_symbols(): + raises(UnificationFailed, lambda: ZZ[x, y].unify_with_symbols(ZZ, (y, z))) + raises(UnificationFailed, lambda: ZZ.unify_with_symbols(ZZ[x, y], (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 CC) 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 CC) 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 CC) 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 (Rational(-1, 7) in EX) is True + assert (Rational(-1, 7) in ZZ) is False + assert (Rational(-1, 7) in QQ) is True + assert (Rational(-1, 7) in RR) is True + assert (Rational(-1, 7) in CC) is True + assert (Rational(-1, 7) in ALG) is True + assert (Rational(-1, 7) in ZZ[x, y]) is False + assert (Rational(-1, 7) in QQ[x, y]) is True + assert (Rational(-1, 7) in RR[x, y]) is True + + assert (Rational(3, 5) in EX) is True + assert (Rational(3, 5) in ZZ) is False + assert (Rational(3, 5) in QQ) is True + assert (Rational(3, 5) in RR) is True + assert (Rational(3, 5) in CC) is True + assert (Rational(3, 5) in ALG) is True + assert (Rational(3, 5) in ZZ[x, y]) is False + assert (Rational(3, 5) in QQ[x, y]) is True + assert (Rational(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 CC) 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 CC) 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 ALG) is False + assert (oo in ZZ[x, y]) is False + assert (oo in QQ[x, y]) is False + + assert (-oo in ZZ) is False + assert (-oo in QQ) 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 (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 CC) 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 CC) 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 CC) 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 CC) 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 CC) 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 (Rational(3, 2)*x/(y + 1) - z in QQ[x, y, z]) is False + + +def test_issue_14433(): + assert (Rational(2, 3)*x in QQ.frac_field(1/x)) is True + assert (1/x in QQ.frac_field(x)) is True + assert ((x**2 + y**2) in QQ.frac_field(1/x, 1/y)) is True + assert ((x + y) in QQ.frac_field(1/x, y)) is True + assert ((x - y) in QQ.frac_field(x, 1/y)) is True + + +def test_Domain_is_field(): + assert ZZ.is_Field is False + assert GF(5).is_Field is True + assert GF(6).is_Field is False + assert QQ.is_Field is True + assert RR.is_Field is True + assert CC.is_Field is True + assert EX.is_Field is True + assert ALG.is_Field is True + assert QQ[x].is_Field is False + assert ZZ.frac_field(x).is_Field is True + + +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 + + assert RR.get_ring() == RR + # XXX: This should also be like RR + 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 True + 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 + assert RR.get_field() == RR + 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_set_domain(): + doms = [GF(5), ZZ, QQ, ALG, RR, CC, EX, ZZ[z], QQ[z], RR[z], CC[z], EX[z]] + for D1 in doms: + for D2 in doms: + assert D1[x].set_domain(D2) == D2[x] + assert D1[x, y].set_domain(D2) == D2[x, y] + assert D1.frac_field(x).set_domain(D2) == D2.frac_field(x) + assert D1.frac_field(x, y).set_domain(D2) == D2.frac_field(x, y) + assert D1.old_poly_ring(x).set_domain(D2) == D2.old_poly_ring(x) + assert D1.old_poly_ring(x, y).set_domain(D2) == D2.old_poly_ring(x, y) + assert D1.old_frac_field(x).set_domain(D2) == D2.old_frac_field(x) + assert D1.old_frac_field(x, y).set_domain(D2) == D2.old_frac_field(x, y) + + +def test_Domain_is_Exact(): + exact = [GF(5), ZZ, QQ, ALG, EX] + inexact = [RR, CC] + for D in exact + inexact: + for R in D, D[x], D.frac_field(x), D.old_poly_ring(x), D.old_frac_field(x): + if D in exact: + assert R.is_Exact is True + else: + assert R.is_Exact is False + + +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 CC.get_exact() == QQ_I + assert ALG.get_exact() == ALG + assert ZZ[x].get_exact() == ZZ[x] + assert QQ[x].get_exact() == QQ[x] + assert RR[x].get_exact() == QQ[x] + assert CC[x].get_exact() == QQ_I[x] + assert ZZ[x, y].get_exact() == ZZ[x, y] + assert QQ[x, y].get_exact() == QQ[x, y] + assert RR[x, y].get_exact() == QQ[x, y] + assert CC[x, y].get_exact() == QQ_I[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 RR.frac_field(x).get_exact() == QQ.frac_field(x) + assert CC.frac_field(x).get_exact() == QQ_I.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) + assert RR.frac_field(x, y).get_exact() == QQ.frac_field(x, y) + assert CC.frac_field(x, y).get_exact() == QQ_I.frac_field(x, y) + assert ZZ.old_poly_ring(x).get_exact() == ZZ.old_poly_ring(x) + assert QQ.old_poly_ring(x).get_exact() == QQ.old_poly_ring(x) + assert RR.old_poly_ring(x).get_exact() == QQ.old_poly_ring(x) + assert CC.old_poly_ring(x).get_exact() == QQ_I.old_poly_ring(x) + assert ZZ.old_poly_ring(x, y).get_exact() == ZZ.old_poly_ring(x, y) + assert QQ.old_poly_ring(x, y).get_exact() == QQ.old_poly_ring(x, y) + assert RR.old_poly_ring(x, y).get_exact() == QQ.old_poly_ring(x, y) + assert CC.old_poly_ring(x, y).get_exact() == QQ_I.old_poly_ring(x, y) + assert ZZ.old_frac_field(x).get_exact() == ZZ.old_frac_field(x) + assert QQ.old_frac_field(x).get_exact() == QQ.old_frac_field(x) + assert RR.old_frac_field(x).get_exact() == QQ.old_frac_field(x) + assert CC.old_frac_field(x).get_exact() == QQ_I.old_frac_field(x) + assert ZZ.old_frac_field(x, y).get_exact() == ZZ.old_frac_field(x, y) + assert QQ.old_frac_field(x, y).get_exact() == QQ.old_frac_field(x, y) + assert RR.old_frac_field(x, y).get_exact() == QQ.old_frac_field(x, y) + assert CC.old_frac_field(x, y).get_exact() == QQ_I.old_frac_field(x, y) + + +def test_Domain_characteristic(): + for F, c in [(FF(3), 3), (FF(5), 5), (FF(7), 7)]: + for R in F, F[x], F.frac_field(x), F.old_poly_ring(x), F.old_frac_field(x): + assert R.has_CharacteristicZero is False + assert R.characteristic() == c + for D in ZZ, QQ, ZZ_I, QQ_I, ALG: + for R in D, D[x], D.frac_field(x), D.old_poly_ring(x), D.old_frac_field(x): + assert R.has_CharacteristicZero is True + assert R.characteristic() == 0 + + +def test_Domain_is_unit(): + nums = [-2, -1, 0, 1, 2] + invring = [False, True, False, True, False] + invfield = [True, True, False, True, True] + ZZx, QQx, QQxf = ZZ[x], QQ[x], QQ.frac_field(x) + assert [ZZ.is_unit(ZZ(n)) for n in nums] == invring + assert [QQ.is_unit(QQ(n)) for n in nums] == invfield + assert [ZZx.is_unit(ZZx(n)) for n in nums] == invring + assert [QQx.is_unit(QQx(n)) for n in nums] == invfield + assert [QQxf.is_unit(QQxf(n)) for n in nums] == invfield + assert ZZx.is_unit(ZZx(x)) is False + assert QQx.is_unit(QQx(x)) is False + assert QQxf.is_unit(QQxf(x)) is True + + +def test_Domain_convert(): + + def check_element(e1, e2, K1, K2, K3): + if isinstance(e1, PolyElement): + assert isinstance(e2, PolyElement) and e1.ring == e2.ring + elif isinstance(e1, FracElement): + assert isinstance(e2, FracElement) and e1.field == e2.field + else: + assert type(e1) is type(e2), '%s, %s: %s %s -> %s' % (e1, e2, K1, K2, K3) + assert e1 == e2, '%s, %s: %s %s -> %s' % (e1, e2, K1, K2, K3) + + def check_domains(K1, K2): + K3 = K1.unify(K2) + check_element(K3.convert_from(K1.one, K1), K3.one, K1, K2, K3) + check_element(K3.convert_from(K2.one, K2), K3.one, K1, K2, K3) + check_element(K3.convert_from(K1.zero, K1), K3.zero, K1, K2, K3) + check_element(K3.convert_from(K2.zero, K2), K3.zero, K1, K2, K3) + + def composite_domains(K): + domains = [ + K, + K[y], K[z], K[y, z], + K.frac_field(y), K.frac_field(z), K.frac_field(y, z), + # XXX: These should be tested and made to work... + # K.old_poly_ring(y), K.old_frac_field(y), + ] + return domains + + QQ2 = QQ.algebraic_field(sqrt(2)) + QQ3 = QQ.algebraic_field(sqrt(3)) + doms = [ZZ, QQ, QQ2, QQ3, QQ_I, ZZ_I, RR, CC] + + for i, K1 in enumerate(doms): + for K2 in doms[i:]: + for K3 in composite_domains(K1): + for K4 in composite_domains(K2): + check_domains(K3, K4) + + assert QQ.convert(10e-52) == QQ(1684996666696915, 1684996666696914987166688442938726917102321526408785780068975640576) + + R, xr = ring("x", ZZ) + assert ZZ.convert(xr - xr) == 0 + assert ZZ.convert(xr - xr, R.to_domain()) == 0 + + assert CC.convert(ZZ_I(1, 2)) == CC(1, 2) + assert CC.convert(QQ_I(1, 2)) == CC(1, 2) + + assert QQ.convert_from(RR(0.5), RR) == QQ(1, 2) + assert RR.convert_from(QQ(1, 2), QQ) == RR(0.5) + assert QQ_I.convert_from(CC(0.5, 0.75), CC) == QQ_I(QQ(1, 2), QQ(3, 4)) + assert CC.convert_from(QQ_I(QQ(1, 2), QQ(3, 4)), QQ_I) == CC(0.5, 0.75) + + K1 = QQ.frac_field(x) + K2 = ZZ.frac_field(x) + K3 = QQ[x] + K4 = ZZ[x] + Ks = [K1, K2, K3, K4] + for Ka, Kb in product(Ks, Ks): + assert Ka.convert_from(Kb.from_sympy(x), Kb) == Ka.from_sympy(x) + + assert K2.convert_from(QQ(1, 2), QQ) == K2(QQ(1, 2)) + + +def test_EX_convert(): + + elements = [ + (ZZ, ZZ(3)), + (QQ, QQ(1,2)), + (ZZ_I, ZZ_I(1,2)), + (QQ_I, QQ_I(1,2)), + (RR, RR(3)), + (CC, CC(1,2)), + (EX, EX(3)), + (EXRAW, EXRAW(3)), + (ALG, ALG.from_sympy(sqrt(2))), + ] + + for R, e in elements: + for EE in EX, EXRAW: + elem = EE.from_sympy(R.to_sympy(e)) + assert EE.convert_from(e, R) == elem + assert R.convert_from(elem, EE) == e + + +def test_GlobalPolynomialRing_convert(): + K1 = QQ.old_poly_ring(x) + K2 = QQ[x] + assert K1.convert(x) == K1.convert(K2.convert(x), K2) + assert K2.convert(x) == K2.convert(K1.convert(x), K1) + + K1 = QQ.old_poly_ring(x, y) + K2 = QQ[x] + assert K1.convert(x) == K1.convert(K2.convert(x), K2) + #assert K2.convert(x) == K2.convert(K1.convert(x), K1) + + K1 = ZZ.old_poly_ring(x, y) + K2 = QQ[x] + assert K1.convert(x) == K1.convert(K2.convert(x), K2) + #assert K2.convert(x) == K2.convert(K1.convert(x), K1) + + +def test_PolynomialRing__init(): + R, = ring("", ZZ) + assert ZZ.poly_ring() == R.to_domain() + + +def test_FractionField__init(): + F, = field("", ZZ) + assert ZZ.frac_field() == F.to_domain() + + +def test_FractionField_convert(): + K = QQ.frac_field(x) + assert K.convert(QQ(2, 3), QQ) == K.from_sympy(Rational(2, 3)) + K = QQ.frac_field(x) + assert K.convert(ZZ(2), ZZ) == K.from_sympy(Integer(2)) + + +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_drop(): + assert ZZ.drop(x) == ZZ + assert ZZ[x].drop(x) == ZZ + assert ZZ[x, y].drop(x) == ZZ[y] + assert ZZ.frac_field(x).drop(x) == ZZ + assert ZZ.frac_field(x, y).drop(x) == ZZ.frac_field(y) + assert ZZ[x][y].drop(y) == ZZ[x] + assert ZZ[x][y].drop(x) == ZZ[y] + assert ZZ.frac_field(x)[y].drop(x) == ZZ[y] + assert ZZ.frac_field(x)[y].drop(y) == ZZ.frac_field(x) + Ky = FiniteExtension(Poly(x**2-1, x, domain=ZZ[y])) + K = FiniteExtension(Poly(x**2-1, x, domain=ZZ)) + assert Ky.drop(y) == K + raises(GeneratorsError, lambda: Ky.drop(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 + + assert RealField()[x] == RR[x] + + +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_Domain_alg_field_from_poly(): + f = Poly(x**2 - 2) + g = Poly(x**2 - 3) + h = Poly(x**4 - 10*x**2 + 1) + + alg = ZZ.alg_field_from_poly(f) + assert alg.ext.minpoly == f + assert alg.dom == QQ + + alg = QQ.alg_field_from_poly(f) + assert alg.ext.minpoly == f + assert alg.dom == QQ + + alg = alg.alg_field_from_poly(g) + assert alg.ext.minpoly == h + assert alg.dom == QQ + + +def test_Domain_cyclotomic_field(): + K = ZZ.cyclotomic_field(12) + assert K.ext.minpoly == Poly(cyclotomic_poly(12)) + assert K.dom == QQ + + F = QQ.cyclotomic_field(3) + assert F.ext.minpoly == Poly(cyclotomic_poly(3)) + assert F.dom == QQ + + E = F.cyclotomic_field(4) + assert field_isomorphism(E.ext, K.ext) is not None + assert E.dom == QQ + + +def test_PolynomialRing_from_FractionField(): + F, x,y = field("x,y", ZZ) + R, X,Y = ring("x,y", ZZ) + + f = (x**2 + y**2)/(x + 1) + g = (x**2 + y**2)/4 + h = x**2 + y**2 + + assert R.to_domain().from_FractionField(f, F.to_domain()) is None + assert R.to_domain().from_FractionField(g, F.to_domain()) == X**2/4 + Y**2/4 + assert R.to_domain().from_FractionField(h, F.to_domain()) == X**2 + Y**2 + + F, x,y = field("x,y", QQ) + R, X,Y = ring("x,y", QQ) + + f = (x**2 + y**2)/(x + 1) + g = (x**2 + y**2)/4 + h = x**2 + y**2 + + assert R.to_domain().from_FractionField(f, F.to_domain()) is None + assert R.to_domain().from_FractionField(g, F.to_domain()) == X**2/4 + Y**2/4 + assert R.to_domain().from_FractionField(h, F.to_domain()) == X**2 + Y**2 + + +def test_FractionField_from_PolynomialRing(): + R, x,y = ring("x,y", QQ) + F, X,Y = field("x,y", ZZ) + + f = 3*x**2 + 5*y**2 + g = x**2/3 + y**2/5 + + assert F.to_domain().from_PolynomialRing(f, R.to_domain()) == 3*X**2 + 5*Y**2 + assert F.to_domain().from_PolynomialRing(g, R.to_domain()) == (5*X**2 + 3*Y**2)/15 + + +def test_FF_of_type(): + # XXX: of_type is not very useful here because in the case of ground types + # = flint all elements are of type nmod. + assert FF(3).of_type(FF(3)(1)) is True + assert FF(5).of_type(FF(5)(3)) is True + + +def test___eq__(): + assert not QQ[x] == ZZ[x] + assert not QQ.frac_field(x) == ZZ.frac_field(x) + + +def test_RealField_from_sympy(): + assert RR.convert(S.Zero) == RR.dtype(0) + assert RR.convert(S(0.0)) == RR.dtype(0.0) + assert RR.convert(S.One) == RR.dtype(1) + assert RR.convert(S(1.0)) == RR.dtype(1.0) + assert RR.convert(sin(1)) == RR.dtype(sin(1).evalf()) + + +def test_not_in_any_domain(): + check = list(_illegal) + [x] + [ + float(i) for i in _illegal[:3]] + for dom in (ZZ, QQ, RR, CC, EX): + for i in check: + if i == x and dom == EX: + continue + assert i not in dom, (i, dom) + raises(CoercionFailed, lambda: dom.convert(i)) + + +def test_ModularInteger(): + F3 = FF(3) + + a = F3(0) + assert F3.of_type(a) and a == 0 + a = F3(1) + assert F3.of_type(a) and a == 1 + a = F3(2) + assert F3.of_type(a) and a == 2 + a = F3(3) + assert F3.of_type(a) and a == 0 + a = F3(4) + assert F3.of_type(a) and a == 1 + + a = F3(F3(0)) + assert F3.of_type(a) and a == 0 + a = F3(F3(1)) + assert F3.of_type(a) and a == 1 + a = F3(F3(2)) + assert F3.of_type(a) and a == 2 + a = F3(F3(3)) + assert F3.of_type(a) and a == 0 + a = F3(F3(4)) + assert F3.of_type(a) and a == 1 + + a = -F3(1) + assert F3.of_type(a) and a == 2 + a = -F3(2) + assert F3.of_type(a) and a == 1 + + a = 2 + F3(2) + assert F3.of_type(a) and a == 1 + a = F3(2) + 2 + assert F3.of_type(a) and a == 1 + a = F3(2) + F3(2) + assert F3.of_type(a) and a == 1 + a = F3(2) + F3(2) + assert F3.of_type(a) and a == 1 + + a = 3 - F3(2) + assert F3.of_type(a) and a == 1 + a = F3(3) - 2 + assert F3.of_type(a) and a == 1 + a = F3(3) - F3(2) + assert F3.of_type(a) and a == 1 + a = F3(3) - F3(2) + assert F3.of_type(a) and a == 1 + + a = 2*F3(2) + assert F3.of_type(a) and a == 1 + a = F3(2)*2 + assert F3.of_type(a) and a == 1 + a = F3(2)*F3(2) + assert F3.of_type(a) and a == 1 + a = F3(2)*F3(2) + assert F3.of_type(a) and a == 1 + + a = 2/F3(2) + assert F3.of_type(a) and a == 1 + a = F3(2)/2 + assert F3.of_type(a) and a == 1 + a = F3(2)/F3(2) + assert F3.of_type(a) and a == 1 + a = F3(2)/F3(2) + assert F3.of_type(a) and a == 1 + + a = F3(2)**0 + assert F3.of_type(a) and a == 1 + a = F3(2)**1 + assert F3.of_type(a) and a == 2 + a = F3(2)**2 + assert F3.of_type(a) and a == 1 + + F7 = FF(7) + + a = F7(3)**100000000000 + assert F7.of_type(a) and a == 4 + a = F7(3)**-100000000000 + assert F7.of_type(a) and a == 2 + + assert bool(F3(3)) is False + assert bool(F3(4)) is True + + F5 = FF(5) + + a = F5(1)**(-1) + assert F5.of_type(a) and a == 1 + a = F5(2)**(-1) + assert F5.of_type(a) and a == 3 + a = F5(3)**(-1) + assert F5.of_type(a) and a == 2 + a = F5(4)**(-1) + assert F5.of_type(a) and a == 4 + + if GROUND_TYPES != 'flint': + # XXX: This gives a core dump with python-flint... + raises(NotInvertible, lambda: F5(0)**(-1)) + raises(NotInvertible, lambda: F5(5)**(-1)) + + raises(ValueError, lambda: FF(0)) + raises(ValueError, lambda: FF(2.1)) + + for n1 in range(5): + for n2 in range(5): + if GROUND_TYPES != 'flint': + with warns_deprecated_sympy(): + assert (F5(n1) < F5(n2)) is (n1 < n2) + with warns_deprecated_sympy(): + assert (F5(n1) <= F5(n2)) is (n1 <= n2) + with warns_deprecated_sympy(): + assert (F5(n1) > F5(n2)) is (n1 > n2) + with warns_deprecated_sympy(): + assert (F5(n1) >= F5(n2)) is (n1 >= n2) + else: + raises(TypeError, lambda: F5(n1) < F5(n2)) + raises(TypeError, lambda: F5(n1) <= F5(n2)) + raises(TypeError, lambda: F5(n1) > F5(n2)) + raises(TypeError, lambda: F5(n1) >= F5(n2)) + + # https://github.com/sympy/sympy/issues/26789 + assert GF(Integer(5)) == F5 + assert F5(Integer(3)) == F5(3) + + +def test_QQ_int(): + assert int(QQ(2**2000, 3**1250)) == 455431 + assert int(QQ(2**100, 3)) == 422550200076076467165567735125 + + +def test_RR_double(): + assert RR(3.14) > 1e-50 + assert RR(1e-13) > 1e-50 + assert RR(1e-14) > 1e-50 + assert RR(1e-15) > 1e-50 + assert RR(1e-20) > 1e-50 + assert RR(1e-40) > 1e-50 + + +def test_RR_Float(): + f1 = Float("1.01") + f2 = Float("1.0000000000000000000001") + assert f1._prec == 53 + assert f2._prec == 80 + assert RR(f1)-1 > 1e-50 + assert RR(f2)-1 < 1e-50 # RR's precision is lower than f2's + + RR2 = RealField(prec=f2._prec) + assert RR2(f1)-1 > 1e-50 + assert RR2(f2)-1 > 1e-50 # RR's precision is equal to f2's + + +def test_CC_double(): + assert CC(3.14).real > 1e-50 + assert CC(1e-13).real > 1e-50 + assert CC(1e-14).real > 1e-50 + assert CC(1e-15).real > 1e-50 + assert CC(1e-20).real > 1e-50 + assert CC(1e-40).real > 1e-50 + + assert CC(3.14j).imag > 1e-50 + assert CC(1e-13j).imag > 1e-50 + assert CC(1e-14j).imag > 1e-50 + assert CC(1e-15j).imag > 1e-50 + assert CC(1e-20j).imag > 1e-50 + assert CC(1e-40j).imag > 1e-50 + + +def test_gaussian_domains(): + I = S.ImaginaryUnit + a, b, c, d = [ZZ_I.convert(x) for x in (5, 2 + I, 3 - I, 5 - 5*I)] + assert ZZ_I.gcd(a, b) == b + assert ZZ_I.gcd(a, c) == b + assert ZZ_I.lcm(a, b) == a + assert ZZ_I.lcm(a, c) == d + assert ZZ_I(3, 4) != QQ_I(3, 4) # XXX is this right or should QQ->ZZ if possible? + assert ZZ_I(3, 0) != 3 # and should this go to Integer? + assert QQ_I(S(3)/4, 0) != S(3)/4 # and this to Rational? + assert ZZ_I(0, 0).quadrant() == 0 + assert ZZ_I(-1, 0).quadrant() == 2 + + assert QQ_I.convert(QQ(3, 2)) == QQ_I(QQ(3, 2), QQ(0)) + assert QQ_I.convert(QQ(3, 2), QQ) == QQ_I(QQ(3, 2), QQ(0)) + + for G in (QQ_I, ZZ_I): + + q = G(3, 4) + assert str(q) == '3 + 4*I' + assert q.parent() == G + assert q._get_xy(pi) == (None, None) + assert q._get_xy(2) == (2, 0) + assert q._get_xy(2*I) == (0, 2) + + assert hash(q) == hash((3, 4)) + assert G(1, 2) == G(1, 2) + assert G(1, 2) != G(1, 3) + assert G(3, 0) == G(3) + + assert q + q == G(6, 8) + assert q - q == G(0, 0) + assert 3 - q == -q + 3 == G(0, -4) + assert 3 + q == q + 3 == G(6, 4) + assert q * q == G(-7, 24) + assert 3 * q == q * 3 == G(9, 12) + assert q ** 0 == G(1, 0) + assert q ** 1 == q + assert q ** 2 == q * q == G(-7, 24) + assert q ** 3 == q * q * q == G(-117, 44) + assert 1 / q == q ** -1 == QQ_I(S(3)/25, - S(4)/25) + assert q / 1 == QQ_I(3, 4) + assert q / 2 == QQ_I(S(3)/2, 2) + assert q/3 == QQ_I(1, S(4)/3) + assert 3/q == QQ_I(S(9)/25, -S(12)/25) + i, r = divmod(q, 2) + assert 2*i + r == q + i, r = divmod(2, q) + assert q*i + r == G(2, 0) + + a, b = G(2, 0), G(1, -1) + c, d, g = G.gcdex(a, b) + assert g == G.gcd(a, b) + assert c * a + d * b == g + + raises(ZeroDivisionError, lambda: q % 0) + raises(ZeroDivisionError, lambda: q / 0) + raises(ZeroDivisionError, lambda: q // 0) + raises(ZeroDivisionError, lambda: divmod(q, 0)) + raises(ZeroDivisionError, lambda: divmod(q, 0)) + raises(TypeError, lambda: q + x) + raises(TypeError, lambda: q - x) + raises(TypeError, lambda: x + q) + raises(TypeError, lambda: x - q) + raises(TypeError, lambda: q * x) + raises(TypeError, lambda: x * q) + raises(TypeError, lambda: q / x) + raises(TypeError, lambda: x / q) + raises(TypeError, lambda: q // x) + raises(TypeError, lambda: x // q) + + assert G.from_sympy(S(2)) == G(2, 0) + assert G.to_sympy(G(2, 0)) == S(2) + raises(CoercionFailed, lambda: G.from_sympy(pi)) + + PR = G.inject(x) + assert isinstance(PR, PolynomialRing) + assert PR.domain == G + assert len(PR.gens) == 1 and PR.gens[0].as_expr() == x + + if G is QQ_I: + AF = G.as_AlgebraicField() + assert isinstance(AF, AlgebraicField) + assert AF.domain == QQ + assert AF.ext.args[0] == I + + for qi in [G(-1, 0), G(1, 0), G(0, -1), G(0, 1)]: + assert G.is_negative(qi) is False + assert G.is_positive(qi) is False + assert G.is_nonnegative(qi) is False + assert G.is_nonpositive(qi) is False + + domains = [ZZ, QQ, AlgebraicField(QQ, I)] + + # XXX: These domains are all obsolete because ZZ/QQ with MPZ/MPQ + # already use either gmpy, flint or python depending on the + # availability of these libraries. We can keep these tests for now but + # ideally we should remove these alternate domains entirely. + domains += [ZZ_python(), QQ_python()] + if GROUND_TYPES == 'gmpy': + domains += [ZZ_gmpy(), QQ_gmpy()] + + for K in domains: + assert G.convert(K(2)) == G(2, 0) + assert G.convert(K(2), K) == G(2, 0) + + for K in ZZ_I, QQ_I: + assert G.convert(K(1, 1)) == G(1, 1) + assert G.convert(K(1, 1), K) == G(1, 1) + + if G == ZZ_I: + assert repr(q) == 'ZZ_I(3, 4)' + assert q//3 == G(1, 1) + assert 12//q == G(1, -2) + assert 12 % q == G(1, 2) + assert q % 2 == G(-1, 0) + assert i == G(0, 0) + assert r == G(2, 0) + assert G.get_ring() == G + assert G.get_field() == QQ_I + else: + assert repr(q) == 'QQ_I(3, 4)' + assert G.get_ring() == ZZ_I + assert G.get_field() == G + assert q//3 == G(1, S(4)/3) + assert 12//q == G(S(36)/25, -S(48)/25) + assert 12 % q == G(0, 0) + assert q % 2 == G(0, 0) + assert i == G(S(6)/25, -S(8)/25), (G,i) + assert r == G(0, 0) + q2 = G(S(3)/2, S(5)/3) + assert G.numer(q2) == ZZ_I(9, 10) + assert G.denom(q2) == ZZ_I(6) + + +def test_EX_EXRAW(): + assert EXRAW.zero is S.Zero + assert EXRAW.one is S.One + + assert EX(1) == EX.Expression(1) + assert EX(1).ex is S.One + assert EXRAW(1) is S.One + + # EX has cancelling but EXRAW does not + assert 2*EX((x + y*x)/x) == EX(2 + 2*y) != 2*((x + y*x)/x) + assert 2*EXRAW((x + y*x)/x) == 2*((x + y*x)/x) != (1 + y) + + assert EXRAW.convert_from(EX(1), EX) is EXRAW.one + assert EX.convert_from(EXRAW(1), EXRAW) == EX.one + + assert EXRAW.from_sympy(S.One) is S.One + assert EXRAW.to_sympy(EXRAW.one) is S.One + raises(CoercionFailed, lambda: EXRAW.from_sympy([])) + + assert EXRAW.get_field() == EXRAW + + assert EXRAW.unify(EX) == EXRAW + assert EX.unify(EXRAW) == EXRAW + + +def test_EX_ordering(): + elements = [EX(1), EX(x), EX(3)] + assert sorted(elements) == [EX(1), EX(3), EX(x)] + + +def test_canonical_unit(): + + for K in [ZZ, QQ, RR]: # CC? + assert K.canonical_unit(K(2)) == K(1) + assert K.canonical_unit(K(-2)) == K(-1) + + for K in [ZZ_I, QQ_I]: + i = K.from_sympy(I) + assert K.canonical_unit(K(2)) == K(1) + assert K.canonical_unit(K(2)*i) == -i + assert K.canonical_unit(-K(2)) == K(-1) + assert K.canonical_unit(-K(2)*i) == i + + K = ZZ[x] + assert K.canonical_unit(K(x + 1)) == K(1) + assert K.canonical_unit(K(-x + 1)) == K(-1) + + K = ZZ_I[x] + assert K.canonical_unit(K.from_sympy(I*x)) == ZZ_I(0, -1) + + K = ZZ_I.frac_field(x, y) + i = K.from_sympy(I) + assert i / i == K.one + assert (K.one + i)/(i - K.one) == -i + + +def test_Domain_is_negative(): + I = S.ImaginaryUnit + a, b = [CC.convert(x) for x in (2 + I, 5)] + assert CC.is_negative(a) == False + assert CC.is_negative(b) == False + + +def test_Domain_is_positive(): + I = S.ImaginaryUnit + a, b = [CC.convert(x) for x in (2 + I, 5)] + assert CC.is_positive(a) == False + assert CC.is_positive(b) == False + + +def test_Domain_is_nonnegative(): + I = S.ImaginaryUnit + a, b = [CC.convert(x) for x in (2 + I, 5)] + assert CC.is_nonnegative(a) == False + assert CC.is_nonnegative(b) == False + + +def test_Domain_is_nonpositive(): + I = S.ImaginaryUnit + a, b = [CC.convert(x) for x in (2 + I, 5)] + assert CC.is_nonpositive(a) == False + assert CC.is_nonpositive(b) == False + + +def test_exponential_domain(): + K = ZZ[E] + eK = K.from_sympy(E) + assert K.from_sympy(exp(3)) == eK ** 3 + assert K.convert(exp(3)) == eK ** 3 + + +def test_AlgebraicField_alias(): + # No default alias: + k = QQ.algebraic_field(sqrt(2)) + assert k.ext.alias is None + + # For a single extension, its alias is used: + alpha = AlgebraicNumber(sqrt(2), alias='alpha') + k = QQ.algebraic_field(alpha) + assert k.ext.alias.name == 'alpha' + + # Can override the alias of a single extension: + k = QQ.algebraic_field(alpha, alias='theta') + assert k.ext.alias.name == 'theta' + + # With multiple extensions, no default alias: + k = QQ.algebraic_field(sqrt(2), sqrt(3)) + assert k.ext.alias is None + + # With multiple extensions, no default alias, even if one of + # the extensions has one: + k = QQ.algebraic_field(alpha, sqrt(3)) + assert k.ext.alias is None + + # With multiple extensions, may set an alias: + k = QQ.algebraic_field(sqrt(2), sqrt(3), alias='theta') + assert k.ext.alias.name == 'theta' + + # Alias is passed to constructed field elements: + k = QQ.algebraic_field(alpha) + beta = k.to_alg_num(k([1, 2, 3])) + assert beta.alias is alpha.alias + + +def test_exsqrt(): + assert ZZ.is_square(ZZ(4)) is True + assert ZZ.exsqrt(ZZ(4)) == ZZ(2) + assert ZZ.is_square(ZZ(42)) is False + assert ZZ.exsqrt(ZZ(42)) is None + assert ZZ.is_square(ZZ(0)) is True + assert ZZ.exsqrt(ZZ(0)) == ZZ(0) + assert ZZ.is_square(ZZ(-1)) is False + assert ZZ.exsqrt(ZZ(-1)) is None + + assert QQ.is_square(QQ(9, 4)) is True + assert QQ.exsqrt(QQ(9, 4)) == QQ(3, 2) + assert QQ.is_square(QQ(18, 8)) is True + assert QQ.exsqrt(QQ(18, 8)) == QQ(3, 2) + assert QQ.is_square(QQ(-9, -4)) is True + assert QQ.exsqrt(QQ(-9, -4)) == QQ(3, 2) + assert QQ.is_square(QQ(11, 4)) is False + assert QQ.exsqrt(QQ(11, 4)) is None + assert QQ.is_square(QQ(9, 5)) is False + assert QQ.exsqrt(QQ(9, 5)) is None + assert QQ.is_square(QQ(4)) is True + assert QQ.exsqrt(QQ(4)) == QQ(2) + assert QQ.is_square(QQ(0)) is True + assert QQ.exsqrt(QQ(0)) == QQ(0) + assert QQ.is_square(QQ(-16, 9)) is False + assert QQ.exsqrt(QQ(-16, 9)) is None + + assert RR.is_square(RR(6.25)) is True + assert RR.exsqrt(RR(6.25)) == RR(2.5) + assert RR.is_square(RR(2)) is True + assert RR.almosteq(RR.exsqrt(RR(2)), RR(1.4142135623730951), tolerance=1e-15) + assert RR.is_square(RR(0)) is True + assert RR.exsqrt(RR(0)) == RR(0) + assert RR.is_square(RR(-1)) is False + assert RR.exsqrt(RR(-1)) is None + + assert CC.is_square(CC(2)) is True + assert CC.almosteq(CC.exsqrt(CC(2)), CC(1.4142135623730951), tolerance=1e-15) + assert CC.is_square(CC(0)) is True + assert CC.exsqrt(CC(0)) == CC(0) + assert CC.is_square(CC(-1)) is True + assert CC.exsqrt(CC(-1)) == CC(0, 1) + assert CC.is_square(CC(0, 2)) is True + assert CC.exsqrt(CC(0, 2)) == CC(1, 1) + assert CC.is_square(CC(-3, -4)) is True + assert CC.exsqrt(CC(-3, -4)) == CC(1, -2) + + F2 = FF(2) + assert F2.is_square(F2(1)) is True + assert F2.exsqrt(F2(1)) == F2(1) + assert F2.is_square(F2(0)) is True + assert F2.exsqrt(F2(0)) == F2(0) + + F7 = FF(7) + assert F7.is_square(F7(2)) is True + assert F7.exsqrt(F7(2)) == F7(3) + assert F7.is_square(F7(3)) is False + assert F7.exsqrt(F7(3)) is None + assert F7.is_square(F7(0)) is True + assert F7.exsqrt(F7(0)) == F7(0) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/tests/test_polynomialring.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/tests/test_polynomialring.py new file mode 100644 index 0000000000000000000000000000000000000000..6cb1fdf3f9f9250518289019b0bb108047e8cb6c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/tests/test_polynomialring.py @@ -0,0 +1,93 @@ +"""Tests for the PolynomialRing classes. """ + +from sympy.polys.domains import QQ, ZZ +from sympy.polys.polyerrors import ExactQuotientFailed, CoercionFailed, NotReversible + +from sympy.abc import x, y + +from sympy.testing.pytest import raises + + +def test_build_order(): + R = QQ.old_poly_ring(x, y, order=(("lex", x), ("ilex", y))) + assert R.order((1, 5)) == ((1,), (-5,)) + + +def test_globalring(): + Qxy = QQ.old_frac_field(x, y) + R = QQ.old_poly_ring(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 * (Y**2 + 1) == R.convert(x * (y**2 + 1)) + assert X + 1 == R.convert(x + 1) + raises(ExactQuotientFailed, lambda: X/Y) + raises(TypeError, lambda: x/Y) + raises(TypeError, lambda: X/y) + assert X**2 / X == X + + assert R.from_GlobalPolynomialRing(ZZ.old_poly_ring(x, y).convert(x), ZZ.old_poly_ring(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.old_frac_field(x, y) + R = QQ.old_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*(Y**2 + 1)/(1 + X) == R.convert(x*(y**2 + 1)/(1 + x)) + raises(TypeError, lambda: x/Y) + raises(TypeError, lambda: X/y) + assert X + 1 == R.convert(x + 1) + assert X**2 / X == X + + assert R.from_GlobalPolynomialRing(ZZ.old_poly_ring(x, y).convert(x), ZZ.old_poly_ring(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: R.exquo(X, Y)) + raises(NotReversible, lambda: R.revert(X)) + + 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.old_poly_ring(x, y, order="ilex") + G = QQ.old_poly_ring(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.old_poly_ring(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.old_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.old_poly_ring(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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/tests/test_quotientring.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/tests/test_quotientring.py new file mode 100644 index 0000000000000000000000000000000000000000..aff167bdd72dc4400785efefef7b3e9057fd0727 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/domains/tests/test_quotientring.py @@ -0,0 +1,52 @@ +"""Tests for quotient rings.""" + +from sympy.polys.domains.integerring import ZZ +from sympy.polys.domains.rationalfield import QQ +from sympy.abc import x, y + +from sympy.polys.polyerrors import NotReversible + +from sympy.testing.pytest import raises + + +def test_QuotientRingElement(): + R = QQ.old_poly_ring(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.old_poly_ring(x).ideal(x**2 + 1) + R = QQ.old_poly_ring(x)/I + + assert R == QQ.old_poly_ring(x)/[x**2 + 1] + assert R == QQ.old_poly_ring(x)/QQ.old_poly_ring(x).ideal(x**2 + 1) + assert R != QQ.old_poly_ring(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.old_poly_ring(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.old_poly_ring(x)/QQ.old_poly_ring(x, y).ideal(x)) + + R = QQ.old_poly_ring(x, order="ilex") + I = R.ideal(x) + assert R.convert(1) + I == (R/I).convert(1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e4ebc3d71ba3dac9ccc695d046d6b3d2ad940fa1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/__init__.py @@ -0,0 +1,15 @@ +""" + +sympy.polys.matrices package. + +The main export from this package is the DomainMatrix class which is a +lower-level implementation of matrices based on the polys Domains. This +implementation is typically a lot faster than SymPy's standard Matrix class +but is a work in progress and is still experimental. + +""" +from .domainmatrix import DomainMatrix, DM + +__all__ = [ + 'DomainMatrix', 'DM', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/_dfm.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/_dfm.py new file mode 100644 index 0000000000000000000000000000000000000000..1d02076014168ed4966fecd07f3d7a1d4828ae63 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/_dfm.py @@ -0,0 +1,951 @@ +# +# sympy.polys.matrices.dfm +# +# This modules defines the DFM class which is a wrapper for dense flint +# matrices as found in python-flint. +# +# As of python-flint 0.4.1 matrices over the following domains can be supported +# by python-flint: +# +# ZZ: flint.fmpz_mat +# QQ: flint.fmpq_mat +# GF(p): flint.nmod_mat (p prime and p < ~2**62) +# +# The underlying flint library has many more domains, but these are not yet +# supported by python-flint. +# +# The DFM class is a wrapper for the flint matrices and provides a common +# interface for all supported domains that is interchangeable with the DDM +# and SDM classes so that DomainMatrix can be used with any as its internal +# matrix representation. +# + +# TODO: +# +# Implement the following methods that are provided by python-flint: +# +# - hnf (Hermite normal form) +# - snf (Smith normal form) +# - minpoly +# - is_hnf +# - is_snf +# - rank +# +# The other types DDM and SDM do not have these methods and the algorithms +# for hnf, snf and rank are already implemented. Algorithms for minpoly, +# is_hnf and is_snf would need to be added. +# +# Add more methods to python-flint to expose more of Flint's functionality +# and also to make some of the above methods simpler or more efficient e.g. +# slicing, fancy indexing etc. + +from sympy.external.gmpy import GROUND_TYPES +from sympy.external.importtools import import_module +from sympy.utilities.decorator import doctest_depends_on + +from sympy.polys.domains import ZZ, QQ + +from .exceptions import ( + DMBadInputError, + DMDomainError, + DMNonSquareMatrixError, + DMNonInvertibleMatrixError, + DMRankError, + DMShapeError, + DMValueError, +) + + +if GROUND_TYPES != 'flint': + __doctest_skip__ = ['*'] + + +flint = import_module('flint') + + +__all__ = ['DFM'] + + +@doctest_depends_on(ground_types=['flint']) +class DFM: + """ + Dense FLINT matrix. This class is a wrapper for matrices from python-flint. + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.matrices.dfm import DFM + >>> dfm = DFM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> dfm + [[1, 2], [3, 4]] + >>> dfm.rep + [1, 2] + [3, 4] + >>> type(dfm.rep) # doctest: +SKIP + + + Usually, the DFM class is not instantiated directly, but is created as the + internal representation of :class:`~.DomainMatrix`. When + `SYMPY_GROUND_TYPES` is set to `flint` and `python-flint` is installed, the + :class:`DFM` class is used automatically as the internal representation of + :class:`~.DomainMatrix` in dense format if the domain is supported by + python-flint. + + >>> from sympy.polys.matrices.domainmatrix import DM + >>> dM = DM([[1, 2], [3, 4]], ZZ) + >>> dM.rep + [[1, 2], [3, 4]] + + A :class:`~.DomainMatrix` can be converted to :class:`DFM` by calling the + :meth:`to_dfm` method: + + >>> dM.to_dfm() + [[1, 2], [3, 4]] + + """ + + fmt = 'dense' + is_DFM = True + is_DDM = False + + def __new__(cls, rowslist, shape, domain): + """Construct from a nested list.""" + flint_mat = cls._get_flint_func(domain) + + if 0 not in shape: + try: + rep = flint_mat(rowslist) + except (ValueError, TypeError): + raise DMBadInputError(f"Input should be a list of list of {domain}") + else: + rep = flint_mat(*shape) + + return cls._new(rep, shape, domain) + + @classmethod + def _new(cls, rep, shape, domain): + """Internal constructor from a flint matrix.""" + cls._check(rep, shape, domain) + obj = object.__new__(cls) + obj.rep = rep + obj.shape = obj.rows, obj.cols = shape + obj.domain = domain + return obj + + def _new_rep(self, rep): + """Create a new DFM with the same shape and domain but a new rep.""" + return self._new(rep, self.shape, self.domain) + + @classmethod + def _check(cls, rep, shape, domain): + repshape = (rep.nrows(), rep.ncols()) + if repshape != shape: + raise DMBadInputError("Shape of rep does not match shape of DFM") + if domain == ZZ and not isinstance(rep, flint.fmpz_mat): + raise RuntimeError("Rep is not a flint.fmpz_mat") + elif domain == QQ and not isinstance(rep, flint.fmpq_mat): + raise RuntimeError("Rep is not a flint.fmpq_mat") + elif domain.is_FF and not isinstance(rep, (flint.fmpz_mod_mat, flint.nmod_mat)): + raise RuntimeError("Rep is not a flint.fmpz_mod_mat or flint.nmod_mat") + elif domain not in (ZZ, QQ) and not domain.is_FF: + raise NotImplementedError("Only ZZ and QQ are supported by DFM") + + @classmethod + def _supports_domain(cls, domain): + """Return True if the given domain is supported by DFM.""" + return domain in (ZZ, QQ) or domain.is_FF and domain._is_flint + + @classmethod + def _get_flint_func(cls, domain): + """Return the flint matrix class for the given domain.""" + if domain == ZZ: + return flint.fmpz_mat + elif domain == QQ: + return flint.fmpq_mat + elif domain.is_FF: + c = domain.characteristic() + if isinstance(domain.one, flint.nmod): + _cls = flint.nmod_mat + def _func(*e): + if len(e) == 1 and isinstance(e[0], flint.nmod_mat): + return _cls(e[0]) + else: + return _cls(*e, c) + else: + m = flint.fmpz_mod_ctx(c) + _func = lambda *e: flint.fmpz_mod_mat(*e, m) + return _func + else: + raise NotImplementedError("Only ZZ and QQ are supported by DFM") + + @property + def _func(self): + """Callable to create a flint matrix of the same domain.""" + return self._get_flint_func(self.domain) + + def __str__(self): + """Return ``str(self)``.""" + return str(self.to_ddm()) + + def __repr__(self): + """Return ``repr(self)``.""" + return f'DFM{repr(self.to_ddm())[3:]}' + + def __eq__(self, other): + """Return ``self == other``.""" + if not isinstance(other, DFM): + return NotImplemented + # Compare domains first because we do *not* want matrices with + # different domains to be equal but e.g. a flint fmpz_mat and fmpq_mat + # with the same entries will compare equal. + return self.domain == other.domain and self.rep == other.rep + + @classmethod + def from_list(cls, rowslist, shape, domain): + """Construct from a nested list.""" + return cls(rowslist, shape, domain) + + def to_list(self): + """Convert to a nested list.""" + return self.rep.tolist() + + def copy(self): + """Return a copy of self.""" + return self._new_rep(self._func(self.rep)) + + def to_ddm(self): + """Convert to a DDM.""" + return DDM.from_list(self.to_list(), self.shape, self.domain) + + def to_sdm(self): + """Convert to a SDM.""" + return SDM.from_list(self.to_list(), self.shape, self.domain) + + def to_dfm(self): + """Return self.""" + return self + + def to_dfm_or_ddm(self): + """ + Convert to a :class:`DFM`. + + This :class:`DFM` method exists to parallel the :class:`~.DDM` and + :class:`~.SDM` methods. For :class:`DFM` it will always return self. + + See Also + ======== + + to_ddm + to_sdm + sympy.polys.matrices.domainmatrix.DomainMatrix.to_dfm_or_ddm + """ + return self + + @classmethod + def from_ddm(cls, ddm): + """Convert from a DDM.""" + return cls.from_list(ddm.to_list(), ddm.shape, ddm.domain) + + @classmethod + def from_list_flat(cls, elements, shape, domain): + """Inverse of :meth:`to_list_flat`.""" + func = cls._get_flint_func(domain) + try: + rep = func(*shape, elements) + except ValueError: + raise DMBadInputError(f"Incorrect number of elements for shape {shape}") + except TypeError: + raise DMBadInputError(f"Input should be a list of {domain}") + return cls(rep, shape, domain) + + def to_list_flat(self): + """Convert to a flat list.""" + return self.rep.entries() + + def to_flat_nz(self): + """Convert to a flat list of non-zeros.""" + return self.to_ddm().to_flat_nz() + + @classmethod + def from_flat_nz(cls, elements, data, domain): + """Inverse of :meth:`to_flat_nz`.""" + return DDM.from_flat_nz(elements, data, domain).to_dfm() + + def to_dod(self): + """Convert to a DOD.""" + return self.to_ddm().to_dod() + + @classmethod + def from_dod(cls, dod, shape, domain): + """Inverse of :meth:`to_dod`.""" + return DDM.from_dod(dod, shape, domain).to_dfm() + + def to_dok(self): + """Convert to a DOK.""" + return self.to_ddm().to_dok() + + @classmethod + def from_dok(cls, dok, shape, domain): + """Inverse of :math:`to_dod`.""" + return DDM.from_dok(dok, shape, domain).to_dfm() + + def iter_values(self): + """Iterate over the non-zero values of the matrix.""" + m, n = self.shape + rep = self.rep + for i in range(m): + for j in range(n): + repij = rep[i, j] + if repij: + yield rep[i, j] + + def iter_items(self): + """Iterate over indices and values of nonzero elements of the matrix.""" + m, n = self.shape + rep = self.rep + for i in range(m): + for j in range(n): + repij = rep[i, j] + if repij: + yield ((i, j), repij) + + def convert_to(self, domain): + """Convert to a new domain.""" + if domain == self.domain: + return self.copy() + elif domain == QQ and self.domain == ZZ: + return self._new(flint.fmpq_mat(self.rep), self.shape, domain) + elif self._supports_domain(domain): + # XXX: Use more efficient conversions when possible. + return self.to_ddm().convert_to(domain).to_dfm() + else: + # It is the callers responsibility to convert to DDM before calling + # this method if the domain is not supported by DFM. + raise NotImplementedError("Only ZZ and QQ are supported by DFM") + + def getitem(self, i, j): + """Get the ``(i, j)``-th entry.""" + # XXX: flint matrices do not support negative indices + # XXX: They also raise ValueError instead of IndexError + m, n = self.shape + if i < 0: + i += m + if j < 0: + j += n + try: + return self.rep[i, j] + except ValueError: + raise IndexError(f"Invalid indices ({i}, {j}) for Matrix of shape {self.shape}") + + def setitem(self, i, j, value): + """Set the ``(i, j)``-th entry.""" + # XXX: flint matrices do not support negative indices + # XXX: They also raise ValueError instead of IndexError + m, n = self.shape + if i < 0: + i += m + if j < 0: + j += n + try: + self.rep[i, j] = value + except ValueError: + raise IndexError(f"Invalid indices ({i}, {j}) for Matrix of shape {self.shape}") + + def _extract(self, i_indices, j_indices): + """Extract a submatrix with no checking.""" + # Indices must be positive and in range. + M = self.rep + lol = [[M[i, j] for j in j_indices] for i in i_indices] + shape = (len(i_indices), len(j_indices)) + return self.from_list(lol, shape, self.domain) + + def extract(self, rowslist, colslist): + """Extract a submatrix.""" + # XXX: flint matrices do not support fancy indexing or negative indices + # + # Check and convert negative indices before calling _extract. + m, n = self.shape + + new_rows = [] + new_cols = [] + + for i in rowslist: + if i < 0: + i_pos = i + m + else: + i_pos = i + if not 0 <= i_pos < m: + raise IndexError(f"Invalid row index {i} for Matrix of shape {self.shape}") + new_rows.append(i_pos) + + for j in colslist: + if j < 0: + j_pos = j + n + else: + j_pos = j + if not 0 <= j_pos < n: + raise IndexError(f"Invalid column index {j} for Matrix of shape {self.shape}") + new_cols.append(j_pos) + + return self._extract(new_rows, new_cols) + + def extract_slice(self, rowslice, colslice): + """Slice a DFM.""" + # XXX: flint matrices do not support slicing + m, n = self.shape + i_indices = range(m)[rowslice] + j_indices = range(n)[colslice] + return self._extract(i_indices, j_indices) + + def neg(self): + """Negate a DFM matrix.""" + return self._new_rep(-self.rep) + + def add(self, other): + """Add two DFM matrices.""" + return self._new_rep(self.rep + other.rep) + + def sub(self, other): + """Subtract two DFM matrices.""" + return self._new_rep(self.rep - other.rep) + + def mul(self, other): + """Multiply a DFM matrix from the right by a scalar.""" + return self._new_rep(self.rep * other) + + def rmul(self, other): + """Multiply a DFM matrix from the left by a scalar.""" + return self._new_rep(other * self.rep) + + def mul_elementwise(self, other): + """Elementwise multiplication of two DFM matrices.""" + # XXX: flint matrices do not support elementwise multiplication + return self.to_ddm().mul_elementwise(other.to_ddm()).to_dfm() + + def matmul(self, other): + """Multiply two DFM matrices.""" + shape = (self.rows, other.cols) + return self._new(self.rep * other.rep, shape, self.domain) + + # XXX: For the most part DomainMatrix does not expect DDM, SDM, or DFM to + # have arithmetic operators defined. The only exception is negation. + # Perhaps that should be removed. + + def __neg__(self): + """Negate a DFM matrix.""" + return self.neg() + + @classmethod + def zeros(cls, shape, domain): + """Return a zero DFM matrix.""" + func = cls._get_flint_func(domain) + return cls._new(func(*shape), shape, domain) + + # XXX: flint matrices do not have anything like ones or eye + # In the methods below we convert to DDM and then back to DFM which is + # probably about as efficient as implementing these methods directly. + + @classmethod + def ones(cls, shape, domain): + """Return a one DFM matrix.""" + # XXX: flint matrices do not have anything like ones + return DDM.ones(shape, domain).to_dfm() + + @classmethod + def eye(cls, n, domain): + """Return the identity matrix of size n.""" + # XXX: flint matrices do not have anything like eye + return DDM.eye(n, domain).to_dfm() + + @classmethod + def diag(cls, elements, domain): + """Return a diagonal matrix.""" + return DDM.diag(elements, domain).to_dfm() + + def applyfunc(self, func, domain): + """Apply a function to each entry of a DFM matrix.""" + return self.to_ddm().applyfunc(func, domain).to_dfm() + + def transpose(self): + """Transpose a DFM matrix.""" + return self._new(self.rep.transpose(), (self.cols, self.rows), self.domain) + + def hstack(self, *others): + """Horizontally stack matrices.""" + return self.to_ddm().hstack(*[o.to_ddm() for o in others]).to_dfm() + + def vstack(self, *others): + """Vertically stack matrices.""" + return self.to_ddm().vstack(*[o.to_ddm() for o in others]).to_dfm() + + def diagonal(self): + """Return the diagonal of a DFM matrix.""" + M = self.rep + m, n = self.shape + return [M[i, i] for i in range(min(m, n))] + + def is_upper(self): + """Return ``True`` if the matrix is upper triangular.""" + M = self.rep + for i in range(self.rows): + for j in range(min(i, self.cols)): + if M[i, j]: + return False + return True + + def is_lower(self): + """Return ``True`` if the matrix is lower triangular.""" + M = self.rep + for i in range(self.rows): + for j in range(i + 1, self.cols): + if M[i, j]: + return False + return True + + def is_diagonal(self): + """Return ``True`` if the matrix is diagonal.""" + return self.is_upper() and self.is_lower() + + def is_zero_matrix(self): + """Return ``True`` if the matrix is the zero matrix.""" + M = self.rep + for i in range(self.rows): + for j in range(self.cols): + if M[i, j]: + return False + return True + + def nnz(self): + """Return the number of non-zero elements in the matrix.""" + return self.to_ddm().nnz() + + def scc(self): + """Return the strongly connected components of the matrix.""" + return self.to_ddm().scc() + + @doctest_depends_on(ground_types='flint') + def det(self): + """ + Compute the determinant of the matrix using FLINT. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2], [3, 4]]) + >>> dfm = M.to_DM().to_dfm() + >>> dfm + [[1, 2], [3, 4]] + >>> dfm.det() + -2 + + Notes + ===== + + Calls the ``.det()`` method of the underlying FLINT matrix. + + For :ref:`ZZ` or :ref:`QQ` this calls ``fmpz_mat_det`` or + ``fmpq_mat_det`` respectively. + + At the time of writing the implementation of ``fmpz_mat_det`` uses one + of several algorithms depending on the size of the matrix and bit size + of the entries. The algorithms used are: + + - Cofactor for very small (up to 4x4) matrices. + - Bareiss for small (up to 25x25) matrices. + - Modular algorithms for larger matrices (up to 60x60) or for larger + matrices with large bit sizes. + - Modular "accelerated" for larger matrices (60x60 upwards) if the bit + size is smaller than the dimensions of the matrix. + + The implementation of ``fmpq_mat_det`` clears denominators from each + row (not the whole matrix) and then calls ``fmpz_mat_det`` and divides + by the product of the denominators. + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.det + Higher level interface to compute the determinant of a matrix. + """ + # XXX: At least the first three algorithms described above should also + # be implemented in the pure Python DDM and SDM classes which at the + # time of writng just use Bareiss for all matrices and domains. + # Probably in Python the thresholds would be different though. + return self.rep.det() + + @doctest_depends_on(ground_types='flint') + def charpoly(self): + """ + Compute the characteristic polynomial of the matrix using FLINT. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2], [3, 4]]) + >>> dfm = M.to_DM().to_dfm() # need ground types = 'flint' + >>> dfm + [[1, 2], [3, 4]] + >>> dfm.charpoly() + [1, -5, -2] + + Notes + ===== + + Calls the ``.charpoly()`` method of the underlying FLINT matrix. + + For :ref:`ZZ` or :ref:`QQ` this calls ``fmpz_mat_charpoly`` or + ``fmpq_mat_charpoly`` respectively. + + At the time of writing the implementation of ``fmpq_mat_charpoly`` + clears a denominator from the whole matrix and then calls + ``fmpz_mat_charpoly``. The coefficients of the characteristic + polynomial are then multiplied by powers of the denominator. + + The ``fmpz_mat_charpoly`` method uses a modular algorithm with CRT + reconstruction. The modular algorithm uses ``nmod_mat_charpoly`` which + uses Berkowitz for small matrices and non-prime moduli or otherwise + the Danilevsky method. + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.charpoly + Higher level interface to compute the characteristic polynomial of + a matrix. + """ + # FLINT polynomial coefficients are in reverse order compared to SymPy. + return self.rep.charpoly().coeffs()[::-1] + + @doctest_depends_on(ground_types='flint') + def inv(self): + """ + Compute the inverse of a matrix using FLINT. + + Examples + ======== + + >>> from sympy import Matrix, QQ + >>> M = Matrix([[1, 2], [3, 4]]) + >>> dfm = M.to_DM().to_dfm().convert_to(QQ) + >>> dfm + [[1, 2], [3, 4]] + >>> dfm.inv() + [[-2, 1], [3/2, -1/2]] + >>> dfm.matmul(dfm.inv()) + [[1, 0], [0, 1]] + + Notes + ===== + + Calls the ``.inv()`` method of the underlying FLINT matrix. + + For now this will raise an error if the domain is :ref:`ZZ` but will + use the FLINT method for :ref:`QQ`. + + The FLINT methods for :ref:`ZZ` and :ref:`QQ` are ``fmpz_mat_inv`` and + ``fmpq_mat_inv`` respectively. The ``fmpz_mat_inv`` method computes an + inverse with denominator. This is implemented by calling + ``fmpz_mat_solve`` (see notes in :meth:`lu_solve` about the algorithm). + + The ``fmpq_mat_inv`` method clears denominators from each row and then + multiplies those into the rhs identity matrix before calling + ``fmpz_mat_solve``. + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.inv + Higher level method for computing the inverse of a matrix. + """ + # TODO: Implement similar algorithms for DDM and SDM. + # + # XXX: The flint fmpz_mat and fmpq_mat inv methods both return fmpq_mat + # by default. The fmpz_mat method has an optional argument to return + # fmpz_mat instead for unimodular matrices. + # + # The convention in DomainMatrix is to raise an error if the matrix is + # not over a field regardless of whether the matrix is invertible over + # its domain or over any associated field. Maybe DomainMatrix.inv + # should be changed to always return a matrix over an associated field + # except with a unimodular argument for returning an inverse over a + # ring if possible. + # + # For now we follow the existing DomainMatrix convention... + K = self.domain + m, n = self.shape + + if m != n: + raise DMNonSquareMatrixError("cannot invert a non-square matrix") + + if K == ZZ: + raise DMDomainError("field expected, got %s" % K) + elif K == QQ or K.is_FF: + try: + return self._new_rep(self.rep.inv()) + except ZeroDivisionError: + raise DMNonInvertibleMatrixError("matrix is not invertible") + else: + # If more domains are added for DFM then we will need to consider + # what happens here. + raise NotImplementedError("DFM.inv() is not implemented for %s" % K) + + def lu(self): + """Return the LU decomposition of the matrix.""" + L, U, swaps = self.to_ddm().lu() + return L.to_dfm(), U.to_dfm(), swaps + + def qr(self): + """Return the QR decomposition of the matrix.""" + Q, R = self.to_ddm().qr() + return Q.to_dfm(), R.to_dfm() + + # XXX: The lu_solve function should be renamed to solve. Whether or not it + # uses an LU decomposition is an implementation detail. A method called + # lu_solve would make sense for a situation in which an LU decomposition is + # reused several times to solve with different rhs but that would imply a + # different call signature. + # + # The underlying python-flint method has an algorithm= argument so we could + # use that and have e.g. solve_lu and solve_modular or perhaps also a + # method= argument to choose between the two. Flint itself has more + # possible algorithms to choose from than are exposed by python-flint. + + @doctest_depends_on(ground_types='flint') + def lu_solve(self, rhs): + """ + Solve a matrix equation using FLINT. + + Examples + ======== + + >>> from sympy import Matrix, QQ + >>> M = Matrix([[1, 2], [3, 4]]) + >>> dfm = M.to_DM().to_dfm().convert_to(QQ) + >>> dfm + [[1, 2], [3, 4]] + >>> rhs = Matrix([1, 2]).to_DM().to_dfm().convert_to(QQ) + >>> dfm.lu_solve(rhs) + [[0], [1/2]] + + Notes + ===== + + Calls the ``.solve()`` method of the underlying FLINT matrix. + + For now this will raise an error if the domain is :ref:`ZZ` but will + use the FLINT method for :ref:`QQ`. + + The FLINT methods for :ref:`ZZ` and :ref:`QQ` are ``fmpz_mat_solve`` + and ``fmpq_mat_solve`` respectively. The ``fmpq_mat_solve`` method + uses one of two algorithms: + + - For small matrices (<25 rows) it clears denominators between the + matrix and rhs and uses ``fmpz_mat_solve``. + - For larger matrices it uses ``fmpq_mat_solve_dixon`` which is a + modular approach with CRT reconstruction over :ref:`QQ`. + + The ``fmpz_mat_solve`` method uses one of four algorithms: + + - For very small (<= 3x3) matrices it uses a Cramer's rule. + - For small (<= 15x15) matrices it uses a fraction-free LU solve. + - Otherwise it uses either Dixon or another multimodular approach. + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.lu_solve + Higher level interface to solve a matrix equation. + """ + if not self.domain == rhs.domain: + raise DMDomainError("Domains must match: %s != %s" % (self.domain, rhs.domain)) + + # XXX: As for inv we should consider whether to return a matrix over + # over an associated field or attempt to find a solution in the ring. + # For now we follow the existing DomainMatrix convention... + if not self.domain.is_Field: + raise DMDomainError("Field expected, got %s" % self.domain) + + m, n = self.shape + j, k = rhs.shape + if m != j: + raise DMShapeError("Matrix size mismatch: %s * %s vs %s * %s" % (m, n, j, k)) + sol_shape = (n, k) + + # XXX: The Flint solve method only handles square matrices. Probably + # Flint has functions that could be used to solve non-square systems + # but they are not exposed in python-flint yet. Alternatively we could + # put something here using the features that are available like rref. + if m != n: + return self.to_ddm().lu_solve(rhs.to_ddm()).to_dfm() + + try: + sol = self.rep.solve(rhs.rep) + except ZeroDivisionError: + raise DMNonInvertibleMatrixError("Matrix det == 0; not invertible.") + + return self._new(sol, sol_shape, self.domain) + + def fflu(self): + """ + Fraction-free LU decomposition of DFM. + + Explanation + =========== + + Uses `python-flint` if possible for a matrix of + integers otherwise uses the DDM method. + + See Also + ======== + + sympy.polys.matrices.ddm.DDM.fflu + """ + if self.domain == ZZ: + fflu = getattr(self.rep, 'fflu', None) + if fflu is not None: + P, L, D, U = self.rep.fflu() + m, n = self.shape + return ( + self._new(P, (m, m), self.domain), + self._new(L, (m, m), self.domain), + self._new(D, (m, m), self.domain), + self._new(U, self.shape, self.domain) + ) + ddm_p, ddm_l, ddm_d, ddm_u = self.to_ddm().fflu() + P = ddm_p.to_dfm() + L = ddm_l.to_dfm() + D = ddm_d.to_dfm() + U = ddm_u.to_dfm() + return P, L, D, U + + def nullspace(self): + """Return a basis for the nullspace of the matrix.""" + # Code to compute nullspace using flint: + # + # V, nullity = self.rep.nullspace() + # V_dfm = self._new_rep(V)._extract(range(self.rows), range(nullity)) + # + # XXX: That gives the nullspace but does not give us nonpivots. So we + # use the slower DDM method anyway. It would be better to change the + # signature of the nullspace method to not return nonpivots. + # + # XXX: Also python-flint exposes a nullspace method for fmpz_mat but + # not for fmpq_mat. This is the reverse of the situation for DDM etc + # which only allow nullspace over a field. The nullspace method for + # DDM, SDM etc should be changed to allow nullspace over ZZ as well. + # The DomainMatrix nullspace method does allow the domain to be a ring + # but does not directly call the lower-level nullspace methods and uses + # rref_den instead. Nullspace methods should also be added to all + # matrix types in python-flint. + ddm, nonpivots = self.to_ddm().nullspace() + return ddm.to_dfm(), nonpivots + + def nullspace_from_rref(self, pivots=None): + """Return a basis for the nullspace of the matrix.""" + # XXX: Use the flint nullspace method!!! + sdm, nonpivots = self.to_sdm().nullspace_from_rref(pivots=pivots) + return sdm.to_dfm(), nonpivots + + def particular(self): + """Return a particular solution to the system.""" + return self.to_ddm().particular().to_dfm() + + def _lll(self, transform=False, delta=0.99, eta=0.51, rep='zbasis', gram='approx'): + """Call the fmpz_mat.lll() method but check rank to avoid segfaults.""" + + # XXX: There are tests that pass e.g. QQ(5,6) for delta. That fails + # with a TypeError in flint because if QQ is fmpq then conversion with + # float fails. We handle that here but there are two better fixes: + # + # - Make python-flint's fmpq convert with float(x) + # - Change the tests because delta should just be a float. + + def to_float(x): + if QQ.of_type(x): + return float(x.numerator) / float(x.denominator) + else: + return float(x) + + delta = to_float(delta) + eta = to_float(eta) + + if not 0.25 < delta < 1: + raise DMValueError("delta must be between 0.25 and 1") + + # XXX: The flint lll method segfaults if the matrix is not full rank. + m, n = self.shape + if self.rep.rank() != m: + raise DMRankError("Matrix must have full row rank for Flint LLL.") + + # Actually call the flint method. + return self.rep.lll(transform=transform, delta=delta, eta=eta, rep=rep, gram=gram) + + @doctest_depends_on(ground_types='flint') + def lll(self, delta=0.75): + """Compute LLL-reduced basis using FLINT. + + See :meth:`lll_transform` for more information. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2, 3], [4, 5, 6]]) + >>> M.to_DM().to_dfm().lll() + [[2, 1, 0], [-1, 1, 3]] + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.lll + Higher level interface to compute LLL-reduced basis. + lll_transform + Compute LLL-reduced basis and transform matrix. + """ + if self.domain != ZZ: + raise DMDomainError("ZZ expected, got %s" % self.domain) + elif self.rows > self.cols: + raise DMShapeError("Matrix must not have more rows than columns.") + + rep = self._lll(delta=delta) + return self._new_rep(rep) + + @doctest_depends_on(ground_types='flint') + def lll_transform(self, delta=0.75): + """Compute LLL-reduced basis and transform using FLINT. + + Examples + ======== + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2, 3], [4, 5, 6]]).to_DM().to_dfm() + >>> M_lll, T = M.lll_transform() + >>> M_lll + [[2, 1, 0], [-1, 1, 3]] + >>> T + [[-2, 1], [3, -1]] + >>> T.matmul(M) == M_lll + True + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.lll + Higher level interface to compute LLL-reduced basis. + lll + Compute LLL-reduced basis without transform matrix. + """ + if self.domain != ZZ: + raise DMDomainError("ZZ expected, got %s" % self.domain) + elif self.rows > self.cols: + raise DMShapeError("Matrix must not have more rows than columns.") + + rep, T = self._lll(transform=True, delta=delta) + basis = self._new_rep(rep) + T_dfm = self._new(T, (self.rows, self.rows), self.domain) + return basis, T_dfm + + +# Avoid circular imports +from sympy.polys.matrices.ddm import DDM +from sympy.polys.matrices.ddm import SDM diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/_typing.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/_typing.py new file mode 100644 index 0000000000000000000000000000000000000000..fc7c3b601fe85d591ddf853acbf33f5bba64b11c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/_typing.py @@ -0,0 +1,16 @@ +from typing import TypeVar, Protocol + + +T = TypeVar('T') + + +class RingElement(Protocol): + """A ring element. + + Must support ``+``, ``-``, ``*``, ``**`` and ``-``. + """ + def __add__(self: T, other: T, /) -> T: ... + def __sub__(self: T, other: T, /) -> T: ... + def __mul__(self: T, other: T, /) -> T: ... + def __pow__(self: T, other: int, /) -> T: ... + def __neg__(self: T, /) -> T: ... diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/ddm.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/ddm.py new file mode 100644 index 0000000000000000000000000000000000000000..9b7836ef298fe27a1c02ed069f33711a632d6ed8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/ddm.py @@ -0,0 +1,1176 @@ +""" + +Module for the DDM class. + +The DDM class is an internal representation used by DomainMatrix. The letters +DDM stand for Dense Domain Matrix. A DDM instance represents a matrix using +elements from a polynomial Domain (e.g. ZZ, QQ, ...) in a dense-matrix +representation. + +Basic usage: + + >>> from sympy import ZZ, QQ + >>> from sympy.polys.matrices.ddm import DDM + >>> A = DDM([[ZZ(0), ZZ(1)], [ZZ(-1), ZZ(0)]], (2, 2), ZZ) + >>> A.shape + (2, 2) + >>> A + [[0, 1], [-1, 0]] + >>> type(A) + + >>> A @ A + [[-1, 0], [0, -1]] + +The ddm_* functions are designed to operate on DDM as well as on an ordinary +list of lists: + + >>> from sympy.polys.matrices.dense import ddm_idet + >>> ddm_idet(A, QQ) + 1 + >>> ddm_idet([[0, 1], [-1, 0]], QQ) + 1 + >>> A + [[-1, 0], [0, -1]] + +Note that ddm_idet modifies the input matrix in-place. It is recommended to +use the DDM.det method as a friendlier interface to this instead which takes +care of copying the matrix: + + >>> B = DDM([[ZZ(0), ZZ(1)], [ZZ(-1), ZZ(0)]], (2, 2), ZZ) + >>> B.det() + 1 + +Normally DDM would not be used directly and is just part of the internal +representation of DomainMatrix which adds further functionality including e.g. +unifying domains. + +The dense format used by DDM is a list of lists of elements e.g. the 2x2 +identity matrix is like [[1, 0], [0, 1]]. The DDM class itself is a subclass +of list and its list items are plain lists. Elements are accessed as e.g. +ddm[i][j] where ddm[i] gives the ith row and ddm[i][j] gets the element in the +jth column of that row. Subclassing list makes e.g. iteration and indexing +very efficient. We do not override __getitem__ because it would lose that +benefit. + +The core routines are implemented by the ddm_* functions defined in dense.py. +Those functions are intended to be able to operate on a raw list-of-lists +representation of matrices with most functions operating in-place. The DDM +class takes care of copying etc and also stores a Domain object associated +with its elements. This makes it possible to implement things like A + B with +domain checking and also shape checking so that the list of lists +representation is friendlier. + +""" +from itertools import chain + +from sympy.external.gmpy import GROUND_TYPES +from sympy.utilities.decorator import doctest_depends_on + +from .exceptions import ( + DMBadInputError, + DMDomainError, + DMNonSquareMatrixError, + DMShapeError, +) + +from sympy.polys.domains import QQ + +from .dense import ( + ddm_transpose, + ddm_iadd, + ddm_isub, + ddm_ineg, + ddm_imul, + ddm_irmul, + ddm_imatmul, + ddm_irref, + ddm_irref_den, + ddm_idet, + ddm_iinv, + ddm_ilu_split, + ddm_ilu_solve, + ddm_berk, + ) + +from .lll import ddm_lll, ddm_lll_transform + + +if GROUND_TYPES != 'flint': + __doctest_skip__ = ['DDM.to_dfm', 'DDM.to_dfm_or_ddm'] + + +class DDM(list): + """Dense matrix based on polys domain elements + + This is a list subclass and is a wrapper for a list of lists that supports + basic matrix arithmetic +, -, *, **. + """ + + fmt = 'dense' + is_DFM = False + is_DDM = True + + def __init__(self, rowslist, shape, domain): + if not (isinstance(rowslist, list) and all(type(row) is list for row in rowslist)): + raise DMBadInputError("rowslist must be a list of lists") + m, n = shape + if len(rowslist) != m or any(len(row) != n for row in rowslist): + raise DMBadInputError("Inconsistent row-list/shape") + + super().__init__([i.copy() for i in rowslist]) + self.shape = (m, n) + self.rows = m + self.cols = n + self.domain = domain + + def getitem(self, i, j): + return self[i][j] + + def setitem(self, i, j, value): + self[i][j] = value + + def extract_slice(self, slice1, slice2): + ddm = [row[slice2] for row in self[slice1]] + rows = len(ddm) + cols = len(ddm[0]) if ddm else len(range(self.shape[1])[slice2]) + return DDM(ddm, (rows, cols), self.domain) + + def extract(self, rows, cols): + ddm = [] + for i in rows: + rowi = self[i] + ddm.append([rowi[j] for j in cols]) + return DDM(ddm, (len(rows), len(cols)), self.domain) + + @classmethod + def from_list(cls, rowslist, shape, domain): + """ + Create a :class:`DDM` from a list of lists. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.ddm import DDM + >>> A = DDM.from_list([[ZZ(0), ZZ(1)], [ZZ(-1), ZZ(0)]], (2, 2), ZZ) + >>> A + [[0, 1], [-1, 0]] + >>> A == DDM([[ZZ(0), ZZ(1)], [ZZ(-1), ZZ(0)]], (2, 2), ZZ) + True + + See Also + ======== + + from_list_flat + """ + return cls(rowslist, shape, domain) + + @classmethod + def from_ddm(cls, other): + return other.copy() + + def to_list(self): + """ + Convert to a list of lists. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices.ddm import DDM + >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ) + >>> A.to_list() + [[1, 2], [3, 4]] + + See Also + ======== + + to_list_flat + sympy.polys.matrices.domainmatrix.DomainMatrix.to_list + """ + return [row[:] for row in self] + + def to_list_flat(self): + """ + Convert to a flat list of elements. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices.ddm import DDM + >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ) + >>> A.to_list_flat() + [1, 2, 3, 4] + >>> A == DDM.from_list_flat(A.to_list_flat(), A.shape, A.domain) + True + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.to_list_flat + """ + flat = [] + for row in self: + flat.extend(row) + return flat + + @classmethod + def from_list_flat(cls, flat, shape, domain): + """ + Create a :class:`DDM` from a flat list of elements. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices.ddm import DDM + >>> A = DDM.from_list_flat([1, 2, 3, 4], (2, 2), QQ) + >>> A + [[1, 2], [3, 4]] + >>> A == DDM.from_list_flat(A.to_list_flat(), A.shape, A.domain) + True + + See Also + ======== + + to_list_flat + sympy.polys.matrices.domainmatrix.DomainMatrix.from_list_flat + """ + assert type(flat) is list + rows, cols = shape + if not (len(flat) == rows*cols): + raise DMBadInputError("Inconsistent flat-list shape") + lol = [flat[i*cols:(i+1)*cols] for i in range(rows)] + return cls(lol, shape, domain) + + def flatiter(self): + return chain.from_iterable(self) + + def flat(self): + items = [] + for row in self: + items.extend(row) + return items + + def to_flat_nz(self): + """ + Convert to a flat list of nonzero elements and data. + + Explanation + =========== + + This is used to operate on a list of the elements of a matrix and then + reconstruct a matrix using :meth:`from_flat_nz`. Zero elements are + included in the list but that may change in the future. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy import QQ + >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ) + >>> elements, data = A.to_flat_nz() + >>> elements + [1, 2, 3, 4] + >>> A == DDM.from_flat_nz(elements, data, A.domain) + True + + See Also + ======== + + from_flat_nz + sympy.polys.matrices.sdm.SDM.to_flat_nz + sympy.polys.matrices.domainmatrix.DomainMatrix.to_flat_nz + """ + return self.to_sdm().to_flat_nz() + + @classmethod + def from_flat_nz(cls, elements, data, domain): + """ + Reconstruct a :class:`DDM` after calling :meth:`to_flat_nz`. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy import QQ + >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ) + >>> elements, data = A.to_flat_nz() + >>> elements + [1, 2, 3, 4] + >>> A == DDM.from_flat_nz(elements, data, A.domain) + True + + See Also + ======== + + to_flat_nz + sympy.polys.matrices.sdm.SDM.from_flat_nz + sympy.polys.matrices.domainmatrix.DomainMatrix.from_flat_nz + """ + return SDM.from_flat_nz(elements, data, domain).to_ddm() + + def to_dod(self): + """ + Convert to a dictionary of dictionaries (dod) format. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy import QQ + >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ) + >>> A.to_dod() + {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}} + + See Also + ======== + + from_dod + sympy.polys.matrices.sdm.SDM.to_dod + sympy.polys.matrices.domainmatrix.DomainMatrix.to_dod + """ + dod = {} + for i, row in enumerate(self): + row = {j:e for j, e in enumerate(row) if e} + if row: + dod[i] = row + return dod + + @classmethod + def from_dod(cls, dod, shape, domain): + """ + Create a :class:`DDM` from a dictionary of dictionaries (dod) format. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy import QQ + >>> dod = {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}} + >>> A = DDM.from_dod(dod, (2, 2), QQ) + >>> A + [[1, 2], [3, 4]] + + See Also + ======== + + to_dod + sympy.polys.matrices.sdm.SDM.from_dod + sympy.polys.matrices.domainmatrix.DomainMatrix.from_dod + """ + rows, cols = shape + lol = [[domain.zero] * cols for _ in range(rows)] + for i, row in dod.items(): + for j, element in row.items(): + lol[i][j] = element + return DDM(lol, shape, domain) + + def to_dok(self): + """ + Convert :class:`DDM` to dictionary of keys (dok) format. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy import QQ + >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ) + >>> A.to_dok() + {(0, 0): 1, (0, 1): 2, (1, 0): 3, (1, 1): 4} + + See Also + ======== + + from_dok + sympy.polys.matrices.sdm.SDM.to_dok + sympy.polys.matrices.domainmatrix.DomainMatrix.to_dok + """ + dok = {} + for i, row in enumerate(self): + for j, element in enumerate(row): + if element: + dok[i, j] = element + return dok + + @classmethod + def from_dok(cls, dok, shape, domain): + """ + Create a :class:`DDM` from a dictionary of keys (dok) format. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy import QQ + >>> dok = {(0, 0): 1, (0, 1): 2, (1, 0): 3, (1, 1): 4} + >>> A = DDM.from_dok(dok, (2, 2), QQ) + >>> A + [[1, 2], [3, 4]] + + See Also + ======== + + to_dok + sympy.polys.matrices.sdm.SDM.from_dok + sympy.polys.matrices.domainmatrix.DomainMatrix.from_dok + """ + rows, cols = shape + lol = [[domain.zero] * cols for _ in range(rows)] + for (i, j), element in dok.items(): + lol[i][j] = element + return DDM(lol, shape, domain) + + def iter_values(self): + """ + Iterate over the non-zero values of the matrix. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy import QQ + >>> A = DDM([[QQ(1), QQ(0)], [QQ(3), QQ(4)]], (2, 2), QQ) + >>> list(A.iter_values()) + [1, 3, 4] + + See Also + ======== + + iter_items + to_list_flat + sympy.polys.matrices.domainmatrix.DomainMatrix.iter_values + """ + for row in self: + yield from filter(None, row) + + def iter_items(self): + """ + Iterate over indices and values of nonzero elements of the matrix. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy import QQ + >>> A = DDM([[QQ(1), QQ(0)], [QQ(3), QQ(4)]], (2, 2), QQ) + >>> list(A.iter_items()) + [((0, 0), 1), ((1, 0), 3), ((1, 1), 4)] + + See Also + ======== + + iter_values + to_dok + sympy.polys.matrices.domainmatrix.DomainMatrix.iter_items + """ + for i, row in enumerate(self): + for j, element in enumerate(row): + if element: + yield (i, j), element + + def to_ddm(self): + """ + Convert to a :class:`DDM`. + + This just returns ``self`` but exists to parallel the corresponding + method in other matrix types like :class:`~.SDM`. + + See Also + ======== + + to_sdm + to_dfm + to_dfm_or_ddm + sympy.polys.matrices.sdm.SDM.to_ddm + sympy.polys.matrices.domainmatrix.DomainMatrix.to_ddm + """ + return self + + def to_sdm(self): + """ + Convert to a :class:`~.SDM`. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy import QQ + >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ) + >>> A.to_sdm() + {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}} + >>> type(A.to_sdm()) + + + See Also + ======== + + SDM + sympy.polys.matrices.sdm.SDM.to_ddm + """ + return SDM.from_list(self, self.shape, self.domain) + + @doctest_depends_on(ground_types=['flint']) + def to_dfm(self): + """ + Convert to :class:`~.DDM` to :class:`~.DFM`. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy import QQ + >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ) + >>> A.to_dfm() + [[1, 2], [3, 4]] + >>> type(A.to_dfm()) + + + See Also + ======== + + DFM + sympy.polys.matrices._dfm.DFM.to_ddm + """ + return DFM(list(self), self.shape, self.domain) + + @doctest_depends_on(ground_types=['flint']) + def to_dfm_or_ddm(self): + """ + Convert to :class:`~.DFM` if possible or otherwise return self. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy import QQ + >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ) + >>> A.to_dfm_or_ddm() + [[1, 2], [3, 4]] + >>> type(A.to_dfm_or_ddm()) + + + See Also + ======== + + to_dfm + to_ddm + sympy.polys.matrices.domainmatrix.DomainMatrix.to_dfm_or_ddm + """ + if DFM._supports_domain(self.domain): + return self.to_dfm() + return self + + def convert_to(self, K): + Kold = self.domain + if K == Kold: + return self.copy() + rows = [[K.convert_from(e, Kold) for e in row] for row in self] + return DDM(rows, self.shape, K) + + def __str__(self): + rowsstr = ['[%s]' % ', '.join(map(str, row)) for row in self] + return '[%s]' % ', '.join(rowsstr) + + def __repr__(self): + cls = type(self).__name__ + rows = list.__repr__(self) + return '%s(%s, %s, %s)' % (cls, rows, self.shape, self.domain) + + def __eq__(self, other): + if not isinstance(other, DDM): + return False + return (super().__eq__(other) and self.domain == other.domain) + + def __ne__(self, other): + return not self.__eq__(other) + + @classmethod + def zeros(cls, shape, domain): + z = domain.zero + m, n = shape + rowslist = [[z] * n for _ in range(m)] + return DDM(rowslist, shape, domain) + + @classmethod + def ones(cls, shape, domain): + one = domain.one + m, n = shape + rowlist = [[one] * n for _ in range(m)] + return DDM(rowlist, shape, domain) + + @classmethod + def eye(cls, size, domain): + if isinstance(size, tuple): + m, n = size + elif isinstance(size, int): + m = n = size + one = domain.one + ddm = cls.zeros((m, n), domain) + for i in range(min(m, n)): + ddm[i][i] = one + return ddm + + def copy(self): + copyrows = [row[:] for row in self] + return DDM(copyrows, self.shape, self.domain) + + def transpose(self): + rows, cols = self.shape + if rows: + ddmT = ddm_transpose(self) + else: + ddmT = [[]] * cols + return DDM(ddmT, (cols, rows), self.domain) + + def __add__(a, b): + if not isinstance(b, DDM): + return NotImplemented + return a.add(b) + + def __sub__(a, b): + if not isinstance(b, DDM): + return NotImplemented + return a.sub(b) + + def __neg__(a): + return a.neg() + + def __mul__(a, b): + if b in a.domain: + return a.mul(b) + else: + return NotImplemented + + def __rmul__(a, b): + if b in a.domain: + return a.mul(b) + else: + return NotImplemented + + def __matmul__(a, b): + if isinstance(b, DDM): + return a.matmul(b) + else: + return NotImplemented + + @classmethod + def _check(cls, a, op, b, ashape, bshape): + if a.domain != b.domain: + msg = "Domain mismatch: %s %s %s" % (a.domain, op, b.domain) + raise DMDomainError(msg) + if ashape != bshape: + msg = "Shape mismatch: %s %s %s" % (a.shape, op, b.shape) + raise DMShapeError(msg) + + def add(a, b): + """a + b""" + a._check(a, '+', b, a.shape, b.shape) + c = a.copy() + ddm_iadd(c, b) + return c + + def sub(a, b): + """a - b""" + a._check(a, '-', b, a.shape, b.shape) + c = a.copy() + ddm_isub(c, b) + return c + + def neg(a): + """-a""" + b = a.copy() + ddm_ineg(b) + return b + + def mul(a, b): + c = a.copy() + ddm_imul(c, b) + return c + + def rmul(a, b): + c = a.copy() + ddm_irmul(c, b) + return c + + def matmul(a, b): + """a @ b (matrix product)""" + m, o = a.shape + o2, n = b.shape + a._check(a, '*', b, o, o2) + c = a.zeros((m, n), a.domain) + ddm_imatmul(c, a, b) + return c + + def mul_elementwise(a, b): + assert a.shape == b.shape + assert a.domain == b.domain + c = [[aij * bij for aij, bij in zip(ai, bi)] for ai, bi in zip(a, b)] + return DDM(c, a.shape, a.domain) + + def hstack(A, *B): + """Horizontally stacks :py:class:`~.DDM` matrices. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import DDM + + >>> A = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> B = DDM([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ) + >>> A.hstack(B) + [[1, 2, 5, 6], [3, 4, 7, 8]] + + >>> C = DDM([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ) + >>> A.hstack(B, C) + [[1, 2, 5, 6, 9, 10], [3, 4, 7, 8, 11, 12]] + """ + Anew = list(A.copy()) + rows, cols = A.shape + domain = A.domain + + for Bk in B: + Bkrows, Bkcols = Bk.shape + assert Bkrows == rows + assert Bk.domain == domain + + cols += Bkcols + + for i, Bki in enumerate(Bk): + Anew[i].extend(Bki) + + return DDM(Anew, (rows, cols), A.domain) + + def vstack(A, *B): + """Vertically stacks :py:class:`~.DDM` matrices. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import DDM + + >>> A = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> B = DDM([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ) + >>> A.vstack(B) + [[1, 2], [3, 4], [5, 6], [7, 8]] + + >>> C = DDM([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ) + >>> A.vstack(B, C) + [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]] + """ + Anew = list(A.copy()) + rows, cols = A.shape + domain = A.domain + + for Bk in B: + Bkrows, Bkcols = Bk.shape + assert Bkcols == cols + assert Bk.domain == domain + + rows += Bkrows + + Anew.extend(Bk.copy()) + + return DDM(Anew, (rows, cols), A.domain) + + def applyfunc(self, func, domain): + elements = [list(map(func, row)) for row in self] + return DDM(elements, self.shape, domain) + + def nnz(a): + """Number of non-zero entries in :py:class:`~.DDM` matrix. + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.nnz + """ + return sum(sum(map(bool, row)) for row in a) + + def scc(a): + """Strongly connected components of a square matrix *a*. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import DDM + >>> A = DDM([[ZZ(1), ZZ(0)], [ZZ(0), ZZ(1)]], (2, 2), ZZ) + >>> A.scc() + [[0], [1]] + + See also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.scc + + """ + return a.to_sdm().scc() + + @classmethod + def diag(cls, values, domain): + """Returns a square diagonal matrix with *values* on the diagonal. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import DDM + >>> DDM.diag([ZZ(1), ZZ(2), ZZ(3)], ZZ) + [[1, 0, 0], [0, 2, 0], [0, 0, 3]] + + See also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.diag + """ + return SDM.diag(values, domain).to_ddm() + + def rref(a): + """Reduced-row echelon form of a and list of pivots. + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.rref + Higher level interface to this function. + sympy.polys.matrices.dense.ddm_irref + The underlying algorithm. + """ + b = a.copy() + K = a.domain + partial_pivot = K.is_RealField or K.is_ComplexField + pivots = ddm_irref(b, _partial_pivot=partial_pivot) + return b, pivots + + def rref_den(a): + """Reduced-row echelon form of a with denominator and list of pivots + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.rref_den + Higher level interface to this function. + sympy.polys.matrices.dense.ddm_irref_den + The underlying algorithm. + """ + b = a.copy() + K = a.domain + denom, pivots = ddm_irref_den(b, K) + return b, denom, pivots + + def nullspace(a): + """Returns a basis for the nullspace of a. + + The domain of the matrix must be a field. + + See Also + ======== + + rref + sympy.polys.matrices.domainmatrix.DomainMatrix.nullspace + """ + rref, pivots = a.rref() + return rref.nullspace_from_rref(pivots) + + def nullspace_from_rref(a, pivots=None): + """Compute the nullspace of a matrix from its rref. + + The domain of the matrix can be any domain. + + Returns a tuple (basis, nonpivots). + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.nullspace + The higher level interface to this function. + """ + m, n = a.shape + K = a.domain + + if pivots is None: + pivots = [] + last_pivot = -1 + for i in range(m): + ai = a[i] + for j in range(last_pivot+1, n): + if ai[j]: + last_pivot = j + pivots.append(j) + break + + if not pivots: + return (a.eye(n, K), list(range(n))) + + # After rref the pivots are all one but after rref_den they may not be. + pivot_val = a[0][pivots[0]] + + basis = [] + nonpivots = [] + for i in range(n): + if i in pivots: + continue + nonpivots.append(i) + vec = [pivot_val if i == j else K.zero for j in range(n)] + for ii, jj in enumerate(pivots): + vec[jj] -= a[ii][i] + basis.append(vec) + + basis_ddm = DDM(basis, (len(basis), n), K) + + return (basis_ddm, nonpivots) + + def particular(a): + return a.to_sdm().particular().to_ddm() + + def det(a): + """Determinant of a""" + m, n = a.shape + if m != n: + raise DMNonSquareMatrixError("Determinant of non-square matrix") + b = a.copy() + K = b.domain + deta = ddm_idet(b, K) + return deta + + def inv(a): + """Inverse of a""" + m, n = a.shape + if m != n: + raise DMNonSquareMatrixError("Determinant of non-square matrix") + ainv = a.copy() + K = a.domain + ddm_iinv(ainv, a, K) + return ainv + + def lu(a): + """L, U decomposition of a""" + m, n = a.shape + K = a.domain + + U = a.copy() + L = a.eye(m, K) + swaps = ddm_ilu_split(L, U, K) + + return L, U, swaps + + def _fflu(self): + """ + Private method for Phase 1 of fraction-free LU decomposition. + Performs row operations and elimination to compute U and permutation indices. + + Returns: + LU : decomposition as a single matrix. + perm (list): Permutation indices for row swaps. + """ + rows, cols = self.shape + K = self.domain + + LU = self.copy() + perm = list(range(rows)) + rank = 0 + + for j in range(min(rows, cols)): + # Skip columns where all entries are zero + if all(LU[i][j] == K.zero for i in range(rows)): + continue + + # Find the first non-zero pivot in the current column + pivot_row = -1 + for i in range(rank, rows): + if LU[i][j] != K.zero: + pivot_row = i + break + + # If no pivot is found, skip column + if pivot_row == -1: + continue + + # Swap rows to bring the pivot to the current rank + if pivot_row != rank: + LU[rank], LU[pivot_row] = LU[pivot_row], LU[rank] + perm[rank], perm[pivot_row] = perm[pivot_row], perm[rank] + + # Found pivot - (Gauss-Bareiss elimination) + pivot = LU[rank][j] + for i in range(rank + 1, rows): + multiplier = LU[i][j] + # Denominator is previous pivot or 1 + denominator = LU[rank - 1][rank - 1] if rank > 0 else K.one + for k in range(j + 1, cols): + LU[i][k] = K.exquo(pivot * LU[i][k] - LU[rank][k] * multiplier, denominator) + # Keep the multiplier for L matrix + LU[i][j] = multiplier + rank += 1 + + return LU, perm + + def fflu(self): + """ + Fraction-free LU decomposition of DDM. + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.fflu + The higher-level interface to this function. + """ + rows, cols = self.shape + K = self.domain + + # Phase 1: Perform row operations and get permutation + U, perm = self._fflu() + + # Phase 2: Construct P, L, D matrices + # Create P from permutation + P = self.zeros((rows, rows), K) + for i, pi in enumerate(perm): + P[i][pi] = K.one + + # Create L matrix + L = self.zeros((rows, rows), K) + i = j = 0 + while i < rows and j < cols: + if U[i][j] != K.zero: + # Found non-zero pivot + # Diagonal entry is the pivot + L[i][i] = U[i][j] + for l in range(i + 1, rows): + # Off-diagonal entries are the multipliers + L[l][i] = U[l][j] + # zero out the entries in U + U[l][j] = K.zero + i += 1 + j += 1 + + # Fill remaining diagonal of L with ones + for i in range(i, rows): + L[i][i] = K.one + + # Create D matrix - using FLINT's approach with accumulator + D = self.zeros((rows, rows), K) + if rows >= 1: + D[0][0] = L[0][0] + di = K.one + for i in range(1, rows): + # Accumulate product of pivots + di = L[i - 1][i - 1] * L[i][i] + D[i][i] = di + + return P, L, D, U + + def qr(self): + """ + QR decomposition for DDM. + + Returns: + - Q: Orthogonal matrix as a DDM. + - R: Upper triangular matrix as a DDM. + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.qr + The higher-level interface to this function. + """ + rows, cols = self.shape + K = self.domain + Q = self.copy() + R = self.zeros((min(rows, cols), cols), K) + + # Check that the domain is a field + if not K.is_Field: + raise DMDomainError("QR decomposition requires a field (e.g. QQ).") + + dot_cols = lambda i, j: K.sum(Q[k][i] * Q[k][j] for k in range(rows)) + + for j in range(cols): + for i in range(min(j, rows)): + dot_ii = dot_cols(i, i) + if dot_ii != K.zero: + R[i][j] = dot_cols(i, j) / dot_ii + for k in range(rows): + Q[k][j] -= R[i][j] * Q[k][i] + + if j < rows: + dot_jj = dot_cols(j, j) + if dot_jj != K.zero: + R[j][j] = K.one + + Q = Q.extract(range(rows), range(min(rows, cols))) + + return Q, R + + def lu_solve(a, b): + """x where a*x = b""" + m, n = a.shape + m2, o = b.shape + a._check(a, 'lu_solve', b, m, m2) + if not a.domain.is_Field: + raise DMDomainError("lu_solve requires a field") + + L, U, swaps = a.lu() + x = a.zeros((n, o), a.domain) + ddm_ilu_solve(x, L, U, swaps, b) + return x + + def charpoly(a): + """Coefficients of characteristic polynomial of a""" + K = a.domain + m, n = a.shape + if m != n: + raise DMNonSquareMatrixError("Charpoly of non-square matrix") + vec = ddm_berk(a, K) + coeffs = [vec[i][0] for i in range(n+1)] + return coeffs + + def is_zero_matrix(self): + """ + Says whether this matrix has all zero entries. + """ + zero = self.domain.zero + return all(Mij == zero for Mij in self.flatiter()) + + def is_upper(self): + """ + Says whether this matrix is upper-triangular. True can be returned + even if the matrix is not square. + """ + zero = self.domain.zero + return all(Mij == zero for i, Mi in enumerate(self) for Mij in Mi[:i]) + + def is_lower(self): + """ + Says whether this matrix is lower-triangular. True can be returned + even if the matrix is not square. + """ + zero = self.domain.zero + return all(Mij == zero for i, Mi in enumerate(self) for Mij in Mi[i+1:]) + + def is_diagonal(self): + """ + Says whether this matrix is diagonal. True can be returned even if + the matrix is not square. + """ + return self.is_upper() and self.is_lower() + + def diagonal(self): + """ + Returns a list of the elements from the diagonal of the matrix. + """ + m, n = self.shape + return [self[i][i] for i in range(min(m, n))] + + def lll(A, delta=QQ(3, 4)): + return ddm_lll(A, delta=delta) + + def lll_transform(A, delta=QQ(3, 4)): + return ddm_lll_transform(A, delta=delta) + + +from .sdm import SDM +from .dfm import DFM diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/dense.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/dense.py new file mode 100644 index 0000000000000000000000000000000000000000..47ab2d6897c6d9f3781af23ccb68f96f15c7e859 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/dense.py @@ -0,0 +1,824 @@ +""" + +Module for the ddm_* routines for operating on a matrix in list of lists +matrix representation. + +These routines are used internally by the DDM class which also provides a +friendlier interface for them. The idea here is to implement core matrix +routines in a way that can be applied to any simple list representation +without the need to use any particular matrix class. For example we can +compute the RREF of a matrix like: + + >>> from sympy.polys.matrices.dense import ddm_irref + >>> M = [[1, 2, 3], [4, 5, 6]] + >>> pivots = ddm_irref(M) + >>> M + [[1.0, 0.0, -1.0], [0, 1.0, 2.0]] + +These are lower-level routines that work mostly in place.The routines at this +level should not need to know what the domain of the elements is but should +ideally document what operations they will use and what functions they need to +be provided with. + +The next-level up is the DDM class which uses these routines but wraps them up +with an interface that handles copying etc and keeps track of the Domain of +the elements of the matrix: + + >>> from sympy.polys.domains import QQ + >>> from sympy.polys.matrices.ddm import DDM + >>> M = DDM([[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]], (2, 3), QQ) + >>> M + [[1, 2, 3], [4, 5, 6]] + >>> Mrref, pivots = M.rref() + >>> Mrref + [[1, 0, -1], [0, 1, 2]] + +""" +from __future__ import annotations +from operator import mul +from .exceptions import ( + DMShapeError, + DMDomainError, + DMNonInvertibleMatrixError, + DMNonSquareMatrixError, +) +from typing import Sequence, TypeVar +from sympy.polys.matrices._typing import RingElement + + +#: Type variable for the elements of the matrix +T = TypeVar('T') + +#: Type variable for the elements of the matrix that are in a ring +R = TypeVar('R', bound=RingElement) + + +def ddm_transpose(matrix: Sequence[Sequence[T]]) -> list[list[T]]: + """matrix transpose""" + return list(map(list, zip(*matrix))) + + +def ddm_iadd(a: list[list[R]], b: Sequence[Sequence[R]]) -> None: + """a += b""" + for ai, bi in zip(a, b): + for j, bij in enumerate(bi): + ai[j] += bij + + +def ddm_isub(a: list[list[R]], b: Sequence[Sequence[R]]) -> None: + """a -= b""" + for ai, bi in zip(a, b): + for j, bij in enumerate(bi): + ai[j] -= bij + + +def ddm_ineg(a: list[list[R]]) -> None: + """a <-- -a""" + for ai in a: + for j, aij in enumerate(ai): + ai[j] = -aij + + +def ddm_imul(a: list[list[R]], b: R) -> None: + """a <-- a*b""" + for ai in a: + for j, aij in enumerate(ai): + ai[j] = aij * b + + +def ddm_irmul(a: list[list[R]], b: R) -> None: + """a <-- b*a""" + for ai in a: + for j, aij in enumerate(ai): + ai[j] = b * aij + + +def ddm_imatmul( + a: list[list[R]], b: Sequence[Sequence[R]], c: Sequence[Sequence[R]] +) -> None: + """a += b @ c""" + cT = list(zip(*c)) + + for bi, ai in zip(b, a): + for j, cTj in enumerate(cT): + ai[j] = sum(map(mul, bi, cTj), ai[j]) + + +def ddm_irref(a, _partial_pivot=False): + """In-place reduced row echelon form of a matrix. + + Compute the reduced row echelon form of $a$. Modifies $a$ in place and + returns a list of the pivot columns. + + Uses naive Gauss-Jordan elimination in the ground domain which must be a + field. + + This routine is only really suitable for use with simple field domains like + :ref:`GF(p)`, :ref:`QQ` and :ref:`QQ(a)` although even for :ref:`QQ` with + larger matrices it is possibly more efficient to use fraction free + approaches. + + This method is not suitable for use with rational function fields + (:ref:`K(x)`) because the elements will blowup leading to costly gcd + operations. In this case clearing denominators and using fraction free + approaches is likely to be more efficient. + + For inexact numeric domains like :ref:`RR` and :ref:`CC` pass + ``_partial_pivot=True`` to use partial pivoting to control rounding errors. + + Examples + ======== + + >>> from sympy.polys.matrices.dense import ddm_irref + >>> from sympy import QQ + >>> M = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]] + >>> pivots = ddm_irref(M) + >>> M + [[1, 0, -1], [0, 1, 2]] + >>> pivots + [0, 1] + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.rref + Higher level interface to this routine. + ddm_irref_den + The fraction free version of this routine. + sdm_irref + A sparse version of this routine. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Row_echelon_form#Reduced_row_echelon_form + """ + # We compute aij**-1 below and then use multiplication instead of division + # in the innermost loop. The domain here is a field so either operation is + # defined. There are significant performance differences for some domains + # though. In the case of e.g. QQ or QQ(x) inversion is free but + # multiplication and division have the same cost so it makes no difference. + # In cases like GF(p), QQ, RR or CC though multiplication is + # faster than division so reusing a precomputed inverse for many + # multiplications can be a lot faster. The biggest win is QQ when + # deg(minpoly(a)) is large. + # + # With domains like QQ(x) this can perform badly for other reasons. + # Typically the initial matrix has simple denominators and the + # fraction-free approach with exquo (ddm_irref_den) will preserve that + # property throughout. The method here causes denominator blowup leading to + # expensive gcd reductions in the intermediate expressions. With many + # generators like QQ(x,y,z,...) this is extremely bad. + # + # TODO: Use a nontrivial pivoting strategy to control intermediate + # expression growth. Rearranging rows and/or columns could defer the most + # complicated elements until the end. If the first pivot is a + # complicated/large element then the first round of reduction will + # immediately introduce expression blowup across the whole matrix. + + # a is (m x n) + m = len(a) + if not m: + return [] + n = len(a[0]) + + i = 0 + pivots = [] + + for j in range(n): + # Proper pivoting should be used for all domains for performance + # reasons but it is only strictly needed for RR and CC (and possibly + # other domains like RR(x)). This path is used by DDM.rref() if the + # domain is RR or CC. It uses partial (row) pivoting based on the + # absolute value of the pivot candidates. + if _partial_pivot: + ip = max(range(i, m), key=lambda ip: abs(a[ip][j])) + a[i], a[ip] = a[ip], a[i] + + # pivot + aij = a[i][j] + + # zero-pivot + if not aij: + for ip in range(i+1, m): + aij = a[ip][j] + # row-swap + if aij: + a[i], a[ip] = a[ip], a[i] + break + else: + # next column + continue + + # normalise row + ai = a[i] + aijinv = aij**-1 + for l in range(j, n): + ai[l] *= aijinv # ai[j] = one + + # eliminate above and below to the right + for k, ak in enumerate(a): + if k == i or not ak[j]: + continue + akj = ak[j] + ak[j] -= akj # ak[j] = zero + for l in range(j+1, n): + ak[l] -= akj * ai[l] + + # next row + pivots.append(j) + i += 1 + + # no more rows? + if i >= m: + break + + return pivots + + +def ddm_irref_den(a, K): + """a <-- rref(a); return (den, pivots) + + Compute the fraction-free reduced row echelon form (RREF) of $a$. Modifies + $a$ in place and returns a tuple containing the denominator of the RREF and + a list of the pivot columns. + + Explanation + =========== + + The algorithm used is the fraction-free version of Gauss-Jordan elimination + described as FFGJ in [1]_. Here it is modified to handle zero or missing + pivots and to avoid redundant arithmetic. + + The domain $K$ must support exact division (``K.exquo``) but does not need + to be a field. This method is suitable for most exact rings and fields like + :ref:`ZZ`, :ref:`QQ` and :ref:`QQ(a)`. In the case of :ref:`QQ` or + :ref:`K(x)` it might be more efficient to clear denominators and use + :ref:`ZZ` or :ref:`K[x]` instead. + + For inexact domains like :ref:`RR` and :ref:`CC` use ``ddm_irref`` instead. + + Examples + ======== + + >>> from sympy.polys.matrices.dense import ddm_irref_den + >>> from sympy import ZZ, Matrix + >>> M = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)]] + >>> den, pivots = ddm_irref_den(M, ZZ) + >>> M + [[-3, 0, 3], [0, -3, -6]] + >>> den + -3 + >>> pivots + [0, 1] + >>> Matrix(M).rref()[0] + Matrix([ + [1, 0, -1], + [0, 1, 2]]) + + See Also + ======== + + ddm_irref + A version of this routine that uses field division. + sdm_irref + A sparse version of :func:`ddm_irref`. + sdm_rref_den + A sparse version of :func:`ddm_irref_den`. + sympy.polys.matrices.domainmatrix.DomainMatrix.rref_den + Higher level interface. + + References + ========== + + .. [1] Fraction-free algorithms for linear and polynomial equations. + George C. Nakos , Peter R. Turner , Robert M. Williams. + https://dl.acm.org/doi/10.1145/271130.271133 + """ + # + # A simpler presentation of this algorithm is given in [1]: + # + # Given an n x n matrix A and n x 1 matrix b: + # + # for i in range(n): + # if i != 0: + # d = a[i-1][i-1] + # for j in range(n): + # if j == i: + # continue + # b[j] = a[i][i]*b[j] - a[j][i]*b[i] + # for k in range(n): + # a[j][k] = a[i][i]*a[j][k] - a[j][i]*a[i][k] + # if i != 0: + # a[j][k] /= d + # + # Our version here is a bit more complicated because: + # + # 1. We use row-swaps to avoid zero pivots. + # 2. We allow for some columns to be missing pivots. + # 3. We avoid a lot of redundant arithmetic. + # + # TODO: Use a non-trivial pivoting strategy. Even just row swapping makes a + # big difference to performance if e.g. the upper-left entry of the matrix + # is a huge polynomial. + + # a is (m x n) + m = len(a) + if not m: + return K.one, [] + n = len(a[0]) + + d = None + pivots = [] + no_pivots = [] + + # i, j will be the row and column indices of the current pivot + i = 0 + for j in range(n): + # next pivot? + aij = a[i][j] + + # swap rows if zero + if not aij: + for ip in range(i+1, m): + aij = a[ip][j] + # row-swap + if aij: + a[i], a[ip] = a[ip], a[i] + break + else: + # go to next column + no_pivots.append(j) + continue + + # Now aij is the pivot and i,j are the row and column. We need to clear + # the column above and below but we also need to keep track of the + # denominator of the RREF which means also multiplying everything above + # and to the left by the current pivot aij and dividing by d (which we + # multiplied everything by in the previous iteration so this is an + # exact division). + # + # First handle the upper left corner which is usually already diagonal + # with all diagonal entries equal to the current denominator but there + # can be other non-zero entries in any column that has no pivot. + + # Update previous pivots in the matrix + if pivots: + pivot_val = aij * a[0][pivots[0]] + # Divide out the common factor + if d is not None: + pivot_val = K.exquo(pivot_val, d) + + # Could defer this until the end but it is pretty cheap and + # helps when debugging. + for ip, jp in enumerate(pivots): + a[ip][jp] = pivot_val + + # Update columns without pivots + for jnp in no_pivots: + for ip in range(i): + aijp = a[ip][jnp] + if aijp: + aijp *= aij + if d is not None: + aijp = K.exquo(aijp, d) + a[ip][jnp] = aijp + + # Eliminate above, below and to the right as in ordinary division free + # Gauss-Jordan elmination except also dividing out d from every entry. + + for jp, aj in enumerate(a): + + # Skip the current row + if jp == i: + continue + + # Eliminate to the right in all rows + for kp in range(j+1, n): + ajk = aij * aj[kp] - aj[j] * a[i][kp] + if d is not None: + ajk = K.exquo(ajk, d) + aj[kp] = ajk + + # Set to zero above and below the pivot + aj[j] = K.zero + + # next row + pivots.append(j) + i += 1 + + # no more rows left? + if i >= m: + break + + if not K.is_one(aij): + d = aij + else: + d = None + + if not pivots: + denom = K.one + else: + denom = a[0][pivots[0]] + + return denom, pivots + + +def ddm_idet(a, K): + """a <-- echelon(a); return det + + Explanation + =========== + + Compute the determinant of $a$ using the Bareiss fraction-free algorithm. + The matrix $a$ is modified in place. Its diagonal elements are the + determinants of the leading principal minors. The determinant of $a$ is + returned. + + The domain $K$ must support exact division (``K.exquo``). This method is + suitable for most exact rings and fields like :ref:`ZZ`, :ref:`QQ` and + :ref:`QQ(a)` but not for inexact domains like :ref:`RR` and :ref:`CC`. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.ddm import ddm_idet + >>> a = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]] + >>> a + [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + >>> ddm_idet(a, ZZ) + 0 + >>> a + [[1, 2, 3], [4, -3, -6], [7, -6, 0]] + >>> [a[i][i] for i in range(len(a))] + [1, -3, 0] + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.det + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Bareiss_algorithm + .. [2] https://www.math.usm.edu/perry/Research/Thesis_DRL.pdf + """ + # Bareiss algorithm + # https://www.math.usm.edu/perry/Research/Thesis_DRL.pdf + + # a is (m x n) + m = len(a) + if not m: + return K.one + n = len(a[0]) + + exquo = K.exquo + # uf keeps track of the sign change from row swaps + uf = K.one + + for k in range(n-1): + if not a[k][k]: + for i in range(k+1, n): + if a[i][k]: + a[k], a[i] = a[i], a[k] + uf = -uf + break + else: + return K.zero + + akkm1 = a[k-1][k-1] if k else K.one + + for i in range(k+1, n): + for j in range(k+1, n): + a[i][j] = exquo(a[i][j]*a[k][k] - a[i][k]*a[k][j], akkm1) + + return uf * a[-1][-1] + + +def ddm_iinv(ainv, a, K): + """ainv <-- inv(a) + + Compute the inverse of a matrix $a$ over a field $K$ using Gauss-Jordan + elimination. The result is stored in $ainv$. + + Uses division in the ground domain which should be an exact field. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import ddm_iinv, ddm_imatmul + >>> from sympy import QQ + >>> a = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]] + >>> ainv = [[None, None], [None, None]] + >>> ddm_iinv(ainv, a, QQ) + >>> ainv + [[-2, 1], [3/2, -1/2]] + >>> result = [[QQ(0), QQ(0)], [QQ(0), QQ(0)]] + >>> ddm_imatmul(result, a, ainv) + >>> result + [[1, 0], [0, 1]] + + See Also + ======== + + ddm_irref: the underlying routine. + """ + if not K.is_Field: + raise DMDomainError('Not a field') + + # a is (m x n) + m = len(a) + if not m: + return + n = len(a[0]) + if m != n: + raise DMNonSquareMatrixError + + eye = [[K.one if i==j else K.zero for j in range(n)] for i in range(n)] + Aaug = [row + eyerow for row, eyerow in zip(a, eye)] + pivots = ddm_irref(Aaug) + if pivots != list(range(n)): + raise DMNonInvertibleMatrixError('Matrix det == 0; not invertible.') + ainv[:] = [row[n:] for row in Aaug] + + +def ddm_ilu_split(L, U, K): + """L, U <-- LU(U) + + Compute the LU decomposition of a matrix $L$ in place and store the lower + and upper triangular matrices in $L$ and $U$, respectively. Returns a list + of row swaps that were performed. + + Uses division in the ground domain which should be an exact field. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import ddm_ilu_split + >>> from sympy import QQ + >>> L = [[QQ(0), QQ(0)], [QQ(0), QQ(0)]] + >>> U = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]] + >>> swaps = ddm_ilu_split(L, U, QQ) + >>> swaps + [] + >>> L + [[0, 0], [3, 0]] + >>> U + [[1, 2], [0, -2]] + + See Also + ======== + + ddm_ilu + ddm_ilu_solve + """ + m = len(U) + if not m: + return [] + n = len(U[0]) + + swaps = ddm_ilu(U) + + zeros = [K.zero] * min(m, n) + for i in range(1, m): + j = min(i, n) + L[i][:j] = U[i][:j] + U[i][:j] = zeros[:j] + + return swaps + + +def ddm_ilu(a): + """a <-- LU(a) + + Computes the LU decomposition of a matrix in place. Returns a list of + row swaps that were performed. + + Uses division in the ground domain which should be an exact field. + + This is only suitable for domains like :ref:`GF(p)`, :ref:`QQ`, :ref:`QQ_I` + and :ref:`QQ(a)`. With a rational function field like :ref:`K(x)` it is + better to clear denominators and use division-free algorithms. Pivoting is + used to avoid exact zeros but not for floating point accuracy so :ref:`RR` + and :ref:`CC` are not suitable (use :func:`ddm_irref` instead). + + Examples + ======== + + >>> from sympy.polys.matrices.dense import ddm_ilu + >>> from sympy import QQ + >>> a = [[QQ(1, 2), QQ(1, 3)], [QQ(1, 4), QQ(1, 5)]] + >>> swaps = ddm_ilu(a) + >>> swaps + [] + >>> a + [[1/2, 1/3], [1/2, 1/30]] + + The same example using ``Matrix``: + + >>> from sympy import Matrix, S + >>> M = Matrix([[S(1)/2, S(1)/3], [S(1)/4, S(1)/5]]) + >>> L, U, swaps = M.LUdecomposition() + >>> L + Matrix([ + [ 1, 0], + [1/2, 1]]) + >>> U + Matrix([ + [1/2, 1/3], + [ 0, 1/30]]) + >>> swaps + [] + + See Also + ======== + + ddm_irref + ddm_ilu_solve + sympy.matrices.matrixbase.MatrixBase.LUdecomposition + """ + m = len(a) + if not m: + return [] + n = len(a[0]) + + swaps = [] + + for i in range(min(m, n)): + if not a[i][i]: + for ip in range(i+1, m): + if a[ip][i]: + swaps.append((i, ip)) + a[i], a[ip] = a[ip], a[i] + break + else: + # M = Matrix([[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 2]]) + continue + for j in range(i+1, m): + l_ji = a[j][i] / a[i][i] + a[j][i] = l_ji + for k in range(i+1, n): + a[j][k] -= l_ji * a[i][k] + + return swaps + + +def ddm_ilu_solve(x, L, U, swaps, b): + """x <-- solve(L*U*x = swaps(b)) + + Solve a linear system, $A*x = b$, given an LU factorization of $A$. + + Uses division in the ground domain which must be a field. + + Modifies $x$ in place. + + Examples + ======== + + Compute the LU decomposition of $A$ (in place): + + >>> from sympy import QQ + >>> from sympy.polys.matrices.dense import ddm_ilu, ddm_ilu_solve + >>> A = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]] + >>> swaps = ddm_ilu(A) + >>> A + [[1, 2], [3, -2]] + >>> L = U = A + + Solve the linear system: + + >>> b = [[QQ(5)], [QQ(6)]] + >>> x = [[None], [None]] + >>> ddm_ilu_solve(x, L, U, swaps, b) + >>> x + [[-4], [9/2]] + + See Also + ======== + + ddm_ilu + Compute the LU decomposition of a matrix in place. + ddm_ilu_split + Compute the LU decomposition of a matrix and separate $L$ and $U$. + sympy.polys.matrices.domainmatrix.DomainMatrix.lu_solve + Higher level interface to this function. + """ + m = len(U) + if not m: + return + n = len(U[0]) + + m2 = len(b) + if not m2: + raise DMShapeError("Shape mismtch") + o = len(b[0]) + + if m != m2: + raise DMShapeError("Shape mismtch") + if m < n: + raise NotImplementedError("Underdetermined") + + if swaps: + b = [row[:] for row in b] + for i1, i2 in swaps: + b[i1], b[i2] = b[i2], b[i1] + + # solve Ly = b + y = [[None] * o for _ in range(m)] + for k in range(o): + for i in range(m): + rhs = b[i][k] + for j in range(i): + rhs -= L[i][j] * y[j][k] + y[i][k] = rhs + + if m > n: + for i in range(n, m): + for j in range(o): + if y[i][j]: + raise DMNonInvertibleMatrixError + + # Solve Ux = y + for k in range(o): + for i in reversed(range(n)): + if not U[i][i]: + raise DMNonInvertibleMatrixError + rhs = y[i][k] + for j in range(i+1, n): + rhs -= U[i][j] * x[j][k] + x[i][k] = rhs / U[i][i] + + +def ddm_berk(M, K): + """ + Berkowitz algorithm for computing the characteristic polynomial. + + Explanation + =========== + + The Berkowitz algorithm is a division-free algorithm for computing the + characteristic polynomial of a matrix over any commutative ring using only + arithmetic in the coefficient ring. + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.polys.matrices.dense import ddm_berk + >>> from sympy.polys.domains import ZZ + >>> M = [[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]] + >>> ddm_berk(M, ZZ) + [[1], [-5], [-2]] + >>> Matrix(M).charpoly() + PurePoly(lambda**2 - 5*lambda - 2, lambda, domain='ZZ') + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.charpoly + The high-level interface to this function. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Samuelson%E2%80%93Berkowitz_algorithm + """ + m = len(M) + if not m: + return [[K.one]] + n = len(M[0]) + + if m != n: + raise DMShapeError("Not square") + + if n == 1: + return [[K.one], [-M[0][0]]] + + a = M[0][0] + R = [M[0][1:]] + C = [[row[0]] for row in M[1:]] + A = [row[1:] for row in M[1:]] + + q = ddm_berk(A, K) + + T = [[K.zero] * n for _ in range(n+1)] + for i in range(n): + T[i][i] = K.one + T[i+1][i] = -a + for i in range(2, n+1): + if i == 2: + AnC = C + else: + C = AnC + AnC = [[K.zero] for row in C] + ddm_imatmul(AnC, A, C) + RAnC = [[K.zero]] + ddm_imatmul(RAnC, R, AnC) + for j in range(0, n+1-i): + T[i+j][j] = -RAnC[0][0] + + qout = [[K.zero] for _ in range(n+1)] + ddm_imatmul(qout, T, q) + return qout diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/dfm.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/dfm.py new file mode 100644 index 0000000000000000000000000000000000000000..22938b7004654121f74b020bd6649bee84909e1e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/dfm.py @@ -0,0 +1,35 @@ +""" +sympy.polys.matrices.dfm + +Provides the :class:`DFM` class if ``GROUND_TYPES=flint'``. Otherwise, ``DFM`` +is a placeholder class that raises NotImplementedError when instantiated. +""" + +from sympy.external.gmpy import GROUND_TYPES + +if GROUND_TYPES == "flint": # pragma: no cover + # When python-flint is installed we will try to use it for dense matrices + # if the domain is supported by python-flint. + from ._dfm import DFM + +else: # pragma: no cover + # Other code should be able to import this and it should just present as a + # version of DFM that does not support any domains. + class DFM_dummy: + """ + Placeholder class for DFM when python-flint is not installed. + """ + def __init__(*args, **kwargs): + raise NotImplementedError("DFM requires GROUND_TYPES=flint.") + + @classmethod + def _supports_domain(cls, domain): + return False + + @classmethod + def _get_flint_func(cls, domain): + raise NotImplementedError("DFM requires GROUND_TYPES=flint.") + + # mypy really struggles with this kind of conditional type assignment. + # Maybe there is a better way to annotate this rather than type: ignore. + DFM = DFM_dummy # type: ignore diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/domainmatrix.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/domainmatrix.py new file mode 100644 index 0000000000000000000000000000000000000000..627835eca93b5e70f9aa121f097c9828a709ca78 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/domainmatrix.py @@ -0,0 +1,3983 @@ +""" + +Module for the DomainMatrix class. + +A DomainMatrix represents a matrix with elements that are in a particular +Domain. Each DomainMatrix internally wraps a DDM which is used for the +lower-level operations. The idea is that the DomainMatrix class provides the +convenience routines for converting between Expr and the poly domains as well +as unifying matrices with different domains. + +""" +from __future__ import annotations +from collections import Counter +from functools import reduce + +from sympy.external.gmpy import GROUND_TYPES +from sympy.utilities.decorator import doctest_depends_on + +from sympy.core.sympify import _sympify + +from ..domains import Domain + +from ..constructor import construct_domain + +from .exceptions import ( + DMFormatError, + DMBadInputError, + DMShapeError, + DMDomainError, + DMNotAField, + DMNonSquareMatrixError, + DMNonInvertibleMatrixError +) + +from .domainscalar import DomainScalar + +from sympy.polys.domains import ZZ, EXRAW, QQ + +from sympy.polys.densearith import dup_mul +from sympy.polys.densebasic import dup_convert +from sympy.polys.densetools import ( + dup_mul_ground, + dup_quo_ground, + dup_content, + dup_clear_denoms, + dup_primitive, + dup_transform, +) +from sympy.polys.factortools import dup_factor_list +from sympy.polys.polyutils import _sort_factors + +from .ddm import DDM + +from .sdm import SDM + +from .dfm import DFM + +from .rref import _dm_rref, _dm_rref_den + + +if GROUND_TYPES != 'flint': + __doctest_skip__ = ['DomainMatrix.to_dfm', 'DomainMatrix.to_dfm_or_ddm'] +else: + __doctest_skip__ = ['DomainMatrix.from_list'] + + +def DM(rows, domain): + """Convenient alias for DomainMatrix.from_list + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DM + >>> DM([[1, 2], [3, 4]], ZZ) + DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ) + + See Also + ======== + + DomainMatrix.from_list + """ + return DomainMatrix.from_list(rows, domain) + + +class DomainMatrix: + r""" + Associate Matrix with :py:class:`~.Domain` + + Explanation + =========== + + DomainMatrix uses :py:class:`~.Domain` for its internal representation + which makes it faster than the SymPy Matrix class (currently) for many + common operations, but this advantage makes it not entirely compatible + with Matrix. DomainMatrix are analogous to numpy arrays with "dtype". + In the DomainMatrix, each element has a domain such as :ref:`ZZ` + or :ref:`QQ(a)`. + + + Examples + ======== + + Creating a DomainMatrix from the existing Matrix class: + + >>> from sympy import Matrix + >>> from sympy.polys.matrices import DomainMatrix + >>> Matrix1 = Matrix([ + ... [1, 2], + ... [3, 4]]) + >>> A = DomainMatrix.from_Matrix(Matrix1) + >>> A + DomainMatrix({0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}, (2, 2), ZZ) + + Directly forming a DomainMatrix: + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> A + DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ) + + See Also + ======== + + DDM + SDM + Domain + Poly + + """ + rep: SDM | DDM | DFM + shape: tuple[int, int] + domain: Domain + + def __new__(cls, rows, shape, domain, *, fmt=None): + """ + Creates a :py:class:`~.DomainMatrix`. + + Parameters + ========== + + rows : Represents elements of DomainMatrix as list of lists + shape : Represents dimension of DomainMatrix + domain : Represents :py:class:`~.Domain` of DomainMatrix + + Raises + ====== + + TypeError + If any of rows, shape and domain are not provided + + """ + if isinstance(rows, (DDM, SDM, DFM)): + raise TypeError("Use from_rep to initialise from SDM/DDM") + elif isinstance(rows, list): + rep = DDM(rows, shape, domain) + elif isinstance(rows, dict): + rep = SDM(rows, shape, domain) + else: + msg = "Input should be list-of-lists or dict-of-dicts" + raise TypeError(msg) + + if fmt is not None: + if fmt == 'sparse': + rep = rep.to_sdm() + elif fmt == 'dense': + rep = rep.to_ddm() + else: + raise ValueError("fmt should be 'sparse' or 'dense'") + + # Use python-flint for dense matrices if possible + if rep.fmt == 'dense' and DFM._supports_domain(domain): + rep = rep.to_dfm() + + return cls.from_rep(rep) + + def __reduce__(self): + rep = self.rep + if rep.fmt == 'dense': + arg = self.to_list() + elif rep.fmt == 'sparse': + arg = dict(rep) + else: + raise RuntimeError # pragma: no cover + args = (arg, rep.shape, rep.domain) + return (self.__class__, args) + + def __getitem__(self, key): + i, j = key + m, n = self.shape + if not (isinstance(i, slice) or isinstance(j, slice)): + return DomainScalar(self.rep.getitem(i, j), self.domain) + + if not isinstance(i, slice): + if not -m <= i < m: + raise IndexError("Row index out of range") + i = i % m + i = slice(i, i+1) + if not isinstance(j, slice): + if not -n <= j < n: + raise IndexError("Column index out of range") + j = j % n + j = slice(j, j+1) + + return self.from_rep(self.rep.extract_slice(i, j)) + + def getitem_sympy(self, i, j): + return self.domain.to_sympy(self.rep.getitem(i, j)) + + def extract(self, rowslist, colslist): + return self.from_rep(self.rep.extract(rowslist, colslist)) + + def __setitem__(self, key, value): + i, j = key + if not self.domain.of_type(value): + raise TypeError + if isinstance(i, int) and isinstance(j, int): + self.rep.setitem(i, j, value) + else: + raise NotImplementedError + + @classmethod + def from_rep(cls, rep): + """Create a new DomainMatrix efficiently from DDM/SDM. + + Examples + ======== + + Create a :py:class:`~.DomainMatrix` with an dense internal + representation as :py:class:`~.DDM`: + + >>> from sympy.polys.domains import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy.polys.matrices.ddm import DDM + >>> drep = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> dM = DomainMatrix.from_rep(drep) + >>> dM + DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ) + + Create a :py:class:`~.DomainMatrix` with a sparse internal + representation as :py:class:`~.SDM`: + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import ZZ + >>> drep = SDM({0:{1:ZZ(1)},1:{0:ZZ(2)}}, (2, 2), ZZ) + >>> dM = DomainMatrix.from_rep(drep) + >>> dM + DomainMatrix({0: {1: 1}, 1: {0: 2}}, (2, 2), ZZ) + + Parameters + ========== + + rep: SDM or DDM + The internal sparse or dense representation of the matrix. + + Returns + ======= + + DomainMatrix + A :py:class:`~.DomainMatrix` wrapping *rep*. + + Notes + ===== + + This takes ownership of rep as its internal representation. If rep is + being mutated elsewhere then a copy should be provided to + ``from_rep``. Only minimal verification or checking is done on *rep* + as this is supposed to be an efficient internal routine. + + """ + if not (isinstance(rep, (DDM, SDM)) or (DFM is not None and isinstance(rep, DFM))): + raise TypeError("rep should be of type DDM or SDM") + self = super().__new__(cls) + self.rep = rep + self.shape = rep.shape + self.domain = rep.domain + return self + + @classmethod + @doctest_depends_on(ground_types=['python', 'gmpy']) + def from_list(cls, rows, domain): + r""" + Convert a list of lists into a DomainMatrix + + Parameters + ========== + + rows: list of lists + Each element of the inner lists should be either the single arg, + or tuple of args, that would be passed to the domain constructor + in order to form an element of the domain. See examples. + + Returns + ======= + + DomainMatrix containing elements defined in rows + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy import FF, QQ, ZZ + >>> A = DomainMatrix.from_list([[1, 0, 1], [0, 0, 1]], ZZ) + >>> A + DomainMatrix([[1, 0, 1], [0, 0, 1]], (2, 3), ZZ) + >>> B = DomainMatrix.from_list([[1, 0, 1], [0, 0, 1]], FF(7)) + >>> B + DomainMatrix([[1 mod 7, 0 mod 7, 1 mod 7], [0 mod 7, 0 mod 7, 1 mod 7]], (2, 3), GF(7)) + >>> C = DomainMatrix.from_list([[(1, 2), (3, 1)], [(1, 4), (5, 1)]], QQ) + >>> C + DomainMatrix([[1/2, 3], [1/4, 5]], (2, 2), QQ) + + See Also + ======== + + from_list_sympy + + """ + nrows = len(rows) + ncols = 0 if not nrows else len(rows[0]) + conv = lambda e: domain(*e) if isinstance(e, tuple) else domain(e) + domain_rows = [[conv(e) for e in row] for row in rows] + return DomainMatrix(domain_rows, (nrows, ncols), domain) + + @classmethod + def from_list_sympy(cls, nrows, ncols, rows, **kwargs): + r""" + Convert a list of lists of Expr into a DomainMatrix using construct_domain + + Parameters + ========== + + nrows: number of rows + ncols: number of columns + rows: list of lists + + Returns + ======= + + DomainMatrix containing elements of rows + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy.abc import x, y, z + >>> A = DomainMatrix.from_list_sympy(1, 3, [[x, y, z]]) + >>> A + DomainMatrix([[x, y, z]], (1, 3), ZZ[x,y,z]) + + See Also + ======== + + sympy.polys.constructor.construct_domain, from_dict_sympy + + """ + assert len(rows) == nrows + assert all(len(row) == ncols for row in rows) + + items_sympy = [_sympify(item) for row in rows for item in row] + + domain, items_domain = cls.get_domain(items_sympy, **kwargs) + + domain_rows = [[items_domain[ncols*r + c] for c in range(ncols)] for r in range(nrows)] + + return DomainMatrix(domain_rows, (nrows, ncols), domain) + + @classmethod + def from_dict_sympy(cls, nrows, ncols, elemsdict, **kwargs): + """ + + Parameters + ========== + + nrows: number of rows + ncols: number of cols + elemsdict: dict of dicts containing non-zero elements of the DomainMatrix + + Returns + ======= + + DomainMatrix containing elements of elemsdict + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy.abc import x,y,z + >>> elemsdict = {0: {0:x}, 1:{1: y}, 2: {2: z}} + >>> A = DomainMatrix.from_dict_sympy(3, 3, elemsdict) + >>> A + DomainMatrix({0: {0: x}, 1: {1: y}, 2: {2: z}}, (3, 3), ZZ[x,y,z]) + + See Also + ======== + + from_list_sympy + + """ + if not all(0 <= r < nrows for r in elemsdict): + raise DMBadInputError("Row out of range") + if not all(0 <= c < ncols for row in elemsdict.values() for c in row): + raise DMBadInputError("Column out of range") + + items_sympy = [_sympify(item) for row in elemsdict.values() for item in row.values()] + domain, items_domain = cls.get_domain(items_sympy, **kwargs) + + idx = 0 + items_dict = {} + for i, row in elemsdict.items(): + items_dict[i] = {} + for j in row: + items_dict[i][j] = items_domain[idx] + idx += 1 + + return DomainMatrix(items_dict, (nrows, ncols), domain) + + @classmethod + def from_Matrix(cls, M, fmt='sparse',**kwargs): + r""" + Convert Matrix to DomainMatrix + + Parameters + ========== + + M: Matrix + + Returns + ======= + + Returns DomainMatrix with identical elements as M + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.polys.matrices import DomainMatrix + >>> M = Matrix([ + ... [1.0, 3.4], + ... [2.4, 1]]) + >>> A = DomainMatrix.from_Matrix(M) + >>> A + DomainMatrix({0: {0: 1.0, 1: 3.4}, 1: {0: 2.4, 1: 1.0}}, (2, 2), RR) + + We can keep internal representation as ddm using fmt='dense' + >>> from sympy import Matrix, QQ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix.from_Matrix(Matrix([[QQ(1, 2), QQ(3, 4)], [QQ(0, 1), QQ(0, 1)]]), fmt='dense') + >>> A.rep + [[1/2, 3/4], [0, 0]] + + See Also + ======== + + Matrix + + """ + if fmt == 'dense': + return cls.from_list_sympy(*M.shape, M.tolist(), **kwargs) + + return cls.from_dict_sympy(*M.shape, M.todod(), **kwargs) + + @classmethod + def get_domain(cls, items_sympy, **kwargs): + K, items_K = construct_domain(items_sympy, **kwargs) + return K, items_K + + def choose_domain(self, **opts): + """Convert to a domain found by :func:`~.construct_domain`. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DM + >>> M = DM([[1, 2], [3, 4]], ZZ) + >>> M + DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ) + >>> M.choose_domain(field=True) + DomainMatrix([[1, 2], [3, 4]], (2, 2), QQ) + + >>> from sympy.abc import x + >>> M = DM([[1, x], [x**2, x**3]], ZZ[x]) + >>> M.choose_domain(field=True).domain + ZZ(x) + + Keyword arguments are passed to :func:`~.construct_domain`. + + See Also + ======== + + construct_domain + convert_to + """ + elements, data = self.to_sympy().to_flat_nz() + dom, elements_dom = construct_domain(elements, **opts) + return self.from_flat_nz(elements_dom, data, dom) + + def copy(self): + return self.from_rep(self.rep.copy()) + + def convert_to(self, K): + r""" + Change the domain of DomainMatrix to desired domain or field + + Parameters + ========== + + K : Represents the desired domain or field. + Alternatively, ``None`` may be passed, in which case this method + just returns a copy of this DomainMatrix. + + Returns + ======= + + DomainMatrix + DomainMatrix with the desired domain or field + + Examples + ======== + + >>> from sympy import ZZ, ZZ_I + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + + >>> A.convert_to(ZZ_I) + DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ_I) + + """ + if K == self.domain: + return self.copy() + + rep = self.rep + + # The DFM, DDM and SDM types do not do any implicit conversions so we + # manage switching between DDM and DFM here. + if rep.is_DFM and not DFM._supports_domain(K): + rep_K = rep.to_ddm().convert_to(K) + elif rep.is_DDM and DFM._supports_domain(K): + rep_K = rep.convert_to(K).to_dfm() + else: + rep_K = rep.convert_to(K) + + return self.from_rep(rep_K) + + def to_sympy(self): + return self.convert_to(EXRAW) + + def to_field(self): + r""" + Returns a DomainMatrix with the appropriate field + + Returns + ======= + + DomainMatrix + DomainMatrix with the appropriate field + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + + >>> A.to_field() + DomainMatrix([[1, 2], [3, 4]], (2, 2), QQ) + + """ + K = self.domain.get_field() + return self.convert_to(K) + + def to_sparse(self): + """ + Return a sparse DomainMatrix representation of *self*. + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy import QQ + >>> A = DomainMatrix([[1, 0],[0, 2]], (2, 2), QQ) + >>> A.rep + [[1, 0], [0, 2]] + >>> B = A.to_sparse() + >>> B.rep + {0: {0: 1}, 1: {1: 2}} + """ + if self.rep.fmt == 'sparse': + return self + + return self.from_rep(self.rep.to_sdm()) + + def to_dense(self): + """ + Return a dense DomainMatrix representation of *self*. + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy import QQ + >>> A = DomainMatrix({0: {0: 1}, 1: {1: 2}}, (2, 2), QQ) + >>> A.rep + {0: {0: 1}, 1: {1: 2}} + >>> B = A.to_dense() + >>> B.rep + [[1, 0], [0, 2]] + + """ + rep = self.rep + + if rep.fmt == 'dense': + return self + + return self.from_rep(rep.to_dfm_or_ddm()) + + def to_ddm(self): + """ + Return a :class:`~.DDM` representation of *self*. + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy import QQ + >>> A = DomainMatrix({0: {0: 1}, 1: {1: 2}}, (2, 2), QQ) + >>> ddm = A.to_ddm() + >>> ddm + [[1, 0], [0, 2]] + >>> type(ddm) + + + See Also + ======== + + to_sdm + to_dense + sympy.polys.matrices.ddm.DDM.to_sdm + """ + return self.rep.to_ddm() + + def to_sdm(self): + """ + Return a :class:`~.SDM` representation of *self*. + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy import QQ + >>> A = DomainMatrix([[1, 0],[0, 2]], (2, 2), QQ) + >>> sdm = A.to_sdm() + >>> sdm + {0: {0: 1}, 1: {1: 2}} + >>> type(sdm) + + + See Also + ======== + + to_ddm + to_sparse + sympy.polys.matrices.sdm.SDM.to_ddm + """ + return self.rep.to_sdm() + + @doctest_depends_on(ground_types=['flint']) + def to_dfm(self): + """ + Return a :class:`~.DFM` representation of *self*. + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy import QQ + >>> A = DomainMatrix([[1, 0],[0, 2]], (2, 2), QQ) + >>> dfm = A.to_dfm() + >>> dfm + [[1, 0], [0, 2]] + >>> type(dfm) + + + See Also + ======== + + to_ddm + to_dense + DFM + """ + return self.rep.to_dfm() + + @doctest_depends_on(ground_types=['flint']) + def to_dfm_or_ddm(self): + """ + Return a :class:`~.DFM` or :class:`~.DDM` representation of *self*. + + Explanation + =========== + + The :class:`~.DFM` representation can only be used if the ground types + are ``flint`` and the ground domain is supported by ``python-flint``. + This method will return a :class:`~.DFM` representation if possible, + but will return a :class:`~.DDM` representation otherwise. + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy import QQ + >>> A = DomainMatrix([[1, 0],[0, 2]], (2, 2), QQ) + >>> dfm = A.to_dfm_or_ddm() + >>> dfm + [[1, 0], [0, 2]] + >>> type(dfm) # Depends on the ground domain and ground types + + + See Also + ======== + + to_ddm: Always return a :class:`~.DDM` representation. + to_dfm: Returns a :class:`~.DFM` representation or raise an error. + to_dense: Convert internally to a :class:`~.DFM` or :class:`~.DDM` + DFM: The :class:`~.DFM` dense FLINT matrix representation. + DDM: The Python :class:`~.DDM` dense domain matrix representation. + """ + return self.rep.to_dfm_or_ddm() + + @classmethod + def _unify_domain(cls, *matrices): + """Convert matrices to a common domain""" + domains = {matrix.domain for matrix in matrices} + if len(domains) == 1: + return matrices + domain = reduce(lambda x, y: x.unify(y), domains) + return tuple(matrix.convert_to(domain) for matrix in matrices) + + @classmethod + def _unify_fmt(cls, *matrices, fmt=None): + """Convert matrices to the same format. + + If all matrices have the same format, then return unmodified. + Otherwise convert both to the preferred format given as *fmt* which + should be 'dense' or 'sparse'. + """ + formats = {matrix.rep.fmt for matrix in matrices} + if len(formats) == 1: + return matrices + if fmt == 'sparse': + return tuple(matrix.to_sparse() for matrix in matrices) + elif fmt == 'dense': + return tuple(matrix.to_dense() for matrix in matrices) + else: + raise ValueError("fmt should be 'sparse' or 'dense'") + + def unify(self, *others, fmt=None): + """ + Unifies the domains and the format of self and other + matrices. + + Parameters + ========== + + others : DomainMatrix + + fmt: string 'dense', 'sparse' or `None` (default) + The preferred format to convert to if self and other are not + already in the same format. If `None` or not specified then no + conversion if performed. + + Returns + ======= + + Tuple[DomainMatrix] + Matrices with unified domain and format + + Examples + ======== + + Unify the domain of DomainMatrix that have different domains: + + >>> from sympy import ZZ, QQ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ) + >>> B = DomainMatrix([[QQ(1, 2), QQ(2)]], (1, 2), QQ) + >>> Aq, Bq = A.unify(B) + >>> Aq + DomainMatrix([[1, 2]], (1, 2), QQ) + >>> Bq + DomainMatrix([[1/2, 2]], (1, 2), QQ) + + Unify the format (dense or sparse): + + >>> A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ) + >>> B = DomainMatrix({0:{0: ZZ(1)}}, (2, 2), ZZ) + >>> B.rep + {0: {0: 1}} + + >>> A2, B2 = A.unify(B, fmt='dense') + >>> B2.rep + [[1, 0], [0, 0]] + + See Also + ======== + + convert_to, to_dense, to_sparse + + """ + matrices = (self,) + others + matrices = DomainMatrix._unify_domain(*matrices) + if fmt is not None: + matrices = DomainMatrix._unify_fmt(*matrices, fmt=fmt) + return matrices + + def to_Matrix(self): + r""" + Convert DomainMatrix to Matrix + + Returns + ======= + + Matrix + MutableDenseMatrix for the DomainMatrix + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + + >>> A.to_Matrix() + Matrix([ + [1, 2], + [3, 4]]) + + See Also + ======== + + from_Matrix + + """ + from sympy.matrices.dense import MutableDenseMatrix + + # XXX: If the internal representation of RepMatrix changes then this + # might need to be changed also. + if self.domain in (ZZ, QQ, EXRAW): + if self.rep.fmt == "sparse": + rep = self.copy() + else: + rep = self.to_sparse() + else: + rep = self.convert_to(EXRAW).to_sparse() + + return MutableDenseMatrix._fromrep(rep) + + def to_list(self): + """ + Convert :class:`DomainMatrix` to list of lists. + + See Also + ======== + + from_list + to_list_flat + to_flat_nz + to_dok + """ + return self.rep.to_list() + + def to_list_flat(self): + """ + Convert :class:`DomainMatrix` to flat list. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> A.to_list_flat() + [1, 2, 3, 4] + + See Also + ======== + + from_list_flat + to_list + to_flat_nz + to_dok + """ + return self.rep.to_list_flat() + + @classmethod + def from_list_flat(cls, elements, shape, domain): + """ + Create :class:`DomainMatrix` from flat list. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> element_list = [ZZ(1), ZZ(2), ZZ(3), ZZ(4)] + >>> A = DomainMatrix.from_list_flat(element_list, (2, 2), ZZ) + >>> A + DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ) + >>> A == A.from_list_flat(A.to_list_flat(), A.shape, A.domain) + True + + See Also + ======== + + to_list_flat + """ + ddm = DDM.from_list_flat(elements, shape, domain) + return cls.from_rep(ddm.to_dfm_or_ddm()) + + def to_flat_nz(self): + """ + Convert :class:`DomainMatrix` to list of nonzero elements and data. + + Explanation + =========== + + Returns a tuple ``(elements, data)`` where ``elements`` is a list of + elements of the matrix with zeros possibly excluded. The matrix can be + reconstructed by passing these to :meth:`from_flat_nz`. The idea is to + be able to modify a flat list of the elements and then create a new + matrix of the same shape with the modified elements in the same + positions. + + The format of ``data`` differs depending on whether the underlying + representation is dense or sparse but either way it represents the + positions of the elements in the list in a way that + :meth:`from_flat_nz` can use to reconstruct the matrix. The + :meth:`from_flat_nz` method should be called on the same + :class:`DomainMatrix` that was used to call :meth:`to_flat_nz`. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> elements, data = A.to_flat_nz() + >>> elements + [1, 2, 3, 4] + >>> A == A.from_flat_nz(elements, data, A.domain) + True + + Create a matrix with the elements doubled: + + >>> elements_doubled = [2*x for x in elements] + >>> A2 = A.from_flat_nz(elements_doubled, data, A.domain) + >>> A2 == 2*A + True + + See Also + ======== + + from_flat_nz + """ + return self.rep.to_flat_nz() + + def from_flat_nz(self, elements, data, domain): + """ + Reconstruct :class:`DomainMatrix` after calling :meth:`to_flat_nz`. + + See :meth:`to_flat_nz` for explanation. + + See Also + ======== + + to_flat_nz + """ + rep = self.rep.from_flat_nz(elements, data, domain) + return self.from_rep(rep) + + def to_dod(self): + """ + Convert :class:`DomainMatrix` to dictionary of dictionaries (dod) format. + + Explanation + =========== + + Returns a dictionary of dictionaries representing the matrix. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DM + >>> A = DM([[ZZ(1), ZZ(2), ZZ(0)], [ZZ(3), ZZ(0), ZZ(4)]], ZZ) + >>> A.to_dod() + {0: {0: 1, 1: 2}, 1: {0: 3, 2: 4}} + >>> A.to_sparse() == A.from_dod(A.to_dod(), A.shape, A.domain) + True + >>> A == A.from_dod_like(A.to_dod()) + True + + See Also + ======== + + from_dod + from_dod_like + to_dok + to_list + to_list_flat + to_flat_nz + sympy.matrices.matrixbase.MatrixBase.todod + """ + return self.rep.to_dod() + + @classmethod + def from_dod(cls, dod, shape, domain): + """ + Create sparse :class:`DomainMatrix` from dict of dict (dod) format. + + See :meth:`to_dod` for explanation. + + See Also + ======== + + to_dod + from_dod_like + """ + return cls.from_rep(SDM.from_dod(dod, shape, domain)) + + def from_dod_like(self, dod, domain=None): + """ + Create :class:`DomainMatrix` like ``self`` from dict of dict (dod) format. + + See :meth:`to_dod` for explanation. + + See Also + ======== + + to_dod + from_dod + """ + if domain is None: + domain = self.domain + return self.from_rep(self.rep.from_dod(dod, self.shape, domain)) + + def to_dok(self): + """ + Convert :class:`DomainMatrix` to dictionary of keys (dok) format. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(0)], + ... [ZZ(0), ZZ(4)]], (2, 2), ZZ) + >>> A.to_dok() + {(0, 0): 1, (1, 1): 4} + + The matrix can be reconstructed by calling :meth:`from_dok` although + the reconstructed matrix will always be in sparse format: + + >>> A.to_sparse() == A.from_dok(A.to_dok(), A.shape, A.domain) + True + + See Also + ======== + + from_dok + to_list + to_list_flat + to_flat_nz + """ + return self.rep.to_dok() + + @classmethod + def from_dok(cls, dok, shape, domain): + """ + Create :class:`DomainMatrix` from dictionary of keys (dok) format. + + See :meth:`to_dok` for explanation. + + See Also + ======== + + to_dok + """ + return cls.from_rep(SDM.from_dok(dok, shape, domain)) + + def iter_values(self): + """ + Iterate over nonzero elements of the matrix. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([[ZZ(1), ZZ(0)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> list(A.iter_values()) + [1, 3, 4] + + See Also + ======== + + iter_items + to_list_flat + sympy.matrices.matrixbase.MatrixBase.iter_values + """ + return self.rep.iter_values() + + def iter_items(self): + """ + Iterate over indices and values of nonzero elements of the matrix. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([[ZZ(1), ZZ(0)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> list(A.iter_items()) + [((0, 0), 1), ((1, 0), 3), ((1, 1), 4)] + + See Also + ======== + + iter_values + to_dok + sympy.matrices.matrixbase.MatrixBase.iter_items + """ + return self.rep.iter_items() + + def nnz(self): + """ + Number of nonzero elements in the matrix. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DM + >>> A = DM([[1, 0], [0, 4]], ZZ) + >>> A.nnz() + 2 + """ + return self.rep.nnz() + + def __repr__(self): + return 'DomainMatrix(%s, %r, %r)' % (str(self.rep), self.shape, self.domain) + + def transpose(self): + """Matrix transpose of ``self``""" + return self.from_rep(self.rep.transpose()) + + def flat(self): + rows, cols = self.shape + return [self[i,j].element for i in range(rows) for j in range(cols)] + + @property + def is_zero_matrix(self): + return self.rep.is_zero_matrix() + + @property + def is_upper(self): + """ + Says whether this matrix is upper-triangular. True can be returned + even if the matrix is not square. + """ + return self.rep.is_upper() + + @property + def is_lower(self): + """ + Says whether this matrix is lower-triangular. True can be returned + even if the matrix is not square. + """ + return self.rep.is_lower() + + @property + def is_diagonal(self): + """ + True if the matrix is diagonal. + + Can return true for non-square matrices. A matrix is diagonal if + ``M[i,j] == 0`` whenever ``i != j``. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DM + >>> M = DM([[ZZ(1), ZZ(0)], [ZZ(0), ZZ(1)]], ZZ) + >>> M.is_diagonal + True + + See Also + ======== + + is_upper + is_lower + is_square + diagonal + """ + return self.rep.is_diagonal() + + def diagonal(self): + """ + Get the diagonal entries of the matrix as a list. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DM + >>> M = DM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], ZZ) + >>> M.diagonal() + [1, 4] + + See Also + ======== + + is_diagonal + diag + """ + return self.rep.diagonal() + + @property + def is_square(self): + """ + True if the matrix is square. + """ + return self.shape[0] == self.shape[1] + + def rank(self): + rref, pivots = self.rref() + return len(pivots) + + def hstack(A, *B): + r"""Horizontally stack the given matrices. + + Parameters + ========== + + B: DomainMatrix + Matrices to stack horizontally. + + Returns + ======= + + DomainMatrix + DomainMatrix by stacking horizontally. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + + >>> A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ) + >>> A.hstack(B) + DomainMatrix([[1, 2, 5, 6], [3, 4, 7, 8]], (2, 4), ZZ) + + >>> C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ) + >>> A.hstack(B, C) + DomainMatrix([[1, 2, 5, 6, 9, 10], [3, 4, 7, 8, 11, 12]], (2, 6), ZZ) + + See Also + ======== + + unify + """ + A, *B = A.unify(*B, fmt=A.rep.fmt) + return DomainMatrix.from_rep(A.rep.hstack(*(Bk.rep for Bk in B))) + + def vstack(A, *B): + r"""Vertically stack the given matrices. + + Parameters + ========== + + B: DomainMatrix + Matrices to stack vertically. + + Returns + ======= + + DomainMatrix + DomainMatrix by stacking vertically. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + + >>> A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ) + >>> A.vstack(B) + DomainMatrix([[1, 2], [3, 4], [5, 6], [7, 8]], (4, 2), ZZ) + + >>> C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ) + >>> A.vstack(B, C) + DomainMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]], (6, 2), ZZ) + + See Also + ======== + + unify + """ + A, *B = A.unify(*B, fmt='dense') + return DomainMatrix.from_rep(A.rep.vstack(*(Bk.rep for Bk in B))) + + def applyfunc(self, func, domain=None): + if domain is None: + domain = self.domain + return self.from_rep(self.rep.applyfunc(func, domain)) + + def __add__(A, B): + if not isinstance(B, DomainMatrix): + return NotImplemented + A, B = A.unify(B, fmt='dense') + return A.add(B) + + def __sub__(A, B): + if not isinstance(B, DomainMatrix): + return NotImplemented + A, B = A.unify(B, fmt='dense') + return A.sub(B) + + def __neg__(A): + return A.neg() + + def __mul__(A, B): + """A * B""" + if isinstance(B, DomainMatrix): + A, B = A.unify(B, fmt='dense') + return A.matmul(B) + elif B in A.domain: + return A.scalarmul(B) + elif isinstance(B, DomainScalar): + A, B = A.unify(B) + return A.scalarmul(B.element) + else: + return NotImplemented + + def __rmul__(A, B): + if B in A.domain: + return A.rscalarmul(B) + elif isinstance(B, DomainScalar): + A, B = A.unify(B) + return A.rscalarmul(B.element) + else: + return NotImplemented + + def __pow__(A, n): + """A ** n""" + if not isinstance(n, int): + return NotImplemented + return A.pow(n) + + def _check(a, op, b, ashape, bshape): + if a.domain != b.domain: + msg = "Domain mismatch: %s %s %s" % (a.domain, op, b.domain) + raise DMDomainError(msg) + if ashape != bshape: + msg = "Shape mismatch: %s %s %s" % (a.shape, op, b.shape) + raise DMShapeError(msg) + if a.rep.fmt != b.rep.fmt: + msg = "Format mismatch: %s %s %s" % (a.rep.fmt, op, b.rep.fmt) + raise DMFormatError(msg) + if type(a.rep) != type(b.rep): + msg = "Type mismatch: %s %s %s" % (type(a.rep), op, type(b.rep)) + raise DMFormatError(msg) + + def add(A, B): + r""" + Adds two DomainMatrix matrices of the same Domain + + Parameters + ========== + + A, B: DomainMatrix + matrices to add + + Returns + ======= + + DomainMatrix + DomainMatrix after Addition + + Raises + ====== + + DMShapeError + If the dimensions of the two DomainMatrix are not equal + + ValueError + If the domain of the two DomainMatrix are not same + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> B = DomainMatrix([ + ... [ZZ(4), ZZ(3)], + ... [ZZ(2), ZZ(1)]], (2, 2), ZZ) + + >>> A.add(B) + DomainMatrix([[5, 5], [5, 5]], (2, 2), ZZ) + + See Also + ======== + + sub, matmul + + """ + A._check('+', B, A.shape, B.shape) + return A.from_rep(A.rep.add(B.rep)) + + + def sub(A, B): + r""" + Subtracts two DomainMatrix matrices of the same Domain + + Parameters + ========== + + A, B: DomainMatrix + matrices to subtract + + Returns + ======= + + DomainMatrix + DomainMatrix after Subtraction + + Raises + ====== + + DMShapeError + If the dimensions of the two DomainMatrix are not equal + + ValueError + If the domain of the two DomainMatrix are not same + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> B = DomainMatrix([ + ... [ZZ(4), ZZ(3)], + ... [ZZ(2), ZZ(1)]], (2, 2), ZZ) + + >>> A.sub(B) + DomainMatrix([[-3, -1], [1, 3]], (2, 2), ZZ) + + See Also + ======== + + add, matmul + + """ + A._check('-', B, A.shape, B.shape) + return A.from_rep(A.rep.sub(B.rep)) + + def neg(A): + r""" + Returns the negative of DomainMatrix + + Parameters + ========== + + A : Represents a DomainMatrix + + Returns + ======= + + DomainMatrix + DomainMatrix after Negation + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + + >>> A.neg() + DomainMatrix([[-1, -2], [-3, -4]], (2, 2), ZZ) + + """ + return A.from_rep(A.rep.neg()) + + def mul(A, b): + r""" + Performs term by term multiplication for the second DomainMatrix + w.r.t first DomainMatrix. Returns a DomainMatrix whose rows are + list of DomainMatrix matrices created after term by term multiplication. + + Parameters + ========== + + A, B: DomainMatrix + matrices to multiply term-wise + + Returns + ======= + + DomainMatrix + DomainMatrix after term by term multiplication + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> b = ZZ(2) + + >>> A.mul(b) + DomainMatrix([[2, 4], [6, 8]], (2, 2), ZZ) + + See Also + ======== + + matmul + + """ + return A.from_rep(A.rep.mul(b)) + + def rmul(A, b): + return A.from_rep(A.rep.rmul(b)) + + def matmul(A, B): + r""" + Performs matrix multiplication of two DomainMatrix matrices + + Parameters + ========== + + A, B: DomainMatrix + to multiply + + Returns + ======= + + DomainMatrix + DomainMatrix after multiplication + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> B = DomainMatrix([ + ... [ZZ(1), ZZ(1)], + ... [ZZ(0), ZZ(1)]], (2, 2), ZZ) + + >>> A.matmul(B) + DomainMatrix([[1, 3], [3, 7]], (2, 2), ZZ) + + See Also + ======== + + mul, pow, add, sub + + """ + + A._check('*', B, A.shape[1], B.shape[0]) + return A.from_rep(A.rep.matmul(B.rep)) + + def _scalarmul(A, lamda, reverse): + if lamda == A.domain.zero: + return DomainMatrix.zeros(A.shape, A.domain) + elif lamda == A.domain.one: + return A.copy() + elif reverse: + return A.rmul(lamda) + else: + return A.mul(lamda) + + def scalarmul(A, lamda): + return A._scalarmul(lamda, reverse=False) + + def rscalarmul(A, lamda): + return A._scalarmul(lamda, reverse=True) + + def mul_elementwise(A, B): + assert A.domain == B.domain + return A.from_rep(A.rep.mul_elementwise(B.rep)) + + def __truediv__(A, lamda): + """ Method for Scalar Division""" + if isinstance(lamda, int) or ZZ.of_type(lamda): + lamda = DomainScalar(ZZ(lamda), ZZ) + elif A.domain.is_Field and lamda in A.domain: + K = A.domain + lamda = DomainScalar(K.convert(lamda), K) + + if not isinstance(lamda, DomainScalar): + return NotImplemented + + A, lamda = A.to_field().unify(lamda) + if lamda.element == lamda.domain.zero: + raise ZeroDivisionError + if lamda.element == lamda.domain.one: + return A + + return A.mul(1 / lamda.element) + + def pow(A, n): + r""" + Computes A**n + + Parameters + ========== + + A : DomainMatrix + + n : exponent for A + + Returns + ======= + + DomainMatrix + DomainMatrix on computing A**n + + Raises + ====== + + NotImplementedError + if n is negative. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(1)], + ... [ZZ(0), ZZ(1)]], (2, 2), ZZ) + + >>> A.pow(2) + DomainMatrix([[1, 2], [0, 1]], (2, 2), ZZ) + + See Also + ======== + + matmul + + """ + nrows, ncols = A.shape + if nrows != ncols: + raise DMNonSquareMatrixError('Power of a nonsquare matrix') + if n < 0: + raise NotImplementedError('Negative powers') + elif n == 0: + return A.eye(nrows, A.domain) + elif n == 1: + return A + elif n % 2 == 1: + return A * A**(n - 1) + else: + sqrtAn = A ** (n // 2) + return sqrtAn * sqrtAn + + def scc(self): + """Compute the strongly connected components of a DomainMatrix + + Explanation + =========== + + A square matrix can be considered as the adjacency matrix for a + directed graph where the row and column indices are the vertices. In + this graph if there is an edge from vertex ``i`` to vertex ``j`` if + ``M[i, j]`` is nonzero. This routine computes the strongly connected + components of that graph which are subsets of the rows and columns that + are connected by some nonzero element of the matrix. The strongly + connected components are useful because many operations such as the + determinant can be computed by working with the submatrices + corresponding to each component. + + Examples + ======== + + Find the strongly connected components of a matrix: + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> M = DomainMatrix([[ZZ(1), ZZ(0), ZZ(2)], + ... [ZZ(0), ZZ(3), ZZ(0)], + ... [ZZ(4), ZZ(6), ZZ(5)]], (3, 3), ZZ) + >>> M.scc() + [[1], [0, 2]] + + Compute the determinant from the components: + + >>> MM = M.to_Matrix() + >>> MM + Matrix([ + [1, 0, 2], + [0, 3, 0], + [4, 6, 5]]) + >>> MM[[1], [1]] + Matrix([[3]]) + >>> MM[[0, 2], [0, 2]] + Matrix([ + [1, 2], + [4, 5]]) + >>> MM.det() + -9 + >>> MM[[1], [1]].det() * MM[[0, 2], [0, 2]].det() + -9 + + The components are given in reverse topological order and represent a + permutation of the rows and columns that will bring the matrix into + block lower-triangular form: + + >>> MM[[1, 0, 2], [1, 0, 2]] + Matrix([ + [3, 0, 0], + [0, 1, 2], + [6, 4, 5]]) + + Returns + ======= + + List of lists of integers + Each list represents a strongly connected component. + + See also + ======== + + sympy.matrices.matrixbase.MatrixBase.strongly_connected_components + sympy.utilities.iterables.strongly_connected_components + + """ + if not self.is_square: + raise DMNonSquareMatrixError('Matrix must be square for scc') + + return self.rep.scc() + + def clear_denoms(self, convert=False): + """ + Clear denominators, but keep the domain unchanged. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DM + >>> A = DM([[(1,2), (1,3)], [(1,4), (1,5)]], QQ) + >>> den, Anum = A.clear_denoms() + >>> den.to_sympy() + 60 + >>> Anum.to_Matrix() + Matrix([ + [30, 20], + [15, 12]]) + >>> den * A == Anum + True + + The numerator matrix will be in the same domain as the original matrix + unless ``convert`` is set to ``True``: + + >>> A.clear_denoms()[1].domain + QQ + >>> A.clear_denoms(convert=True)[1].domain + ZZ + + The denominator is always in the associated ring: + + >>> A.clear_denoms()[0].domain + ZZ + >>> A.domain.get_ring() + ZZ + + See Also + ======== + + sympy.polys.polytools.Poly.clear_denoms + clear_denoms_rowwise + """ + elems0, data = self.to_flat_nz() + + K0 = self.domain + K1 = K0.get_ring() if K0.has_assoc_Ring else K0 + + den, elems1 = dup_clear_denoms(elems0, K0, K1, convert=convert) + + if convert: + Kden, Knum = K1, K1 + else: + Kden, Knum = K1, K0 + + den = DomainScalar(den, Kden) + num = self.from_flat_nz(elems1, data, Knum) + + return den, num + + def clear_denoms_rowwise(self, convert=False): + """ + Clear denominators from each row of the matrix. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DM + >>> A = DM([[(1,2), (1,3), (1,4)], [(1,5), (1,6), (1,7)]], QQ) + >>> den, Anum = A.clear_denoms_rowwise() + >>> den.to_Matrix() + Matrix([ + [12, 0], + [ 0, 210]]) + >>> Anum.to_Matrix() + Matrix([ + [ 6, 4, 3], + [42, 35, 30]]) + + The denominator matrix is a diagonal matrix with the denominators of + each row on the diagonal. The invariants are: + + >>> den * A == Anum + True + >>> A == den.to_field().inv() * Anum + True + + The numerator matrix will be in the same domain as the original matrix + unless ``convert`` is set to ``True``: + + >>> A.clear_denoms_rowwise()[1].domain + QQ + >>> A.clear_denoms_rowwise(convert=True)[1].domain + ZZ + + The domain of the denominator matrix is the associated ring: + + >>> A.clear_denoms_rowwise()[0].domain + ZZ + + See Also + ======== + + sympy.polys.polytools.Poly.clear_denoms + clear_denoms + """ + dod = self.to_dod() + + K0 = self.domain + K1 = K0.get_ring() if K0.has_assoc_Ring else K0 + + diagonals = [K0.one] * self.shape[0] + dod_num = {} + for i, rowi in dod.items(): + indices, elems = zip(*rowi.items()) + den, elems_num = dup_clear_denoms(elems, K0, K1, convert=convert) + rowi_num = dict(zip(indices, elems_num)) + diagonals[i] = den + dod_num[i] = rowi_num + + if convert: + Kden, Knum = K1, K1 + else: + Kden, Knum = K1, K0 + + den = self.diag(diagonals, Kden) + num = self.from_dod_like(dod_num, Knum) + + return den, num + + def cancel_denom(self, denom): + """ + Cancel factors between a matrix and a denominator. + + Returns a matrix and denominator on lowest terms. + + Requires ``gcd`` in the ground domain. + + Methods like :meth:`solve_den`, :meth:`inv_den` and :meth:`rref_den` + return a matrix and denominator but not necessarily on lowest terms. + Reduction to lowest terms without fractions can be performed with + :meth:`cancel_denom`. + + Examples + ======== + + >>> from sympy.polys.matrices import DM + >>> from sympy import ZZ + >>> M = DM([[2, 2, 0], + ... [0, 2, 2], + ... [0, 0, 2]], ZZ) + >>> Minv, den = M.inv_den() + >>> Minv.to_Matrix() + Matrix([ + [1, -1, 1], + [0, 1, -1], + [0, 0, 1]]) + >>> den + 2 + >>> Minv_reduced, den_reduced = Minv.cancel_denom(den) + >>> Minv_reduced.to_Matrix() + Matrix([ + [1, -1, 1], + [0, 1, -1], + [0, 0, 1]]) + >>> den_reduced + 2 + >>> Minv_reduced.to_field() / den_reduced == Minv.to_field() / den + True + + The denominator is made canonical with respect to units (e.g. a + negative denominator is made positive): + + >>> M = DM([[2, 2, 0]], ZZ) + >>> den = ZZ(-4) + >>> M.cancel_denom(den) + (DomainMatrix([[-1, -1, 0]], (1, 3), ZZ), 2) + + Any factor common to _all_ elements will be cancelled but there can + still be factors in common between _some_ elements of the matrix and + the denominator. To cancel factors between each element and the + denominator, use :meth:`cancel_denom_elementwise` or otherwise convert + to a field and use division: + + >>> M = DM([[4, 6]], ZZ) + >>> den = ZZ(12) + >>> M.cancel_denom(den) + (DomainMatrix([[2, 3]], (1, 2), ZZ), 6) + >>> numers, denoms = M.cancel_denom_elementwise(den) + >>> numers + DomainMatrix([[1, 1]], (1, 2), ZZ) + >>> denoms + DomainMatrix([[3, 2]], (1, 2), ZZ) + >>> M.to_field() / den + DomainMatrix([[1/3, 1/2]], (1, 2), QQ) + + See Also + ======== + + solve_den + inv_den + rref_den + cancel_denom_elementwise + """ + M = self + K = self.domain + + if K.is_zero(denom): + raise ZeroDivisionError('denominator is zero') + elif K.is_one(denom): + return (M.copy(), denom) + + elements, data = M.to_flat_nz() + + # First canonicalize the denominator (e.g. multiply by -1). + if K.is_negative(denom): + u = -K.one + else: + u = K.canonical_unit(denom) + + # Often after e.g. solve_den the denominator will be much more + # complicated than the elements of the numerator. Hopefully it will be + # quicker to find the gcd of the numerator and if there is no content + # then we do not need to look at the denominator at all. + content = dup_content(elements, K) + common = K.gcd(content, denom) + + if not K.is_one(content): + + common = K.gcd(content, denom) + + if not K.is_one(common): + elements = dup_quo_ground(elements, common, K) + denom = K.quo(denom, common) + + if not K.is_one(u): + elements = dup_mul_ground(elements, u, K) + denom = u * denom + elif K.is_one(common): + return (M.copy(), denom) + + M_cancelled = M.from_flat_nz(elements, data, K) + + return M_cancelled, denom + + def cancel_denom_elementwise(self, denom): + """ + Cancel factors between the elements of a matrix and a denominator. + + Returns a matrix of numerators and matrix of denominators. + + Requires ``gcd`` in the ground domain. + + Examples + ======== + + >>> from sympy.polys.matrices import DM + >>> from sympy import ZZ + >>> M = DM([[2, 3], [4, 12]], ZZ) + >>> denom = ZZ(6) + >>> numers, denoms = M.cancel_denom_elementwise(denom) + >>> numers.to_Matrix() + Matrix([ + [1, 1], + [2, 2]]) + >>> denoms.to_Matrix() + Matrix([ + [3, 2], + [3, 1]]) + >>> M_frac = (M.to_field() / denom).to_Matrix() + >>> M_frac + Matrix([ + [1/3, 1/2], + [2/3, 2]]) + >>> denoms_inverted = denoms.to_Matrix().applyfunc(lambda e: 1/e) + >>> numers.to_Matrix().multiply_elementwise(denoms_inverted) == M_frac + True + + Use :meth:`cancel_denom` to cancel factors between the matrix and the + denominator while preserving the form of a matrix with a scalar + denominator. + + See Also + ======== + + cancel_denom + """ + K = self.domain + M = self + + if K.is_zero(denom): + raise ZeroDivisionError('denominator is zero') + elif K.is_one(denom): + M_numers = M.copy() + M_denoms = M.ones(M.shape, M.domain) + return (M_numers, M_denoms) + + elements, data = M.to_flat_nz() + + cofactors = [K.cofactors(numer, denom) for numer in elements] + gcds, numers, denoms = zip(*cofactors) + + M_numers = M.from_flat_nz(list(numers), data, K) + M_denoms = M.from_flat_nz(list(denoms), data, K) + + return (M_numers, M_denoms) + + def content(self): + """ + Return the gcd of the elements of the matrix. + + Requires ``gcd`` in the ground domain. + + Examples + ======== + + >>> from sympy.polys.matrices import DM + >>> from sympy import ZZ + >>> M = DM([[2, 4], [4, 12]], ZZ) + >>> M.content() + 2 + + See Also + ======== + + primitive + cancel_denom + """ + K = self.domain + elements, _ = self.to_flat_nz() + return dup_content(elements, K) + + def primitive(self): + """ + Factor out gcd of the elements of a matrix. + + Requires ``gcd`` in the ground domain. + + Examples + ======== + + >>> from sympy.polys.matrices import DM + >>> from sympy import ZZ + >>> M = DM([[2, 4], [4, 12]], ZZ) + >>> content, M_primitive = M.primitive() + >>> content + 2 + >>> M_primitive + DomainMatrix([[1, 2], [2, 6]], (2, 2), ZZ) + >>> content * M_primitive == M + True + >>> M_primitive.content() == ZZ(1) + True + + See Also + ======== + + content + cancel_denom + """ + K = self.domain + elements, data = self.to_flat_nz() + content, prims = dup_primitive(elements, K) + M_primitive = self.from_flat_nz(prims, data, K) + return content, M_primitive + + def rref(self, *, method='auto'): + r""" + Returns reduced-row echelon form (RREF) and list of pivots. + + If the domain is not a field then it will be converted to a field. See + :meth:`rref_den` for the fraction-free version of this routine that + returns RREF with denominator instead. + + The domain must either be a field or have an associated fraction field + (see :meth:`to_field`). + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [QQ(2), QQ(-1), QQ(0)], + ... [QQ(-1), QQ(2), QQ(-1)], + ... [QQ(0), QQ(0), QQ(2)]], (3, 3), QQ) + + >>> rref_matrix, rref_pivots = A.rref() + >>> rref_matrix + DomainMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]], (3, 3), QQ) + >>> rref_pivots + (0, 1, 2) + + Parameters + ========== + + method : str, optional (default: 'auto') + The method to use to compute the RREF. The default is ``'auto'``, + which will attempt to choose the fastest method. The other options + are: + + - ``A.rref(method='GJ')`` uses Gauss-Jordan elimination with + division. If the domain is not a field then it will be converted + to a field with :meth:`to_field` first and RREF will be computed + by inverting the pivot elements in each row. This is most + efficient for very sparse matrices or for matrices whose elements + have complex denominators. + + - ``A.rref(method='FF')`` uses fraction-free Gauss-Jordan + elimination. Elimination is performed using exact division + (``exquo``) to control the growth of the coefficients. In this + case the current domain is always used for elimination but if + the domain is not a field then it will be converted to a field + at the end and divided by the denominator. This is most efficient + for dense matrices or for matrices with simple denominators. + + - ``A.rref(method='CD')`` clears the denominators before using + fraction-free Gauss-Jordan elimination in the associated ring. + This is most efficient for dense matrices with very simple + denominators. + + - ``A.rref(method='GJ_dense')``, ``A.rref(method='FF_dense')``, and + ``A.rref(method='CD_dense')`` are the same as the above methods + except that the dense implementations of the algorithms are used. + By default ``A.rref(method='auto')`` will usually choose the + sparse implementations for RREF. + + Regardless of which algorithm is used the returned matrix will + always have the same format (sparse or dense) as the input and its + domain will always be the field of fractions of the input domain. + + Returns + ======= + + (DomainMatrix, list) + reduced-row echelon form and list of pivots for the DomainMatrix + + See Also + ======== + + rref_den + RREF with denominator + sympy.polys.matrices.sdm.sdm_irref + Sparse implementation of ``method='GJ'``. + sympy.polys.matrices.sdm.sdm_rref_den + Sparse implementation of ``method='FF'`` and ``method='CD'``. + sympy.polys.matrices.dense.ddm_irref + Dense implementation of ``method='GJ'``. + sympy.polys.matrices.dense.ddm_irref_den + Dense implementation of ``method='FF'`` and ``method='CD'``. + clear_denoms + Clear denominators from a matrix, used by ``method='CD'`` and + by ``method='GJ'`` when the original domain is not a field. + + """ + return _dm_rref(self, method=method) + + def rref_den(self, *, method='auto', keep_domain=True): + r""" + Returns reduced-row echelon form with denominator and list of pivots. + + Requires exact division in the ground domain (``exquo``). + + Examples + ======== + + >>> from sympy import ZZ, QQ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(2), ZZ(-1), ZZ(0)], + ... [ZZ(-1), ZZ(2), ZZ(-1)], + ... [ZZ(0), ZZ(0), ZZ(2)]], (3, 3), ZZ) + + >>> A_rref, denom, pivots = A.rref_den() + >>> A_rref + DomainMatrix([[6, 0, 0], [0, 6, 0], [0, 0, 6]], (3, 3), ZZ) + >>> denom + 6 + >>> pivots + (0, 1, 2) + >>> A_rref.to_field() / denom + DomainMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]], (3, 3), QQ) + >>> A_rref.to_field() / denom == A.convert_to(QQ).rref()[0] + True + + Parameters + ========== + + method : str, optional (default: 'auto') + The method to use to compute the RREF. The default is ``'auto'``, + which will attempt to choose the fastest method. The other options + are: + + - ``A.rref(method='FF')`` uses fraction-free Gauss-Jordan + elimination. Elimination is performed using exact division + (``exquo``) to control the growth of the coefficients. In this + case the current domain is always used for elimination and the + result is always returned as a matrix over the current domain. + This is most efficient for dense matrices or for matrices with + simple denominators. + + - ``A.rref(method='CD')`` clears denominators before using + fraction-free Gauss-Jordan elimination in the associated ring. + The result will be converted back to the original domain unless + ``keep_domain=False`` is passed in which case the result will be + over the ring used for elimination. This is most efficient for + dense matrices with very simple denominators. + + - ``A.rref(method='GJ')`` uses Gauss-Jordan elimination with + division. If the domain is not a field then it will be converted + to a field with :meth:`to_field` first and RREF will be computed + by inverting the pivot elements in each row. The result is + converted back to the original domain by clearing denominators + unless ``keep_domain=False`` is passed in which case the result + will be over the field used for elimination. This is most + efficient for very sparse matrices or for matrices whose elements + have complex denominators. + + - ``A.rref(method='GJ_dense')``, ``A.rref(method='FF_dense')``, and + ``A.rref(method='CD_dense')`` are the same as the above methods + except that the dense implementations of the algorithms are used. + By default ``A.rref(method='auto')`` will usually choose the + sparse implementations for RREF. + + Regardless of which algorithm is used the returned matrix will + always have the same format (sparse or dense) as the input and if + ``keep_domain=True`` its domain will always be the same as the + input. + + keep_domain : bool, optional + If True (the default), the domain of the returned matrix and + denominator are the same as the domain of the input matrix. If + False, the domain of the returned matrix might be changed to an + associated ring or field if the algorithm used a different domain. + This is useful for efficiency if the caller does not need the + result to be in the original domain e.g. it avoids clearing + denominators in the case of ``A.rref(method='GJ')``. + + Returns + ======= + + (DomainMatrix, scalar, list) + Reduced-row echelon form, denominator and list of pivot indices. + + See Also + ======== + + rref + RREF without denominator for field domains. + sympy.polys.matrices.sdm.sdm_irref + Sparse implementation of ``method='GJ'``. + sympy.polys.matrices.sdm.sdm_rref_den + Sparse implementation of ``method='FF'`` and ``method='CD'``. + sympy.polys.matrices.dense.ddm_irref + Dense implementation of ``method='GJ'``. + sympy.polys.matrices.dense.ddm_irref_den + Dense implementation of ``method='FF'`` and ``method='CD'``. + clear_denoms + Clear denominators from a matrix, used by ``method='CD'``. + + """ + return _dm_rref_den(self, method=method, keep_domain=keep_domain) + + def columnspace(self): + r""" + Returns the columnspace for the DomainMatrix + + Returns + ======= + + DomainMatrix + The columns of this matrix form a basis for the columnspace. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [QQ(1), QQ(-1)], + ... [QQ(2), QQ(-2)]], (2, 2), QQ) + >>> A.columnspace() + DomainMatrix([[1], [2]], (2, 1), QQ) + + """ + if not self.domain.is_Field: + raise DMNotAField('Not a field') + rref, pivots = self.rref() + rows, cols = self.shape + return self.extract(range(rows), pivots) + + def rowspace(self): + r""" + Returns the rowspace for the DomainMatrix + + Returns + ======= + + DomainMatrix + The rows of this matrix form a basis for the rowspace. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [QQ(1), QQ(-1)], + ... [QQ(2), QQ(-2)]], (2, 2), QQ) + >>> A.rowspace() + DomainMatrix([[1, -1]], (1, 2), QQ) + + """ + if not self.domain.is_Field: + raise DMNotAField('Not a field') + rref, pivots = self.rref() + rows, cols = self.shape + return self.extract(range(len(pivots)), range(cols)) + + def nullspace(self, divide_last=False): + r""" + Returns the nullspace for the DomainMatrix + + Returns + ======= + + DomainMatrix + The rows of this matrix form a basis for the nullspace. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DM + >>> A = DM([ + ... [QQ(2), QQ(-2)], + ... [QQ(4), QQ(-4)]], QQ) + >>> A.nullspace() + DomainMatrix([[1, 1]], (1, 2), QQ) + + The returned matrix is a basis for the nullspace: + + >>> A_null = A.nullspace().transpose() + >>> A * A_null + DomainMatrix([[0], [0]], (2, 1), QQ) + >>> rows, cols = A.shape + >>> nullity = rows - A.rank() + >>> A_null.shape == (cols, nullity) + True + + Nullspace can also be computed for non-field rings. If the ring is not + a field then division is not used. Setting ``divide_last`` to True will + raise an error in this case: + + >>> from sympy import ZZ + >>> B = DM([[6, -3], + ... [4, -2]], ZZ) + >>> B.nullspace() + DomainMatrix([[3, 6]], (1, 2), ZZ) + >>> B.nullspace(divide_last=True) + Traceback (most recent call last): + ... + DMNotAField: Cannot normalize vectors over a non-field + + Over a ring with ``gcd`` defined the nullspace can potentially be + reduced with :meth:`primitive`: + + >>> B.nullspace().primitive() + (3, DomainMatrix([[1, 2]], (1, 2), ZZ)) + + A matrix over a ring can often be normalized by converting it to a + field but it is often a bad idea to do so: + + >>> from sympy.abc import a, b, c + >>> from sympy import Matrix + >>> M = Matrix([[ a*b, b + c, c], + ... [ a - b, b*c, c**2], + ... [a*b + a - b, b*c + b + c, c**2 + c]]) + >>> M.to_DM().domain + ZZ[a,b,c] + >>> M.to_DM().nullspace().to_Matrix().transpose() + Matrix([ + [ c**3], + [ -a*b*c**2 + a*c - b*c], + [a*b**2*c - a*b - a*c + b**2 + b*c]]) + + The unnormalized form here is nicer than the normalized form that + spreads a large denominator throughout the matrix: + + >>> M.to_DM().to_field().nullspace(divide_last=True).to_Matrix().transpose() + Matrix([ + [ c**3/(a*b**2*c - a*b - a*c + b**2 + b*c)], + [(-a*b*c**2 + a*c - b*c)/(a*b**2*c - a*b - a*c + b**2 + b*c)], + [ 1]]) + + Parameters + ========== + + divide_last : bool, optional + If False (the default), the vectors are not normalized and the RREF + is computed using :meth:`rref_den` and the denominator is + discarded. If True, then each row is divided by its final element; + the domain must be a field in this case. + + See Also + ======== + + nullspace_from_rref + rref + rref_den + rowspace + """ + A = self + K = A.domain + + if divide_last and not K.is_Field: + raise DMNotAField("Cannot normalize vectors over a non-field") + + if divide_last: + A_rref, pivots = A.rref() + else: + A_rref, den, pivots = A.rref_den() + + # Ensure that the sign is canonical before discarding the + # denominator. Then M.nullspace().primitive() is canonical. + u = K.canonical_unit(den) + if u != K.one: + A_rref *= u + + A_null = A_rref.nullspace_from_rref(pivots) + + return A_null + + def nullspace_from_rref(self, pivots=None): + """ + Compute nullspace from rref and pivots. + + The domain of the matrix can be any domain. + + The matrix must be in reduced row echelon form already. Otherwise the + result will be incorrect. Use :meth:`rref` or :meth:`rref_den` first + to get the reduced row echelon form or use :meth:`nullspace` instead. + + See Also + ======== + + nullspace + rref + rref_den + sympy.polys.matrices.sdm.SDM.nullspace_from_rref + sympy.polys.matrices.ddm.DDM.nullspace_from_rref + """ + null_rep, nonpivots = self.rep.nullspace_from_rref(pivots) + return self.from_rep(null_rep) + + def inv(self): + r""" + Finds the inverse of the DomainMatrix if exists + + Returns + ======= + + DomainMatrix + DomainMatrix after inverse + + Raises + ====== + + ValueError + If the domain of DomainMatrix not a Field + + DMNonSquareMatrixError + If the DomainMatrix is not a not Square DomainMatrix + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [QQ(2), QQ(-1), QQ(0)], + ... [QQ(-1), QQ(2), QQ(-1)], + ... [QQ(0), QQ(0), QQ(2)]], (3, 3), QQ) + >>> A.inv() + DomainMatrix([[2/3, 1/3, 1/6], [1/3, 2/3, 1/3], [0, 0, 1/2]], (3, 3), QQ) + + See Also + ======== + + neg + + """ + if not self.domain.is_Field: + raise DMNotAField('Not a field') + m, n = self.shape + if m != n: + raise DMNonSquareMatrixError + inv = self.rep.inv() + return self.from_rep(inv) + + def det(self): + r""" + Returns the determinant of a square :class:`DomainMatrix`. + + Returns + ======= + + determinant: DomainElement + Determinant of the matrix. + + Raises + ====== + + ValueError + If the domain of DomainMatrix is not a Field + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + + >>> A.det() + -2 + + """ + m, n = self.shape + if m != n: + raise DMNonSquareMatrixError + return self.rep.det() + + def adj_det(self): + """ + Adjugate and determinant of a square :class:`DomainMatrix`. + + Returns + ======= + + (adjugate, determinant) : (DomainMatrix, DomainScalar) + The adjugate matrix and determinant of this matrix. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DM + >>> A = DM([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], ZZ) + >>> adjA, detA = A.adj_det() + >>> adjA + DomainMatrix([[4, -2], [-3, 1]], (2, 2), ZZ) + >>> detA + -2 + + See Also + ======== + + adjugate + Returns only the adjugate matrix. + det + Returns only the determinant. + inv_den + Returns a matrix/denominator pair representing the inverse matrix + but perhaps differing from the adjugate and determinant by a common + factor. + """ + m, n = self.shape + I_m = self.eye((m, m), self.domain) + adjA, detA = self.solve_den_charpoly(I_m, check=False) + if self.rep.fmt == "dense": + adjA = adjA.to_dense() + return adjA, detA + + def adjugate(self): + """ + Adjugate of a square :class:`DomainMatrix`. + + The adjugate matrix is the transpose of the cofactor matrix and is + related to the inverse by:: + + adj(A) = det(A) * A.inv() + + Unlike the inverse matrix the adjugate matrix can be computed and + expressed without division or fractions in the ground domain. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DM + >>> A = DM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], ZZ) + >>> A.adjugate() + DomainMatrix([[4, -2], [-3, 1]], (2, 2), ZZ) + + Returns + ======= + + DomainMatrix + The adjugate matrix of this matrix with the same domain. + + See Also + ======== + + adj_det + """ + adjA, detA = self.adj_det() + return adjA + + def inv_den(self, method=None): + """ + Return the inverse as a :class:`DomainMatrix` with denominator. + + Returns + ======= + + (inv, den) : (:class:`DomainMatrix`, :class:`~.DomainElement`) + The inverse matrix and its denominator. + + This is more or less equivalent to :meth:`adj_det` except that ``inv`` + and ``den`` are not guaranteed to be the adjugate and inverse. The + ratio ``inv/den`` is equivalent to ``adj/det`` but some factors + might be cancelled between ``inv`` and ``den``. In simple cases this + might just be a minus sign so that ``(inv, den) == (-adj, -det)`` but + factors more complicated than ``-1`` can also be cancelled. + Cancellation is not guaranteed to be complete so ``inv`` and ``den`` + may not be on lowest terms. The denominator ``den`` will be zero if and + only if the determinant is zero. + + If the actual adjugate and determinant are needed, use :meth:`adj_det` + instead. If the intention is to compute the inverse matrix or solve a + system of equations then :meth:`inv_den` is more efficient. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(2), ZZ(-1), ZZ(0)], + ... [ZZ(-1), ZZ(2), ZZ(-1)], + ... [ZZ(0), ZZ(0), ZZ(2)]], (3, 3), ZZ) + >>> Ainv, den = A.inv_den() + >>> den + 6 + >>> Ainv + DomainMatrix([[4, 2, 1], [2, 4, 2], [0, 0, 3]], (3, 3), ZZ) + >>> A * Ainv == den * A.eye(A.shape, A.domain).to_dense() + True + + Parameters + ========== + + method : str, optional + The method to use to compute the inverse. Can be one of ``None``, + ``'rref'`` or ``'charpoly'``. If ``None`` then the method is + chosen automatically (see :meth:`solve_den` for details). + + See Also + ======== + + inv + det + adj_det + solve_den + """ + I = self.eye(self.shape, self.domain) + return self.solve_den(I, method=method) + + def solve_den(self, b, method=None): + """ + Solve matrix equation $Ax = b$ without fractions in the ground domain. + + Examples + ======== + + Solve a matrix equation over the integers: + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DM + >>> A = DM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], ZZ) + >>> b = DM([[ZZ(5)], [ZZ(6)]], ZZ) + >>> xnum, xden = A.solve_den(b) + >>> xden + -2 + >>> xnum + DomainMatrix([[8], [-9]], (2, 1), ZZ) + >>> A * xnum == xden * b + True + + Solve a matrix equation over a polynomial ring: + + >>> from sympy import ZZ + >>> from sympy.abc import x, y, z, a, b + >>> R = ZZ[x, y, z, a, b] + >>> M = DM([[x*y, x*z], [y*z, x*z]], R) + >>> b = DM([[a], [b]], R) + >>> M.to_Matrix() + Matrix([ + [x*y, x*z], + [y*z, x*z]]) + >>> b.to_Matrix() + Matrix([ + [a], + [b]]) + >>> xnum, xden = M.solve_den(b) + >>> xden + x**2*y*z - x*y*z**2 + >>> xnum.to_Matrix() + Matrix([ + [ a*x*z - b*x*z], + [-a*y*z + b*x*y]]) + >>> M * xnum == xden * b + True + + The solution can be expressed over a fraction field which will cancel + gcds between the denominator and the elements of the numerator: + + >>> xsol = xnum.to_field() / xden + >>> xsol.to_Matrix() + Matrix([ + [ (a - b)/(x*y - y*z)], + [(-a*z + b*x)/(x**2*z - x*z**2)]]) + >>> (M * xsol).to_Matrix() == b.to_Matrix() + True + + When solving a large system of equations this cancellation step might + be a lot slower than :func:`solve_den` itself. The solution can also be + expressed as a ``Matrix`` without attempting any polynomial + cancellation between the numerator and denominator giving a less + simplified result more quickly: + + >>> xsol_uncancelled = xnum.to_Matrix() / xnum.domain.to_sympy(xden) + >>> xsol_uncancelled + Matrix([ + [ (a*x*z - b*x*z)/(x**2*y*z - x*y*z**2)], + [(-a*y*z + b*x*y)/(x**2*y*z - x*y*z**2)]]) + >>> from sympy import cancel + >>> cancel(xsol_uncancelled) == xsol.to_Matrix() + True + + Parameters + ========== + + self : :class:`DomainMatrix` + The ``m x n`` matrix $A$ in the equation $Ax = b$. Underdetermined + systems are not supported so ``m >= n``: $A$ should be square or + have more rows than columns. + b : :class:`DomainMatrix` + The ``n x m`` matrix $b$ for the rhs. + cp : list of :class:`~.DomainElement`, optional + The characteristic polynomial of the matrix $A$. If not given, it + will be computed using :meth:`charpoly`. + method: str, optional + The method to use for solving the system. Can be one of ``None``, + ``'charpoly'`` or ``'rref'``. If ``None`` (the default) then the + method will be chosen automatically. + + The ``charpoly`` method uses :meth:`solve_den_charpoly` and can + only be used if the matrix is square. This method is division free + and can be used with any domain. + + The ``rref`` method is fraction free but requires exact division + in the ground domain (``exquo``). This is also suitable for most + domains. This method can be used with overdetermined systems (more + equations than unknowns) but not underdetermined systems as a + unique solution is sought. + + Returns + ======= + + (xnum, xden) : (DomainMatrix, DomainElement) + The solution of the equation $Ax = b$ as a pair consisting of an + ``n x m`` matrix numerator ``xnum`` and a scalar denominator + ``xden``. + + The solution $x$ is given by ``x = xnum / xden``. The division free + invariant is ``A * xnum == xden * b``. If $A$ is square then the + denominator ``xden`` will be a divisor of the determinant $det(A)$. + + Raises + ====== + + DMNonInvertibleMatrixError + If the system $Ax = b$ does not have a unique solution. + + See Also + ======== + + solve_den_charpoly + solve_den_rref + inv_den + """ + m, n = self.shape + bm, bn = b.shape + + if m != bm: + raise DMShapeError("Matrix equation shape mismatch.") + + if method is None: + method = 'rref' + elif method == 'charpoly' and m != n: + raise DMNonSquareMatrixError("method='charpoly' requires a square matrix.") + + if method == 'charpoly': + xnum, xden = self.solve_den_charpoly(b) + elif method == 'rref': + xnum, xden = self.solve_den_rref(b) + else: + raise DMBadInputError("method should be 'rref' or 'charpoly'") + + return xnum, xden + + def solve_den_rref(self, b): + """ + Solve matrix equation $Ax = b$ using fraction-free RREF + + Solves the matrix equation $Ax = b$ for $x$ and returns the solution + as a numerator/denominator pair. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DM + >>> A = DM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], ZZ) + >>> b = DM([[ZZ(5)], [ZZ(6)]], ZZ) + >>> xnum, xden = A.solve_den_rref(b) + >>> xden + -2 + >>> xnum + DomainMatrix([[8], [-9]], (2, 1), ZZ) + >>> A * xnum == xden * b + True + + See Also + ======== + + solve_den + solve_den_charpoly + """ + A = self + m, n = A.shape + bm, bn = b.shape + + if m != bm: + raise DMShapeError("Matrix equation shape mismatch.") + + if m < n: + raise DMShapeError("Underdetermined matrix equation.") + + Aaug = A.hstack(b) + Aaug_rref, denom, pivots = Aaug.rref_den() + + # XXX: We check here if there are pivots after the last column. If + # there were than it possibly means that rref_den performed some + # unnecessary elimination. It would be better if rref methods had a + # parameter indicating how many columns should be used for elimination. + if len(pivots) != n or pivots and pivots[-1] >= n: + raise DMNonInvertibleMatrixError("Non-unique solution.") + + xnum = Aaug_rref[:n, n:] + xden = denom + + return xnum, xden + + def solve_den_charpoly(self, b, cp=None, check=True): + """ + Solve matrix equation $Ax = b$ using the characteristic polynomial. + + This method solves the square matrix equation $Ax = b$ for $x$ using + the characteristic polynomial without any division or fractions in the + ground domain. + + Examples + ======== + + Solve a matrix equation over the integers: + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DM + >>> A = DM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], ZZ) + >>> b = DM([[ZZ(5)], [ZZ(6)]], ZZ) + >>> xnum, detA = A.solve_den_charpoly(b) + >>> detA + -2 + >>> xnum + DomainMatrix([[8], [-9]], (2, 1), ZZ) + >>> A * xnum == detA * b + True + + Parameters + ========== + + self : DomainMatrix + The ``n x n`` matrix `A` in the equation `Ax = b`. Must be square + and invertible. + b : DomainMatrix + The ``n x m`` matrix `b` for the rhs. + cp : list, optional + The characteristic polynomial of the matrix `A` if known. If not + given, it will be computed using :meth:`charpoly`. + check : bool, optional + If ``True`` (the default) check that the determinant is not zero + and raise an error if it is. If ``False`` then if the determinant + is zero the return value will be equal to ``(A.adjugate()*b, 0)``. + + Returns + ======= + + (xnum, detA) : (DomainMatrix, DomainElement) + The solution of the equation `Ax = b` as a matrix numerator and + scalar denominator pair. The denominator is equal to the + determinant of `A` and the numerator is ``adj(A)*b``. + + The solution $x$ is given by ``x = xnum / detA``. The division free + invariant is ``A * xnum == detA * b``. + + If ``b`` is the identity matrix, then ``xnum`` is the adjugate matrix + and we have ``A * adj(A) == detA * I``. + + See Also + ======== + + solve_den + Main frontend for solving matrix equations with denominator. + solve_den_rref + Solve matrix equations using fraction-free RREF. + inv_den + Invert a matrix using the characteristic polynomial. + """ + A, b = self.unify(b) + m, n = self.shape + mb, nb = b.shape + + if m != n: + raise DMNonSquareMatrixError("Matrix must be square") + + if mb != m: + raise DMShapeError("Matrix and vector must have the same number of rows") + + f, detA = self.adj_poly_det(cp=cp) + + if check and not detA: + raise DMNonInvertibleMatrixError("Matrix is not invertible") + + # Compute adj(A)*b = det(A)*inv(A)*b using Horner's method without + # constructing inv(A) explicitly. + adjA_b = self.eval_poly_mul(f, b) + + return (adjA_b, detA) + + def adj_poly_det(self, cp=None): + """ + Return the polynomial $p$ such that $p(A) = adj(A)$ and also the + determinant of $A$. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DM + >>> A = DM([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], QQ) + >>> p, detA = A.adj_poly_det() + >>> p + [-1, 5] + >>> p_A = A.eval_poly(p) + >>> p_A + DomainMatrix([[4, -2], [-3, 1]], (2, 2), QQ) + >>> p[0]*A**1 + p[1]*A**0 == p_A + True + >>> p_A == A.adjugate() + True + >>> A * A.adjugate() == detA * A.eye(A.shape, A.domain).to_dense() + True + + See Also + ======== + + adjugate + eval_poly + adj_det + """ + + # Cayley-Hamilton says that a matrix satisfies its own minimal + # polynomial + # + # p[0]*A^n + p[1]*A^(n-1) + ... + p[n]*I = 0 + # + # with p[0]=1 and p[n]=(-1)^n*det(A) or + # + # det(A)*I = -(-1)^n*(p[0]*A^(n-1) + p[1]*A^(n-2) + ... + p[n-1]*A). + # + # Define a new polynomial f with f[i] = -(-1)^n*p[i] for i=0..n-1. Then + # + # det(A)*I = f[0]*A^n + f[1]*A^(n-1) + ... + f[n-1]*A. + # + # Multiplying on the right by inv(A) gives + # + # det(A)*inv(A) = f[0]*A^(n-1) + f[1]*A^(n-2) + ... + f[n-1]. + # + # So adj(A) = det(A)*inv(A) = f(A) + + A = self + m, n = self.shape + + if m != n: + raise DMNonSquareMatrixError("Matrix must be square") + + if cp is None: + cp = A.charpoly() + + if len(cp) % 2: + # n is even + detA = cp[-1] + f = [-cpi for cpi in cp[:-1]] + else: + # n is odd + detA = -cp[-1] + f = cp[:-1] + + return f, detA + + def eval_poly(self, p): + """ + Evaluate polynomial function of a matrix $p(A)$. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DM + >>> A = DM([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], QQ) + >>> p = [QQ(1), QQ(2), QQ(3)] + >>> p_A = A.eval_poly(p) + >>> p_A + DomainMatrix([[12, 14], [21, 33]], (2, 2), QQ) + >>> p_A == p[0]*A**2 + p[1]*A + p[2]*A**0 + True + + See Also + ======== + + eval_poly_mul + """ + A = self + m, n = A.shape + + if m != n: + raise DMNonSquareMatrixError("Matrix must be square") + + if not p: + return self.zeros(self.shape, self.domain) + elif len(p) == 1: + return p[0] * self.eye(self.shape, self.domain) + + # Evaluate p(A) using Horner's method: + # XXX: Use Paterson-Stockmeyer method? + I = A.eye(A.shape, A.domain) + p_A = p[0] * I + for pi in p[1:]: + p_A = A*p_A + pi*I + + return p_A + + def eval_poly_mul(self, p, B): + r""" + Evaluate polynomial matrix product $p(A) \times B$. + + Evaluate the polynomial matrix product $p(A) \times B$ using Horner's + method without creating the matrix $p(A)$ explicitly. If $B$ is a + column matrix then this method will only use matrix-vector multiplies + and no matrix-matrix multiplies are needed. + + If $B$ is square or wide or if $A$ can be represented in a simpler + domain than $B$ then it might be faster to evaluate $p(A)$ explicitly + (see :func:`eval_poly`) and then multiply with $B$. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DM + >>> A = DM([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], QQ) + >>> b = DM([[QQ(5)], [QQ(6)]], QQ) + >>> p = [QQ(1), QQ(2), QQ(3)] + >>> p_A_b = A.eval_poly_mul(p, b) + >>> p_A_b + DomainMatrix([[144], [303]], (2, 1), QQ) + >>> p_A_b == p[0]*A**2*b + p[1]*A*b + p[2]*b + True + >>> A.eval_poly_mul(p, b) == A.eval_poly(p)*b + True + + See Also + ======== + + eval_poly + solve_den_charpoly + """ + A = self + m, n = A.shape + mb, nb = B.shape + + if m != n: + raise DMNonSquareMatrixError("Matrix must be square") + + if mb != n: + raise DMShapeError("Matrices are not aligned") + + if A.domain != B.domain: + raise DMDomainError("Matrices must have the same domain") + + # Given a polynomial p(x) = p[0]*x^n + p[1]*x^(n-1) + ... + p[n-1] + # and matrices A and B we want to find + # + # p(A)*B = p[0]*A^n*B + p[1]*A^(n-1)*B + ... + p[n-1]*B + # + # Factoring out A term by term we get + # + # p(A)*B = A*(...A*(A*(A*(p[0]*B) + p[1]*B) + p[2]*B) + ...) + p[n-1]*B + # + # where each pair of brackets represents one iteration of the loop + # below starting from the innermost p[0]*B. If B is a column matrix + # then products like A*(...) are matrix-vector multiplies and products + # like p[i]*B are scalar-vector multiplies so there are no + # matrix-matrix multiplies. + + if not p: + return B.zeros(B.shape, B.domain, fmt=B.rep.fmt) + + p_A_B = p[0]*B + + for p_i in p[1:]: + p_A_B = A*p_A_B + p_i*B + + return p_A_B + + def lu(self): + r""" + Returns Lower and Upper decomposition of the DomainMatrix + + Returns + ======= + + (L, U, exchange) + L, U are Lower and Upper decomposition of the DomainMatrix, + exchange is the list of indices of rows exchanged in the + decomposition. + + Raises + ====== + + ValueError + If the domain of DomainMatrix not a Field + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [QQ(1), QQ(-1)], + ... [QQ(2), QQ(-2)]], (2, 2), QQ) + >>> L, U, exchange = A.lu() + >>> L + DomainMatrix([[1, 0], [2, 1]], (2, 2), QQ) + >>> U + DomainMatrix([[1, -1], [0, 0]], (2, 2), QQ) + >>> exchange + [] + + See Also + ======== + + lu_solve + + """ + if not self.domain.is_Field: + raise DMNotAField('Not a field') + L, U, swaps = self.rep.lu() + return self.from_rep(L), self.from_rep(U), swaps + + def qr(self): + r""" + QR decomposition of the DomainMatrix. + + Explanation + =========== + + The QR decomposition expresses a matrix as the product of an orthogonal + matrix (Q) and an upper triangular matrix (R). In this implementation, + Q is not orthonormal: its columns are orthogonal but not normalized to + unit vectors. This avoids unnecessary divisions and is particularly + suited for exact arithmetic domains. + + Note + ==== + + This implementation is valid only for matrices over real domains. For + matrices over complex domains, a proper QR decomposition would require + handling conjugation to ensure orthogonality. + + Returns + ======= + + (Q, R) + Q is the orthogonal matrix, and R is the upper triangular matrix + resulting from the QR decomposition of the DomainMatrix. + + Raises + ====== + + DMDomainError + If the domain of the DomainMatrix is not a field (e.g., QQ). + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([[1, 2], [3, 4], [5, 6]], (3, 2), QQ) + >>> Q, R = A.qr() + >>> Q + DomainMatrix([[1, 26/35], [3, 8/35], [5, -2/7]], (3, 2), QQ) + >>> R + DomainMatrix([[1, 44/35], [0, 1]], (2, 2), QQ) + >>> Q * R == A + True + >>> (Q.transpose() * Q).is_diagonal + True + >>> R.is_upper + True + + See Also + ======== + + lu + + """ + ddm_q, ddm_r = self.rep.qr() + Q = self.from_rep(ddm_q) + R = self.from_rep(ddm_r) + return Q, R + + def lu_solve(self, rhs): + r""" + Solver for DomainMatrix x in the A*x = B + + Parameters + ========== + + rhs : DomainMatrix B + + Returns + ======= + + DomainMatrix + x in A*x = B + + Raises + ====== + + DMShapeError + If the DomainMatrix A and rhs have different number of rows + + ValueError + If the domain of DomainMatrix A not a Field + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [QQ(1), QQ(2)], + ... [QQ(3), QQ(4)]], (2, 2), QQ) + >>> B = DomainMatrix([ + ... [QQ(1), QQ(1)], + ... [QQ(0), QQ(1)]], (2, 2), QQ) + + >>> A.lu_solve(B) + DomainMatrix([[-2, -1], [3/2, 1]], (2, 2), QQ) + + See Also + ======== + + lu + + """ + if self.shape[0] != rhs.shape[0]: + raise DMShapeError("Shape") + if not self.domain.is_Field: + raise DMNotAField('Not a field') + sol = self.rep.lu_solve(rhs.rep) + return self.from_rep(sol) + + def fflu(self): + """ + Fraction-free LU decomposition of DomainMatrix. + + Explanation + =========== + + This method computes the PLDU decomposition + using Gauss-Bareiss elimination in a fraction-free manner, + it ensures that all intermediate results remain in + the domain of the input matrix. Unlike standard + LU decomposition, which introduces division, this approach + avoids fractions, making it particularly suitable + for exact arithmetic over integers or polynomials. + + This method satisfies the invariant: + + P * A = L * inv(D) * U + + Returns + ======= + + (P, L, D, U) + - P (Permutation matrix) + - L (Lower triangular matrix) + - D (Diagonal matrix) + - U (Upper triangular matrix) + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ) + >>> P, L, D, U = A.fflu() + >>> P + DomainMatrix([[1, 0], [0, 1]], (2, 2), ZZ) + >>> L + DomainMatrix([[1, 0], [3, -2]], (2, 2), ZZ) + >>> D + DomainMatrix([[1, 0], [0, -2]], (2, 2), ZZ) + >>> U + DomainMatrix([[1, 2], [0, -2]], (2, 2), ZZ) + >>> L.is_lower and U.is_upper and D.is_diagonal + True + >>> L * D.to_field().inv() * U == P * A.to_field() + True + >>> I, d = D.inv_den() + >>> L * I * U == d * P * A + True + + See Also + ======== + + sympy.polys.matrices.ddm.DDM.fflu + + References + ========== + + .. [1] Nakos, G. C., Turner, P. R., & Williams, R. M. (1997). Fraction-free + algorithms for linear and polynomial equations. ACM SIGSAM Bulletin, + 31(3), 11-19. https://doi.org/10.1145/271130.271133 + .. [2] Middeke, J.; Jeffrey, D.J.; Koutschan, C. (2020), "Common Factors + in Fraction-Free Matrix Decompositions", Mathematics in Computer Science, + 15 (4): 589–608, arXiv:2005.12380, doi:10.1007/s11786-020-00495-9 + .. [3] https://en.wikipedia.org/wiki/Bareiss_algorithm + """ + from_rep = self.from_rep + P, L, D, U = self.rep.fflu() + return from_rep(P), from_rep(L), from_rep(D), from_rep(U) + + def _solve(A, b): + # XXX: Not sure about this method or its signature. It is just created + # because it is needed by the holonomic module. + if A.shape[0] != b.shape[0]: + raise DMShapeError("Shape") + if A.domain != b.domain or not A.domain.is_Field: + raise DMNotAField('Not a field') + Aaug = A.hstack(b) + Arref, pivots = Aaug.rref() + particular = Arref.from_rep(Arref.rep.particular()) + nullspace_rep, nonpivots = Arref[:,:-1].rep.nullspace() + nullspace = Arref.from_rep(nullspace_rep) + return particular, nullspace + + def charpoly(self): + r""" + Characteristic polynomial of a square matrix. + + Computes the characteristic polynomial in a fully expanded form using + division free arithmetic. If a factorization of the characteristic + polynomial is needed then it is more efficient to call + :meth:`charpoly_factor_list` than calling :meth:`charpoly` and then + factorizing the result. + + Returns + ======= + + list: list of DomainElement + coefficients of the characteristic polynomial + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + + >>> A.charpoly() + [1, -5, -2] + + See Also + ======== + + charpoly_factor_list + Compute the factorisation of the characteristic polynomial. + charpoly_factor_blocks + A partial factorisation of the characteristic polynomial that can + be computed more efficiently than either the full factorisation or + the fully expanded polynomial. + """ + M = self + K = M.domain + + factors = M.charpoly_factor_blocks() + + cp = [K.one] + + for f, mult in factors: + for _ in range(mult): + cp = dup_mul(cp, f, K) + + return cp + + def charpoly_factor_list(self): + """ + Full factorization of the characteristic polynomial. + + Examples + ======== + + >>> from sympy.polys.matrices import DM + >>> from sympy import ZZ + >>> M = DM([[6, -1, 0, 0], + ... [9, 12, 0, 0], + ... [0, 0, 1, 2], + ... [0, 0, 5, 6]], ZZ) + + Compute the factorization of the characteristic polynomial: + + >>> M.charpoly_factor_list() + [([1, -9], 2), ([1, -7, -4], 1)] + + Use :meth:`charpoly` to get the unfactorized characteristic polynomial: + + >>> M.charpoly() + [1, -25, 203, -495, -324] + + The same calculations with ``Matrix``: + + >>> M.to_Matrix().charpoly().as_expr() + lambda**4 - 25*lambda**3 + 203*lambda**2 - 495*lambda - 324 + >>> M.to_Matrix().charpoly().as_expr().factor() + (lambda - 9)**2*(lambda**2 - 7*lambda - 4) + + Returns + ======= + + list: list of pairs (factor, multiplicity) + A full factorization of the characteristic polynomial. + + See Also + ======== + + charpoly + Expanded form of the characteristic polynomial. + charpoly_factor_blocks + A partial factorisation of the characteristic polynomial that can + be computed more efficiently. + """ + M = self + K = M.domain + + # It is more efficient to start from the partial factorization provided + # for free by M.charpoly_factor_blocks than the expanded M.charpoly. + factors = M.charpoly_factor_blocks() + + factors_irreducible = [] + + for factor_i, mult_i in factors: + + _, factors_list = dup_factor_list(factor_i, K) + + for factor_j, mult_j in factors_list: + factors_irreducible.append((factor_j, mult_i * mult_j)) + + return _collect_factors(factors_irreducible) + + def charpoly_factor_blocks(self): + """ + Partial factorisation of the characteristic polynomial. + + This factorisation arises from a block structure of the matrix (if any) + and so the factors are not guaranteed to be irreducible. The + :meth:`charpoly_factor_blocks` method is the most efficient way to get + a representation of the characteristic polynomial but the result is + neither fully expanded nor fully factored. + + Examples + ======== + + >>> from sympy.polys.matrices import DM + >>> from sympy import ZZ + >>> M = DM([[6, -1, 0, 0], + ... [9, 12, 0, 0], + ... [0, 0, 1, 2], + ... [0, 0, 5, 6]], ZZ) + + This computes a partial factorization using only the block structure of + the matrix to reveal factors: + + >>> M.charpoly_factor_blocks() + [([1, -18, 81], 1), ([1, -7, -4], 1)] + + These factors correspond to the two diagonal blocks in the matrix: + + >>> DM([[6, -1], [9, 12]], ZZ).charpoly() + [1, -18, 81] + >>> DM([[1, 2], [5, 6]], ZZ).charpoly() + [1, -7, -4] + + Use :meth:`charpoly_factor_list` to get a complete factorization into + irreducibles: + + >>> M.charpoly_factor_list() + [([1, -9], 2), ([1, -7, -4], 1)] + + Use :meth:`charpoly` to get the expanded characteristic polynomial: + + >>> M.charpoly() + [1, -25, 203, -495, -324] + + Returns + ======= + + list: list of pairs (factor, multiplicity) + A partial factorization of the characteristic polynomial. + + See Also + ======== + + charpoly + Compute the fully expanded characteristic polynomial. + charpoly_factor_list + Compute a full factorization of the characteristic polynomial. + """ + M = self + + if not M.is_square: + raise DMNonSquareMatrixError("not square") + + # scc returns indices that permute the matrix into block triangular + # form and can extract the diagonal blocks. M.charpoly() is equal to + # the product of the diagonal block charpolys. + components = M.scc() + + block_factors = [] + + for indices in components: + block = M.extract(indices, indices) + block_factors.append((block.charpoly_base(), 1)) + + return _collect_factors(block_factors) + + def charpoly_base(self): + """ + Base case for :meth:`charpoly_factor_blocks` after block decomposition. + + This method is used internally by :meth:`charpoly_factor_blocks` as the + base case for computing the characteristic polynomial of a block. It is + more efficient to call :meth:`charpoly_factor_blocks`, :meth:`charpoly` + or :meth:`charpoly_factor_list` rather than call this method directly. + + This will use either the dense or the sparse implementation depending + on the sparsity of the matrix and will clear denominators if possible + before calling :meth:`charpoly_berk` to compute the characteristic + polynomial using the Berkowitz algorithm. + + See Also + ======== + + charpoly + charpoly_factor_list + charpoly_factor_blocks + charpoly_berk + """ + M = self + K = M.domain + + # It seems that the sparse implementation is always faster for random + # matrices with fewer than 50% non-zero entries. This does not seem to + # depend on domain, size, bit count etc. + density = self.nnz() / self.shape[0]**2 + if density < 0.5: + M = M.to_sparse() + else: + M = M.to_dense() + + # Clearing denominators is always more efficient if it can be done. + # Doing it here after block decomposition is good because each block + # might have a smaller denominator. However it might be better for + # charpoly and charpoly_factor_list to restore the denominators only at + # the very end so that they can call e.g. dup_factor_list before + # restoring the denominators. The methods would need to be changed to + # return (poly, denom) pairs to make that work though. + clear_denoms = K.is_Field and K.has_assoc_Ring + + if clear_denoms: + clear_denoms = True + d, M = M.clear_denoms(convert=True) + d = d.element + K_f = K + K_r = M.domain + + # Berkowitz algorithm over K_r. + cp = M.charpoly_berk() + + if clear_denoms: + # Restore the denominator in the charpoly over K_f. + # + # If M = N/d then p_M(x) = p_N(x*d)/d^n. + cp = dup_convert(cp, K_r, K_f) + p = [K_f.one, K_f.zero] + q = [K_f.one/d] + cp = dup_transform(cp, p, q, K_f) + + return cp + + def charpoly_berk(self): + """Compute the characteristic polynomial using the Berkowitz algorithm. + + This method directly calls the underlying implementation of the + Berkowitz algorithm (:meth:`sympy.polys.matrices.dense.ddm_berk` or + :meth:`sympy.polys.matrices.sdm.sdm_berk`). + + This is used by :meth:`charpoly` and other methods as the base case for + for computing the characteristic polynomial. However those methods will + apply other optimizations such as block decomposition, clearing + denominators and converting between dense and sparse representations + before calling this method. It is more efficient to call those methods + instead of this one but this method is provided for direct access to + the Berkowitz algorithm. + + Examples + ======== + + >>> from sympy.polys.matrices import DM + >>> from sympy import QQ + >>> M = DM([[6, -1, 0, 0], + ... [9, 12, 0, 0], + ... [0, 0, 1, 2], + ... [0, 0, 5, 6]], QQ) + >>> M.charpoly_berk() + [1, -25, 203, -495, -324] + + See Also + ======== + + charpoly + charpoly_base + charpoly_factor_list + charpoly_factor_blocks + sympy.polys.matrices.dense.ddm_berk + sympy.polys.matrices.sdm.sdm_berk + """ + return self.rep.charpoly() + + @classmethod + def eye(cls, shape, domain): + r""" + Return identity matrix of size n or shape (m, n). + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy import QQ + >>> DomainMatrix.eye(3, QQ) + DomainMatrix({0: {0: 1}, 1: {1: 1}, 2: {2: 1}}, (3, 3), QQ) + + """ + if isinstance(shape, int): + shape = (shape, shape) + return cls.from_rep(SDM.eye(shape, domain)) + + @classmethod + def diag(cls, diagonal, domain, shape=None): + r""" + Return diagonal matrix with entries from ``diagonal``. + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy import ZZ + >>> DomainMatrix.diag([ZZ(5), ZZ(6)], ZZ) + DomainMatrix({0: {0: 5}, 1: {1: 6}}, (2, 2), ZZ) + + """ + if shape is None: + N = len(diagonal) + shape = (N, N) + return cls.from_rep(SDM.diag(diagonal, domain, shape)) + + @classmethod + def zeros(cls, shape, domain, *, fmt='sparse'): + """Returns a zero DomainMatrix of size shape, belonging to the specified domain + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy import QQ + >>> DomainMatrix.zeros((2, 3), QQ) + DomainMatrix({}, (2, 3), QQ) + + """ + return cls.from_rep(SDM.zeros(shape, domain)) + + @classmethod + def ones(cls, shape, domain): + """Returns a DomainMatrix of 1s, of size shape, belonging to the specified domain + + Examples + ======== + + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy import QQ + >>> DomainMatrix.ones((2,3), QQ) + DomainMatrix([[1, 1, 1], [1, 1, 1]], (2, 3), QQ) + + """ + return cls.from_rep(DDM.ones(shape, domain).to_dfm_or_ddm()) + + def __eq__(A, B): + r""" + Checks for two DomainMatrix matrices to be equal or not + + Parameters + ========== + + A, B: DomainMatrix + to check equality + + Returns + ======= + + Boolean + True for equal, else False + + Raises + ====== + + NotImplementedError + If B is not a DomainMatrix + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> A = DomainMatrix([ + ... [ZZ(1), ZZ(2)], + ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) + >>> B = DomainMatrix([ + ... [ZZ(1), ZZ(1)], + ... [ZZ(0), ZZ(1)]], (2, 2), ZZ) + >>> A.__eq__(A) + True + >>> A.__eq__(B) + False + + """ + if not isinstance(A, type(B)): + return NotImplemented + return A.domain == B.domain and A.rep == B.rep + + def unify_eq(A, B): + if A.shape != B.shape: + return False + if A.domain != B.domain: + A, B = A.unify(B) + return A == B + + def lll(A, delta=QQ(3, 4)): + """ + Performs the Lenstra–Lenstra–Lovász (LLL) basis reduction algorithm. + See [1]_ and [2]_. + + Parameters + ========== + + delta : QQ, optional + The Lovász parameter. Must be in the interval (0.25, 1), with larger + values producing a more reduced basis. The default is 0.75 for + historical reasons. + + Returns + ======= + + The reduced basis as a DomainMatrix over ZZ. + + Throws + ====== + + DMValueError: if delta is not in the range (0.25, 1) + DMShapeError: if the matrix is not of shape (m, n) with m <= n + DMDomainError: if the matrix domain is not ZZ + DMRankError: if the matrix contains linearly dependent rows + + Examples + ======== + + >>> from sympy.polys.domains import ZZ, QQ + >>> from sympy.polys.matrices import DM + >>> x = DM([[1, 0, 0, 0, -20160], + ... [0, 1, 0, 0, 33768], + ... [0, 0, 1, 0, 39578], + ... [0, 0, 0, 1, 47757]], ZZ) + >>> y = DM([[10, -3, -2, 8, -4], + ... [3, -9, 8, 1, -11], + ... [-3, 13, -9, -3, -9], + ... [-12, -7, -11, 9, -1]], ZZ) + >>> assert x.lll(delta=QQ(5, 6)) == y + + Notes + ===== + + The implementation is derived from the Maple code given in Figures 4.3 + and 4.4 of [3]_ (pp.68-69). It uses the efficient method of only calculating + state updates as they are required. + + See also + ======== + + lll_transform + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Lenstra%E2%80%93Lenstra%E2%80%93Lov%C3%A1sz_lattice_basis_reduction_algorithm + .. [2] https://web.archive.org/web/20221029115428/https://web.cs.elte.hu/~lovasz/scans/lll.pdf + .. [3] Murray R. Bremner, "Lattice Basis Reduction: An Introduction to the LLL Algorithm and Its Applications" + + """ + return DomainMatrix.from_rep(A.rep.lll(delta=delta)) + + def lll_transform(A, delta=QQ(3, 4)): + """ + Performs the Lenstra–Lenstra–Lovász (LLL) basis reduction algorithm + and returns the reduced basis and transformation matrix. + + Explanation + =========== + + Parameters, algorithm and basis are the same as for :meth:`lll` except that + the return value is a tuple `(B, T)` with `B` the reduced basis and + `T` a transformation matrix. The original basis `A` is transformed to + `B` with `T*A == B`. If only `B` is needed then :meth:`lll` should be + used as it is a little faster. + + Examples + ======== + + >>> from sympy.polys.domains import ZZ, QQ + >>> from sympy.polys.matrices import DM + >>> X = DM([[1, 0, 0, 0, -20160], + ... [0, 1, 0, 0, 33768], + ... [0, 0, 1, 0, 39578], + ... [0, 0, 0, 1, 47757]], ZZ) + >>> B, T = X.lll_transform(delta=QQ(5, 6)) + >>> T * X == B + True + + See also + ======== + + lll + + """ + reduced, transform = A.rep.lll_transform(delta=delta) + return DomainMatrix.from_rep(reduced), DomainMatrix.from_rep(transform) + + +def _collect_factors(factors_list): + """ + Collect repeating factors and sort. + + >>> from sympy.polys.matrices.domainmatrix import _collect_factors + >>> _collect_factors([([1, 2], 2), ([1, 4], 3), ([1, 2], 5)]) + [([1, 4], 3), ([1, 2], 7)] + """ + factors = Counter() + for factor, exponent in factors_list: + factors[tuple(factor)] += exponent + + factors_list = [(list(f), e) for f, e in factors.items()] + + return _sort_factors(factors_list) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/domainscalar.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/domainscalar.py new file mode 100644 index 0000000000000000000000000000000000000000..df439a60a0ea0df5f6fac988c06da2a06a4fbac2 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/domainscalar.py @@ -0,0 +1,122 @@ +""" + +Module for the DomainScalar class. + +A DomainScalar represents an element which is in a particular +Domain. The idea is that the DomainScalar class provides the +convenience routines for unifying elements with different domains. + +It assists in Scalar Multiplication and getitem for DomainMatrix. + +""" +from ..constructor import construct_domain + +from sympy.polys.domains import Domain, ZZ + + +class DomainScalar: + r""" + docstring + """ + + def __new__(cls, element, domain): + if not isinstance(domain, Domain): + raise TypeError("domain should be of type Domain") + if not domain.of_type(element): + raise TypeError("element %s should be in domain %s" % (element, domain)) + return cls.new(element, domain) + + @classmethod + def new(cls, element, domain): + obj = super().__new__(cls) + obj.element = element + obj.domain = domain + return obj + + def __repr__(self): + return repr(self.element) + + @classmethod + def from_sympy(cls, expr): + [domain, [element]] = construct_domain([expr]) + return cls.new(element, domain) + + def to_sympy(self): + return self.domain.to_sympy(self.element) + + def to_domain(self, domain): + element = domain.convert_from(self.element, self.domain) + return self.new(element, domain) + + def convert_to(self, domain): + return self.to_domain(domain) + + def unify(self, other): + domain = self.domain.unify(other.domain) + return self.to_domain(domain), other.to_domain(domain) + + def __bool__(self): + return bool(self.element) + + def __add__(self, other): + if not isinstance(other, DomainScalar): + return NotImplemented + self, other = self.unify(other) + return self.new(self.element + other.element, self.domain) + + def __sub__(self, other): + if not isinstance(other, DomainScalar): + return NotImplemented + self, other = self.unify(other) + return self.new(self.element - other.element, self.domain) + + def __mul__(self, other): + if not isinstance(other, DomainScalar): + if isinstance(other, int): + other = DomainScalar(ZZ(other), ZZ) + else: + return NotImplemented + + self, other = self.unify(other) + return self.new(self.element * other.element, self.domain) + + def __floordiv__(self, other): + if not isinstance(other, DomainScalar): + return NotImplemented + self, other = self.unify(other) + return self.new(self.domain.quo(self.element, other.element), self.domain) + + def __mod__(self, other): + if not isinstance(other, DomainScalar): + return NotImplemented + self, other = self.unify(other) + return self.new(self.domain.rem(self.element, other.element), self.domain) + + def __divmod__(self, other): + if not isinstance(other, DomainScalar): + return NotImplemented + self, other = self.unify(other) + q, r = self.domain.div(self.element, other.element) + return (self.new(q, self.domain), self.new(r, self.domain)) + + def __pow__(self, n): + if not isinstance(n, int): + return NotImplemented + return self.new(self.element**n, self.domain) + + def __pos__(self): + return self.new(+self.element, self.domain) + + def __neg__(self): + return self.new(-self.element, self.domain) + + def __eq__(self, other): + if not isinstance(other, DomainScalar): + return NotImplemented + return self.element == other.element and self.domain == other.domain + + def is_zero(self): + return self.element == self.domain.zero + + def is_one(self): + return self.element == self.domain.one diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/eigen.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/eigen.py new file mode 100644 index 0000000000000000000000000000000000000000..17d673c6ea09002e1cfd5357f301c447a7af4341 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/eigen.py @@ -0,0 +1,90 @@ +""" + +Routines for computing eigenvectors with DomainMatrix. + +""" +from sympy.core.symbol import Dummy + +from ..agca.extensions import FiniteExtension +from ..factortools import dup_factor_list +from ..polyroots import roots +from ..polytools import Poly +from ..rootoftools import CRootOf + +from .domainmatrix import DomainMatrix + + +def dom_eigenvects(A, l=Dummy('lambda')): + charpoly = A.charpoly() + rows, cols = A.shape + domain = A.domain + _, factors = dup_factor_list(charpoly, domain) + + rational_eigenvects = [] + algebraic_eigenvects = [] + for base, exp in factors: + if len(base) == 2: + field = domain + eigenval = -base[1] / base[0] + + EE_items = [ + [eigenval if i == j else field.zero for j in range(cols)] + for i in range(rows)] + EE = DomainMatrix(EE_items, (rows, cols), field) + + basis = (A - EE).nullspace(divide_last=True) + rational_eigenvects.append((field, eigenval, exp, basis)) + else: + minpoly = Poly.from_list(base, l, domain=domain) + field = FiniteExtension(minpoly) + eigenval = field(l) + + AA_items = [ + [Poly.from_list([item], l, domain=domain).rep for item in row] + for row in A.rep.to_ddm()] + AA_items = [[field(item) for item in row] for row in AA_items] + AA = DomainMatrix(AA_items, (rows, cols), field) + EE_items = [ + [eigenval if i == j else field.zero for j in range(cols)] + for i in range(rows)] + EE = DomainMatrix(EE_items, (rows, cols), field) + + basis = (AA - EE).nullspace(divide_last=True) + algebraic_eigenvects.append((field, minpoly, exp, basis)) + + return rational_eigenvects, algebraic_eigenvects + + +def dom_eigenvects_to_sympy( + rational_eigenvects, algebraic_eigenvects, + Matrix, **kwargs +): + result = [] + + for field, eigenvalue, multiplicity, eigenvects in rational_eigenvects: + eigenvects = eigenvects.rep.to_ddm() + eigenvalue = field.to_sympy(eigenvalue) + new_eigenvects = [ + Matrix([field.to_sympy(x) for x in vect]) + for vect in eigenvects] + result.append((eigenvalue, multiplicity, new_eigenvects)) + + for field, minpoly, multiplicity, eigenvects in algebraic_eigenvects: + eigenvects = eigenvects.rep.to_ddm() + l = minpoly.gens[0] + + eigenvects = [[field.to_sympy(x) for x in vect] for vect in eigenvects] + + degree = minpoly.degree() + minpoly = minpoly.as_expr() + eigenvals = roots(minpoly, l, **kwargs) + if len(eigenvals) != degree: + eigenvals = [CRootOf(minpoly, l, idx) for idx in range(degree)] + + for eigenvalue in eigenvals: + new_eigenvects = [ + Matrix([x.subs(l, eigenvalue) for x in vect]) + for vect in eigenvects] + result.append((eigenvalue, multiplicity, new_eigenvects)) + + return result diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/exceptions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..b1e5a4195c66aceed2d5ac1994381d3dec6a64ba --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/exceptions.py @@ -0,0 +1,67 @@ +""" + +Module to define exceptions to be used in sympy.polys.matrices modules and +classes. + +Ideally all exceptions raised in these modules would be defined and documented +here and not e.g. imported from matrices. Also ideally generic exceptions like +ValueError/TypeError would not be raised anywhere. + +""" + + +class DMError(Exception): + """Base class for errors raised by DomainMatrix""" + pass + + +class DMBadInputError(DMError): + """list of lists is inconsistent with shape""" + pass + + +class DMDomainError(DMError): + """domains do not match""" + pass + + +class DMNotAField(DMDomainError): + """domain is not a field""" + pass + + +class DMFormatError(DMError): + """mixed dense/sparse not supported""" + pass + + +class DMNonInvertibleMatrixError(DMError): + """The matrix in not invertible""" + pass + + +class DMRankError(DMError): + """matrix does not have expected rank""" + pass + + +class DMShapeError(DMError): + """shapes are inconsistent""" + pass + + +class DMNonSquareMatrixError(DMShapeError): + """The matrix is not square""" + pass + + +class DMValueError(DMError): + """The value passed is invalid""" + pass + + +__all__ = [ + 'DMError', 'DMBadInputError', 'DMDomainError', 'DMFormatError', + 'DMRankError', 'DMShapeError', 'DMNotAField', + 'DMNonInvertibleMatrixError', 'DMNonSquareMatrixError', 'DMValueError' +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/linsolve.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/linsolve.py new file mode 100644 index 0000000000000000000000000000000000000000..af74058d859b744cf8fe1059ddb7c775fece79c7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/linsolve.py @@ -0,0 +1,230 @@ +# +# sympy.polys.matrices.linsolve module +# +# This module defines the _linsolve function which is the internal workhorse +# used by linsolve. This computes the solution of a system of linear equations +# using the SDM sparse matrix implementation in sympy.polys.matrices.sdm. This +# is a replacement for solve_lin_sys in sympy.polys.solvers which is +# inefficient for large sparse systems due to the use of a PolyRing with many +# generators: +# +# https://github.com/sympy/sympy/issues/20857 +# +# The implementation of _linsolve here handles: +# +# - Extracting the coefficients from the Expr/Eq input equations. +# - Constructing a domain and converting the coefficients to +# that domain. +# - Using the SDM.rref, SDM.nullspace etc methods to generate the full +# solution working with arithmetic only in the domain of the coefficients. +# +# The routines here are particularly designed to be efficient for large sparse +# systems of linear equations although as well as dense systems. It is +# possible that for some small dense systems solve_lin_sys which uses the +# dense matrix implementation DDM will be more efficient. With smaller systems +# though the bulk of the time is spent just preprocessing the inputs and the +# relative time spent in rref is too small to be noticeable. +# + +from collections import defaultdict + +from sympy.core.add import Add +from sympy.core.mul import Mul +from sympy.core.singleton import S + +from sympy.polys.constructor import construct_domain +from sympy.polys.solvers import PolyNonlinearError + +from .sdm import ( + SDM, + sdm_irref, + sdm_particular_from_rref, + sdm_nullspace_from_rref +) + +from sympy.utilities.misc import filldedent + + +def _linsolve(eqs, syms): + + """Solve a linear system of equations. + + Examples + ======== + + Solve a linear system with a unique solution: + + >>> from sympy import symbols, Eq + >>> from sympy.polys.matrices.linsolve import _linsolve + >>> x, y = symbols('x, y') + >>> eqs = [Eq(x + y, 1), Eq(x - y, 2)] + >>> _linsolve(eqs, [x, y]) + {x: 3/2, y: -1/2} + + In the case of underdetermined systems the solution will be expressed in + terms of the unknown symbols that are unconstrained: + + >>> _linsolve([Eq(x + y, 0)], [x, y]) + {x: -y, y: y} + + """ + # Number of unknowns (columns in the non-augmented matrix) + nsyms = len(syms) + + # Convert to sparse augmented matrix (len(eqs) x (nsyms+1)) + eqsdict, const = _linear_eq_to_dict(eqs, syms) + Aaug = sympy_dict_to_dm(eqsdict, const, syms) + K = Aaug.domain + + # sdm_irref has issues with float matrices. This uses the ddm_rref() + # function. When sdm_rref() can handle float matrices reasonably this + # should be removed... + if K.is_RealField or K.is_ComplexField: + Aaug = Aaug.to_ddm().rref()[0].to_sdm() + + # Compute reduced-row echelon form (RREF) + Arref, pivots, nzcols = sdm_irref(Aaug) + + # No solution: + if pivots and pivots[-1] == nsyms: + return None + + # Particular solution for non-homogeneous system: + P = sdm_particular_from_rref(Arref, nsyms+1, pivots) + + # Nullspace - general solution to homogeneous system + # Note: using nsyms not nsyms+1 to ignore last column + V, nonpivots = sdm_nullspace_from_rref(Arref, K.one, nsyms, pivots, nzcols) + + # Collect together terms from particular and nullspace: + sol = defaultdict(list) + for i, v in P.items(): + sol[syms[i]].append(K.to_sympy(v)) + for npi, Vi in zip(nonpivots, V): + sym = syms[npi] + for i, v in Vi.items(): + sol[syms[i]].append(sym * K.to_sympy(v)) + + # Use a single call to Add for each term: + sol = {s: Add(*terms) for s, terms in sol.items()} + + # Fill in the zeros: + zero = S.Zero + for s in set(syms) - set(sol): + sol[s] = zero + + # All done! + return sol + + +def sympy_dict_to_dm(eqs_coeffs, eqs_rhs, syms): + """Convert a system of dict equations to a sparse augmented matrix""" + elems = set(eqs_rhs).union(*(e.values() for e in eqs_coeffs)) + K, elems_K = construct_domain(elems, field=True, extension=True) + elem_map = dict(zip(elems, elems_K)) + neqs = len(eqs_coeffs) + nsyms = len(syms) + sym2index = dict(zip(syms, range(nsyms))) + eqsdict = [] + for eq, rhs in zip(eqs_coeffs, eqs_rhs): + eqdict = {sym2index[s]: elem_map[c] for s, c in eq.items()} + if rhs: + eqdict[nsyms] = -elem_map[rhs] + if eqdict: + eqsdict.append(eqdict) + sdm_aug = SDM(enumerate(eqsdict), (neqs, nsyms + 1), K) + return sdm_aug + + +def _linear_eq_to_dict(eqs, syms): + """Convert a system Expr/Eq equations into dict form, returning + the coefficient dictionaries and a list of syms-independent terms + from each expression in ``eqs```. + + Examples + ======== + + >>> from sympy.polys.matrices.linsolve import _linear_eq_to_dict + >>> from sympy.abc import x + >>> _linear_eq_to_dict([2*x + 3], {x}) + ([{x: 2}], [3]) + """ + coeffs = [] + ind = [] + symset = set(syms) + for e in eqs: + if e.is_Equality: + coeff, terms = _lin_eq2dict(e.lhs, symset) + cR, tR = _lin_eq2dict(e.rhs, symset) + # there were no nonlinear errors so now + # cancellation is allowed + coeff -= cR + for k, v in tR.items(): + if k in terms: + terms[k] -= v + else: + terms[k] = -v + # don't store coefficients of 0, however + terms = {k: v for k, v in terms.items() if v} + c, d = coeff, terms + else: + c, d = _lin_eq2dict(e, symset) + coeffs.append(d) + ind.append(c) + return coeffs, ind + + +def _lin_eq2dict(a, symset): + """return (c, d) where c is the sym-independent part of ``a`` and + ``d`` is an efficiently calculated dictionary mapping symbols to + their coefficients. A PolyNonlinearError is raised if non-linearity + is detected. + + The values in the dictionary will be non-zero. + + Examples + ======== + + >>> from sympy.polys.matrices.linsolve import _lin_eq2dict + >>> from sympy.abc import x, y + >>> _lin_eq2dict(x + 2*y + 3, {x, y}) + (3, {x: 1, y: 2}) + """ + if a in symset: + return S.Zero, {a: S.One} + elif a.is_Add: + terms_list = defaultdict(list) + coeff_list = [] + for ai in a.args: + ci, ti = _lin_eq2dict(ai, symset) + coeff_list.append(ci) + for mij, cij in ti.items(): + terms_list[mij].append(cij) + coeff = Add(*coeff_list) + terms = {sym: Add(*coeffs) for sym, coeffs in terms_list.items()} + return coeff, terms + elif a.is_Mul: + terms = terms_coeff = None + coeff_list = [] + for ai in a.args: + ci, ti = _lin_eq2dict(ai, symset) + if not ti: + coeff_list.append(ci) + elif terms is None: + terms = ti + terms_coeff = ci + else: + # since ti is not null and we already have + # a term, this is a cross term + raise PolyNonlinearError(filldedent(''' + nonlinear cross-term: %s''' % a)) + coeff = Mul._from_args(coeff_list) + if terms is None: + return coeff, {} + else: + terms = {sym: coeff * c for sym, c in terms.items()} + return coeff * terms_coeff, terms + elif not a.has_xfree(symset): + return a, {} + else: + raise PolyNonlinearError('nonlinear term: %s' % a) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/lll.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/lll.py new file mode 100644 index 0000000000000000000000000000000000000000..f33f91d92c5e20f89f302991e494a6a5b9fa4b2e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/lll.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +from math import floor as mfloor + +from sympy.polys.domains import ZZ, QQ +from sympy.polys.matrices.exceptions import DMRankError, DMShapeError, DMValueError, DMDomainError + + +def _ddm_lll(x, delta=QQ(3, 4), return_transform=False): + if QQ(1, 4) >= delta or delta >= QQ(1, 1): + raise DMValueError("delta must lie in range (0.25, 1)") + if x.shape[0] > x.shape[1]: + raise DMShapeError("input matrix must have shape (m, n) with m <= n") + if x.domain != ZZ: + raise DMDomainError("input matrix domain must be ZZ") + m = x.shape[0] + n = x.shape[1] + k = 1 + y = x.copy() + y_star = x.zeros((m, n), QQ) + mu = x.zeros((m, m), QQ) + g_star = [QQ(0, 1) for _ in range(m)] + half = QQ(1, 2) + T = x.eye(m, ZZ) if return_transform else None + linear_dependent_error = "input matrix contains linearly dependent rows" + + def closest_integer(x): + return ZZ(mfloor(x + half)) + + def lovasz_condition(k: int) -> bool: + return g_star[k] >= ((delta - mu[k][k - 1] ** 2) * g_star[k - 1]) + + def mu_small(k: int, j: int) -> bool: + return abs(mu[k][j]) <= half + + def dot_rows(x, y, rows: tuple[int, int]): + return sum(x[rows[0]][z] * y[rows[1]][z] for z in range(x.shape[1])) + + def reduce_row(T, mu, y, rows: tuple[int, int]): + r = closest_integer(mu[rows[0]][rows[1]]) + y[rows[0]] = [y[rows[0]][z] - r * y[rows[1]][z] for z in range(n)] + mu[rows[0]][:rows[1]] = [mu[rows[0]][z] - r * mu[rows[1]][z] for z in range(rows[1])] + mu[rows[0]][rows[1]] -= r + if return_transform: + T[rows[0]] = [T[rows[0]][z] - r * T[rows[1]][z] for z in range(m)] + + for i in range(m): + y_star[i] = [QQ.convert_from(z, ZZ) for z in y[i]] + for j in range(i): + row_dot = dot_rows(y, y_star, (i, j)) + try: + mu[i][j] = row_dot / g_star[j] + except ZeroDivisionError: + raise DMRankError(linear_dependent_error) + y_star[i] = [y_star[i][z] - mu[i][j] * y_star[j][z] for z in range(n)] + g_star[i] = dot_rows(y_star, y_star, (i, i)) + while k < m: + if not mu_small(k, k - 1): + reduce_row(T, mu, y, (k, k - 1)) + if lovasz_condition(k): + for l in range(k - 2, -1, -1): + if not mu_small(k, l): + reduce_row(T, mu, y, (k, l)) + k += 1 + else: + nu = mu[k][k - 1] + alpha = g_star[k] + nu ** 2 * g_star[k - 1] + try: + beta = g_star[k - 1] / alpha + except ZeroDivisionError: + raise DMRankError(linear_dependent_error) + mu[k][k - 1] = nu * beta + g_star[k] = g_star[k] * beta + g_star[k - 1] = alpha + y[k], y[k - 1] = y[k - 1], y[k] + mu[k][:k - 1], mu[k - 1][:k - 1] = mu[k - 1][:k - 1], mu[k][:k - 1] + for i in range(k + 1, m): + xi = mu[i][k] + mu[i][k] = mu[i][k - 1] - nu * xi + mu[i][k - 1] = mu[k][k - 1] * mu[i][k] + xi + if return_transform: + T[k], T[k - 1] = T[k - 1], T[k] + k = max(k - 1, 1) + assert all(lovasz_condition(i) for i in range(1, m)) + assert all(mu_small(i, j) for i in range(m) for j in range(i)) + return y, T + + +def ddm_lll(x, delta=QQ(3, 4)): + return _ddm_lll(x, delta=delta, return_transform=False)[0] + + +def ddm_lll_transform(x, delta=QQ(3, 4)): + return _ddm_lll(x, delta=delta, return_transform=True) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/normalforms.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/normalforms.py new file mode 100644 index 0000000000000000000000000000000000000000..506a68b6946acbeb235eed7650246104da265b78 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/normalforms.py @@ -0,0 +1,540 @@ +'''Functions returning normal forms of matrices''' + +from collections import defaultdict + +from .domainmatrix import DomainMatrix +from .exceptions import DMDomainError, DMShapeError +from sympy.ntheory.modular import symmetric_residue +from sympy.polys.domains import QQ, ZZ + + +# TODO (future work): +# There are faster algorithms for Smith and Hermite normal forms, which +# we should implement. See e.g. the Kannan-Bachem algorithm: +# + + +def smith_normal_form(m): + ''' + Return the Smith Normal Form of a matrix `m` over the ring `domain`. + This will only work if the ring is a principal ideal domain. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy.polys.matrices.normalforms import smith_normal_form + >>> m = DomainMatrix([[ZZ(12), ZZ(6), ZZ(4)], + ... [ZZ(3), ZZ(9), ZZ(6)], + ... [ZZ(2), ZZ(16), ZZ(14)]], (3, 3), ZZ) + >>> print(smith_normal_form(m).to_Matrix()) + Matrix([[1, 0, 0], [0, 10, 0], [0, 0, 30]]) + + ''' + invs = invariant_factors(m) + smf = DomainMatrix.diag(invs, m.domain, m.shape) + return smf + + +def is_smith_normal_form(m): + ''' + Checks that the matrix is in Smith Normal Form + ''' + domain = m.domain + shape = m.shape + zero = domain.zero + m = m.to_list() + + for i in range(shape[0]): + for j in range(shape[1]): + if i == j: + continue + if not m[i][j] == zero: + return False + + upper = min(shape[0], shape[1]) + for i in range(1, upper): + if m[i-1][i-1] == zero: + if m[i][i] != zero: + return False + else: + r = domain.div(m[i][i], m[i-1][i-1])[1] + if r != zero: + return False + + return True + + +def add_columns(m, i, j, a, b, c, d): + # replace m[:, i] by a*m[:, i] + b*m[:, j] + # and m[:, j] by c*m[:, i] + d*m[:, j] + for k in range(len(m)): + e = m[k][i] + m[k][i] = a*e + b*m[k][j] + m[k][j] = c*e + d*m[k][j] + + +def invariant_factors(m): + ''' + Return the tuple of abelian invariants for a matrix `m` + (as in the Smith-Normal form) + + References + ========== + + [1] https://en.wikipedia.org/wiki/Smith_normal_form#Algorithm + [2] https://web.archive.org/web/20200331143852/https://sierra.nmsu.edu/morandi/notes/SmithNormalForm.pdf + + ''' + domain = m.domain + shape = m.shape + m = m.to_list() + return _smith_normal_decomp(m, domain, shape=shape, full=False) + + +def smith_normal_decomp(m): + ''' + Return the Smith-Normal form decomposition of matrix `m`. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy.polys.matrices.normalforms import smith_normal_decomp + >>> m = DomainMatrix([[ZZ(12), ZZ(6), ZZ(4)], + ... [ZZ(3), ZZ(9), ZZ(6)], + ... [ZZ(2), ZZ(16), ZZ(14)]], (3, 3), ZZ) + >>> a, s, t = smith_normal_decomp(m) + >>> assert a == s * m * t + ''' + domain = m.domain + rows, cols = shape = m.shape + m = m.to_list() + + invs, s, t = _smith_normal_decomp(m, domain, shape=shape, full=True) + smf = DomainMatrix.diag(invs, domain, shape).to_dense() + + s = DomainMatrix(s, domain=domain, shape=(rows, rows)) + t = DomainMatrix(t, domain=domain, shape=(cols, cols)) + return smf, s, t + + +def _smith_normal_decomp(m, domain, shape, full): + ''' + Return the tuple of abelian invariants for a matrix `m` + (as in the Smith-Normal form). If `full=True` then invertible matrices + ``s, t`` such that the product ``s, m, t`` is the Smith Normal Form + are also returned. + ''' + if not domain.is_PID: + msg = f"The matrix entries must be over a principal ideal domain, but got {domain}" + raise ValueError(msg) + + rows, cols = shape + zero = domain.zero + one = domain.one + + def eye(n): + return [[one if i == j else zero for i in range(n)] for j in range(n)] + + if 0 in shape: + if full: + return (), eye(rows), eye(cols) + else: + return () + + if full: + s = eye(rows) + t = eye(cols) + + def add_rows(m, i, j, a, b, c, d): + # replace m[i, :] by a*m[i, :] + b*m[j, :] + # and m[j, :] by c*m[i, :] + d*m[j, :] + for k in range(len(m[0])): + e = m[i][k] + m[i][k] = a*e + b*m[j][k] + m[j][k] = c*e + d*m[j][k] + + def clear_column(): + # make m[1:, 0] zero by row and column operations + pivot = m[0][0] + for j in range(1, rows): + if m[j][0] == zero: + continue + d, r = domain.div(m[j][0], pivot) + if r == zero: + add_rows(m, 0, j, 1, 0, -d, 1) + if full: + add_rows(s, 0, j, 1, 0, -d, 1) + else: + a, b, g = domain.gcdex(pivot, m[j][0]) + d_0 = domain.exquo(m[j][0], g) + d_j = domain.exquo(pivot, g) + add_rows(m, 0, j, a, b, d_0, -d_j) + if full: + add_rows(s, 0, j, a, b, d_0, -d_j) + pivot = g + + def clear_row(): + # make m[0, 1:] zero by row and column operations + pivot = m[0][0] + for j in range(1, cols): + if m[0][j] == zero: + continue + d, r = domain.div(m[0][j], pivot) + if r == zero: + add_columns(m, 0, j, 1, 0, -d, 1) + if full: + add_columns(t, 0, j, 1, 0, -d, 1) + else: + a, b, g = domain.gcdex(pivot, m[0][j]) + d_0 = domain.exquo(m[0][j], g) + d_j = domain.exquo(pivot, g) + add_columns(m, 0, j, a, b, d_0, -d_j) + if full: + add_columns(t, 0, j, a, b, d_0, -d_j) + pivot = g + + # permute the rows and columns until m[0,0] is non-zero if possible + ind = [i for i in range(rows) if m[i][0] != zero] + if ind and ind[0] != zero: + m[0], m[ind[0]] = m[ind[0]], m[0] + if full: + s[0], s[ind[0]] = s[ind[0]], s[0] + else: + ind = [j for j in range(cols) if m[0][j] != zero] + if ind and ind[0] != zero: + for row in m: + row[0], row[ind[0]] = row[ind[0]], row[0] + if full: + for row in t: + row[0], row[ind[0]] = row[ind[0]], row[0] + + # make the first row and column except m[0,0] zero + while (any(m[0][i] != zero for i in range(1,cols)) or + any(m[i][0] != zero for i in range(1,rows))): + clear_column() + clear_row() + + def to_domain_matrix(m): + return DomainMatrix(m, shape=(len(m), len(m[0])), domain=domain) + + if m[0][0] != 0: + c = domain.canonical_unit(m[0][0]) + if domain.is_Field: + c = 1 / m[0][0] + if c != domain.one: + m[0][0] *= c + if full: + s[0] = [elem * c for elem in s[0]] + + if 1 in shape: + invs = () + else: + lower_right = [r[1:] for r in m[1:]] + ret = _smith_normal_decomp(lower_right, domain, + shape=(rows - 1, cols - 1), full=full) + if full: + invs, s_small, t_small = ret + s2 = [[1] + [0]*(rows-1)] + [[0] + row for row in s_small] + t2 = [[1] + [0]*(cols-1)] + [[0] + row for row in t_small] + s, s2, t, t2 = list(map(to_domain_matrix, [s, s2, t, t2])) + s = s2 * s + t = t * t2 + s = s.to_list() + t = t.to_list() + else: + invs = ret + + if m[0][0]: + result = [m[0][0]] + result.extend(invs) + # in case m[0] doesn't divide the invariants of the rest of the matrix + for i in range(len(result)-1): + a, b = result[i], result[i+1] + if b and domain.div(b, a)[1] != zero: + if full: + x, y, d = domain.gcdex(a, b) + else: + d = domain.gcd(a, b) + + alpha = domain.div(a, d)[0] + if full: + beta = domain.div(b, d)[0] + add_rows(s, i, i + 1, 1, 0, x, 1) + add_columns(t, i, i + 1, 1, y, 0, 1) + add_rows(s, i, i + 1, 1, -alpha, 0, 1) + add_columns(t, i, i + 1, 1, 0, -beta, 1) + add_rows(s, i, i + 1, 0, 1, -1, 0) + + result[i+1] = b * alpha + result[i] = d + else: + break + else: + if full: + if rows > 1: + s = s[1:] + [s[0]] + if cols > 1: + t = [row[1:] + [row[0]] for row in t] + result = invs + (m[0][0],) + + if full: + return tuple(result), s, t + else: + return tuple(result) + + +def _gcdex(a, b): + r""" + This supports the functions that compute Hermite Normal Form. + + Explanation + =========== + + Let x, y be the coefficients returned by the extended Euclidean + Algorithm, so that x*a + y*b = g. In the algorithms for computing HNF, + it is critical that x, y not only satisfy the condition of being small + in magnitude -- namely that |x| <= |b|/g, |y| <- |a|/g -- but also that + y == 0 when a | b. + + """ + x, y, g = ZZ.gcdex(a, b) + if a != 0 and b % a == 0: + y = 0 + x = -1 if a < 0 else 1 + return x, y, g + + +def _hermite_normal_form(A): + r""" + Compute the Hermite Normal Form of DomainMatrix *A* over :ref:`ZZ`. + + Parameters + ========== + + A : :py:class:`~.DomainMatrix` over domain :ref:`ZZ`. + + Returns + ======= + + :py:class:`~.DomainMatrix` + The HNF of matrix *A*. + + Raises + ====== + + DMDomainError + If the domain of the matrix is not :ref:`ZZ`. + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* + (See Algorithm 2.4.5.) + + """ + if not A.domain.is_ZZ: + raise DMDomainError('Matrix must be over domain ZZ.') + # We work one row at a time, starting from the bottom row, and working our + # way up. + m, n = A.shape + A = A.to_ddm().copy() + # Our goal is to put pivot entries in the rightmost columns. + # Invariant: Before processing each row, k should be the index of the + # leftmost column in which we have so far put a pivot. + k = n + for i in range(m - 1, -1, -1): + if k == 0: + # This case can arise when n < m and we've already found n pivots. + # We don't need to consider any more rows, because this is already + # the maximum possible number of pivots. + break + k -= 1 + # k now points to the column in which we want to put a pivot. + # We want zeros in all entries to the left of the pivot column. + for j in range(k - 1, -1, -1): + if A[i][j] != 0: + # Replace cols j, k by lin combs of these cols such that, in row i, + # col j has 0, while col k has the gcd of their row i entries. Note + # that this ensures a nonzero entry in col k. + u, v, d = _gcdex(A[i][k], A[i][j]) + r, s = A[i][k] // d, A[i][j] // d + add_columns(A, k, j, u, v, -s, r) + b = A[i][k] + # Do not want the pivot entry to be negative. + if b < 0: + add_columns(A, k, k, -1, 0, -1, 0) + b = -b + # The pivot entry will be 0 iff the row was 0 from the pivot col all the + # way to the left. In this case, we are still working on the same pivot + # col for the next row. Therefore: + if b == 0: + k += 1 + # If the pivot entry is nonzero, then we want to reduce all entries to its + # right in the sense of the division algorithm, i.e. make them all remainders + # w.r.t. the pivot as divisor. + else: + for j in range(k + 1, n): + q = A[i][j] // b + add_columns(A, j, k, 1, -q, 0, 1) + # Finally, the HNF consists of those columns of A in which we succeeded in making + # a nonzero pivot. + return DomainMatrix.from_rep(A.to_dfm_or_ddm())[:, k:] + + +def _hermite_normal_form_modulo_D(A, D): + r""" + Perform the mod *D* Hermite Normal Form reduction algorithm on + :py:class:`~.DomainMatrix` *A*. + + Explanation + =========== + + If *A* is an $m \times n$ matrix of rank $m$, having Hermite Normal Form + $W$, and if *D* is any positive integer known in advance to be a multiple + of $\det(W)$, then the HNF of *A* can be computed by an algorithm that + works mod *D* in order to prevent coefficient explosion. + + Parameters + ========== + + A : :py:class:`~.DomainMatrix` over :ref:`ZZ` + $m \times n$ matrix, having rank $m$. + D : :ref:`ZZ` + Positive integer, known to be a multiple of the determinant of the + HNF of *A*. + + Returns + ======= + + :py:class:`~.DomainMatrix` + The HNF of matrix *A*. + + Raises + ====== + + DMDomainError + If the domain of the matrix is not :ref:`ZZ`, or + if *D* is given but is not in :ref:`ZZ`. + + DMShapeError + If the matrix has more rows than columns. + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* + (See Algorithm 2.4.8.) + + """ + if not A.domain.is_ZZ: + raise DMDomainError('Matrix must be over domain ZZ.') + if not ZZ.of_type(D) or D < 1: + raise DMDomainError('Modulus D must be positive element of domain ZZ.') + + def add_columns_mod_R(m, R, i, j, a, b, c, d): + # replace m[:, i] by (a*m[:, i] + b*m[:, j]) % R + # and m[:, j] by (c*m[:, i] + d*m[:, j]) % R + for k in range(len(m)): + e = m[k][i] + m[k][i] = symmetric_residue((a * e + b * m[k][j]) % R, R) + m[k][j] = symmetric_residue((c * e + d * m[k][j]) % R, R) + + W = defaultdict(dict) + + m, n = A.shape + if n < m: + raise DMShapeError('Matrix must have at least as many columns as rows.') + A = A.to_list() + k = n + R = D + for i in range(m - 1, -1, -1): + k -= 1 + for j in range(k - 1, -1, -1): + if A[i][j] != 0: + u, v, d = _gcdex(A[i][k], A[i][j]) + r, s = A[i][k] // d, A[i][j] // d + add_columns_mod_R(A, R, k, j, u, v, -s, r) + b = A[i][k] + if b == 0: + A[i][k] = b = R + u, v, d = _gcdex(b, R) + for ii in range(m): + W[ii][i] = u*A[ii][k] % R + if W[i][i] == 0: + W[i][i] = R + for j in range(i + 1, m): + q = W[i][j] // W[i][i] + add_columns(W, j, i, 1, -q, 0, 1) + R //= d + return DomainMatrix(W, (m, m), ZZ).to_dense() + + +def hermite_normal_form(A, *, D=None, check_rank=False): + r""" + Compute the Hermite Normal Form of :py:class:`~.DomainMatrix` *A* over + :ref:`ZZ`. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy.polys.matrices.normalforms import hermite_normal_form + >>> m = DomainMatrix([[ZZ(12), ZZ(6), ZZ(4)], + ... [ZZ(3), ZZ(9), ZZ(6)], + ... [ZZ(2), ZZ(16), ZZ(14)]], (3, 3), ZZ) + >>> print(hermite_normal_form(m).to_Matrix()) + Matrix([[10, 0, 2], [0, 15, 3], [0, 0, 2]]) + + Parameters + ========== + + A : $m \times n$ ``DomainMatrix`` over :ref:`ZZ`. + + D : :ref:`ZZ`, optional + Let $W$ be the HNF of *A*. If known in advance, a positive integer *D* + being any multiple of $\det(W)$ may be provided. In this case, if *A* + also has rank $m$, then we may use an alternative algorithm that works + mod *D* in order to prevent coefficient explosion. + + check_rank : boolean, optional (default=False) + The basic assumption is that, if you pass a value for *D*, then + you already believe that *A* has rank $m$, so we do not waste time + checking it for you. If you do want this to be checked (and the + ordinary, non-modulo *D* algorithm to be used if the check fails), then + set *check_rank* to ``True``. + + Returns + ======= + + :py:class:`~.DomainMatrix` + The HNF of matrix *A*. + + Raises + ====== + + DMDomainError + If the domain of the matrix is not :ref:`ZZ`, or + if *D* is given but is not in :ref:`ZZ`. + + DMShapeError + If the mod *D* algorithm is used but the matrix has more rows than + columns. + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* + (See Algorithms 2.4.5 and 2.4.8.) + + """ + if not A.domain.is_ZZ: + raise DMDomainError('Matrix must be over domain ZZ.') + if D is not None and (not check_rank or A.convert_to(QQ).rank() == A.shape[0]): + return _hermite_normal_form_modulo_D(A, D) + else: + return _hermite_normal_form(A) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/rref.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/rref.py new file mode 100644 index 0000000000000000000000000000000000000000..c5a71b04971e8dc8ecac5cc2691f98ba68e35d45 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/rref.py @@ -0,0 +1,422 @@ +# Algorithms for computing the reduced row echelon form of a matrix. +# +# We need to choose carefully which algorithms to use depending on the domain, +# shape, and sparsity of the matrix as well as things like the bit count in the +# case of ZZ or QQ. This is important because the algorithms have different +# performance characteristics in the extremes of dense vs sparse. +# +# In all cases we use the sparse implementations but we need to choose between +# Gauss-Jordan elimination with division and fraction-free Gauss-Jordan +# elimination. For very sparse matrices over ZZ with low bit counts it is +# asymptotically faster to use Gauss-Jordan elimination with division. For +# dense matrices with high bit counts it is asymptotically faster to use +# fraction-free Gauss-Jordan. +# +# The most important thing is to get the extreme cases right because it can +# make a big difference. In between the extremes though we have to make a +# choice and here we use empirically determined thresholds based on timings +# with random sparse matrices. +# +# In the case of QQ we have to consider the denominators as well. If the +# denominators are small then it is faster to clear them and use fraction-free +# Gauss-Jordan over ZZ. If the denominators are large then it is faster to use +# Gauss-Jordan elimination with division over QQ. +# +# Timings for the various algorithms can be found at +# +# https://github.com/sympy/sympy/issues/25410 +# https://github.com/sympy/sympy/pull/25443 + +from sympy.polys.domains import ZZ + +from sympy.polys.matrices.sdm import SDM, sdm_irref, sdm_rref_den +from sympy.polys.matrices.ddm import DDM +from sympy.polys.matrices.dense import ddm_irref, ddm_irref_den + + +def _dm_rref(M, *, method='auto'): + """ + Compute the reduced row echelon form of a ``DomainMatrix``. + + This function is the implementation of :meth:`DomainMatrix.rref`. + + Chooses the best algorithm depending on the domain, shape, and sparsity of + the matrix as well as things like the bit count in the case of :ref:`ZZ` or + :ref:`QQ`. The result is returned over the field associated with the domain + of the Matrix. + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.rref + The ``DomainMatrix`` method that calls this function. + sympy.polys.matrices.rref._dm_rref_den + Alternative function for computing RREF with denominator. + """ + method, use_fmt = _dm_rref_choose_method(M, method, denominator=False) + + M, old_fmt = _dm_to_fmt(M, use_fmt) + + if method == 'GJ': + # Use Gauss-Jordan with division over the associated field. + Mf = _to_field(M) + M_rref, pivots = _dm_rref_GJ(Mf) + + elif method == 'FF': + # Use fraction-free GJ over the current domain. + M_rref_f, den, pivots = _dm_rref_den_FF(M) + M_rref = _to_field(M_rref_f) / den + + elif method == 'CD': + # Clear denominators and use fraction-free GJ in the associated ring. + _, Mr = M.clear_denoms_rowwise(convert=True) + M_rref_f, den, pivots = _dm_rref_den_FF(Mr) + M_rref = _to_field(M_rref_f) / den + + else: + raise ValueError(f"Unknown method for rref: {method}") + + M_rref, _ = _dm_to_fmt(M_rref, old_fmt) + + # Invariants: + # - M_rref is in the same format (sparse or dense) as the input matrix. + # - M_rref is in the associated field domain and any denominator was + # divided in (so is implicitly 1 now). + + return M_rref, pivots + + +def _dm_rref_den(M, *, keep_domain=True, method='auto'): + """ + Compute the reduced row echelon form of a ``DomainMatrix`` with denominator. + + This function is the implementation of :meth:`DomainMatrix.rref_den`. + + Chooses the best algorithm depending on the domain, shape, and sparsity of + the matrix as well as things like the bit count in the case of :ref:`ZZ` or + :ref:`QQ`. The result is returned over the same domain as the input matrix + unless ``keep_domain=False`` in which case the result might be over an + associated ring or field domain. + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.rref_den + The ``DomainMatrix`` method that calls this function. + sympy.polys.matrices.rref._dm_rref + Alternative function for computing RREF without denominator. + """ + method, use_fmt = _dm_rref_choose_method(M, method, denominator=True) + + M, old_fmt = _dm_to_fmt(M, use_fmt) + + if method == 'FF': + # Use fraction-free GJ over the current domain. + M_rref, den, pivots = _dm_rref_den_FF(M) + + elif method == 'GJ': + # Use Gauss-Jordan with division over the associated field. + M_rref_f, pivots = _dm_rref_GJ(_to_field(M)) + + # Convert back to the ring? + if keep_domain and M_rref_f.domain != M.domain: + _, M_rref = M_rref_f.clear_denoms(convert=True) + + if pivots: + den = M_rref[0, pivots[0]].element + else: + den = M_rref.domain.one + else: + # Possibly an associated field + M_rref = M_rref_f + den = M_rref.domain.one + + elif method == 'CD': + # Clear denominators and use fraction-free GJ in the associated ring. + _, Mr = M.clear_denoms_rowwise(convert=True) + + M_rref_r, den, pivots = _dm_rref_den_FF(Mr) + + if keep_domain and M_rref_r.domain != M.domain: + # Convert back to the field + M_rref = _to_field(M_rref_r) / den + den = M.domain.one + else: + # Possibly an associated ring + M_rref = M_rref_r + + if pivots: + den = M_rref[0, pivots[0]].element + else: + den = M_rref.domain.one + else: + raise ValueError(f"Unknown method for rref: {method}") + + M_rref, _ = _dm_to_fmt(M_rref, old_fmt) + + # Invariants: + # - M_rref is in the same format (sparse or dense) as the input matrix. + # - If keep_domain=True then M_rref and den are in the same domain as the + # input matrix + # - If keep_domain=False then M_rref might be in an associated ring or + # field domain but den is always in the same domain as M_rref. + + return M_rref, den, pivots + + +def _dm_to_fmt(M, fmt): + """Convert a matrix to the given format and return the old format.""" + old_fmt = M.rep.fmt + if old_fmt == fmt: + pass + elif fmt == 'dense': + M = M.to_dense() + elif fmt == 'sparse': + M = M.to_sparse() + else: + raise ValueError(f'Unknown format: {fmt}') # pragma: no cover + return M, old_fmt + + +# These are the four basic implementations that we want to choose between: + + +def _dm_rref_GJ(M): + """Compute RREF using Gauss-Jordan elimination with division.""" + if M.rep.fmt == 'sparse': + return _dm_rref_GJ_sparse(M) + else: + return _dm_rref_GJ_dense(M) + + +def _dm_rref_den_FF(M): + """Compute RREF using fraction-free Gauss-Jordan elimination.""" + if M.rep.fmt == 'sparse': + return _dm_rref_den_FF_sparse(M) + else: + return _dm_rref_den_FF_dense(M) + + +def _dm_rref_GJ_sparse(M): + """Compute RREF using sparse Gauss-Jordan elimination with division.""" + M_rref_d, pivots, _ = sdm_irref(M.rep) + M_rref_sdm = SDM(M_rref_d, M.shape, M.domain) + pivots = tuple(pivots) + return M.from_rep(M_rref_sdm), pivots + + +def _dm_rref_GJ_dense(M): + """Compute RREF using dense Gauss-Jordan elimination with division.""" + partial_pivot = M.domain.is_RR or M.domain.is_CC + ddm = M.rep.to_ddm().copy() + pivots = ddm_irref(ddm, _partial_pivot=partial_pivot) + M_rref_ddm = DDM(ddm, M.shape, M.domain) + pivots = tuple(pivots) + return M.from_rep(M_rref_ddm.to_dfm_or_ddm()), pivots + + +def _dm_rref_den_FF_sparse(M): + """Compute RREF using sparse fraction-free Gauss-Jordan elimination.""" + M_rref_d, den, pivots = sdm_rref_den(M.rep, M.domain) + M_rref_sdm = SDM(M_rref_d, M.shape, M.domain) + pivots = tuple(pivots) + return M.from_rep(M_rref_sdm), den, pivots + + +def _dm_rref_den_FF_dense(M): + """Compute RREF using sparse fraction-free Gauss-Jordan elimination.""" + ddm = M.rep.to_ddm().copy() + den, pivots = ddm_irref_den(ddm, M.domain) + M_rref_ddm = DDM(ddm, M.shape, M.domain) + pivots = tuple(pivots) + return M.from_rep(M_rref_ddm.to_dfm_or_ddm()), den, pivots + + +def _dm_rref_choose_method(M, method, *, denominator=False): + """Choose the fastest method for computing RREF for M.""" + + if method != 'auto': + if method.endswith('_dense'): + method = method[:-len('_dense')] + use_fmt = 'dense' + else: + use_fmt = 'sparse' + + else: + # The sparse implementations are always faster + use_fmt = 'sparse' + + K = M.domain + + if K.is_ZZ: + method = _dm_rref_choose_method_ZZ(M, denominator=denominator) + elif K.is_QQ: + method = _dm_rref_choose_method_QQ(M, denominator=denominator) + elif K.is_RR or K.is_CC: + # TODO: Add partial pivot support to the sparse implementations. + method = 'GJ' + use_fmt = 'dense' + elif K.is_EX and M.rep.fmt == 'dense' and not denominator: + # Do not switch to the sparse implementation for EX because the + # domain does not have proper canonicalization and the sparse + # implementation gives equivalent but non-identical results over EX + # from performing arithmetic in a different order. Specifically + # test_issue_23718 ends up getting a more complicated expression + # when using the sparse implementation. Probably the best fix for + # this is something else but for now we stick with the dense + # implementation for EX if the matrix is already dense. + method = 'GJ' + use_fmt = 'dense' + else: + # This is definitely suboptimal. More work is needed to determine + # the best method for computing RREF over different domains. + if denominator: + method = 'FF' + else: + method = 'GJ' + + return method, use_fmt + + +def _dm_rref_choose_method_QQ(M, *, denominator=False): + """Choose the fastest method for computing RREF over QQ.""" + # The same sorts of considerations apply here as in the case of ZZ. Here + # though a new more significant consideration is what sort of denominators + # we have and what to do with them so we focus on that. + + # First compute the density. This is the average number of non-zero entries + # per row but only counting rows that have at least one non-zero entry + # since RREF can ignore fully zero rows. + density, _, ncols = _dm_row_density(M) + + # For sparse matrices use Gauss-Jordan elimination over QQ regardless. + if density < min(5, ncols/2): + return 'GJ' + + # Compare the bit-length of the lcm of the denominators to the bit length + # of the numerators. + # + # The threshold here is empirical: we prefer rref over QQ if clearing + # denominators would result in a numerator matrix having 5x the bit size of + # the current numerators. + numers, denoms = _dm_QQ_numers_denoms(M) + numer_bits = max([n.bit_length() for n in numers], default=1) + + denom_lcm = ZZ.one + for d in denoms: + denom_lcm = ZZ.lcm(denom_lcm, d) + if denom_lcm.bit_length() > 5*numer_bits: + return 'GJ' + + # If we get here then the matrix is dense and the lcm of the denominators + # is not too large compared to the numerators. For particularly small + # denominators it is fastest just to clear them and use fraction-free + # Gauss-Jordan over ZZ. With very small denominators this is a little + # faster than using rref_den over QQ but there is an intermediate regime + # where rref_den over QQ is significantly faster. The small denominator + # case is probably very common because small fractions like 1/2 or 1/3 are + # often seen in user inputs. + + if denom_lcm.bit_length() < 50: + return 'CD' + else: + return 'FF' + + +def _dm_rref_choose_method_ZZ(M, *, denominator=False): + """Choose the fastest method for computing RREF over ZZ.""" + # In the extreme of very sparse matrices and low bit counts it is faster to + # use Gauss-Jordan elimination over QQ rather than fraction-free + # Gauss-Jordan over ZZ. In the opposite extreme of dense matrices and high + # bit counts it is faster to use fraction-free Gauss-Jordan over ZZ. These + # two extreme cases need to be handled differently because they lead to + # different asymptotic complexities. In between these two extremes we need + # a threshold for deciding which method to use. This threshold is + # determined empirically by timing the two methods with random matrices. + + # The disadvantage of using empirical timings is that future optimisations + # might change the relative speeds so this can easily become out of date. + # The main thing is to get the asymptotic complexity right for the extreme + # cases though so the precise value of the threshold is hopefully not too + # important. + + # Empirically determined parameter. + PARAM = 10000 + + # First compute the density. This is the average number of non-zero entries + # per row but only counting rows that have at least one non-zero entry + # since RREF can ignore fully zero rows. + density, nrows_nz, ncols = _dm_row_density(M) + + # For small matrices use QQ if more than half the entries are zero. + if nrows_nz < 10: + if density < ncols/2: + return 'GJ' + else: + return 'FF' + + # These are just shortcuts for the formula below. + if density < 5: + return 'GJ' + elif density > 5 + PARAM/nrows_nz: + return 'FF' # pragma: no cover + + # Maximum bitsize of any entry. + elements = _dm_elements(M) + bits = max([e.bit_length() for e in elements], default=1) + + # Wideness parameter. This is 1 for square or tall matrices but >1 for wide + # matrices. + wideness = max(1, 2/3*ncols/nrows_nz) + + max_density = (5 + PARAM/(nrows_nz*bits**2)) * wideness + + if density < max_density: + return 'GJ' + else: + return 'FF' + + +def _dm_row_density(M): + """Density measure for sparse matrices. + + Defines the "density", ``d`` as the average number of non-zero entries per + row except ignoring rows that are fully zero. RREF can ignore fully zero + rows so they are excluded. By definition ``d >= 1`` except that we define + ``d = 0`` for the zero matrix. + + Returns ``(density, nrows_nz, ncols)`` where ``nrows_nz`` counts the number + of nonzero rows and ``ncols`` is the number of columns. + """ + # Uses the SDM dict-of-dicts representation. + ncols = M.shape[1] + rows_nz = M.rep.to_sdm().values() + if not rows_nz: + return 0, 0, ncols + else: + nrows_nz = len(rows_nz) + density = sum(map(len, rows_nz)) / nrows_nz + return density, nrows_nz, ncols + + +def _dm_elements(M): + """Return nonzero elements of a DomainMatrix.""" + elements, _ = M.to_flat_nz() + return elements + + +def _dm_QQ_numers_denoms(Mq): + """Returns the numerators and denominators of a DomainMatrix over QQ.""" + elements = _dm_elements(Mq) + numers = [e.numerator for e in elements] + denoms = [e.denominator for e in elements] + return numers, denoms + + +def _to_field(M): + """Convert a DomainMatrix to a field if possible.""" + K = M.domain + if K.has_assoc_Field: + return M.to_field() + else: + return M diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/sdm.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/sdm.py new file mode 100644 index 0000000000000000000000000000000000000000..84558d83b6f58a3a9074d31f1a315ac901cd68da --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/matrices/sdm.py @@ -0,0 +1,2197 @@ +""" + +Module for the SDM class. + +""" + +from operator import add, neg, pos, sub, mul +from collections import defaultdict + +from sympy.external.gmpy import GROUND_TYPES +from sympy.utilities.decorator import doctest_depends_on +from sympy.utilities.iterables import _strongly_connected_components + +from .exceptions import DMBadInputError, DMDomainError, DMShapeError + +from sympy.polys.domains import QQ + +from .ddm import DDM + + +if GROUND_TYPES != 'flint': + __doctest_skip__ = ['SDM.to_dfm', 'SDM.to_dfm_or_ddm'] + + +class SDM(dict): + r"""Sparse matrix based on polys domain elements + + This is a dict subclass and is a wrapper for a dict of dicts that supports + basic matrix arithmetic +, -, *, **. + + + In order to create a new :py:class:`~.SDM`, a dict + of dicts mapping non-zero elements to their + corresponding row and column in the matrix is needed. + + We also need to specify the shape and :py:class:`~.Domain` + of our :py:class:`~.SDM` object. + + We declare a 2x2 :py:class:`~.SDM` matrix belonging + to QQ domain as shown below. + The 2x2 Matrix in the example is + + .. math:: + A = \left[\begin{array}{ccc} + 0 & \frac{1}{2} \\ + 0 & 0 \end{array} \right] + + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> elemsdict = {0:{1:QQ(1, 2)}} + >>> A = SDM(elemsdict, (2, 2), QQ) + >>> A + {0: {1: 1/2}} + + We can manipulate :py:class:`~.SDM` the same way + as a Matrix class + + >>> from sympy import ZZ + >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) + >>> B = SDM({0:{0: ZZ(3)}, 1:{1:ZZ(4)}}, (2, 2), ZZ) + >>> A + B + {0: {0: 3, 1: 2}, 1: {0: 1, 1: 4}} + + Multiplication + + >>> A*B + {0: {1: 8}, 1: {0: 3}} + >>> A*ZZ(2) + {0: {1: 4}, 1: {0: 2}} + + """ + + fmt = 'sparse' + is_DFM = False + is_DDM = False + + def __init__(self, elemsdict, shape, domain): + super().__init__(elemsdict) + self.shape = self.rows, self.cols = m, n = shape + self.domain = domain + + if not all(0 <= r < m for r in self): + raise DMBadInputError("Row out of range") + if not all(0 <= c < n for row in self.values() for c in row): + raise DMBadInputError("Column out of range") + + def getitem(self, i, j): + try: + return self[i][j] + except KeyError: + m, n = self.shape + if -m <= i < m and -n <= j < n: + try: + return self[i % m][j % n] + except KeyError: + return self.domain.zero + else: + raise IndexError("index out of range") + + def setitem(self, i, j, value): + m, n = self.shape + if not (-m <= i < m and -n <= j < n): + raise IndexError("index out of range") + i, j = i % m, j % n + if value: + try: + self[i][j] = value + except KeyError: + self[i] = {j: value} + else: + rowi = self.get(i, None) + if rowi is not None: + try: + del rowi[j] + except KeyError: + pass + else: + if not rowi: + del self[i] + + def extract_slice(self, slice1, slice2): + m, n = self.shape + ri = range(m)[slice1] + ci = range(n)[slice2] + + sdm = {} + for i, row in self.items(): + if i in ri: + row = {ci.index(j): e for j, e in row.items() if j in ci} + if row: + sdm[ri.index(i)] = row + + return self.new(sdm, (len(ri), len(ci)), self.domain) + + def extract(self, rows, cols): + if not (self and rows and cols): + return self.zeros((len(rows), len(cols)), self.domain) + + m, n = self.shape + if not (-m <= min(rows) <= max(rows) < m): + raise IndexError('Row index out of range') + if not (-n <= min(cols) <= max(cols) < n): + raise IndexError('Column index out of range') + + # rows and cols can contain duplicates e.g. M[[1, 2, 2], [0, 1]] + # Build a map from row/col in self to list of rows/cols in output + rowmap = defaultdict(list) + colmap = defaultdict(list) + for i2, i1 in enumerate(rows): + rowmap[i1 % m].append(i2) + for j2, j1 in enumerate(cols): + colmap[j1 % n].append(j2) + + # Used to efficiently skip zero rows/cols + rowset = set(rowmap) + colset = set(colmap) + + sdm1 = self + sdm2 = {} + for i1 in rowset & sdm1.keys(): + row1 = sdm1[i1] + row2 = {} + for j1 in colset & row1.keys(): + row1_j1 = row1[j1] + for j2 in colmap[j1]: + row2[j2] = row1_j1 + if row2: + for i2 in rowmap[i1]: + sdm2[i2] = row2.copy() + + return self.new(sdm2, (len(rows), len(cols)), self.domain) + + def __str__(self): + rowsstr = [] + for i, row in self.items(): + elemsstr = ', '.join('%s: %s' % (j, elem) for j, elem in row.items()) + rowsstr.append('%s: {%s}' % (i, elemsstr)) + return '{%s}' % ', '.join(rowsstr) + + def __repr__(self): + cls = type(self).__name__ + rows = dict.__repr__(self) + return '%s(%s, %s, %s)' % (cls, rows, self.shape, self.domain) + + @classmethod + def new(cls, sdm, shape, domain): + """ + + Parameters + ========== + + sdm: A dict of dicts for non-zero elements in SDM + shape: tuple representing dimension of SDM + domain: Represents :py:class:`~.Domain` of SDM + + Returns + ======= + + An :py:class:`~.SDM` object + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> elemsdict = {0:{1: QQ(2)}} + >>> A = SDM.new(elemsdict, (2, 2), QQ) + >>> A + {0: {1: 2}} + + """ + return cls(sdm, shape, domain) + + def copy(A): + """ + Returns the copy of a :py:class:`~.SDM` object + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> elemsdict = {0:{1:QQ(2)}, 1:{}} + >>> A = SDM(elemsdict, (2, 2), QQ) + >>> B = A.copy() + >>> B + {0: {1: 2}, 1: {}} + + """ + Ac = {i: Ai.copy() for i, Ai in A.items()} + return A.new(Ac, A.shape, A.domain) + + @classmethod + def from_list(cls, ddm, shape, domain): + """ + Create :py:class:`~.SDM` object from a list of lists. + + Parameters + ========== + + ddm: + list of lists containing domain elements + shape: + Dimensions of :py:class:`~.SDM` matrix + domain: + Represents :py:class:`~.Domain` of :py:class:`~.SDM` object + + Returns + ======= + + :py:class:`~.SDM` containing elements of ddm + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> ddm = [[QQ(1, 2), QQ(0)], [QQ(0), QQ(3, 4)]] + >>> A = SDM.from_list(ddm, (2, 2), QQ) + >>> A + {0: {0: 1/2}, 1: {1: 3/4}} + + See Also + ======== + + to_list + from_list_flat + from_dok + from_ddm + """ + + m, n = shape + if not (len(ddm) == m and all(len(row) == n for row in ddm)): + raise DMBadInputError("Inconsistent row-list/shape") + getrow = lambda i: {j:ddm[i][j] for j in range(n) if ddm[i][j]} + irows = ((i, getrow(i)) for i in range(m)) + sdm = {i: row for i, row in irows if row} + return cls(sdm, shape, domain) + + @classmethod + def from_ddm(cls, ddm): + """ + Create :py:class:`~.SDM` from a :py:class:`~.DDM`. + + Examples + ======== + + >>> from sympy.polys.matrices.ddm import DDM + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> ddm = DDM( [[QQ(1, 2), 0], [0, QQ(3, 4)]], (2, 2), QQ) + >>> A = SDM.from_ddm(ddm) + >>> A + {0: {0: 1/2}, 1: {1: 3/4}} + >>> SDM.from_ddm(ddm).to_ddm() == ddm + True + + See Also + ======== + + to_ddm + from_list + from_list_flat + from_dok + """ + return cls.from_list(ddm, ddm.shape, ddm.domain) + + def to_list(M): + """ + Convert a :py:class:`~.SDM` object to a list of lists. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> elemsdict = {0:{1:QQ(2)}, 1:{}} + >>> A = SDM(elemsdict, (2, 2), QQ) + >>> A.to_list() + [[0, 2], [0, 0]] + + + """ + m, n = M.shape + zero = M.domain.zero + ddm = [[zero] * n for _ in range(m)] + for i, row in M.items(): + for j, e in row.items(): + ddm[i][j] = e + return ddm + + def to_list_flat(M): + """ + Convert :py:class:`~.SDM` to a flat list. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM({0:{1:QQ(2)}, 1:{0: QQ(3)}}, (2, 2), QQ) + >>> A.to_list_flat() + [0, 2, 3, 0] + >>> A == A.from_list_flat(A.to_list_flat(), A.shape, A.domain) + True + + See Also + ======== + + from_list_flat + to_list + to_dok + to_ddm + """ + m, n = M.shape + zero = M.domain.zero + flat = [zero] * (m * n) + for i, row in M.items(): + for j, e in row.items(): + flat[i*n + j] = e + return flat + + @classmethod + def from_list_flat(cls, elements, shape, domain): + """ + Create :py:class:`~.SDM` from a flat list of elements. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM.from_list_flat([QQ(0), QQ(2), QQ(0), QQ(0)], (2, 2), QQ) + >>> A + {0: {1: 2}} + >>> A == A.from_list_flat(A.to_list_flat(), A.shape, A.domain) + True + + See Also + ======== + + to_list_flat + from_list + from_dok + from_ddm + """ + m, n = shape + if len(elements) != m * n: + raise DMBadInputError("Inconsistent flat-list shape") + sdm = defaultdict(dict) + for inj, element in enumerate(elements): + if element: + i, j = divmod(inj, n) + sdm[i][j] = element + return cls(sdm, shape, domain) + + def to_flat_nz(M): + """ + Convert :class:`SDM` to a flat list of nonzero elements and data. + + Explanation + =========== + + This is used to operate on a list of the elements of a matrix and then + reconstruct a modified matrix with elements in the same positions using + :meth:`from_flat_nz`. Zero elements are omitted from the list. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM({0:{1:QQ(2)}, 1:{0: QQ(3)}}, (2, 2), QQ) + >>> elements, data = A.to_flat_nz() + >>> elements + [2, 3] + >>> A == A.from_flat_nz(elements, data, A.domain) + True + + See Also + ======== + + from_flat_nz + to_list_flat + sympy.polys.matrices.ddm.DDM.to_flat_nz + sympy.polys.matrices.domainmatrix.DomainMatrix.to_flat_nz + """ + dok = M.to_dok() + indices = tuple(dok) + elements = list(dok.values()) + data = (indices, M.shape) + return elements, data + + @classmethod + def from_flat_nz(cls, elements, data, domain): + """ + Reconstruct a :class:`~.SDM` after calling :meth:`to_flat_nz`. + + See :meth:`to_flat_nz` for explanation. + + See Also + ======== + + to_flat_nz + from_list_flat + sympy.polys.matrices.ddm.DDM.from_flat_nz + sympy.polys.matrices.domainmatrix.DomainMatrix.from_flat_nz + """ + indices, shape = data + dok = dict(zip(indices, elements)) + return cls.from_dok(dok, shape, domain) + + def to_dod(M): + """ + Convert to dictionary of dictionaries (dod) format. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM({0: {1: QQ(2)}, 1: {0: QQ(3)}}, (2, 2), QQ) + >>> A.to_dod() + {0: {1: 2}, 1: {0: 3}} + + See Also + ======== + + from_dod + sympy.polys.matrices.domainmatrix.DomainMatrix.to_dod + """ + return {i: row.copy() for i, row in M.items()} + + @classmethod + def from_dod(cls, dod, shape, domain): + """ + Create :py:class:`~.SDM` from dictionary of dictionaries (dod) format. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> dod = {0: {1: QQ(2)}, 1: {0: QQ(3)}} + >>> A = SDM.from_dod(dod, (2, 2), QQ) + >>> A + {0: {1: 2}, 1: {0: 3}} + >>> A == SDM.from_dod(A.to_dod(), A.shape, A.domain) + True + + See Also + ======== + + to_dod + sympy.polys.matrices.domainmatrix.DomainMatrix.to_dod + """ + sdm = defaultdict(dict) + for i, row in dod.items(): + for j, e in row.items(): + if e: + sdm[i][j] = e + return cls(sdm, shape, domain) + + def to_dok(M): + """ + Convert to dictionary of keys (dok) format. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM({0: {1: QQ(2)}, 1: {0: QQ(3)}}, (2, 2), QQ) + >>> A.to_dok() + {(0, 1): 2, (1, 0): 3} + + See Also + ======== + + from_dok + to_list + to_list_flat + to_ddm + """ + return {(i, j): e for i, row in M.items() for j, e in row.items()} + + @classmethod + def from_dok(cls, dok, shape, domain): + """ + Create :py:class:`~.SDM` from dictionary of keys (dok) format. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> dok = {(0, 1): QQ(2), (1, 0): QQ(3)} + >>> A = SDM.from_dok(dok, (2, 2), QQ) + >>> A + {0: {1: 2}, 1: {0: 3}} + >>> A == SDM.from_dok(A.to_dok(), A.shape, A.domain) + True + + See Also + ======== + + to_dok + from_list + from_list_flat + from_ddm + """ + sdm = defaultdict(dict) + for (i, j), e in dok.items(): + if e: + sdm[i][j] = e + return cls(sdm, shape, domain) + + def iter_values(M): + """ + Iterate over the nonzero values of a :py:class:`~.SDM` matrix. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM({0: {1: QQ(2)}, 1: {0: QQ(3)}}, (2, 2), QQ) + >>> list(A.iter_values()) + [2, 3] + + """ + for row in M.values(): + yield from row.values() + + def iter_items(M): + """ + Iterate over indices and values of the nonzero elements. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM({0: {1: QQ(2)}, 1: {0: QQ(3)}}, (2, 2), QQ) + >>> list(A.iter_items()) + [((0, 1), 2), ((1, 0), 3)] + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.iter_items + """ + for i, row in M.items(): + for j, e in row.items(): + yield (i, j), e + + def to_ddm(M): + """ + Convert a :py:class:`~.SDM` object to a :py:class:`~.DDM` object + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM({0:{1:QQ(2)}, 1:{}}, (2, 2), QQ) + >>> A.to_ddm() + [[0, 2], [0, 0]] + + """ + return DDM(M.to_list(), M.shape, M.domain) + + def to_sdm(M): + """ + Convert to :py:class:`~.SDM` format (returns self). + """ + return M + + @doctest_depends_on(ground_types=['flint']) + def to_dfm(M): + """ + Convert a :py:class:`~.SDM` object to a :py:class:`~.DFM` object + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM({0:{1:QQ(2)}, 1:{}}, (2, 2), QQ) + >>> A.to_dfm() + [[0, 2], [0, 0]] + + See Also + ======== + + to_ddm + to_dfm_or_ddm + sympy.polys.matrices.domainmatrix.DomainMatrix.to_dfm + """ + return M.to_ddm().to_dfm() + + @doctest_depends_on(ground_types=['flint']) + def to_dfm_or_ddm(M): + """ + Convert to :py:class:`~.DFM` if possible, else :py:class:`~.DDM`. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM({0:{1:QQ(2)}, 1:{}}, (2, 2), QQ) + >>> A.to_dfm_or_ddm() + [[0, 2], [0, 0]] + >>> type(A.to_dfm_or_ddm()) # depends on the ground types + + + See Also + ======== + + to_ddm + to_dfm + sympy.polys.matrices.domainmatrix.DomainMatrix.to_dfm_or_ddm + """ + return M.to_ddm().to_dfm_or_ddm() + + @classmethod + def zeros(cls, shape, domain): + r""" + + Returns a :py:class:`~.SDM` of size shape, + belonging to the specified domain + + In the example below we declare a matrix A where, + + .. math:: + A := \left[\begin{array}{ccc} + 0 & 0 & 0 \\ + 0 & 0 & 0 \end{array} \right] + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM.zeros((2, 3), QQ) + >>> A + {} + + """ + return cls({}, shape, domain) + + @classmethod + def ones(cls, shape, domain): + one = domain.one + m, n = shape + row = dict(zip(range(n), [one]*n)) + sdm = {i: row.copy() for i in range(m)} + return cls(sdm, shape, domain) + + @classmethod + def eye(cls, shape, domain): + """ + + Returns a identity :py:class:`~.SDM` matrix of dimensions + size x size, belonging to the specified domain + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> I = SDM.eye((2, 2), QQ) + >>> I + {0: {0: 1}, 1: {1: 1}} + + """ + if isinstance(shape, int): + rows, cols = shape, shape + else: + rows, cols = shape + one = domain.one + sdm = {i: {i: one} for i in range(min(rows, cols))} + return cls(sdm, (rows, cols), domain) + + @classmethod + def diag(cls, diagonal, domain, shape=None): + if shape is None: + shape = (len(diagonal), len(diagonal)) + sdm = {i: {i: v} for i, v in enumerate(diagonal) if v} + return cls(sdm, shape, domain) + + def transpose(M): + """ + + Returns the transpose of a :py:class:`~.SDM` matrix + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy import QQ + >>> A = SDM({0:{1:QQ(2)}, 1:{}}, (2, 2), QQ) + >>> A.transpose() + {1: {0: 2}} + + """ + MT = sdm_transpose(M) + return M.new(MT, M.shape[::-1], M.domain) + + def __add__(A, B): + if not isinstance(B, SDM): + return NotImplemented + elif A.shape != B.shape: + raise DMShapeError("Matrix size mismatch: %s + %s" % (A.shape, B.shape)) + return A.add(B) + + def __sub__(A, B): + if not isinstance(B, SDM): + return NotImplemented + elif A.shape != B.shape: + raise DMShapeError("Matrix size mismatch: %s - %s" % (A.shape, B.shape)) + return A.sub(B) + + def __neg__(A): + return A.neg() + + def __mul__(A, B): + """A * B""" + if isinstance(B, SDM): + return A.matmul(B) + elif B in A.domain: + return A.mul(B) + else: + return NotImplemented + + def __rmul__(a, b): + if b in a.domain: + return a.rmul(b) + else: + return NotImplemented + + def matmul(A, B): + """ + Performs matrix multiplication of two SDM matrices + + Parameters + ========== + + A, B: SDM to multiply + + Returns + ======= + + SDM + SDM after multiplication + + Raises + ====== + + DomainError + If domain of A does not match + with that of B + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) + >>> B = SDM({0:{0:ZZ(2), 1:ZZ(3)}, 1:{0:ZZ(4)}}, (2, 2), ZZ) + >>> A.matmul(B) + {0: {0: 8}, 1: {0: 2, 1: 3}} + + """ + if A.domain != B.domain: + raise DMDomainError + m, n = A.shape + n2, o = B.shape + if n != n2: + raise DMShapeError + C = sdm_matmul(A, B, A.domain, m, o) + return A.new(C, (m, o), A.domain) + + def mul(A, b): + """ + Multiplies each element of A with a scalar b + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) + >>> A.mul(ZZ(3)) + {0: {1: 6}, 1: {0: 3}} + + """ + Csdm = unop_dict(A, lambda aij: aij*b) + return A.new(Csdm, A.shape, A.domain) + + def rmul(A, b): + Csdm = unop_dict(A, lambda aij: b*aij) + return A.new(Csdm, A.shape, A.domain) + + def mul_elementwise(A, B): + if A.domain != B.domain: + raise DMDomainError + if A.shape != B.shape: + raise DMShapeError + zero = A.domain.zero + fzero = lambda e: zero + Csdm = binop_dict(A, B, mul, fzero, fzero) + return A.new(Csdm, A.shape, A.domain) + + def add(A, B): + """ + + Adds two :py:class:`~.SDM` matrices + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) + >>> B = SDM({0:{0: ZZ(3)}, 1:{1:ZZ(4)}}, (2, 2), ZZ) + >>> A.add(B) + {0: {0: 3, 1: 2}, 1: {0: 1, 1: 4}} + + """ + Csdm = binop_dict(A, B, add, pos, pos) + return A.new(Csdm, A.shape, A.domain) + + def sub(A, B): + """ + + Subtracts two :py:class:`~.SDM` matrices + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) + >>> B = SDM({0:{0: ZZ(3)}, 1:{1:ZZ(4)}}, (2, 2), ZZ) + >>> A.sub(B) + {0: {0: -3, 1: 2}, 1: {0: 1, 1: -4}} + + """ + Csdm = binop_dict(A, B, sub, pos, neg) + return A.new(Csdm, A.shape, A.domain) + + def neg(A): + """ + + Returns the negative of a :py:class:`~.SDM` matrix + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) + >>> A.neg() + {0: {1: -2}, 1: {0: -1}} + + """ + Csdm = unop_dict(A, neg) + return A.new(Csdm, A.shape, A.domain) + + def convert_to(A, K): + """ + Converts the :py:class:`~.Domain` of a :py:class:`~.SDM` matrix to K + + Examples + ======== + + >>> from sympy import ZZ, QQ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) + >>> A.convert_to(QQ) + {0: {1: 2}, 1: {0: 1}} + + """ + Kold = A.domain + if K == Kold: + return A.copy() + Ak = unop_dict(A, lambda e: K.convert_from(e, Kold)) + return A.new(Ak, A.shape, K) + + def nnz(A): + """Number of non-zero elements in the :py:class:`~.SDM` matrix. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) + >>> A.nnz() + 2 + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.nnz + """ + return sum(map(len, A.values())) + + def scc(A): + """Strongly connected components of a square matrix *A*. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{0: ZZ(2)}, 1:{1:ZZ(1)}}, (2, 2), ZZ) + >>> A.scc() + [[0], [1]] + + See also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.scc + """ + rows, cols = A.shape + assert rows == cols + V = range(rows) + Emap = {v: list(A.get(v, [])) for v in V} + return _strongly_connected_components(V, Emap) + + def rref(A): + """ + + Returns reduced-row echelon form and list of pivots for the :py:class:`~.SDM` + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(2), 1:QQ(4)}}, (2, 2), QQ) + >>> A.rref() + ({0: {0: 1, 1: 2}}, [0]) + + """ + B, pivots, _ = sdm_irref(A) + return A.new(B, A.shape, A.domain), pivots + + def rref_den(A): + """ + + Returns reduced-row echelon form (RREF) with denominator and pivots. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(2), 1:QQ(4)}}, (2, 2), QQ) + >>> A.rref_den() + ({0: {0: 1, 1: 2}}, 1, [0]) + + """ + K = A.domain + A_rref_sdm, denom, pivots = sdm_rref_den(A, K) + A_rref = A.new(A_rref_sdm, A.shape, A.domain) + return A_rref, denom, pivots + + def inv(A): + """ + + Returns inverse of a matrix A + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) + >>> A.inv() + {0: {0: -2, 1: 1}, 1: {0: 3/2, 1: -1/2}} + + """ + return A.to_dfm_or_ddm().inv().to_sdm() + + def det(A): + """ + Returns determinant of A + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) + >>> A.det() + -2 + + """ + # It would be better to have a sparse implementation of det for use + # with very sparse matrices. Extremely sparse matrices probably just + # have determinant zero and we could probably detect that very quickly. + # In the meantime, we convert to a dense matrix and use ddm_idet. + # + # If GROUND_TYPES=flint though then we will use Flint's implementation + # if possible (dfm). + return A.to_dfm_or_ddm().det() + + def lu(A): + """ + + Returns LU decomposition for a matrix A + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) + >>> A.lu() + ({0: {0: 1}, 1: {0: 3, 1: 1}}, {0: {0: 1, 1: 2}, 1: {1: -2}}, []) + + """ + L, U, swaps = A.to_ddm().lu() + return A.from_ddm(L), A.from_ddm(U), swaps + + def qr(self): + """ + QR decomposition for SDM (Sparse Domain Matrix). + + Returns: + - Q: Orthogonal matrix as a SDM. + - R: Upper triangular matrix as a SDM. + """ + ddm_q, ddm_r = self.to_ddm().qr() + Q = ddm_q.to_sdm() + R = ddm_r.to_sdm() + return Q, R + + def lu_solve(A, b): + """ + + Uses LU decomposition to solve Ax = b, + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) + >>> b = SDM({0:{0:QQ(1)}, 1:{0:QQ(2)}}, (2, 1), QQ) + >>> A.lu_solve(b) + {1: {0: 1/2}} + + """ + return A.from_ddm(A.to_ddm().lu_solve(b.to_ddm())) + + def fflu(self): + """ + Fraction free LU decomposition of SDM. + + Uses DDM implementation. + + See Also + ======== + + sympy.polys.matrices.ddm.DDM.fflu + """ + ddm_p, ddm_l, ddm_d, ddm_u = self.to_dfm_or_ddm().fflu() + P = ddm_p.to_sdm() + L = ddm_l.to_sdm() + D = ddm_d.to_sdm() + U = ddm_u.to_sdm() + return P, L, D, U + + def nullspace(A): + """ + Nullspace of a :py:class:`~.SDM` matrix A. + + The domain of the matrix must be a field. + + It is better to use the :meth:`~.DomainMatrix.nullspace` method rather + than this method which is otherwise no longer used. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0: QQ(2), 1: QQ(4)}}, (2, 2), QQ) + >>> A.nullspace() + ({0: {0: -2, 1: 1}}, [1]) + + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.nullspace + The preferred way to get the nullspace of a matrix. + + """ + ncols = A.shape[1] + one = A.domain.one + B, pivots, nzcols = sdm_irref(A) + K, nonpivots = sdm_nullspace_from_rref(B, one, ncols, pivots, nzcols) + K = dict(enumerate(K)) + shape = (len(K), ncols) + return A.new(K, shape, A.domain), nonpivots + + def nullspace_from_rref(A, pivots=None): + """ + Returns nullspace for a :py:class:`~.SDM` matrix ``A`` in RREF. + + The domain of the matrix can be any domain. + + The matrix must already be in reduced row echelon form (RREF). + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.matrices.sdm import SDM + >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0: QQ(2), 1: QQ(4)}}, (2, 2), QQ) + >>> A_rref, pivots = A.rref() + >>> A_null, nonpivots = A_rref.nullspace_from_rref(pivots) + >>> A_null + {0: {0: -2, 1: 1}} + >>> pivots + [0] + >>> nonpivots + [1] + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.nullspace + The higher-level function that would usually be called instead of + calling this one directly. + + sympy.polys.matrices.domainmatrix.DomainMatrix.nullspace_from_rref + The higher-level direct equivalent of this function. + + sympy.polys.matrices.ddm.DDM.nullspace_from_rref + The equivalent function for dense :py:class:`~.DDM` matrices. + + """ + m, n = A.shape + K = A.domain + + if pivots is None: + pivots = sorted(map(min, A.values())) + + if not pivots: + return A.eye((n, n), K), list(range(n)) + elif len(pivots) == n: + return A.zeros((0, n), K), [] + + # In fraction-free RREF the nonzero entry inserted for the pivots is + # not necessarily 1. + pivot_val = A[0][pivots[0]] + assert not K.is_zero(pivot_val) + + pivots_set = set(pivots) + + # Loop once over all nonzero entries making a map from column indices + # to the nonzero entries in that column along with the row index of the + # nonzero entry. This is basically the transpose of the matrix. + nonzero_cols = defaultdict(list) + for i, Ai in A.items(): + for j, Aij in Ai.items(): + nonzero_cols[j].append((i, Aij)) + + # Usually in SDM we want to avoid looping over the dimensions of the + # matrix because it is optimised to support extremely sparse matrices. + # Here in nullspace though every zero column becomes a nonzero column + # so we need to loop once over the columns at least (range(n)) rather + # than just the nonzero entries of the matrix. We can still avoid + # an inner loop over the rows though by using the nonzero_cols map. + basis = [] + nonpivots = [] + for j in range(n): + if j in pivots_set: + continue + nonpivots.append(j) + + vec = {j: pivot_val} + for ip, Aij in nonzero_cols[j]: + vec[pivots[ip]] = -Aij + + basis.append(vec) + + sdm = dict(enumerate(basis)) + A_null = A.new(sdm, (len(basis), n), K) + + return (A_null, nonpivots) + + def particular(A): + ncols = A.shape[1] + B, pivots, nzcols = sdm_irref(A) + P = sdm_particular_from_rref(B, ncols, pivots) + rep = {0:P} if P else {} + return A.new(rep, (1, ncols-1), A.domain) + + def hstack(A, *B): + """Horizontally stacks :py:class:`~.SDM` matrices. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import SDM + + >>> A = SDM({0: {0: ZZ(1), 1: ZZ(2)}, 1: {0: ZZ(3), 1: ZZ(4)}}, (2, 2), ZZ) + >>> B = SDM({0: {0: ZZ(5), 1: ZZ(6)}, 1: {0: ZZ(7), 1: ZZ(8)}}, (2, 2), ZZ) + >>> A.hstack(B) + {0: {0: 1, 1: 2, 2: 5, 3: 6}, 1: {0: 3, 1: 4, 2: 7, 3: 8}} + + >>> C = SDM({0: {0: ZZ(9), 1: ZZ(10)}, 1: {0: ZZ(11), 1: ZZ(12)}}, (2, 2), ZZ) + >>> A.hstack(B, C) + {0: {0: 1, 1: 2, 2: 5, 3: 6, 4: 9, 5: 10}, 1: {0: 3, 1: 4, 2: 7, 3: 8, 4: 11, 5: 12}} + """ + Anew = dict(A.copy()) + rows, cols = A.shape + domain = A.domain + + for Bk in B: + Bkrows, Bkcols = Bk.shape + assert Bkrows == rows + assert Bk.domain == domain + + for i, Bki in Bk.items(): + Ai = Anew.get(i, None) + if Ai is None: + Anew[i] = Ai = {} + for j, Bkij in Bki.items(): + Ai[j + cols] = Bkij + cols += Bkcols + + return A.new(Anew, (rows, cols), A.domain) + + def vstack(A, *B): + """Vertically stacks :py:class:`~.SDM` matrices. + + Examples + ======== + + >>> from sympy import ZZ + >>> from sympy.polys.matrices.sdm import SDM + + >>> A = SDM({0: {0: ZZ(1), 1: ZZ(2)}, 1: {0: ZZ(3), 1: ZZ(4)}}, (2, 2), ZZ) + >>> B = SDM({0: {0: ZZ(5), 1: ZZ(6)}, 1: {0: ZZ(7), 1: ZZ(8)}}, (2, 2), ZZ) + >>> A.vstack(B) + {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}, 2: {0: 5, 1: 6}, 3: {0: 7, 1: 8}} + + >>> C = SDM({0: {0: ZZ(9), 1: ZZ(10)}, 1: {0: ZZ(11), 1: ZZ(12)}}, (2, 2), ZZ) + >>> A.vstack(B, C) + {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}, 2: {0: 5, 1: 6}, 3: {0: 7, 1: 8}, 4: {0: 9, 1: 10}, 5: {0: 11, 1: 12}} + """ + Anew = dict(A.copy()) + rows, cols = A.shape + domain = A.domain + + for Bk in B: + Bkrows, Bkcols = Bk.shape + assert Bkcols == cols + assert Bk.domain == domain + + for i, Bki in Bk.items(): + Anew[i + rows] = Bki + rows += Bkrows + + return A.new(Anew, (rows, cols), A.domain) + + def applyfunc(self, func, domain): + sdm = {i: {j: func(e) for j, e in row.items()} for i, row in self.items()} + return self.new(sdm, self.shape, domain) + + def charpoly(A): + """ + Returns the coefficients of the characteristic polynomial + of the :py:class:`~.SDM` matrix. These elements will be domain elements. + The domain of the elements will be same as domain of the :py:class:`~.SDM`. + + Examples + ======== + + >>> from sympy import QQ, Symbol + >>> from sympy.polys.matrices.sdm import SDM + >>> from sympy.polys import Poly + >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) + >>> A.charpoly() + [1, -5, -2] + + We can create a polynomial using the + coefficients using :py:class:`~.Poly` + + >>> x = Symbol('x') + >>> p = Poly(A.charpoly(), x, domain=A.domain) + >>> p + Poly(x**2 - 5*x - 2, x, domain='QQ') + + """ + K = A.domain + n, _ = A.shape + pdict = sdm_berk(A, n, K) + plist = [K.zero] * (n + 1) + for i, pi in pdict.items(): + plist[i] = pi + return plist + + def is_zero_matrix(self): + """ + Says whether this matrix has all zero entries. + """ + return not self + + def is_upper(self): + """ + Says whether this matrix is upper-triangular. True can be returned + even if the matrix is not square. + """ + return all(i <= j for i, row in self.items() for j in row) + + def is_lower(self): + """ + Says whether this matrix is lower-triangular. True can be returned + even if the matrix is not square. + """ + return all(i >= j for i, row in self.items() for j in row) + + def is_diagonal(self): + """ + Says whether this matrix is diagonal. True can be returned + even if the matrix is not square. + """ + return all(i == j for i, row in self.items() for j in row) + + def diagonal(self): + """ + Returns the diagonal of the matrix as a list. + """ + m, n = self.shape + zero = self.domain.zero + return [row.get(i, zero) for i, row in self.items() if i < n] + + def lll(A, delta=QQ(3, 4)): + """ + Returns the LLL-reduced basis for the :py:class:`~.SDM` matrix. + """ + return A.to_dfm_or_ddm().lll(delta=delta).to_sdm() + + def lll_transform(A, delta=QQ(3, 4)): + """ + Returns the LLL-reduced basis and transformation matrix. + """ + reduced, transform = A.to_dfm_or_ddm().lll_transform(delta=delta) + return reduced.to_sdm(), transform.to_sdm() + + +def binop_dict(A, B, fab, fa, fb): + Anz, Bnz = set(A), set(B) + C = {} + + for i in Anz & Bnz: + Ai, Bi = A[i], B[i] + Ci = {} + Anzi, Bnzi = set(Ai), set(Bi) + for j in Anzi & Bnzi: + Cij = fab(Ai[j], Bi[j]) + if Cij: + Ci[j] = Cij + for j in Anzi - Bnzi: + Cij = fa(Ai[j]) + if Cij: + Ci[j] = Cij + for j in Bnzi - Anzi: + Cij = fb(Bi[j]) + if Cij: + Ci[j] = Cij + if Ci: + C[i] = Ci + + for i in Anz - Bnz: + Ai = A[i] + Ci = {} + for j, Aij in Ai.items(): + Cij = fa(Aij) + if Cij: + Ci[j] = Cij + if Ci: + C[i] = Ci + + for i in Bnz - Anz: + Bi = B[i] + Ci = {} + for j, Bij in Bi.items(): + Cij = fb(Bij) + if Cij: + Ci[j] = Cij + if Ci: + C[i] = Ci + + return C + + +def unop_dict(A, f): + B = {} + for i, Ai in A.items(): + Bi = {} + for j, Aij in Ai.items(): + Bij = f(Aij) + if Bij: + Bi[j] = Bij + if Bi: + B[i] = Bi + return B + + +def sdm_transpose(M): + MT = {} + for i, Mi in M.items(): + for j, Mij in Mi.items(): + try: + MT[j][i] = Mij + except KeyError: + MT[j] = {i: Mij} + return MT + + +def sdm_dotvec(A, B, K): + return K.sum(A[j] * B[j] for j in A.keys() & B.keys()) + + +def sdm_matvecmul(A, B, K): + C = {} + for i, Ai in A.items(): + Ci = sdm_dotvec(Ai, B, K) + if Ci: + C[i] = Ci + return C + + +def sdm_matmul(A, B, K, m, o): + # + # Should be fast if A and B are very sparse. + # Consider e.g. A = B = eye(1000). + # + # The idea here is that we compute C = A*B in terms of the rows of C and + # B since the dict of dicts representation naturally stores the matrix as + # rows. The ith row of C (Ci) is equal to the sum of Aik * Bk where Bk is + # the kth row of B. The algorithm below loops over each nonzero element + # Aik of A and if the corresponding row Bj is nonzero then we do + # Ci += Aik * Bk. + # To make this more efficient we don't need to loop over all elements Aik. + # Instead for each row Ai we compute the intersection of the nonzero + # columns in Ai with the nonzero rows in B. That gives the k such that + # Aik and Bk are both nonzero. In Python the intersection of two sets + # of int can be computed very efficiently. + # + if K.is_EXRAW: + return sdm_matmul_exraw(A, B, K, m, o) + + C = {} + B_knz = set(B) + for i, Ai in A.items(): + Ci = {} + Ai_knz = set(Ai) + for k in Ai_knz & B_knz: + Aik = Ai[k] + for j, Bkj in B[k].items(): + Cij = Ci.get(j, None) + if Cij is not None: + Cij = Cij + Aik * Bkj + if Cij: + Ci[j] = Cij + else: + Ci.pop(j) + else: + Cij = Aik * Bkj + if Cij: + Ci[j] = Cij + if Ci: + C[i] = Ci + return C + + +def sdm_matmul_exraw(A, B, K, m, o): + # + # Like sdm_matmul above except that: + # + # - Handles cases like 0*oo -> nan (sdm_matmul skips multiplication by zero) + # - Uses K.sum (Add(*items)) for efficient addition of Expr + # + zero = K.zero + C = {} + B_knz = set(B) + for i, Ai in A.items(): + Ci_list = defaultdict(list) + Ai_knz = set(Ai) + + # Nonzero row/column pair + for k in Ai_knz & B_knz: + Aik = Ai[k] + if zero * Aik == zero: + # This is the main inner loop: + for j, Bkj in B[k].items(): + Ci_list[j].append(Aik * Bkj) + else: + for j in range(o): + Ci_list[j].append(Aik * B[k].get(j, zero)) + + # Zero row in B, check for infinities in A + for k in Ai_knz - B_knz: + zAik = zero * Ai[k] + if zAik != zero: + for j in range(o): + Ci_list[j].append(zAik) + + # Add terms using K.sum (Add(*terms)) for efficiency + Ci = {} + for j, Cij_list in Ci_list.items(): + Cij = K.sum(Cij_list) + if Cij: + Ci[j] = Cij + if Ci: + C[i] = Ci + + # Find all infinities in B + for k, Bk in B.items(): + for j, Bkj in Bk.items(): + if zero * Bkj != zero: + for i in range(m): + Aik = A.get(i, {}).get(k, zero) + # If Aik is not zero then this was handled above + if Aik == zero: + Ci = C.get(i, {}) + Cij = Ci.get(j, zero) + Aik * Bkj + if Cij != zero: + Ci[j] = Cij + C[i] = Ci + else: + Ci.pop(j, None) + if Ci: + C[i] = Ci + else: + C.pop(i, None) + + return C + + +def sdm_irref(A): + """RREF and pivots of a sparse matrix *A*. + + Compute the reduced row echelon form (RREF) of the matrix *A* and return a + list of the pivot columns. This routine does not work in place and leaves + the original matrix *A* unmodified. + + The domain of the matrix must be a field. + + Examples + ======== + + This routine works with a dict of dicts sparse representation of a matrix: + + >>> from sympy import QQ + >>> from sympy.polys.matrices.sdm import sdm_irref + >>> A = {0: {0: QQ(1), 1: QQ(2)}, 1: {0: QQ(3), 1: QQ(4)}} + >>> Arref, pivots, _ = sdm_irref(A) + >>> Arref + {0: {0: 1}, 1: {1: 1}} + >>> pivots + [0, 1] + + The analogous calculation with :py:class:`~.MutableDenseMatrix` would be + + >>> from sympy import Matrix + >>> M = Matrix([[1, 2], [3, 4]]) + >>> Mrref, pivots = M.rref() + >>> Mrref + Matrix([ + [1, 0], + [0, 1]]) + >>> pivots + (0, 1) + + Notes + ===== + + The cost of this algorithm is determined purely by the nonzero elements of + the matrix. No part of the cost of any step in this algorithm depends on + the number of rows or columns in the matrix. No step depends even on the + number of nonzero rows apart from the primary loop over those rows. The + implementation is much faster than ddm_rref for sparse matrices. In fact + at the time of writing it is also (slightly) faster than the dense + implementation even if the input is a fully dense matrix so it seems to be + faster in all cases. + + The elements of the matrix should support exact division with ``/``. For + example elements of any domain that is a field (e.g. ``QQ``) should be + fine. No attempt is made to handle inexact arithmetic. + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.rref + The higher-level function that would normally be used to call this + routine. + sympy.polys.matrices.dense.ddm_irref + The dense equivalent of this routine. + sdm_rref_den + Fraction-free version of this routine. + """ + # + # Any zeros in the matrix are not stored at all so an element is zero if + # its row dict has no index at that key. A row is entirely zero if its + # row index is not in the outer dict. Since rref reorders the rows and + # removes zero rows we can completely discard the row indices. The first + # step then copies the row dicts into a list sorted by the index of the + # first nonzero column in each row. + # + # The algorithm then processes each row Ai one at a time. Previously seen + # rows are used to cancel their pivot columns from Ai. Then a pivot from + # Ai is chosen and is cancelled from all previously seen rows. At this + # point Ai joins the previously seen rows. Once all rows are seen all + # elimination has occurred and the rows are sorted by pivot column index. + # + # The previously seen rows are stored in two separate groups. The reduced + # group consists of all rows that have been reduced to a single nonzero + # element (the pivot). There is no need to attempt any further reduction + # with these. Rows that still have other nonzeros need to be considered + # when Ai is cancelled from the previously seen rows. + # + # A dict nonzerocolumns is used to map from a column index to a set of + # previously seen rows that still have a nonzero element in that column. + # This means that we can cancel the pivot from Ai into the previously seen + # rows without needing to loop over each row that might have a zero in + # that column. + # + + # Row dicts sorted by index of first nonzero column + # (Maybe sorting is not needed/useful.) + Arows = sorted((Ai.copy() for Ai in A.values()), key=min) + + # Each processed row has an associated pivot column. + # pivot_row_map maps from the pivot column index to the row dict. + # This means that we can represent a set of rows purely as a set of their + # pivot indices. + pivot_row_map = {} + + # Set of pivot indices for rows that are fully reduced to a single nonzero. + reduced_pivots = set() + + # Set of pivot indices for rows not fully reduced + nonreduced_pivots = set() + + # Map from column index to a set of pivot indices representing the rows + # that have a nonzero at that column. + nonzero_columns = defaultdict(set) + + while Arows: + # Select pivot element and row + Ai = Arows.pop() + + # Nonzero columns from fully reduced pivot rows can be removed + Ai = {j: Aij for j, Aij in Ai.items() if j not in reduced_pivots} + + # Others require full row cancellation + for j in nonreduced_pivots & set(Ai): + Aj = pivot_row_map[j] + Aij = Ai[j] + Ainz = set(Ai) + Ajnz = set(Aj) + for k in Ajnz - Ainz: + Ai[k] = - Aij * Aj[k] + Ai.pop(j) + Ainz.remove(j) + for k in Ajnz & Ainz: + Aik = Ai[k] - Aij * Aj[k] + if Aik: + Ai[k] = Aik + else: + Ai.pop(k) + + # We have now cancelled previously seen pivots from Ai. + # If it is zero then discard it. + if not Ai: + continue + + # Choose a pivot from Ai: + j = min(Ai) + Aij = Ai[j] + pivot_row_map[j] = Ai + Ainz = set(Ai) + + # Normalise the pivot row to make the pivot 1. + # + # This approach is slow for some domains. Cross cancellation might be + # better for e.g. QQ(x) with division delayed to the final steps. + Aijinv = Aij**-1 + for l in Ai: + Ai[l] *= Aijinv + + # Use Aij to cancel column j from all previously seen rows + for k in nonzero_columns.pop(j, ()): + Ak = pivot_row_map[k] + Akj = Ak[j] + Aknz = set(Ak) + for l in Ainz - Aknz: + Ak[l] = - Akj * Ai[l] + nonzero_columns[l].add(k) + Ak.pop(j) + Aknz.remove(j) + for l in Ainz & Aknz: + Akl = Ak[l] - Akj * Ai[l] + if Akl: + Ak[l] = Akl + else: + # Drop nonzero elements + Ak.pop(l) + if l != j: + nonzero_columns[l].remove(k) + if len(Ak) == 1: + reduced_pivots.add(k) + nonreduced_pivots.remove(k) + + if len(Ai) == 1: + reduced_pivots.add(j) + else: + nonreduced_pivots.add(j) + for l in Ai: + if l != j: + nonzero_columns[l].add(j) + + # All done! + pivots = sorted(reduced_pivots | nonreduced_pivots) + pivot2row = {p: n for n, p in enumerate(pivots)} + nonzero_columns = {c: {pivot2row[p] for p in s} for c, s in nonzero_columns.items()} + rows = [pivot_row_map[i] for i in pivots] + rref = dict(enumerate(rows)) + return rref, pivots, nonzero_columns + + +def sdm_rref_den(A, K): + """ + Return the reduced row echelon form (RREF) of A with denominator. + + The RREF is computed using fraction-free Gauss-Jordan elimination. + + Explanation + =========== + + The algorithm used is the fraction-free version of Gauss-Jordan elimination + described as FFGJ in [1]_. Here it is modified to handle zero or missing + pivots and to avoid redundant arithmetic. This implementation is also + optimized for sparse matrices. + + The domain $K$ must support exact division (``K.exquo``) but does not need + to be a field. This method is suitable for most exact rings and fields like + :ref:`ZZ`, :ref:`QQ` and :ref:`QQ(a)`. In the case of :ref:`QQ` or + :ref:`K(x)` it might be more efficient to clear denominators and use + :ref:`ZZ` or :ref:`K[x]` instead. + + For inexact domains like :ref:`RR` and :ref:`CC` use ``ddm_irref`` instead. + + Examples + ======== + + >>> from sympy.polys.matrices.sdm import sdm_rref_den + >>> from sympy.polys.domains import ZZ + >>> A = {0: {0: ZZ(1), 1: ZZ(2)}, 1: {0: ZZ(3), 1: ZZ(4)}} + >>> A_rref, den, pivots = sdm_rref_den(A, ZZ) + >>> A_rref + {0: {0: -2}, 1: {1: -2}} + >>> den + -2 + >>> pivots + [0, 1] + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.rref_den + Higher-level interface to ``sdm_rref_den`` that would usually be used + instead of calling this function directly. + sympy.polys.matrices.sdm.sdm_rref_den + The ``SDM`` method that uses this function. + sdm_irref + Computes RREF using field division. + ddm_irref_den + The dense version of this algorithm. + + References + ========== + + .. [1] Fraction-free algorithms for linear and polynomial equations. + George C. Nakos , Peter R. Turner , Robert M. Williams. + https://dl.acm.org/doi/10.1145/271130.271133 + """ + # + # We represent each row of the matrix as a dict mapping column indices to + # nonzero elements. We will build the RREF matrix starting from an empty + # matrix and appending one row at a time. At each step we will have the + # RREF of the rows we have processed so far. + # + # Our representation of the RREF divides it into three parts: + # + # 1. Fully reduced rows having only a single nonzero element (the pivot). + # 2. Partially reduced rows having nonzeros after the pivot. + # 3. The current denominator and divisor. + # + # For example if the incremental RREF might be: + # + # [2, 0, 0, 0, 0, 0, 0, 0, 0, 0] + # [0, 0, 2, 0, 0, 0, 7, 0, 0, 0] + # [0, 0, 0, 0, 0, 2, 0, 0, 0, 0] + # [0, 0, 0, 0, 0, 0, 0, 2, 0, 0] + # [0, 0, 0, 0, 0, 0, 0, 0, 2, 0] + # + # Here the second row is partially reduced and the other rows are fully + # reduced. The denominator would be 2 in this case. We distinguish the + # fully reduced rows because we can handle them more efficiently when + # adding a new row. + # + # When adding a new row we need to multiply it by the current denominator. + # Then we reduce the new row by cross cancellation with the previous rows. + # Then if it is not reduced to zero we take its leading entry as the new + # pivot, cross cancel the new row from the previous rows and update the + # denominator. In the fraction-free version this last step requires + # multiplying and dividing the whole matrix by the new pivot and the + # current divisor. The advantage of building the RREF one row at a time is + # that in the sparse case we only need to work with the relatively sparse + # upper rows of the matrix. The simple version of FFGJ in [1] would + # multiply and divide all the dense lower rows at each step. + + # Handle the trivial cases. + if not A: + return ({}, K.one, []) + elif len(A) == 1: + Ai, = A.values() + j = min(Ai) + Aij = Ai[j] + return ({0: Ai.copy()}, Aij, [j]) + + # For inexact domains like RR[x] we use quo and discard the remainder. + # Maybe it would be better for K.exquo to do this automatically. + if K.is_Exact: + exquo = K.exquo + else: + exquo = K.quo + + # Make sure we have the rows in order to make this deterministic from the + # outset. + _, rows_in_order = zip(*sorted(A.items())) + + col_to_row_reduced = {} + col_to_row_unreduced = {} + reduced = col_to_row_reduced.keys() + unreduced = col_to_row_unreduced.keys() + + # Our representation of the RREF so far. + A_rref_rows = [] + denom = None + divisor = None + + # The rows that remain to be added to the RREF. These are sorted by the + # column index of their leading entry. Note that sorted() is stable so the + # previous sort by unique row index is still needed to make this + # deterministic (there may be multiple rows with the same leading column). + A_rows = sorted(rows_in_order, key=min) + + for Ai in A_rows: + + # All fully reduced columns can be immediately discarded. + Ai = {j: Aij for j, Aij in Ai.items() if j not in reduced} + + # We need to multiply the new row by the current denominator to bring + # it into the same scale as the previous rows and then cross-cancel to + # reduce it wrt the previous unreduced rows. All pivots in the previous + # rows are equal to denom so the coefficients we need to make a linear + # combination of the previous rows to cancel into the new row are just + # the ones that are already in the new row *before* we multiply by + # denom. We compute that linear combination first and then multiply the + # new row by denom before subtraction. + Ai_cancel = {} + + for j in unreduced & Ai.keys(): + # Remove the pivot column from the new row since it would become + # zero anyway. + Aij = Ai.pop(j) + + Aj = A_rref_rows[col_to_row_unreduced[j]] + + for k, Ajk in Aj.items(): + Aik_cancel = Ai_cancel.get(k) + if Aik_cancel is None: + Ai_cancel[k] = Aij * Ajk + else: + Aik_cancel = Aik_cancel + Aij * Ajk + if Aik_cancel: + Ai_cancel[k] = Aik_cancel + else: + Ai_cancel.pop(k) + + # Multiply the new row by the current denominator and subtract. + Ai_nz = set(Ai) + Ai_cancel_nz = set(Ai_cancel) + + d = denom or K.one + + for k in Ai_cancel_nz - Ai_nz: + Ai[k] = -Ai_cancel[k] + + for k in Ai_nz - Ai_cancel_nz: + Ai[k] = Ai[k] * d + + for k in Ai_cancel_nz & Ai_nz: + Aik = Ai[k] * d - Ai_cancel[k] + if Aik: + Ai[k] = Aik + else: + Ai.pop(k) + + # Now Ai has the same scale as the other rows and is reduced wrt the + # unreduced rows. + + # If the row is reduced to zero then discard it. + if not Ai: + continue + + # Choose a pivot for this row. + j = min(Ai) + Aij = Ai.pop(j) + + # Cross cancel the unreduced rows by the new row. + # a[k][l] = (a[i][j]*a[k][l] - a[k][j]*a[i][l]) / divisor + for pk, k in list(col_to_row_unreduced.items()): + + Ak = A_rref_rows[k] + + if j not in Ak: + # This row is already reduced wrt the new row but we need to + # bring it to the same scale as the new denominator. This step + # is not needed in sdm_irref. + for l, Akl in Ak.items(): + Akl = Akl * Aij + if divisor is not None: + Akl = exquo(Akl, divisor) + Ak[l] = Akl + continue + + Akj = Ak.pop(j) + Ai_nz = set(Ai) + Ak_nz = set(Ak) + + for l in Ai_nz - Ak_nz: + Ak[l] = - Akj * Ai[l] + if divisor is not None: + Ak[l] = exquo(Ak[l], divisor) + + # This loop also not needed in sdm_irref. + for l in Ak_nz - Ai_nz: + Ak[l] = Aij * Ak[l] + if divisor is not None: + Ak[l] = exquo(Ak[l], divisor) + + for l in Ai_nz & Ak_nz: + Akl = Aij * Ak[l] - Akj * Ai[l] + if Akl: + if divisor is not None: + Akl = exquo(Akl, divisor) + Ak[l] = Akl + else: + Ak.pop(l) + + if not Ak: + col_to_row_unreduced.pop(pk) + col_to_row_reduced[pk] = k + + i = len(A_rref_rows) + A_rref_rows.append(Ai) + if Ai: + col_to_row_unreduced[j] = i + else: + col_to_row_reduced[j] = i + + # Update the denominator. + if not K.is_one(Aij): + if denom is None: + denom = Aij + else: + denom *= Aij + + if divisor is not None: + denom = exquo(denom, divisor) + + # Update the divisor. + divisor = denom + + if denom is None: + denom = K.one + + # Sort the rows by their leading column index. + col_to_row = {**col_to_row_reduced, **col_to_row_unreduced} + row_to_col = {i: j for j, i in col_to_row.items()} + A_rref_rows_col = [(row_to_col[i], Ai) for i, Ai in enumerate(A_rref_rows)] + pivots, A_rref = zip(*sorted(A_rref_rows_col)) + pivots = list(pivots) + + # Insert the pivot values + for i, Ai in enumerate(A_rref): + Ai[pivots[i]] = denom + + A_rref_sdm = dict(enumerate(A_rref)) + + return A_rref_sdm, denom, pivots + + +def sdm_nullspace_from_rref(A, one, ncols, pivots, nonzero_cols): + """Get nullspace from A which is in RREF""" + nonpivots = sorted(set(range(ncols)) - set(pivots)) + + K = [] + for j in nonpivots: + Kj = {j:one} + for i in nonzero_cols.get(j, ()): + Kj[pivots[i]] = -A[i][j] + K.append(Kj) + + return K, nonpivots + + +def sdm_particular_from_rref(A, ncols, pivots): + """Get a particular solution from A which is in RREF""" + P = {} + for i, j in enumerate(pivots): + Ain = A[i].get(ncols-1, None) + if Ain is not None: + P[j] = Ain / A[i][j] + return P + + +def sdm_berk(M, n, K): + """ + Berkowitz algorithm for computing the characteristic polynomial. + + Explanation + =========== + + The Berkowitz algorithm is a division-free algorithm for computing the + characteristic polynomial of a matrix over any commutative ring using only + arithmetic in the coefficient ring. This implementation is for sparse + matrices represented in a dict-of-dicts format (like :class:`SDM`). + + Examples + ======== + + >>> from sympy import Matrix + >>> from sympy.polys.matrices.sdm import sdm_berk + >>> from sympy.polys.domains import ZZ + >>> M = {0: {0: ZZ(1), 1:ZZ(2)}, 1: {0:ZZ(3), 1:ZZ(4)}} + >>> sdm_berk(M, 2, ZZ) + {0: 1, 1: -5, 2: -2} + >>> Matrix([[1, 2], [3, 4]]).charpoly() + PurePoly(lambda**2 - 5*lambda - 2, lambda, domain='ZZ') + + See Also + ======== + + sympy.polys.matrices.domainmatrix.DomainMatrix.charpoly + The high-level interface to this function. + sympy.polys.matrices.dense.ddm_berk + The dense version of this function. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Samuelson%E2%80%93Berkowitz_algorithm + """ + zero = K.zero + one = K.one + + if n == 0: + return {0: one} + elif n == 1: + pdict = {0: one} + if M00 := M.get(0, {}).get(0, zero): + pdict[1] = -M00 + + # M = [[a, R], + # [C, A]] + a, R, C, A = K.zero, {}, {}, defaultdict(dict) + for i, Mi in M.items(): + for j, Mij in Mi.items(): + if i and j: + A[i-1][j-1] = Mij + elif i: + C[i-1] = Mij + elif j: + R[j-1] = Mij + else: + a = Mij + + # T = [ 1, 0, 0, 0, 0, ... ] + # [ -a, 1, 0, 0, 0, ... ] + # [ -R*C, -a, 1, 0, 0, ... ] + # [ -R*A*C, -R*C, -a, 1, 0, ... ] + # [-R*A^2*C, -R*A*C, -R*C, -a, 1, ... ] + # [ ... ] + # T is (n+1) x n + # + # In the sparse case we might have A^m*C = 0 for some m making T banded + # rather than triangular so we just compute the nonzero entries of the + # first column rather than constructing the matrix explicitly. + + AnC = C + RC = sdm_dotvec(R, C, K) + + Tvals = [one, -a, -RC] + for i in range(3, n+1): + AnC = sdm_matvecmul(A, AnC, K) + if not AnC: + break + RAnC = sdm_dotvec(R, AnC, K) + Tvals.append(-RAnC) + + # Strip trailing zeros + while Tvals and not Tvals[-1]: + Tvals.pop() + + q = sdm_berk(A, n-1, K) + + # This would be the explicit multiplication T*q but we can do better: + # + # T = {} + # for i in range(n+1): + # Ti = {} + # for j in range(max(0, i-len(Tvals)+1), min(i+1, n)): + # Ti[j] = Tvals[i-j] + # T[i] = Ti + # Tq = sdm_matvecmul(T, q, K) + # + # In the sparse case q might be mostly zero. We know that T[i,j] is nonzero + # for i <= j < i + len(Tvals) so if q does not have a nonzero entry in that + # range then Tq[j] must be zero. We exploit this potential banded + # structure and the potential sparsity of q to compute Tq more efficiently. + + Tvals = Tvals[::-1] + + Tq = {} + + for i in range(min(q), min(max(q)+len(Tvals), n+1)): + Ti = dict(enumerate(Tvals, i-len(Tvals)+1)) + if Tqi := sdm_dotvec(Ti, q, K): + Tq[i] = Tqi + + return Tq diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..38403fdf80be22d47589a346d1b1878b982c3c93 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__init__.py @@ -0,0 +1,27 @@ +"""Computational algebraic field theory. """ + +__all__ = [ + 'minpoly', 'minimal_polynomial', + + 'field_isomorphism', 'primitive_element', 'to_number_field', + + 'isolate', + + 'round_two', + + 'prime_decomp', 'prime_valuation', + + 'galois_group', +] + +from .minpoly import minpoly, minimal_polynomial + +from .subfield import field_isomorphism, primitive_element, to_number_field + +from .utilities import isolate + +from .basis import round_two + +from .primes import prime_decomp, prime_valuation + +from .galoisgroups import galois_group diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..858d67ee469112de039f5579bc6aa37f108fd569 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/basis.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/basis.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d112b20e457ab3d1037b79586447f8289ccf4bb7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/basis.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/exceptions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/exceptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f067f814ff290bcaa7e90893e5b3f23dc607f17 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/exceptions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/galois_resolvents.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/galois_resolvents.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4698f896ac53030668c87f4d59949d2c60f7e415 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/galois_resolvents.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/galoisgroups.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/galoisgroups.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0bbe7809d399d15c89e22b7dad4abae6535e2e65 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/galoisgroups.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/minpoly.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/minpoly.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..82623dcea97a051da37e11d46a87f4831581bb0f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/minpoly.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/modules.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/modules.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..23e9fadb2c03efa03e41233ace42a713306ceb6b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/modules.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/primes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/primes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e522c8668c2d256603a4f94f65e88b90ba19ba9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/primes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/subfield.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/subfield.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f215ce6c84fbdd770b13ed1fa272e61d473f9056 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/subfield.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/utilities.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/utilities.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a0a710d02a1878e2fa91015981bda298d48b6e0e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/__pycache__/utilities.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/basis.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/basis.py new file mode 100644 index 0000000000000000000000000000000000000000..7c9cb41925973b3a10a80cc6ba1442cf44330971 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/basis.py @@ -0,0 +1,246 @@ +"""Computing integral bases for number fields. """ + +from sympy.polys.polytools import Poly +from sympy.polys.domains.algebraicfield import AlgebraicField +from sympy.polys.domains.integerring import ZZ +from sympy.polys.domains.rationalfield import QQ +from sympy.utilities.decorator import public +from .modules import ModuleEndomorphism, ModuleHomomorphism, PowerBasis +from .utilities import extract_fundamental_discriminant + + +def _apply_Dedekind_criterion(T, p): + r""" + Apply the "Dedekind criterion" to test whether the order needs to be + enlarged relative to a given prime *p*. + """ + x = T.gen + T_bar = Poly(T, modulus=p) + lc, fl = T_bar.factor_list() + assert lc == 1 + g_bar = Poly(1, x, modulus=p) + for ti_bar, _ in fl: + g_bar *= ti_bar + h_bar = T_bar // g_bar + g = Poly(g_bar, domain=ZZ) + h = Poly(h_bar, domain=ZZ) + f = (g * h - T) // p + f_bar = Poly(f, modulus=p) + Z_bar = f_bar + for b in [g_bar, h_bar]: + Z_bar = Z_bar.gcd(b) + U_bar = T_bar // Z_bar + m = Z_bar.degree() + return U_bar, m + + +def nilradical_mod_p(H, p, q=None): + r""" + Compute the nilradical mod *p* for a given order *H*, and prime *p*. + + Explanation + =========== + + This is the ideal $I$ in $H/pH$ consisting of all elements some positive + power of which is zero in this quotient ring, i.e. is a multiple of *p*. + + Parameters + ========== + + H : :py:class:`~.Submodule` + The given order. + p : int + The rational prime. + q : int, optional + If known, the smallest power of *p* that is $>=$ the dimension of *H*. + If not provided, we compute it here. + + Returns + ======= + + :py:class:`~.Module` representing the nilradical mod *p* in *H*. + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory*. + (See Lemma 6.1.6.) + + """ + n = H.n + if q is None: + q = p + while q < n: + q *= p + phi = ModuleEndomorphism(H, lambda x: x**q) + return phi.kernel(modulus=p) + + +def _second_enlargement(H, p, q): + r""" + Perform the second enlargement in the Round Two algorithm. + """ + Ip = nilradical_mod_p(H, p, q=q) + B = H.parent.submodule_from_matrix(H.matrix * Ip.matrix, denom=H.denom) + C = B + p*H + E = C.endomorphism_ring() + phi = ModuleHomomorphism(H, E, lambda x: E.inner_endomorphism(x)) + gamma = phi.kernel(modulus=p) + G = H.parent.submodule_from_matrix(H.matrix * gamma.matrix, denom=H.denom * p) + H1 = G + H + return H1, Ip + + +@public +def round_two(T, radicals=None): + r""" + Zassenhaus's "Round 2" algorithm. + + Explanation + =========== + + Carry out Zassenhaus's "Round 2" algorithm on an irreducible polynomial + *T* over :ref:`ZZ` or :ref:`QQ`. This computes an integral basis and the + discriminant for the field $K = \mathbb{Q}[x]/(T(x))$. + + Alternatively, you may pass an :py:class:`~.AlgebraicField` instance, in + place of the polynomial *T*, in which case the algorithm is applied to the + minimal polynomial for the field's primitive element. + + Ordinarily this function need not be called directly, as one can instead + access the :py:meth:`~.AlgebraicField.maximal_order`, + :py:meth:`~.AlgebraicField.integral_basis`, and + :py:meth:`~.AlgebraicField.discriminant` methods of an + :py:class:`~.AlgebraicField`. + + Examples + ======== + + Working through an AlgebraicField: + + >>> from sympy import Poly, QQ + >>> from sympy.abc import x + >>> T = Poly(x ** 3 + x ** 2 - 2 * x + 8) + >>> K = QQ.alg_field_from_poly(T, "theta") + >>> print(K.maximal_order()) + Submodule[[2, 0, 0], [0, 2, 0], [0, 1, 1]]/2 + >>> print(K.discriminant()) + -503 + >>> print(K.integral_basis(fmt='sympy')) + [1, theta, theta/2 + theta**2/2] + + Calling directly: + + >>> from sympy import Poly + >>> from sympy.abc import x + >>> from sympy.polys.numberfields.basis import round_two + >>> T = Poly(x ** 3 + x ** 2 - 2 * x + 8) + >>> print(round_two(T)) + (Submodule[[2, 0, 0], [0, 2, 0], [0, 1, 1]]/2, -503) + + The nilradicals mod $p$ that are sometimes computed during the Round Two + algorithm may be useful in further calculations. Pass a dictionary under + `radicals` to receive these: + + >>> T = Poly(x**3 + 3*x**2 + 5) + >>> rad = {} + >>> ZK, dK = round_two(T, radicals=rad) + >>> print(rad) + {3: Submodule[[-1, 1, 0], [-1, 0, 1]]} + + Parameters + ========== + + T : :py:class:`~.Poly`, :py:class:`~.AlgebraicField` + Either (1) the irreducible polynomial over :ref:`ZZ` or :ref:`QQ` + defining the number field, or (2) an :py:class:`~.AlgebraicField` + representing the number field itself. + + radicals : dict, optional + This is a way for any $p$-radicals (if computed) to be returned by + reference. If desired, pass an empty dictionary. If the algorithm + reaches the point where it computes the nilradical mod $p$ of the ring + of integers $Z_K$, then an $\mathbb{F}_p$-basis for this ideal will be + stored in this dictionary under the key ``p``. This can be useful for + other algorithms, such as prime decomposition. + + Returns + ======= + + Pair ``(ZK, dK)``, where: + + ``ZK`` is a :py:class:`~sympy.polys.numberfields.modules.Submodule` + representing the maximal order. + + ``dK`` is the discriminant of the field $K = \mathbb{Q}[x]/(T(x))$. + + See Also + ======== + + .AlgebraicField.maximal_order + .AlgebraicField.integral_basis + .AlgebraicField.discriminant + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* + + """ + K = None + if isinstance(T, AlgebraicField): + K, T = T, T.ext.minpoly_of_element() + if ( not T.is_univariate + or not T.is_irreducible + or T.domain not in [ZZ, QQ]): + raise ValueError('Round 2 requires an irreducible univariate polynomial over ZZ or QQ.') + T, _ = T.make_monic_over_integers_by_scaling_roots() + n = T.degree() + D = T.discriminant() + D_modulus = ZZ.from_sympy(abs(D)) + # D must be 0 or 1 mod 4 (see Cohen Sec 4.4), which ensures we can write + # it in the form D = D_0 * F**2, where D_0 is 1 or a fundamental discriminant. + _, F = extract_fundamental_discriminant(D) + Ztheta = PowerBasis(K or T) + H = Ztheta.whole_submodule() + nilrad = None + while F: + # Next prime: + p, e = F.popitem() + U_bar, m = _apply_Dedekind_criterion(T, p) + if m == 0: + continue + # For a given prime p, the first enlargement of the order spanned by + # the current basis can be done in a simple way: + U = Ztheta.element_from_poly(Poly(U_bar, domain=ZZ)) + # TODO: + # Theory says only first m columns of the U//p*H term below are needed. + # Could be slightly more efficient to use only those. Maybe `Submodule` + # class should support a slice operator? + H = H.add(U // p * H, hnf_modulus=D_modulus) + if e <= m: + continue + # A second, and possibly more, enlargements for p will be needed. + # These enlargements require a more involved procedure. + q = p + while q < n: + q *= p + H1, nilrad = _second_enlargement(H, p, q) + while H1 != H: + H = H1 + H1, nilrad = _second_enlargement(H, p, q) + # Note: We do not store all nilradicals mod p, only the very last. This is + # because, unless computed against the entire integral basis, it might not + # be accurate. (In other words, if H was not already equal to ZK when we + # passed it to `_second_enlargement`, then we can't trust the nilradical + # so computed.) Example: if T(x) = x ** 3 + 15 * x ** 2 - 9 * x + 13, then + # F is divisible by 2, 3, and 7, and the nilradical mod 2 as computed above + # will not be accurate for the full, maximal order ZK. + if nilrad is not None and isinstance(radicals, dict): + radicals[p] = nilrad + ZK = H + # Pre-set expensive boolean properties which we already know to be true: + ZK._starts_with_unity = True + ZK._is_sq_maxrank_HNF = True + dK = (D * ZK.matrix.det() ** 2) // ZK.denom ** (2 * n) + return ZK, dK diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/exceptions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/exceptions.py new file mode 100644 index 0000000000000000000000000000000000000000..6e0d1ddc23c39295626fa036cf34974f50e4f53a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/exceptions.py @@ -0,0 +1,54 @@ +"""Special exception classes for numberfields. """ + + +class ClosureFailure(Exception): + r""" + Signals that a :py:class:`ModuleElement` which we tried to represent in a + certain :py:class:`Module` cannot in fact be represented there. + + Examples + ======== + + >>> from sympy.polys import Poly, cyclotomic_poly, ZZ + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy.polys.numberfields.modules import PowerBasis, to_col + >>> T = Poly(cyclotomic_poly(5)) + >>> A = PowerBasis(T) + >>> B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + + Because we are in a cyclotomic field, the power basis ``A`` is an integral + basis, and the submodule ``B`` is just the ideal $(2)$. Therefore ``B`` can + represent an element having all even coefficients over the power basis: + + >>> a1 = A(to_col([2, 4, 6, 8])) + >>> print(B.represent(a1)) + DomainMatrix([[1], [2], [3], [4]], (4, 1), ZZ) + + but ``B`` cannot represent an element with an odd coefficient: + + >>> a2 = A(to_col([1, 2, 2, 2])) + >>> B.represent(a2) + Traceback (most recent call last): + ... + ClosureFailure: Element in QQ-span but not ZZ-span of this basis. + + """ + pass + + +class StructureError(Exception): + r""" + Represents cases in which an algebraic structure was expected to have a + certain property, or be of a certain type, but was not. + """ + pass + + +class MissingUnityError(StructureError): + r"""Structure should contain a unity element but does not.""" + pass + + +__all__ = [ + 'ClosureFailure', 'StructureError', 'MissingUnityError', +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/galois_resolvents.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/galois_resolvents.py new file mode 100644 index 0000000000000000000000000000000000000000..5d73b56870a498f09102787da3517e7520edb3db --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/galois_resolvents.py @@ -0,0 +1,676 @@ +r""" +Galois resolvents + +Each of the functions in ``sympy.polys.numberfields.galoisgroups`` that +computes Galois groups for a particular degree $n$ uses resolvents. Given the +polynomial $T$ whose Galois group is to be computed, a resolvent is a +polynomial $R$ whose roots are defined as functions of the roots of $T$. + +One way to compute the coefficients of $R$ is by approximating the roots of $T$ +to sufficient precision. This module defines a :py:class:`~.Resolvent` class +that handles this job, determining the necessary precision, and computing $R$. + +In some cases, the coefficients of $R$ are symmetric in the roots of $T$, +meaning they are equal to fixed functions of the coefficients of $T$. Therefore +another approach is to compute these functions once and for all, and record +them in a lookup table. This module defines code that can compute such tables. +The tables for polynomials $T$ of degrees 4 through 6, produced by this code, +are recorded in the resolvent_lookup.py module. + +""" + +from sympy.core.evalf import ( + evalf, fastlog, _evalf_with_bounded_error, quad_to_mpmath, +) +from sympy.core.symbol import symbols, Dummy +from sympy.polys.densetools import dup_eval +from sympy.polys.domains import ZZ +from sympy.polys.orderings import lex +from sympy.polys.polyroots import preprocess_roots +from sympy.polys.polytools import Poly +from sympy.polys.rings import xring +from sympy.polys.specialpolys import symmetric_poly +from sympy.utilities.lambdify import lambdify + +from mpmath import MPContext +from mpmath.libmp.libmpf import prec_to_dps + + +class GaloisGroupException(Exception): + ... + + +class ResolventException(GaloisGroupException): + ... + + +class Resolvent: + r""" + If $G$ is a subgroup of the symmetric group $S_n$, + $F$ a multivariate polynomial in $\mathbb{Z}[X_1, \ldots, X_n]$, + $H$ the stabilizer of $F$ in $G$ (i.e. the permutations $\sigma$ such that + $F(X_{\sigma(1)}, \ldots, X_{\sigma(n)}) = F(X_1, \ldots, X_n)$), and $s$ + a set of left coset representatives of $H$ in $G$, then the resolvent + polynomial $R(Y)$ is the product over $\sigma \in s$ of + $Y - F(X_{\sigma(1)}, \ldots, X_{\sigma(n)})$. + + For example, consider the resolvent for the form + $$F = X_0 X_2 + X_1 X_3$$ + and the group $G = S_4$. In this case, the stabilizer $H$ is the dihedral + group $D4 = < (0123), (02) >$, and a set of representatives of $G/H$ is + $\{I, (01), (03)\}$. The resolvent can be constructed as follows: + + >>> from sympy.combinatorics.permutations import Permutation + >>> from sympy.core.symbol import symbols + >>> from sympy.polys.numberfields.galoisgroups import Resolvent + >>> X = symbols('X0 X1 X2 X3') + >>> F = X[0]*X[2] + X[1]*X[3] + >>> s = [Permutation([0, 1, 2, 3]), Permutation([1, 0, 2, 3]), + ... Permutation([3, 1, 2, 0])] + >>> R = Resolvent(F, X, s) + + This resolvent has three roots, which are the conjugates of ``F`` under the + three permutations in ``s``: + + >>> R.root_lambdas[0](*X) + X0*X2 + X1*X3 + >>> R.root_lambdas[1](*X) + X0*X3 + X1*X2 + >>> R.root_lambdas[2](*X) + X0*X1 + X2*X3 + + Resolvents are useful for computing Galois groups. Given a polynomial $T$ + of degree $n$, we will use a resolvent $R$ where $Gal(T) \leq G \leq S_n$. + We will then want to substitute the roots of $T$ for the variables $X_i$ + in $R$, and study things like the discriminant of $R$, and the way $R$ + factors over $\mathbb{Q}$. + + From the symmetry in $R$'s construction, and since $Gal(T) \leq G$, we know + from Galois theory that the coefficients of $R$ must lie in $\mathbb{Z}$. + This allows us to compute the coefficients of $R$ by approximating the + roots of $T$ to sufficient precision, plugging these values in for the + variables $X_i$ in the coefficient expressions of $R$, and then simply + rounding to the nearest integer. + + In order to determine a sufficient precision for the roots of $T$, this + ``Resolvent`` class imposes certain requirements on the form ``F``. It + could be possible to design a different ``Resolvent`` class, that made + different precision estimates, and different assumptions about ``F``. + + ``F`` must be homogeneous, and all terms must have unit coefficient. + Furthermore, if $r$ is the number of terms in ``F``, and $t$ the total + degree, and if $m$ is the number of conjugates of ``F``, i.e. the number + of permutations in ``s``, then we require that $m < r 2^t$. Again, it is + not impossible to work with forms ``F`` that violate these assumptions, but + this ``Resolvent`` class requires them. + + Since determining the integer coefficients of the resolvent for a given + polynomial $T$ is one of the main problems this class solves, we take some + time to explain the precision bounds it uses. + + The general problem is: + Given a multivariate polynomial $P \in \mathbb{Z}[X_1, \ldots, X_n]$, and a + bound $M \in \mathbb{R}_+$, compute an $\varepsilon > 0$ such that for any + complex numbers $a_1, \ldots, a_n$ with $|a_i| < M$, if the $a_i$ are + approximated to within an accuracy of $\varepsilon$ by $b_i$, that is, + $|a_i - b_i| < \varepsilon$ for $i = 1, \ldots, n$, then + $|P(a_1, \ldots, a_n) - P(b_1, \ldots, b_n)| < 1/2$. In other words, if it + is known that $P(a_1, \ldots, a_n) = c$ for some $c \in \mathbb{Z}$, then + $P(b_1, \ldots, b_n)$ can be rounded to the nearest integer in order to + determine $c$. + + To derive our error bound, consider the monomial $xyz$. Defining + $d_i = b_i - a_i$, our error is + $|(a_1 + d_1)(a_2 + d_2)(a_3 + d_3) - a_1 a_2 a_3|$, which is bounded + above by $|(M + \varepsilon)^3 - M^3|$. Passing to a general monomial of + total degree $t$, this expression is bounded by + $M^{t-1}\varepsilon(t + 2^t\varepsilon/M)$ provided $\varepsilon < M$, + and by $(t+1)M^{t-1}\varepsilon$ provided $\varepsilon < M/2^t$. + But since our goal is to make the error less than $1/2$, we will choose + $\varepsilon < 1/(2(t+1)M^{t-1})$, which implies the condition that + $\varepsilon < M/2^t$, as long as $M \geq 2$. + + Passing from the general monomial to the general polynomial is easy, by + scaling and summing error bounds. + + In our specific case, we are given a homogeneous polynomial $F$ of + $r$ terms and total degree $t$, all of whose coefficients are $\pm 1$. We + are given the $m$ permutations that make the conjugates of $F$, and + we want to bound the error in the coefficients of the monic polynomial + $R(Y)$ having $F$ and its conjugates as roots (i.e. the resolvent). + + For $j$ from $1$ to $m$, the coefficient of $Y^{m-j}$ in $R(Y)$ is the + $j$th elementary symmetric polynomial in the conjugates of $F$. This sums + the products of these conjugates, taken $j$ at a time, in all possible + combinations. There are $\binom{m}{j}$ such combinations, and each product + of $j$ conjugates of $F$ expands to a sum of $r^j$ terms, each of unit + coefficient, and total degree $jt$. An error bound for the $j$th coeff of + $R$ is therefore + $$\binom{m}{j} r^j (jt + 1) M^{jt - 1} \varepsilon$$ + When our goal is to evaluate all the coefficients of $R$, we will want to + use the maximum of these error bounds. It is clear that this bound is + strictly increasing for $j$ up to the ceiling of $m/2$. After that point, + the first factor $\binom{m}{j}$ begins to decrease, while the others + continue to increase. However, the binomial coefficient never falls by more + than a factor of $1/m$ at a time, so our assumptions that $M \geq 2$ and + $m < r 2^t$ are enough to tell us that the constant coefficient of $R$, + i.e. that where $j = m$, has the largest error bound. Therefore we can use + $$r^m (mt + 1) M^{mt - 1} \varepsilon$$ + as our error bound for all the coefficients. + + Note that this bound is also (more than) adequate to determine whether any + of the roots of $R$ is an integer. Each of these roots is a single + conjugate of $F$, which contains less error than the trace, i.e. the + coefficient of $Y^{m - 1}$. By rounding the roots of $R$ to the nearest + integers, we therefore get all the candidates for integer roots of $R$. By + plugging these candidates into $R$, we can check whether any of them + actually is a root. + + Note: We take the definition of resolvent from Cohen, but the error bound + is ours. + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory*. + (Def 6.3.2) + + """ + + def __init__(self, F, X, s): + r""" + Parameters + ========== + + F : :py:class:`~.Expr` + polynomial in the symbols in *X* + X : list of :py:class:`~.Symbol` + s : list of :py:class:`~.Permutation` + representing the cosets of the stabilizer of *F* in + some subgroup $G$ of $S_n$, where $n$ is the length of *X*. + """ + self.F = F + self.X = X + self.s = s + + # Number of conjugates: + self.m = len(s) + # Total degree of F (computed below): + self.t = None + # Number of terms in F (computed below): + self.r = 0 + + for monom, coeff in Poly(F).terms(): + if abs(coeff) != 1: + raise ResolventException('Resolvent class expects forms with unit coeffs') + t = sum(monom) + if t != self.t and self.t is not None: + raise ResolventException('Resolvent class expects homogeneous forms') + self.t = t + self.r += 1 + + m, t, r = self.m, self.t, self.r + if not m < r * 2**t: + raise ResolventException('Resolvent class expects m < r*2^t') + M = symbols('M') + # Precision sufficient for computing the coeffs of the resolvent: + self.coeff_prec_func = Poly(r**m*(m*t + 1)*M**(m*t - 1)) + # Precision sufficient for checking whether any of the roots of the + # resolvent are integers: + self.root_prec_func = Poly(r*(t + 1)*M**(t - 1)) + + # The conjugates of F are the roots of the resolvent. + # For evaluating these to required numerical precisions, we need + # lambdified versions. + # Note: for a given permutation sigma, the conjugate (sigma F) is + # equivalent to lambda [sigma^(-1) X]: F. + self.root_lambdas = [ + lambdify((~s[j])(X), F) + for j in range(self.m) + ] + + # For evaluating the coeffs, we'll also need lambdified versions of + # the elementary symmetric functions for degree m. + Y = symbols('Y') + R = symbols(' '.join(f'R{i}' for i in range(m))) + f = 1 + for r in R: + f *= (Y - r) + C = Poly(f, Y).coeffs() + self.esf_lambdas = [lambdify(R, c) for c in C] + + def get_prec(self, M, target='coeffs'): + r""" + For a given upper bound *M* on the magnitude of the complex numbers to + be plugged in for this resolvent's symbols, compute a sufficient + precision for evaluating those complex numbers, such that the + coefficients, or the integer roots, of the resolvent can be determined. + + Parameters + ========== + + M : real number + Upper bound on magnitude of the complex numbers to be plugged in. + + target : str, 'coeffs' or 'roots', default='coeffs' + Name the task for which a sufficient precision is desired. + This is either determining the coefficients of the resolvent + ('coeffs') or determining its possible integer roots ('roots'). + The latter may require significantly lower precision. + + Returns + ======= + + int $m$ + such that $2^{-m}$ is a sufficient upper bound on the + error in approximating the complex numbers to be plugged in. + + """ + # As explained in the docstring for this class, our precision estimates + # require that M be at least 2. + M = max(M, 2) + f = self.coeff_prec_func if target == 'coeffs' else self.root_prec_func + r, _, _, _ = evalf(2*f(M), 1, {}) + return fastlog(r) + 1 + + def approximate_roots_of_poly(self, T, target='coeffs'): + """ + Approximate the roots of a given polynomial *T* to sufficient precision + in order to evaluate this resolvent's coefficients, or determine + whether the resolvent has an integer root. + + Parameters + ========== + + T : :py:class:`~.Poly` + + target : str, 'coeffs' or 'roots', default='coeffs' + Set the approximation precision to be sufficient for the desired + task, which is either determining the coefficients of the resolvent + ('coeffs') or determining its possible integer roots ('roots'). + The latter may require significantly lower precision. + + Returns + ======= + + list of elements of :ref:`CC` + + """ + ctx = MPContext() + # Because sympy.polys.polyroots._integer_basis() is called when a CRootOf + # is formed, we proactively extract the integer basis now. This means that + # when we call T.all_roots(), every root will be a CRootOf, not a Mul + # of Integer*CRootOf. + coeff, T = preprocess_roots(T) + coeff = ctx.mpf(str(coeff)) + + scaled_roots = T.all_roots(radicals=False) + + # Since we're going to be approximating the roots of T anyway, we can + # get a good upper bound on the magnitude of the roots by starting with + # a very low precision approx. + approx0 = [coeff * quad_to_mpmath(_evalf_with_bounded_error(r, m=0)) for r in scaled_roots] + # Here we add 1 to account for the possible error in our initial approximation. + M = max(abs(b) for b in approx0) + 1 + m = self.get_prec(M, target=target) + n = fastlog(M._mpf_) + 1 + p = m + n + 1 + ctx.prec = p + d = prec_to_dps(p) + + approx1 = [r.eval_approx(d, return_mpmath=True) for r in scaled_roots] + approx1 = [coeff*ctx.mpc(r) for r in approx1] + + return approx1 + + @staticmethod + def round_mpf(a): + if isinstance(a, int): + return a + # If we use python's built-in `round()`, we lose precision. + # If we use `ZZ` directly, we may add or subtract 1. + # + # XXX: We have to convert to int before converting to ZZ because + # flint.fmpz cannot convert a mpmath mpf. + return ZZ(int(a.context.nint(a))) + + def round_roots_to_integers_for_poly(self, T): + """ + For a given polynomial *T*, round the roots of this resolvent to the + nearest integers. + + Explanation + =========== + + None of the integers returned by this method is guaranteed to be a + root of the resolvent; however, if the resolvent has any integer roots + (for the given polynomial *T*), then they must be among these. + + If the coefficients of the resolvent are also desired, then this method + should not be used. Instead, use the ``eval_for_poly`` method. This + method may be significantly faster than ``eval_for_poly``. + + Parameters + ========== + + T : :py:class:`~.Poly` + + Returns + ======= + + dict + Keys are the indices of those permutations in ``self.s`` such that + the corresponding root did round to a rational integer. + + Values are :ref:`ZZ`. + + + """ + approx_roots_of_T = self.approximate_roots_of_poly(T, target='roots') + approx_roots_of_self = [r(*approx_roots_of_T) for r in self.root_lambdas] + return { + i: self.round_mpf(r.real) + for i, r in enumerate(approx_roots_of_self) + if self.round_mpf(r.imag) == 0 + } + + def eval_for_poly(self, T, find_integer_root=False): + r""" + Compute the integer values of the coefficients of this resolvent, when + plugging in the roots of a given polynomial. + + Parameters + ========== + + T : :py:class:`~.Poly` + + find_integer_root : ``bool``, default ``False`` + If ``True``, then also determine whether the resolvent has an + integer root, and return the first one found, along with its + index, i.e. the index of the permutation ``self.s[i]`` it + corresponds to. + + Returns + ======= + + Tuple ``(R, a, i)`` + + ``R`` is this resolvent as a dense univariate polynomial over + :ref:`ZZ`, i.e. a list of :ref:`ZZ`. + + If *find_integer_root* was ``True``, then ``a`` and ``i`` are the + first integer root found, and its index, if one exists. + Otherwise ``a`` and ``i`` are both ``None``. + + """ + approx_roots_of_T = self.approximate_roots_of_poly(T, target='coeffs') + approx_roots_of_self = [r(*approx_roots_of_T) for r in self.root_lambdas] + approx_coeffs_of_self = [c(*approx_roots_of_self) for c in self.esf_lambdas] + + R = [] + for c in approx_coeffs_of_self: + if self.round_mpf(c.imag) != 0: + # If precision was enough, this should never happen. + raise ResolventException(f"Got non-integer coeff for resolvent: {c}") + R.append(self.round_mpf(c.real)) + + a0, i0 = None, None + + if find_integer_root: + for i, r in enumerate(approx_roots_of_self): + if self.round_mpf(r.imag) != 0: + continue + if not dup_eval(R, (a := self.round_mpf(r.real)), ZZ): + a0, i0 = a, i + break + + return R, a0, i0 + + +def wrap(text, width=80): + """Line wrap a polynomial expression. """ + out = '' + col = 0 + for c in text: + if c == ' ' and col > width: + c, col = '\n', 0 + else: + col += 1 + out += c + return out + + +def s_vars(n): + """Form the symbols s1, s2, ..., sn to stand for elem. symm. polys. """ + return symbols([f's{i + 1}' for i in range(n)]) + + +def sparse_symmetrize_resolvent_coeffs(F, X, s, verbose=False): + """ + Compute the coefficients of a resolvent as functions of the coefficients of + the associated polynomial. + + F must be a sparse polynomial. + """ + import time, sys + # Roots of resolvent as multivariate forms over vars X: + root_forms = [ + F.compose(list(zip(X, sigma(X)))) + for sigma in s + ] + + # Coeffs of resolvent (besides lead coeff of 1) as symmetric forms over vars X: + Y = [Dummy(f'Y{i}') for i in range(len(s))] + coeff_forms = [] + for i in range(1, len(s) + 1): + if verbose: + print('----') + print(f'Computing symmetric poly of degree {i}...') + sys.stdout.flush() + t0 = time.time() + G = symmetric_poly(i, *Y) + t1 = time.time() + if verbose: + print(f'took {t1 - t0} seconds') + print('lambdifying...') + sys.stdout.flush() + t0 = time.time() + C = lambdify(Y, (-1)**i*G) + t1 = time.time() + if verbose: + print(f'took {t1 - t0} seconds') + sys.stdout.flush() + coeff_forms.append(C) + + coeffs = [] + for i, f in enumerate(coeff_forms): + if verbose: + print('----') + print(f'Plugging root forms into elem symm poly {i+1}...') + sys.stdout.flush() + t0 = time.time() + g = f(*root_forms) + t1 = time.time() + coeffs.append(g) + if verbose: + print(f'took {t1 - t0} seconds') + sys.stdout.flush() + + # Now symmetrize these coeffs. This means recasting them as polynomials in + # the elementary symmetric polys over X. + symmetrized = [] + symmetrization_times = [] + ss = s_vars(len(X)) + for i, A in list(enumerate(coeffs)): + if verbose: + print('-----') + print(f'Coeff {i+1}...') + sys.stdout.flush() + t0 = time.time() + B, rem, _ = A.symmetrize() + t1 = time.time() + if rem != 0: + msg = f"Got nonzero remainder {rem} for resolvent (F, X, s) = ({F}, {X}, {s})" + raise ResolventException(msg) + B_str = str(B.as_expr(*ss)) + symmetrized.append(B_str) + symmetrization_times.append(t1 - t0) + if verbose: + print(wrap(B_str)) + print(f'took {t1 - t0} seconds') + sys.stdout.flush() + + return symmetrized, symmetrization_times + + +def define_resolvents(): + """Define all the resolvents for polys T of degree 4 through 6. """ + from sympy.combinatorics.galois import PGL2F5 + from sympy.combinatorics.permutations import Permutation + + R4, X4 = xring("X0,X1,X2,X3", ZZ, lex) + X = X4 + + # The one resolvent used in `_galois_group_degree_4_lookup()`: + F40 = X[0]*X[1]**2 + X[1]*X[2]**2 + X[2]*X[3]**2 + X[3]*X[0]**2 + s40 = [ + Permutation(3), + Permutation(3)(0, 1), + Permutation(3)(0, 2), + Permutation(3)(0, 3), + Permutation(3)(1, 2), + Permutation(3)(2, 3), + ] + + # First resolvent used in `_galois_group_degree_4_root_approx()`: + F41 = X[0]*X[2] + X[1]*X[3] + s41 = [ + Permutation(3), + Permutation(3)(0, 1), + Permutation(3)(0, 3) + ] + + R5, X5 = xring("X0,X1,X2,X3,X4", ZZ, lex) + X = X5 + + # First resolvent used in `_galois_group_degree_5_hybrid()`, + # and only one used in `_galois_group_degree_5_lookup_ext_factor()`: + F51 = ( X[0]**2*(X[1]*X[4] + X[2]*X[3]) + + X[1]**2*(X[2]*X[0] + X[3]*X[4]) + + X[2]**2*(X[3]*X[1] + X[4]*X[0]) + + X[3]**2*(X[4]*X[2] + X[0]*X[1]) + + X[4]**2*(X[0]*X[3] + X[1]*X[2])) + s51 = [ + Permutation(4), + Permutation(4)(0, 1), + Permutation(4)(0, 2), + Permutation(4)(0, 3), + Permutation(4)(0, 4), + Permutation(4)(1, 4) + ] + + R6, X6 = xring("X0,X1,X2,X3,X4,X5", ZZ, lex) + X = X6 + + # First resolvent used in `_galois_group_degree_6_lookup()`: + H = PGL2F5() + term0 = X[0]**2*X[5]**2*(X[1]*X[4] + X[2]*X[3]) + terms = {term0.compose(list(zip(X, s(X)))) for s in H.elements} + F61 = sum(terms) + s61 = [Permutation(5)] + [Permutation(5)(0, n) for n in range(1, 6)] + + # Second resolvent used in `_galois_group_degree_6_lookup()`: + F62 = X[0]*X[1]*X[2] + X[3]*X[4]*X[5] + s62 = [Permutation(5)] + [ + Permutation(5)(i, j + 3) for i in range(3) for j in range(3) + ] + + return { + (4, 0): (F40, X4, s40), + (4, 1): (F41, X4, s41), + (5, 1): (F51, X5, s51), + (6, 1): (F61, X6, s61), + (6, 2): (F62, X6, s62), + } + + +def generate_lambda_lookup(verbose=False, trial_run=False): + """ + Generate the whole lookup table of coeff lambdas, for all resolvents. + """ + jobs = define_resolvents() + lambda_lists = {} + total_time = 0 + time_for_61 = 0 + time_for_61_last = 0 + for k, (F, X, s) in jobs.items(): + symmetrized, times = sparse_symmetrize_resolvent_coeffs(F, X, s, verbose=verbose) + + total_time += sum(times) + if k == (6, 1): + time_for_61 = sum(times) + time_for_61_last = times[-1] + + sv = s_vars(len(X)) + head = f'lambda {", ".join(str(v) for v in sv)}:' + lambda_lists[k] = ',\n '.join([ + f'{head} ({wrap(f)})' + for f in symmetrized + ]) + + if trial_run: + break + + table = ( + "# This table was generated by a call to\n" + "# `sympy.polys.numberfields.galois_resolvents.generate_lambda_lookup()`.\n" + f"# The entire job took {total_time:.2f}s.\n" + f"# Of this, Case (6, 1) took {time_for_61:.2f}s.\n" + f"# The final polynomial of Case (6, 1) alone took {time_for_61_last:.2f}s.\n" + "resolvent_coeff_lambdas = {\n") + + for k, L in lambda_lists.items(): + table += f" {k}: [\n" + table += " " + L + '\n' + table += " ],\n" + table += "}\n" + return table + + +def get_resolvent_by_lookup(T, number): + """ + Use the lookup table, to return a resolvent (as dup) for a given + polynomial *T*. + + Parameters + ========== + + T : Poly + The polynomial whose resolvent is needed + + number : int + For some degrees, there are multiple resolvents. + Use this to indicate which one you want. + + Returns + ======= + + dup + + """ + from sympy.polys.numberfields.resolvent_lookup import resolvent_coeff_lambdas + degree = T.degree() + L = resolvent_coeff_lambdas[(degree, number)] + T_coeffs = T.rep.to_list()[1:] + return [ZZ(1)] + [c(*T_coeffs) for c in L] + + +# Use +# (.venv) $ python -m sympy.polys.numberfields.galois_resolvents +# to reproduce the table found in resolvent_lookup.py +if __name__ == "__main__": + import sys + verbose = '-v' in sys.argv[1:] + trial_run = '-t' in sys.argv[1:] + table = generate_lambda_lookup(verbose=verbose, trial_run=trial_run) + print(table) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/galoisgroups.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/galoisgroups.py new file mode 100644 index 0000000000000000000000000000000000000000..a0e424bf7554c0cedd926902e7322b9640735a8b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/galoisgroups.py @@ -0,0 +1,623 @@ +""" +Compute Galois groups of polynomials. + +We use algorithms from [1], with some modifications to use lookup tables for +resolvents. + +References +========== + +.. [1] Cohen, H. *A Course in Computational Algebraic Number Theory*. + +""" + +from collections import defaultdict +import random + +from sympy.core.symbol import Dummy, symbols +from sympy.ntheory.primetest import is_square +from sympy.polys.domains import ZZ +from sympy.polys.densebasic import dup_random +from sympy.polys.densetools import dup_eval +from sympy.polys.euclidtools import dup_discriminant +from sympy.polys.factortools import dup_factor_list, dup_irreducible_p +from sympy.polys.numberfields.galois_resolvents import ( + GaloisGroupException, get_resolvent_by_lookup, define_resolvents, + Resolvent, +) +from sympy.polys.numberfields.utilities import coeff_search +from sympy.polys.polytools import (Poly, poly_from_expr, + PolificationFailed, ComputationFailed) +from sympy.polys.sqfreetools import dup_sqf_p +from sympy.utilities import public + + +class MaxTriesException(GaloisGroupException): + ... + + +def tschirnhausen_transformation(T, max_coeff=10, max_tries=30, history=None, + fixed_order=True): + r""" + Given a univariate, monic, irreducible polynomial over the integers, find + another such polynomial defining the same number field. + + Explanation + =========== + + See Alg 6.3.4 of [1]. + + Parameters + ========== + + T : Poly + The given polynomial + max_coeff : int + When choosing a transformation as part of the process, + keep the coeffs between plus and minus this. + max_tries : int + Consider at most this many transformations. + history : set, None, optional (default=None) + Pass a set of ``Poly.rep``'s in order to prevent any of these + polynomials from being returned as the polynomial ``U`` i.e. the + transformation of the given polynomial *T*. The given poly *T* will + automatically be added to this set, before we try to find a new one. + fixed_order : bool, default True + If ``True``, work through candidate transformations A(x) in a fixed + order, from small coeffs to large, resulting in deterministic behavior. + If ``False``, the A(x) are chosen randomly, while still working our way + up from small coefficients to larger ones. + + Returns + ======= + + Pair ``(A, U)`` + + ``A`` and ``U`` are ``Poly``, ``A`` is the + transformation, and ``U`` is the transformed polynomial that defines + the same number field as *T*. The polynomial ``A`` maps the roots of + *T* to the roots of ``U``. + + Raises + ====== + + MaxTriesException + if could not find a polynomial before exceeding *max_tries*. + + """ + X = Dummy('X') + n = T.degree() + if history is None: + history = set() + history.add(T.rep) + + if fixed_order: + coeff_generators = {} + deg_coeff_sum = 3 + current_degree = 2 + + def get_coeff_generator(degree): + gen = coeff_generators.get(degree, coeff_search(degree, 1)) + coeff_generators[degree] = gen + return gen + + for i in range(max_tries): + + # We never use linear A(x), since applying a fixed linear transformation + # to all roots will only multiply the discriminant of T by a square + # integer. This will change nothing important. In particular, if disc(T) + # was zero before, it will still be zero now, and typically we apply + # the transformation in hopes of replacing T by a squarefree poly. + + if fixed_order: + # If d is degree and c max coeff, we move through the dc-space + # along lines of constant sum. First d + c = 3 with (d, c) = (2, 1). + # Then d + c = 4 with (d, c) = (3, 1), (2, 2). Then d + c = 5 with + # (d, c) = (4, 1), (3, 2), (2, 3), and so forth. For a given (d, c) + # we go though all sets of coeffs where max = c, before moving on. + gen = get_coeff_generator(current_degree) + coeffs = next(gen) + m = max(abs(c) for c in coeffs) + if current_degree + m > deg_coeff_sum: + if current_degree == 2: + deg_coeff_sum += 1 + current_degree = deg_coeff_sum - 1 + else: + current_degree -= 1 + gen = get_coeff_generator(current_degree) + coeffs = next(gen) + a = [ZZ(1)] + [ZZ(c) for c in coeffs] + + else: + # We use a progressive coeff bound, up to the max specified, since it + # is preferable to succeed with smaller coeffs. + # Give each coeff bound five tries, before incrementing. + C = min(i//5 + 1, max_coeff) + d = random.randint(2, n - 1) + a = dup_random(d, -C, C, ZZ) + + A = Poly(a, T.gen) + U = Poly(T.resultant(X - A), X) + if U.rep not in history and dup_sqf_p(U.rep.to_list(), ZZ): + return A, U + raise MaxTriesException + + +def has_square_disc(T): + """Convenience to check if a Poly or dup has square discriminant. """ + d = T.discriminant() if isinstance(T, Poly) else dup_discriminant(T, ZZ) + return is_square(d) + + +def _galois_group_degree_3(T, max_tries=30, randomize=False): + r""" + Compute the Galois group of a polynomial of degree 3. + + Explanation + =========== + + Uses Prop 6.3.5 of [1]. + + """ + from sympy.combinatorics.galois import S3TransitiveSubgroups + return ((S3TransitiveSubgroups.A3, True) if has_square_disc(T) + else (S3TransitiveSubgroups.S3, False)) + + +def _galois_group_degree_4_root_approx(T, max_tries=30, randomize=False): + r""" + Compute the Galois group of a polynomial of degree 4. + + Explanation + =========== + + Follows Alg 6.3.7 of [1], using a pure root approximation approach. + + """ + from sympy.combinatorics.permutations import Permutation + from sympy.combinatorics.galois import S4TransitiveSubgroups + + X = symbols('X0 X1 X2 X3') + # We start by considering the resolvent for the form + # F = X0*X2 + X1*X3 + # and the group G = S4. In this case, the stabilizer H is D4 = < (0123), (02) >, + # and a set of representatives of G/H is {I, (01), (03)} + F1 = X[0]*X[2] + X[1]*X[3] + s1 = [ + Permutation(3), + Permutation(3)(0, 1), + Permutation(3)(0, 3) + ] + R1 = Resolvent(F1, X, s1) + + # In the second half of the algorithm (if we reach it), we use another + # form and set of coset representatives. However, we may need to permute + # them first, so cannot form their resolvent now. + F2_pre = X[0]*X[1]**2 + X[1]*X[2]**2 + X[2]*X[3]**2 + X[3]*X[0]**2 + s2_pre = [ + Permutation(3), + Permutation(3)(0, 2) + ] + + history = set() + for i in range(max_tries): + if i > 0: + # If we're retrying, need a new polynomial T. + _, T = tschirnhausen_transformation(T, max_tries=max_tries, + history=history, + fixed_order=not randomize) + + R_dup, _, i0 = R1.eval_for_poly(T, find_integer_root=True) + # If R is not squarefree, must retry. + if not dup_sqf_p(R_dup, ZZ): + continue + + # By Prop 6.3.1 of [1], Gal(T) is contained in A4 iff disc(T) is square. + sq_disc = has_square_disc(T) + + if i0 is None: + # By Thm 6.3.3 of [1], Gal(T) is not conjugate to any subgroup of the + # stabilizer H = D4 that we chose. This means Gal(T) is either A4 or S4. + return ((S4TransitiveSubgroups.A4, True) if sq_disc + else (S4TransitiveSubgroups.S4, False)) + + # Gal(T) is conjugate to a subgroup of H = D4, so it is either V, C4 + # or D4 itself. + + if sq_disc: + # Neither C4 nor D4 is contained in A4, so Gal(T) must be V. + return (S4TransitiveSubgroups.V, True) + + # Gal(T) can only be D4 or C4. + # We will now use our second resolvent, with G being that conjugate of D4 that + # Gal(T) is contained in. To determine the right conjugate, we will need + # the permutation corresponding to the integer root we found. + sigma = s1[i0] + # Applying sigma means permuting the args of F, and + # conjugating the set of coset representatives. + F2 = F2_pre.subs(zip(X, sigma(X)), simultaneous=True) + s2 = [sigma*tau*sigma for tau in s2_pre] + R2 = Resolvent(F2, X, s2) + R_dup, _, _ = R2.eval_for_poly(T) + d = dup_discriminant(R_dup, ZZ) + # If d is zero (R has a repeated root), must retry. + if d == 0: + continue + if is_square(d): + return (S4TransitiveSubgroups.C4, False) + else: + return (S4TransitiveSubgroups.D4, False) + + raise MaxTriesException + + +def _galois_group_degree_4_lookup(T, max_tries=30, randomize=False): + r""" + Compute the Galois group of a polynomial of degree 4. + + Explanation + =========== + + Based on Alg 6.3.6 of [1], but uses resolvent coeff lookup. + + """ + from sympy.combinatorics.galois import S4TransitiveSubgroups + + history = set() + for i in range(max_tries): + R_dup = get_resolvent_by_lookup(T, 0) + if dup_sqf_p(R_dup, ZZ): + break + _, T = tschirnhausen_transformation(T, max_tries=max_tries, + history=history, + fixed_order=not randomize) + else: + raise MaxTriesException + + # Compute list L of degrees of irreducible factors of R, in increasing order: + fl = dup_factor_list(R_dup, ZZ) + L = sorted(sum([ + [len(r) - 1] * e for r, e in fl[1] + ], [])) + + if L == [6]: + return ((S4TransitiveSubgroups.A4, True) if has_square_disc(T) + else (S4TransitiveSubgroups.S4, False)) + + if L == [1, 1, 4]: + return (S4TransitiveSubgroups.C4, False) + + if L == [2, 2, 2]: + return (S4TransitiveSubgroups.V, True) + + assert L == [2, 4] + return (S4TransitiveSubgroups.D4, False) + + +def _galois_group_degree_5_hybrid(T, max_tries=30, randomize=False): + r""" + Compute the Galois group of a polynomial of degree 5. + + Explanation + =========== + + Based on Alg 6.3.9 of [1], but uses a hybrid approach, combining resolvent + coeff lookup, with root approximation. + + """ + from sympy.combinatorics.galois import S5TransitiveSubgroups + from sympy.combinatorics.permutations import Permutation + + X5 = symbols("X0,X1,X2,X3,X4") + res = define_resolvents() + F51, _, s51 = res[(5, 1)] + F51 = F51.as_expr(*X5) + R51 = Resolvent(F51, X5, s51) + + history = set() + reached_second_stage = False + for i in range(max_tries): + if i > 0: + _, T = tschirnhausen_transformation(T, max_tries=max_tries, + history=history, + fixed_order=not randomize) + R51_dup = get_resolvent_by_lookup(T, 1) + if not dup_sqf_p(R51_dup, ZZ): + continue + + # First stage + # If we have not yet reached the second stage, then the group still + # might be S5, A5, or M20, so must test for that. + if not reached_second_stage: + sq_disc = has_square_disc(T) + + if dup_irreducible_p(R51_dup, ZZ): + return ((S5TransitiveSubgroups.A5, True) if sq_disc + else (S5TransitiveSubgroups.S5, False)) + + if not sq_disc: + return (S5TransitiveSubgroups.M20, False) + + # Second stage + reached_second_stage = True + # R51 must have an integer root for T. + # To choose our second resolvent, we need to know which conjugate of + # F51 is a root. + rounded_roots = R51.round_roots_to_integers_for_poly(T) + # These are integers, and candidates to be roots of R51. + # We find the first one that actually is a root. + for permutation_index, candidate_root in rounded_roots.items(): + if not dup_eval(R51_dup, candidate_root, ZZ): + break + + X = X5 + F2_pre = X[0]*X[1]**2 + X[1]*X[2]**2 + X[2]*X[3]**2 + X[3]*X[4]**2 + X[4]*X[0]**2 + s2_pre = [ + Permutation(4), + Permutation(4)(0, 1)(2, 4) + ] + + i0 = permutation_index + sigma = s51[i0] + F2 = F2_pre.subs(zip(X, sigma(X)), simultaneous=True) + s2 = [sigma*tau*sigma for tau in s2_pre] + R2 = Resolvent(F2, X, s2) + R_dup, _, _ = R2.eval_for_poly(T) + d = dup_discriminant(R_dup, ZZ) + + if d == 0: + continue + if is_square(d): + return (S5TransitiveSubgroups.C5, True) + else: + return (S5TransitiveSubgroups.D5, True) + + raise MaxTriesException + + +def _galois_group_degree_5_lookup_ext_factor(T, max_tries=30, randomize=False): + r""" + Compute the Galois group of a polynomial of degree 5. + + Explanation + =========== + + Based on Alg 6.3.9 of [1], but uses resolvent coeff lookup, plus + factorization over an algebraic extension. + + """ + from sympy.combinatorics.galois import S5TransitiveSubgroups + + _T = T + + history = set() + for i in range(max_tries): + R_dup = get_resolvent_by_lookup(T, 1) + if dup_sqf_p(R_dup, ZZ): + break + _, T = tschirnhausen_transformation(T, max_tries=max_tries, + history=history, + fixed_order=not randomize) + else: + raise MaxTriesException + + sq_disc = has_square_disc(T) + + if dup_irreducible_p(R_dup, ZZ): + return ((S5TransitiveSubgroups.A5, True) if sq_disc + else (S5TransitiveSubgroups.S5, False)) + + if not sq_disc: + return (S5TransitiveSubgroups.M20, False) + + # If we get this far, Gal(T) can only be D5 or C5. + # But for Gal(T) to have order 5, T must already split completely in + # the extension field obtained by adjoining a single one of its roots. + fl = Poly(_T, domain=ZZ.alg_field_from_poly(_T)).factor_list()[1] + if len(fl) == 5: + return (S5TransitiveSubgroups.C5, True) + else: + return (S5TransitiveSubgroups.D5, True) + + +def _galois_group_degree_6_lookup(T, max_tries=30, randomize=False): + r""" + Compute the Galois group of a polynomial of degree 6. + + Explanation + =========== + + Based on Alg 6.3.10 of [1], but uses resolvent coeff lookup. + + """ + from sympy.combinatorics.galois import S6TransitiveSubgroups + + # First resolvent: + + history = set() + for i in range(max_tries): + R_dup = get_resolvent_by_lookup(T, 1) + if dup_sqf_p(R_dup, ZZ): + break + _, T = tschirnhausen_transformation(T, max_tries=max_tries, + history=history, + fixed_order=not randomize) + else: + raise MaxTriesException + + fl = dup_factor_list(R_dup, ZZ) + + # Group the factors by degree. + factors_by_deg = defaultdict(list) + for r, _ in fl[1]: + factors_by_deg[len(r) - 1].append(r) + + L = sorted(sum([ + [d] * len(ff) for d, ff in factors_by_deg.items() + ], [])) + + T_has_sq_disc = has_square_disc(T) + + if L == [1, 2, 3]: + f1 = factors_by_deg[3][0] + return ((S6TransitiveSubgroups.C6, False) if has_square_disc(f1) + else (S6TransitiveSubgroups.D6, False)) + + elif L == [3, 3]: + f1, f2 = factors_by_deg[3] + any_square = has_square_disc(f1) or has_square_disc(f2) + return ((S6TransitiveSubgroups.G18, False) if any_square + else (S6TransitiveSubgroups.G36m, False)) + + elif L == [2, 4]: + if T_has_sq_disc: + return (S6TransitiveSubgroups.S4p, True) + else: + f1 = factors_by_deg[4][0] + return ((S6TransitiveSubgroups.A4xC2, False) if has_square_disc(f1) + else (S6TransitiveSubgroups.S4xC2, False)) + + elif L == [1, 1, 4]: + return ((S6TransitiveSubgroups.A4, True) if T_has_sq_disc + else (S6TransitiveSubgroups.S4m, False)) + + elif L == [1, 5]: + return ((S6TransitiveSubgroups.PSL2F5, True) if T_has_sq_disc + else (S6TransitiveSubgroups.PGL2F5, False)) + + elif L == [1, 1, 1, 3]: + return (S6TransitiveSubgroups.S3, False) + + assert L == [6] + + # Second resolvent: + + history = set() + for i in range(max_tries): + R_dup = get_resolvent_by_lookup(T, 2) + if dup_sqf_p(R_dup, ZZ): + break + _, T = tschirnhausen_transformation(T, max_tries=max_tries, + history=history, + fixed_order=not randomize) + else: + raise MaxTriesException + + T_has_sq_disc = has_square_disc(T) + + if dup_irreducible_p(R_dup, ZZ): + return ((S6TransitiveSubgroups.A6, True) if T_has_sq_disc + else (S6TransitiveSubgroups.S6, False)) + else: + return ((S6TransitiveSubgroups.G36p, True) if T_has_sq_disc + else (S6TransitiveSubgroups.G72, False)) + + +@public +def galois_group(f, *gens, by_name=False, max_tries=30, randomize=False, **args): + r""" + Compute the Galois group for polynomials *f* up to degree 6. + + Examples + ======== + + >>> from sympy import galois_group + >>> from sympy.abc import x + >>> f = x**4 + 1 + >>> G, alt = galois_group(f) + >>> print(G) + PermutationGroup([ + (0 1)(2 3), + (0 2)(1 3)]) + + The group is returned along with a boolean, indicating whether it is + contained in the alternating group $A_n$, where $n$ is the degree of *T*. + Along with other group properties, this can help determine which group it + is: + + >>> alt + True + >>> G.order() + 4 + + Alternatively, the group can be returned by name: + + >>> G_name, _ = galois_group(f, by_name=True) + >>> print(G_name) + S4TransitiveSubgroups.V + + The group itself can then be obtained by calling the name's + ``get_perm_group()`` method: + + >>> G_name.get_perm_group() + PermutationGroup([ + (0 1)(2 3), + (0 2)(1 3)]) + + Group names are values of the enum classes + :py:class:`sympy.combinatorics.galois.S1TransitiveSubgroups`, + :py:class:`sympy.combinatorics.galois.S2TransitiveSubgroups`, + etc. + + Parameters + ========== + + f : Expr + Irreducible polynomial over :ref:`ZZ` or :ref:`QQ`, whose Galois group + is to be determined. + gens : optional list of symbols + For converting *f* to Poly, and will be passed on to the + :py:func:`~.poly_from_expr` function. + by_name : bool, default False + If ``True``, the Galois group will be returned by name. + Otherwise it will be returned as a :py:class:`~.PermutationGroup`. + max_tries : int, default 30 + Make at most this many attempts in those steps that involve + generating Tschirnhausen transformations. + randomize : bool, default False + If ``True``, then use random coefficients when generating Tschirnhausen + transformations. Otherwise try transformations in a fixed order. Both + approaches start with small coefficients and degrees and work upward. + args : optional + For converting *f* to Poly, and will be passed on to the + :py:func:`~.poly_from_expr` function. + + Returns + ======= + + Pair ``(G, alt)`` + The first element ``G`` indicates the Galois group. It is an instance + of one of the :py:class:`sympy.combinatorics.galois.S1TransitiveSubgroups` + :py:class:`sympy.combinatorics.galois.S2TransitiveSubgroups`, etc. enum + classes if *by_name* was ``True``, and a :py:class:`~.PermutationGroup` + if ``False``. + + The second element is a boolean, saying whether the group is contained + in the alternating group $A_n$ ($n$ the degree of *T*). + + Raises + ====== + + ValueError + if *f* is of an unsupported degree. + + MaxTriesException + if could not complete before exceeding *max_tries* in those steps + that involve generating Tschirnhausen transformations. + + See Also + ======== + + .Poly.galois_group + + """ + gens = gens or [] + args = args or {} + + try: + F, opt = poly_from_expr(f, *gens, **args) + except PolificationFailed as exc: + raise ComputationFailed('galois_group', 1, exc) + + return F.galois_group(by_name=by_name, max_tries=max_tries, + randomize=randomize) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/minpoly.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/minpoly.py new file mode 100644 index 0000000000000000000000000000000000000000..e5f556e6f82a9790aa7c421fc14ac0fb637b7b49 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/minpoly.py @@ -0,0 +1,882 @@ +"""Minimal polynomials for algebraic numbers.""" + +from functools import reduce + +from sympy.core.add import Add +from sympy.core.exprtools import Factors +from sympy.core.function import expand_mul, expand_multinomial, _mexpand +from sympy.core.mul import Mul +from sympy.core.numbers import (I, Rational, pi, _illegal) +from sympy.core.singleton import S +from sympy.core.symbol import Dummy +from sympy.core.sympify import sympify +from sympy.core.traversal import preorder_traversal +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt, cbrt +from sympy.functions.elementary.trigonometric import cos, sin, tan +from sympy.ntheory.factor_ import divisors +from sympy.utilities.iterables import subsets + +from sympy.polys.domains import ZZ, QQ, FractionField +from sympy.polys.orthopolys import dup_chebyshevt +from sympy.polys.polyerrors import ( + NotAlgebraic, + GeneratorsError, +) +from sympy.polys.polytools import ( + Poly, PurePoly, invert, factor_list, groebner, resultant, + degree, poly_from_expr, parallel_poly_from_expr, lcm +) +from sympy.polys.polyutils import dict_from_expr, expr_from_dict +from sympy.polys.ring_series import rs_compose_add +from sympy.polys.rings import ring +from sympy.polys.rootoftools import CRootOf +from sympy.polys.specialpolys import cyclotomic_poly +from sympy.utilities import ( + numbered_symbols, public, sift +) + + +def _choose_factor(factors, x, v, dom=QQ, prec=200, bound=5): + """ + Return a factor having root ``v`` + It is assumed that one of the factors has root ``v``. + """ + + if isinstance(factors[0], tuple): + factors = [f[0] for f in factors] + if len(factors) == 1: + return factors[0] + + prec1 = 10 + points = {} + symbols = dom.symbols if hasattr(dom, 'symbols') else [] + while prec1 <= prec: + # when dealing with non-Rational numbers we usually evaluate + # with `subs` argument but we only need a ballpark evaluation + fe = [f.as_expr().xreplace({x:v}) for f in factors] + if v.is_number: + fe = [f.n(prec) for f in fe] + + # assign integers [0, n) to symbols (if any) + for n in subsets(range(bound), k=len(symbols), repetition=True): + for s, i in zip(symbols, n): + points[s] = i + + # evaluate the expression at these points + candidates = [(abs(f.subs(points).n(prec1)), i) + for i,f in enumerate(fe)] + + # if we get invalid numbers (e.g. from division by zero) + # we try again + if any(i in _illegal for i, _ in candidates): + continue + + # find the smallest two -- if they differ significantly + # then we assume we have found the factor that becomes + # 0 when v is substituted into it + can = sorted(candidates) + (a, ix), (b, _) = can[:2] + if b > a * 10**6: # XXX what to use? + return factors[ix] + + prec1 *= 2 + + raise NotImplementedError("multiple candidates for the minimal polynomial of %s" % v) + + +def _is_sum_surds(p): + return all(f.is_Rational or f.is_Pow and + f.base.is_Rational and (2*f.exp).is_Integer and f.is_extended_real + for t in Add.make_args(p) for f in Mul.make_args(t)) + + +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.minpoly 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 + + """ + 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 + else: + T, F = sift(y.args, is_sqrt, binary=True) + a.append((Mul(*F), Mul(*T)**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 + from sympy.simplify.radsimp import _split_gcd + 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.minpoly 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 + + """ + p = sympify(p) + n = sympify(n) + 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_element(op, ex1, ex2, x, dom, mp1=None, mp2=None): + """ + return the minimal polynomial for ``op(ex1, ex2)`` + + Parameters + ========== + + op : operation ``Add`` or ``Mul`` + ex1, ex2 : expressions for the algebraic elements + x : indeterminate of the polynomials + dom: ground domain + mp1, mp2 : minimal polynomials for ``ex1`` and ``ex2`` or None + + Examples + ======== + + >>> from sympy import sqrt, Add, Mul, QQ + >>> from sympy.polys.numberfields.minpoly import _minpoly_op_algebraic_element + >>> from sympy.abc import x, y + >>> p1 = sqrt(sqrt(2) + 1) + >>> p2 = sqrt(sqrt(2) - 1) + >>> _minpoly_op_algebraic_element(Mul, p1, p2, x, QQ) + x - 1 + >>> q1 = sqrt(y) + >>> q2 = 1 / y + >>> _minpoly_op_algebraic_element(Add, q1, q2, x, QQ.frac_field(y)) + x**2*y**2 - 2*x*y - y**3 + 1 + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Resultant + .. [2] I.M. Isaacs, Proc. Amer. Math. Soc. 25 (1970), 638 + "Degrees of sums in a separable field extension". + + """ + y = Dummy(str(x)) + if mp1 is None: + mp1 = _minpoly_compose(ex1, x, dom) + if mp2 is None: + mp2 = _minpoly_compose(ex2, y, dom) + else: + mp2 = mp2.subs({x: y}) + + if op is Add: + # mp1a = mp1.subs({x: x - y}) + if dom == QQ: + R, X = ring('X', QQ) + p1 = R(dict_from_expr(mp1)[0]) + p2 = R(dict_from_expr(mp2)[0]) + else: + (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') + + if op is Mul or dom != QQ: + r = resultant(mp1a, mp2, gens=[y, x]) + else: + r = rs_compose_add(p1, p2) + r = expr_from_dict(r.as_expr_dict(), x) + + deg1 = degree(mp1, x) + deg2 = degree(mp2, y) + 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 + + r = Poly(r, x, domain=dom) + _, factors = r.factor_list() + res = _choose_factor(factors, x, op(ex1, ex2), dom) + return res.as_expr() + + +def _invertx(p, x): + """ + Returns ``expand_mul(x**degree(p, x)*p.subs(x, 1/x))`` + """ + p1 = poly_from_expr(p, x)[0] + + n = degree(p1) + a = [c * x**(n - i) for (i,), c in p1.terms()] + return Add(*a) + + +def _muly(p, x, y): + """ + Returns ``_mexpand(y**deg*p.subs({x:x / y}))`` + """ + p1 = poly_from_expr(p, x)[0] + + n = degree(p1) + a = [c * x**i * y**(n - i) for (i,), c in p1.terms()] + return Add(*a) + + +def _minpoly_pow(ex, pw, x, dom, mp=None): + """ + Returns ``minpoly(ex**pw, x)`` + + Parameters + ========== + + ex : algebraic element + pw : rational number + x : indeterminate of the polynomial + dom: ground domain + mp : minimal polynomial of ``p`` + + Examples + ======== + + >>> from sympy import sqrt, QQ, Rational + >>> from sympy.polys.numberfields.minpoly import _minpoly_pow, minpoly + >>> from sympy.abc import x, y + >>> p = sqrt(1 + sqrt(2)) + >>> _minpoly_pow(p, 2, x, QQ) + x**2 - 2*x - 1 + >>> minpoly(p**2, x) + x**2 - 2*x - 1 + >>> _minpoly_pow(y, Rational(1, 3), x, QQ.frac_field(y)) + x**3 - y + >>> minpoly(y**Rational(1, 3), x) + x**3 - y + + """ + pw = sympify(pw) + if not mp: + mp = _minpoly_compose(ex, x, dom) + if not pw.is_rational: + raise NotAlgebraic("%s does not seem to be an algebraic element" % 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 = Poly(resultant(mp, x**d - y**n, gens=[y]), x, domain=dom) + _, factors = res.factor_list() + res = _choose_factor(factors, x, ex**pw, dom) + return res.as_expr() + + +def _minpoly_add(x, dom, *a): + """ + returns ``minpoly(Add(*a), dom, x)`` + """ + mp = _minpoly_op_algebraic_element(Add, a[0], a[1], x, dom) + p = a[0] + a[1] + for px in a[2:]: + mp = _minpoly_op_algebraic_element(Add, p, px, x, dom, mp1=mp) + p = p + px + return mp + + +def _minpoly_mul(x, dom, *a): + """ + returns ``minpoly(Mul(*a), dom, x)`` + """ + mp = _minpoly_op_algebraic_element(Mul, a[0], a[1], x, dom) + p = a[0] * a[1] + for px in a[2:]: + mp = _minpoly_op_algebraic_element(Mul, p, px, x, dom, mp1=mp) + p = p * px + return mp + + +def _minpoly_sin(ex, x): + """ + Returns the minimal polynomial of ``sin(ex)`` + see https://mathworld.wolfram.com/TrigonometryAngles.html + """ + 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 - cos(2*c*pi))/2)**S.Half + res = _minpoly_compose(expr, x, QQ) + return res + + raise NotAlgebraic("%s does not seem to be an algebraic element" % ex) + + +def _minpoly_cos(ex, x): + """ + Returns the minimal polynomial of ``cos(ex)`` + see https://mathworld.wolfram.com/TrigonometryAngles.html + """ + 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 does not seem to be an algebraic element" % ex) + + +def _minpoly_tan(ex, x): + """ + Returns the minimal polynomial of ``tan(ex)`` + see https://github.com/sympy/sympy/issues/21430 + """ + c, a = ex.args[0].as_coeff_Mul() + if a is pi: + if c.is_rational: + c = c * 2 + n = int(c.q) + a = n if c.p % 2 == 0 else 1 + terms = [] + for k in range((c.p+1)%2, n+1, 2): + terms.append(a*x**k) + a = -(a*(n-k-1)*(n-k)) // ((k+1)*(k+2)) + + r = Add(*terms) + _, factors = factor_list(r) + res = _choose_factor(factors, x, ex) + return res + + raise NotAlgebraic("%s does not seem to be an algebraic element" % ex) + + +def _minpoly_exp(ex, x): + """ + Returns the minimal polynomial of ``exp(ex)`` + """ + c, a = ex.args[0].as_coeff_Mul() + if a == I*pi: + if c.is_rational: + q = sympify(c.q) + 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 does not seem to be an algebraic element" % ex) + raise NotAlgebraic("%s does not seem to be an algebraic element" % ex) + + +def _minpoly_rootof(ex, x): + """ + Returns the minimal polynomial of a ``CRootOf`` 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 _minpoly_compose(ex, x, dom): + """ + Computes the minimal polynomial of an algebraic element + using operations on minimal polynomials + + Examples + ======== + + >>> from sympy import minimal_polynomial, sqrt, Rational + >>> from sympy.abc import x, y + >>> minimal_polynomial(sqrt(2) + 3*Rational(1, 3), x, compose=True) + x**2 - 2*x - 1 + >>> minimal_polynomial(sqrt(y) + 1/y, x, compose=True) + x**2*y**2 - 2*x*y - y**3 + 1 + + """ + if ex.is_Rational: + return ex.q*x - ex.p + if ex is I: + _, factors = factor_list(x**2 + 1, x, domain=dom) + return x**2 + 1 if len(factors) == 1 else x - I + + if ex is S.GoldenRatio: + _, factors = factor_list(x**2 - x - 1, x, domain=dom) + if len(factors) == 1: + return x**2 - x - 1 + else: + return _choose_factor(factors, x, (1 + sqrt(5))/2, dom=dom) + + if ex is S.TribonacciConstant: + _, factors = factor_list(x**3 - x**2 - x - 1, x, domain=dom) + if len(factors) == 1: + return x**3 - x**2 - x - 1 + else: + fac = (1 + cbrt(19 - 3*sqrt(33)) + cbrt(19 + 3*sqrt(33))) / 3 + return _choose_factor(factors, x, fac, dom=dom) + + if hasattr(dom, 'symbols') and ex in dom.symbols: + return x - ex + + if dom.is_QQ and _is_sum_surds(ex): + # eliminate the square roots + v = ex + ex -= x + while 1: + ex1 = _separate_sq(ex) + if ex1 is ex: + return _choose_factor(factor_list(ex)[1], x, v) + else: + ex = ex1 + + if ex.is_Add: + res = _minpoly_add(x, dom, *ex.args) + elif ex.is_Mul: + f = Factors(ex).factors + r = sift(f.items(), lambda itx: itx[0].is_Rational and itx[1].is_Rational) + if r[True] and dom == QQ: + ex1 = Mul(*[bx**ex for bx, ex in r[False] + r[None]]) + r1 = dict(r[True]) + dens = [y.q for y in r1.values()] + lcmdens = reduce(lcm, dens, 1) + neg1 = S.NegativeOne + expn1 = r1.pop(neg1, S.Zero) + nums = [base**(y.p*lcmdens // y.q) for base, y in r1.items()] + ex2 = Mul(*nums) + mp1 = minimal_polynomial(ex1, x) + # use the fact that in SymPy canonicalization products of integers + # raised to rational powers are organized in relatively prime + # bases, and that in ``base**(n/d)`` a perfect power is + # simplified with the root + # Powers of -1 have to be treated separately to preserve sign. + mp2 = ex2.q*x**lcmdens - ex2.p*neg1**(expn1*lcmdens) + ex2 = neg1**expn1 * ex2**Rational(1, lcmdens) + res = _minpoly_op_algebraic_element(Mul, ex1, ex2, x, dom, mp1=mp1, mp2=mp2) + else: + res = _minpoly_mul(x, dom, *ex.args) + elif ex.is_Pow: + res = _minpoly_pow(ex.base, ex.exp, x, dom) + elif ex.__class__ is sin: + res = _minpoly_sin(ex, x) + elif ex.__class__ is cos: + res = _minpoly_cos(ex, x) + elif ex.__class__ is tan: + res = _minpoly_tan(ex, x) + elif ex.__class__ is exp: + res = _minpoly_exp(ex, x) + elif ex.__class__ is CRootOf: + res = _minpoly_rootof(ex, x) + else: + raise NotAlgebraic("%s does not seem to be an algebraic element" % ex) + return res + + +@public +def minimal_polynomial(ex, x=None, compose=True, polys=False, domain=None): + """ + Computes the minimal polynomial of an algebraic element. + + Parameters + ========== + + ex : Expr + Element or expression whose minimal polynomial is to be calculated. + + x : Symbol, optional + Independent variable of the minimal polynomial + + compose : boolean, optional (default=True) + Method to use for computing minimal polynomial. If ``compose=True`` + (default) then ``_minpoly_compose`` is used, if ``compose=False`` then + groebner bases are used. + + polys : boolean, optional (default=False) + If ``True`` returns a ``Poly`` object else an ``Expr`` object. + + domain : Domain, optional + Ground domain + + 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. + + If no ground domain is given, it will be generated automatically from the expression. + + Examples + ======== + + >>> from sympy import minimal_polynomial, sqrt, solve, QQ + >>> from sympy.abc import x, y + + >>> minimal_polynomial(sqrt(2), x) + x**2 - 2 + >>> minimal_polynomial(sqrt(2), x, domain=QQ.algebraic_field(sqrt(2))) + x - sqrt(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 + >>> minimal_polynomial(sqrt(y), x) + x**2 - y + + """ + + ex = sympify(ex) + if ex.is_number: + # not sure if it's always needed but try it for numbers (issue 8354) + ex = _mexpand(ex, recursive=True) + for expr in preorder_traversal(ex): + if expr.is_AlgebraicNumber: + compose = False + break + + if x is not None: + x, cls = sympify(x), Poly + else: + x, cls = Dummy('x'), PurePoly + + if not domain: + if ex.free_symbols: + domain = FractionField(QQ, list(ex.free_symbols)) + else: + domain = QQ + if hasattr(domain, 'symbols') and x in domain.symbols: + raise GeneratorsError("the variable %s is an element of the ground " + "domain %s" % (x, domain)) + + if compose: + result = _minpoly_compose(ex, x, domain) + result = result.primitive()[1] + c = result.coeff(x**degree(result, x)) + if c.is_negative: + result = expand_mul(-result) + return cls(result, x, field=True) if polys else result.collect(x) + + if not domain.is_QQ: + raise NotImplementedError("groebner method only works for QQ") + + result = _minpoly_groebner(ex, x, cls) + return cls(result, x, field=True) if polys else result.collect(x) + + +def _minpoly_groebner(ex, x, cls): + """ + Computes the minimal polynomial of an algebraic number + using Groebner bases + + Examples + ======== + + >>> from sympy import minimal_polynomial, sqrt, Rational + >>> from sympy.abc import x + >>> minimal_polynomial(sqrt(2) + 3*Rational(1, 3), x, compose=False) + x**2 - 2*x - 1 + + """ + + generator = numbered_symbols('a', cls=Dummy) + mapping, symbols = {}, {} + + def update_mapping(ex, exp, base=None): + a = next(generator) + symbols[ex] = a + + if base is not None: + mapping[ex] = a**exp + base + else: + mapping[ex] = exp.as_expr(a) + + return a + + def bottom_up_scan(ex): + """ + Transform a given algebraic expression *ex* into a multivariate + polynomial, by introducing fresh variables with defining equations. + + Explanation + =========== + + The critical elements of the algebraic expression *ex* are root + extractions, instances of :py:class:`~.AlgebraicNumber`, and negative + powers. + + When we encounter a root extraction or an :py:class:`~.AlgebraicNumber` + we replace this expression with a fresh variable ``a_i``, and record + the defining polynomial for ``a_i``. For example, if ``a_0**(1/3)`` + occurs, we will replace it with ``a_1``, and record the new defining + polynomial ``a_1**3 - a_0``. + + When we encounter a negative power we transform it into a positive + power by algebraically inverting the base. This means computing the + minimal polynomial in ``x`` for the base, inverting ``x`` modulo this + poly (which generates a new polynomial) and then substituting the + original base expression for ``x`` in this last polynomial. + + We return the transformed expression, and we record the defining + equations for new symbols using the ``update_mapping()`` function. + + """ + if ex.is_Atom: + if ex is S.ImaginaryUnit: + if ex not in mapping: + return update_mapping(ex, 2, 1) + else: + return symbols[ex] + elif ex.is_Rational: + return ex + elif ex.is_Add: + return Add(*[ bottom_up_scan(g) for g in ex.args ]) + elif ex.is_Mul: + return Mul(*[ bottom_up_scan(g) for g in ex.args ]) + elif ex.is_Pow: + if ex.exp.is_Rational: + if ex.exp < 0: + minpoly_base = _minpoly_groebner(ex.base, x, cls) + inverse = invert(x, minpoly_base).as_expr() + base_inv = inverse.subs(x, ex.base).expand() + + if ex.exp == -1: + return bottom_up_scan(base_inv) + else: + ex = base_inv**(-ex.exp) + if not ex.exp.is_Integer: + 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 + + if expr not in mapping: + if exp.is_Integer: + return expr.expand() + else: + return update_mapping(expr, 1 / exp, -base) + else: + return symbols[expr] + elif ex.is_AlgebraicNumber: + if ex not in mapping: + return update_mapping(ex, ex.minpoly_of_element()) + else: + return symbols[ex] + + raise NotAlgebraic("%s does not seem to be an algebraic number" % ex) + + 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 + 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: + return ex.minpoly_of_element().as_expr(x) + elif ex.is_Rational: + result = ex.q*x - ex.p + else: + 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) + + return result + + +@public +def minpoly(ex, x=None, compose=True, polys=False, domain=None): + """This is a synonym for :py:func:`~.minimal_polynomial`.""" + return minimal_polynomial(ex, x=x, compose=compose, polys=polys, domain=domain) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/modules.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/modules.py new file mode 100644 index 0000000000000000000000000000000000000000..af2e29bcc9cf73d97def0701712f90db58601b86 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/modules.py @@ -0,0 +1,2114 @@ +r"""Modules in number fields. + +The classes defined here allow us to work with finitely generated, free +modules, whose generators are algebraic numbers. + +There is an abstract base class called :py:class:`~.Module`, which has two +concrete subclasses, :py:class:`~.PowerBasis` and :py:class:`~.Submodule`. + +Every module is defined by its basis, or set of generators: + +* For a :py:class:`~.PowerBasis`, the generators are the first $n$ powers + (starting with the zeroth) of an algebraic integer $\theta$ of degree $n$. + The :py:class:`~.PowerBasis` is constructed by passing either the minimal + polynomial of $\theta$, or an :py:class:`~.AlgebraicField` having $\theta$ + as its primitive element. + +* For a :py:class:`~.Submodule`, the generators are a set of + $\mathbb{Q}$-linear combinations of the generators of another module. That + other module is then the "parent" of the :py:class:`~.Submodule`. The + coefficients of the $\mathbb{Q}$-linear combinations may be given by an + integer matrix, and a positive integer denominator. Each column of the matrix + defines a generator. + +>>> from sympy.polys import Poly, cyclotomic_poly, ZZ +>>> from sympy.abc import x +>>> from sympy.polys.matrices import DomainMatrix, DM +>>> from sympy.polys.numberfields.modules import PowerBasis +>>> T = Poly(cyclotomic_poly(5, x)) +>>> A = PowerBasis(T) +>>> print(A) +PowerBasis(x**4 + x**3 + x**2 + x + 1) +>>> B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ), denom=3) +>>> print(B) +Submodule[[2, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0], [0, 0, 0, 2]]/3 +>>> print(B.parent) +PowerBasis(x**4 + x**3 + x**2 + x + 1) + +Thus, every module is either a :py:class:`~.PowerBasis`, +or a :py:class:`~.Submodule`, some ancestor of which is a +:py:class:`~.PowerBasis`. (If ``S`` is a :py:class:`~.Submodule`, then its +ancestors are ``S.parent``, ``S.parent.parent``, and so on). + +The :py:class:`~.ModuleElement` class represents a linear combination of the +generators of any module. Critically, the coefficients of this linear +combination are not restricted to be integers, but may be any rational +numbers. This is necessary so that any and all algebraic integers be +representable, starting from the power basis in a primitive element $\theta$ +for the number field in question. For example, in a quadratic field +$\mathbb{Q}(\sqrt{d})$ where $d \equiv 1 \mod{4}$, a denominator of $2$ is +needed. + +A :py:class:`~.ModuleElement` can be constructed from an integer column vector +and a denominator: + +>>> U = Poly(x**2 - 5) +>>> M = PowerBasis(U) +>>> e = M(DM([[1], [1]], ZZ), denom=2) +>>> print(e) +[1, 1]/2 +>>> print(e.module) +PowerBasis(x**2 - 5) + +The :py:class:`~.PowerBasisElement` class is a subclass of +:py:class:`~.ModuleElement` that represents elements of a +:py:class:`~.PowerBasis`, and adds functionality pertinent to elements +represented directly over powers of the primitive element $\theta$. + + +Arithmetic with module elements +=============================== + +While a :py:class:`~.ModuleElement` represents a linear combination over the +generators of a particular module, recall that every module is either a +:py:class:`~.PowerBasis` or a descendant (along a chain of +:py:class:`~.Submodule` objects) thereof, so that in fact every +:py:class:`~.ModuleElement` represents an algebraic number in some field +$\mathbb{Q}(\theta)$, where $\theta$ is the defining element of some +:py:class:`~.PowerBasis`. It thus makes sense to talk about the number field +to which a given :py:class:`~.ModuleElement` belongs. + +This means that any two :py:class:`~.ModuleElement` instances can be added, +subtracted, multiplied, or divided, provided they belong to the same number +field. Similarly, since $\mathbb{Q}$ is a subfield of every number field, +any :py:class:`~.ModuleElement` may be added, multiplied, etc. by any +rational number. + +>>> from sympy import QQ +>>> from sympy.polys.numberfields.modules import to_col +>>> T = Poly(cyclotomic_poly(5)) +>>> A = PowerBasis(T) +>>> C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) +>>> e = A(to_col([0, 2, 0, 0]), denom=3) +>>> f = A(to_col([0, 0, 0, 7]), denom=5) +>>> g = C(to_col([1, 1, 1, 1])) +>>> e + f +[0, 10, 0, 21]/15 +>>> e - f +[0, 10, 0, -21]/15 +>>> e - g +[-9, -7, -9, -9]/3 +>>> e + QQ(7, 10) +[21, 20, 0, 0]/30 +>>> e * f +[-14, -14, -14, -14]/15 +>>> e ** 2 +[0, 0, 4, 0]/9 +>>> f // g +[7, 7, 7, 7]/15 +>>> f * QQ(2, 3) +[0, 0, 0, 14]/15 + +However, care must be taken with arithmetic operations on +:py:class:`~.ModuleElement`, because the module $C$ to which the result will +belong will be the nearest common ancestor (NCA) of the modules $A$, $B$ to +which the two operands belong, and $C$ may be different from either or both +of $A$ and $B$. + +>>> A = PowerBasis(T) +>>> B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) +>>> C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) +>>> print((B(0) * C(0)).module == A) +True + +Before the arithmetic operation is performed, copies of the two operands are +automatically converted into elements of the NCA (the operands themselves are +not modified). This upward conversion along an ancestor chain is easy: it just +requires the successive multiplication by the defining matrix of each +:py:class:`~.Submodule`. + +Conversely, downward conversion, i.e. representing a given +:py:class:`~.ModuleElement` in a submodule, is also supported -- namely by +the :py:meth:`~sympy.polys.numberfields.modules.Submodule.represent` method +-- but is not guaranteed to succeed in general, since the given element may +not belong to the submodule. The main circumstance in which this issue tends +to arise is with multiplication, since modules, while closed under addition, +need not be closed under multiplication. + + +Multiplication +-------------- + +Generally speaking, a module need not be closed under multiplication, i.e. need +not form a ring. However, many of the modules we work with in the context of +number fields are in fact rings, and our classes do support multiplication. + +Specifically, any :py:class:`~.Module` can attempt to compute its own +multiplication table, but this does not happen unless an attempt is made to +multiply two :py:class:`~.ModuleElement` instances belonging to it. + +>>> A = PowerBasis(T) +>>> print(A._mult_tab is None) +True +>>> a = A(0)*A(1) +>>> print(A._mult_tab is None) +False + +Every :py:class:`~.PowerBasis` is, by its nature, closed under multiplication, +so instances of :py:class:`~.PowerBasis` can always successfully compute their +multiplication table. + +When a :py:class:`~.Submodule` attempts to compute its multiplication table, +it converts each of its own generators into elements of its parent module, +multiplies them there, in every possible pairing, and then tries to +represent the results in itself, i.e. as $\mathbb{Z}$-linear combinations +over its own generators. This will succeed if and only if the submodule is +in fact closed under multiplication. + + +Module Homomorphisms +==================== + +Many important number theoretic algorithms require the calculation of the +kernel of one or more module homomorphisms. Accordingly we have several +lightweight classes, :py:class:`~.ModuleHomomorphism`, +:py:class:`~.ModuleEndomorphism`, :py:class:`~.InnerEndomorphism`, and +:py:class:`~.EndomorphismRing`, which provide the minimal necessary machinery +to support this. + +""" + +from sympy.core.intfunc import igcd, ilcm +from sympy.core.symbol import Dummy +from sympy.polys.polyclasses import ANP +from sympy.polys.polytools import Poly +from sympy.polys.densetools import dup_clear_denoms +from sympy.polys.domains.algebraicfield import AlgebraicField +from sympy.polys.domains.finitefield import FF +from sympy.polys.domains.rationalfield import QQ +from sympy.polys.domains.integerring import ZZ +from sympy.polys.matrices.domainmatrix import DomainMatrix +from sympy.polys.matrices.exceptions import DMBadInputError +from sympy.polys.matrices.normalforms import hermite_normal_form +from sympy.polys.polyerrors import CoercionFailed, UnificationFailed +from sympy.polys.polyutils import IntegerPowerable +from .exceptions import ClosureFailure, MissingUnityError, StructureError +from .utilities import AlgIntPowers, is_rat, get_num_denom + + +def to_col(coeffs): + r"""Transform a list of integer coefficients into a column vector.""" + return DomainMatrix([[ZZ(c) for c in coeffs]], (1, len(coeffs)), ZZ).transpose() + + +class Module: + """ + Generic finitely-generated module. + + This is an abstract base class, and should not be instantiated directly. + The two concrete subclasses are :py:class:`~.PowerBasis` and + :py:class:`~.Submodule`. + + Every :py:class:`~.Submodule` is derived from another module, referenced + by its ``parent`` attribute. If ``S`` is a submodule, then we refer to + ``S.parent``, ``S.parent.parent``, and so on, as the "ancestors" of + ``S``. Thus, every :py:class:`~.Module` is either a + :py:class:`~.PowerBasis` or a :py:class:`~.Submodule`, some ancestor of + which is a :py:class:`~.PowerBasis`. + """ + + @property + def n(self): + """The number of generators of this module.""" + raise NotImplementedError + + def mult_tab(self): + """ + Get the multiplication table for this module (if closed under mult). + + Explanation + =========== + + Computes a dictionary ``M`` of dictionaries of lists, representing the + upper triangular half of the multiplication table. + + In other words, if ``0 <= i <= j < self.n``, then ``M[i][j]`` is the + list ``c`` of coefficients such that + ``g[i] * g[j] == sum(c[k]*g[k], k in range(self.n))``, + where ``g`` is the list of generators of this module. + + If ``j < i`` then ``M[i][j]`` is undefined. + + Examples + ======== + + >>> from sympy.polys import Poly, cyclotomic_poly + >>> from sympy.polys.numberfields.modules import PowerBasis + >>> T = Poly(cyclotomic_poly(5)) + >>> A = PowerBasis(T) + >>> print(A.mult_tab()) # doctest: +SKIP + {0: {0: [1, 0, 0, 0], 1: [0, 1, 0, 0], 2: [0, 0, 1, 0], 3: [0, 0, 0, 1]}, + 1: {1: [0, 0, 1, 0], 2: [0, 0, 0, 1], 3: [-1, -1, -1, -1]}, + 2: {2: [-1, -1, -1, -1], 3: [1, 0, 0, 0]}, + 3: {3: [0, 1, 0, 0]}} + + Returns + ======= + + dict of dict of lists + + Raises + ====== + + ClosureFailure + If the module is not closed under multiplication. + + """ + raise NotImplementedError + + @property + def parent(self): + """ + The parent module, if any, for this module. + + Explanation + =========== + + For a :py:class:`~.Submodule` this is its ``parent`` attribute; for a + :py:class:`~.PowerBasis` this is ``None``. + + Returns + ======= + + :py:class:`~.Module`, ``None`` + + See Also + ======== + + Module + + """ + return None + + def represent(self, elt): + r""" + Represent a module element as an integer-linear combination over the + generators of this module. + + Explanation + =========== + + In our system, to "represent" always means to write a + :py:class:`~.ModuleElement` as a :ref:`ZZ`-linear combination over the + generators of the present :py:class:`~.Module`. Furthermore, the + incoming :py:class:`~.ModuleElement` must belong to an ancestor of + the present :py:class:`~.Module` (or to the present + :py:class:`~.Module` itself). + + The most common application is to represent a + :py:class:`~.ModuleElement` in a :py:class:`~.Submodule`. For example, + this is involved in computing multiplication tables. + + On the other hand, representing in a :py:class:`~.PowerBasis` is an + odd case, and one which tends not to arise in practice, except for + example when using a :py:class:`~.ModuleEndomorphism` on a + :py:class:`~.PowerBasis`. + + In such a case, (1) the incoming :py:class:`~.ModuleElement` must + belong to the :py:class:`~.PowerBasis` itself (since the latter has no + proper ancestors) and (2) it is "representable" iff it belongs to + $\mathbb{Z}[\theta]$ (although generally a + :py:class:`~.PowerBasisElement` may represent any element of + $\mathbb{Q}(\theta)$, i.e. any algebraic number). + + Examples + ======== + + >>> from sympy import Poly, cyclotomic_poly + >>> from sympy.polys.numberfields.modules import PowerBasis, to_col + >>> from sympy.abc import zeta + >>> T = Poly(cyclotomic_poly(5)) + >>> A = PowerBasis(T) + >>> a = A(to_col([2, 4, 6, 8])) + + The :py:class:`~.ModuleElement` ``a`` has all even coefficients. + If we represent ``a`` in the submodule ``B = 2*A``, the coefficients in + the column vector will be halved: + + >>> B = A.submodule_from_gens([2*A(i) for i in range(4)]) + >>> b = B.represent(a) + >>> print(b.transpose()) # doctest: +SKIP + DomainMatrix([[1, 2, 3, 4]], (1, 4), ZZ) + + However, the element of ``B`` so defined still represents the same + algebraic number: + + >>> print(a.poly(zeta).as_expr()) + 8*zeta**3 + 6*zeta**2 + 4*zeta + 2 + >>> print(B(b).over_power_basis().poly(zeta).as_expr()) + 8*zeta**3 + 6*zeta**2 + 4*zeta + 2 + + Parameters + ========== + + elt : :py:class:`~.ModuleElement` + The module element to be represented. Must belong to some ancestor + module of this module (including this module itself). + + Returns + ======= + + :py:class:`~.DomainMatrix` over :ref:`ZZ` + This will be a column vector, representing the coefficients of a + linear combination of this module's generators, which equals the + given element. + + Raises + ====== + + ClosureFailure + If the given element cannot be represented as a :ref:`ZZ`-linear + combination over this module. + + See Also + ======== + + .Submodule.represent + .PowerBasis.represent + + """ + raise NotImplementedError + + def ancestors(self, include_self=False): + """ + Return the list of ancestor modules of this module, from the + foundational :py:class:`~.PowerBasis` downward, optionally including + ``self``. + + See Also + ======== + + Module + + """ + c = self.parent + a = [] if c is None else c.ancestors(include_self=True) + if include_self: + a.append(self) + return a + + def power_basis_ancestor(self): + """ + Return the :py:class:`~.PowerBasis` that is an ancestor of this module. + + See Also + ======== + + Module + + """ + if isinstance(self, PowerBasis): + return self + c = self.parent + if c is not None: + return c.power_basis_ancestor() + return None + + def nearest_common_ancestor(self, other): + """ + Locate the nearest common ancestor of this module and another. + + Returns + ======= + + :py:class:`~.Module`, ``None`` + + See Also + ======== + + Module + + """ + sA = self.ancestors(include_self=True) + oA = other.ancestors(include_self=True) + nca = None + for sa, oa in zip(sA, oA): + if sa == oa: + nca = sa + else: + break + return nca + + @property + def number_field(self): + r""" + Return the associated :py:class:`~.AlgebraicField`, if any. + + Explanation + =========== + + A :py:class:`~.PowerBasis` can be constructed on a :py:class:`~.Poly` + $f$ or on an :py:class:`~.AlgebraicField` $K$. In the latter case, the + :py:class:`~.PowerBasis` and all its descendant modules will return $K$ + as their ``.number_field`` property, while in the former case they will + all return ``None``. + + Returns + ======= + + :py:class:`~.AlgebraicField`, ``None`` + + """ + return self.power_basis_ancestor().number_field + + def is_compat_col(self, col): + """Say whether *col* is a suitable column vector for this module.""" + return isinstance(col, DomainMatrix) and col.shape == (self.n, 1) and col.domain.is_ZZ + + def __call__(self, spec, denom=1): + r""" + Generate a :py:class:`~.ModuleElement` belonging to this module. + + Examples + ======== + + >>> from sympy.polys import Poly, cyclotomic_poly + >>> from sympy.polys.numberfields.modules import PowerBasis, to_col + >>> T = Poly(cyclotomic_poly(5)) + >>> A = PowerBasis(T) + >>> e = A(to_col([1, 2, 3, 4]), denom=3) + >>> print(e) # doctest: +SKIP + [1, 2, 3, 4]/3 + >>> f = A(2) + >>> print(f) # doctest: +SKIP + [0, 0, 1, 0] + + Parameters + ========== + + spec : :py:class:`~.DomainMatrix`, int + Specifies the numerators of the coefficients of the + :py:class:`~.ModuleElement`. Can be either a column vector over + :ref:`ZZ`, whose length must equal the number $n$ of generators of + this module, or else an integer ``j``, $0 \leq j < n$, which is a + shorthand for column $j$ of $I_n$, the $n \times n$ identity + matrix. + denom : int, optional (default=1) + Denominator for the coefficients of the + :py:class:`~.ModuleElement`. + + Returns + ======= + + :py:class:`~.ModuleElement` + The coefficients are the entries of the *spec* vector, divided by + *denom*. + + """ + if isinstance(spec, int) and 0 <= spec < self.n: + spec = DomainMatrix.eye(self.n, ZZ)[:, spec].to_dense() + if not self.is_compat_col(spec): + raise ValueError('Compatible column vector required.') + return make_mod_elt(self, spec, denom=denom) + + def starts_with_unity(self): + """Say whether the module's first generator equals unity.""" + raise NotImplementedError + + def basis_elements(self): + """ + Get list of :py:class:`~.ModuleElement` being the generators of this + module. + """ + return [self(j) for j in range(self.n)] + + def zero(self): + """Return a :py:class:`~.ModuleElement` representing zero.""" + return self(0) * 0 + + def one(self): + """ + Return a :py:class:`~.ModuleElement` representing unity, + and belonging to the first ancestor of this module (including + itself) that starts with unity. + """ + return self.element_from_rational(1) + + def element_from_rational(self, a): + """ + Return a :py:class:`~.ModuleElement` representing a rational number. + + Explanation + =========== + + The returned :py:class:`~.ModuleElement` will belong to the first + module on this module's ancestor chain (including this module + itself) that starts with unity. + + Examples + ======== + + >>> from sympy.polys import Poly, cyclotomic_poly, QQ + >>> from sympy.polys.numberfields.modules import PowerBasis + >>> T = Poly(cyclotomic_poly(5)) + >>> A = PowerBasis(T) + >>> a = A.element_from_rational(QQ(2, 3)) + >>> print(a) # doctest: +SKIP + [2, 0, 0, 0]/3 + + Parameters + ========== + + a : int, :ref:`ZZ`, :ref:`QQ` + + Returns + ======= + + :py:class:`~.ModuleElement` + + """ + raise NotImplementedError + + def submodule_from_gens(self, gens, hnf=True, hnf_modulus=None): + """ + Form the submodule generated by a list of :py:class:`~.ModuleElement` + belonging to this module. + + Examples + ======== + + >>> from sympy.polys import Poly, cyclotomic_poly + >>> from sympy.polys.numberfields.modules import PowerBasis + >>> T = Poly(cyclotomic_poly(5)) + >>> A = PowerBasis(T) + >>> gens = [A(0), 2*A(1), 3*A(2), 4*A(3)//5] + >>> B = A.submodule_from_gens(gens) + >>> print(B) # doctest: +SKIP + Submodule[[5, 0, 0, 0], [0, 10, 0, 0], [0, 0, 15, 0], [0, 0, 0, 4]]/5 + + Parameters + ========== + + gens : list of :py:class:`~.ModuleElement` belonging to this module. + hnf : boolean, optional (default=True) + If True, we will reduce the matrix into Hermite Normal Form before + forming the :py:class:`~.Submodule`. + hnf_modulus : int, None, optional (default=None) + Modulus for use in the HNF reduction algorithm. See + :py:func:`~sympy.polys.matrices.normalforms.hermite_normal_form`. + + Returns + ======= + + :py:class:`~.Submodule` + + See Also + ======== + + submodule_from_matrix + + """ + if not all(g.module == self for g in gens): + raise ValueError('Generators must belong to this module.') + n = len(gens) + if n == 0: + raise ValueError('Need at least one generator.') + m = gens[0].n + d = gens[0].denom if n == 1 else ilcm(*[g.denom for g in gens]) + B = DomainMatrix.zeros((m, 0), ZZ).hstack(*[(d // g.denom) * g.col for g in gens]) + if hnf: + B = hermite_normal_form(B, D=hnf_modulus) + return self.submodule_from_matrix(B, denom=d) + + def submodule_from_matrix(self, B, denom=1): + """ + Form the submodule generated by the elements of this module indicated + by the columns of a matrix, with an optional denominator. + + Examples + ======== + + >>> from sympy.polys import Poly, cyclotomic_poly, ZZ + >>> from sympy.polys.matrices import DM + >>> from sympy.polys.numberfields.modules import PowerBasis + >>> T = Poly(cyclotomic_poly(5)) + >>> A = PowerBasis(T) + >>> B = A.submodule_from_matrix(DM([ + ... [0, 10, 0, 0], + ... [0, 0, 7, 0], + ... ], ZZ).transpose(), denom=15) + >>> print(B) # doctest: +SKIP + Submodule[[0, 10, 0, 0], [0, 0, 7, 0]]/15 + + Parameters + ========== + + B : :py:class:`~.DomainMatrix` over :ref:`ZZ` + Each column gives the numerators of the coefficients of one + generator of the submodule. Thus, the number of rows of *B* must + equal the number of generators of the present module. + denom : int, optional (default=1) + Common denominator for all generators of the submodule. + + Returns + ======= + + :py:class:`~.Submodule` + + Raises + ====== + + ValueError + If the given matrix *B* is not over :ref:`ZZ` or its number of rows + does not equal the number of generators of the present module. + + See Also + ======== + + submodule_from_gens + + """ + m, n = B.shape + if not B.domain.is_ZZ: + raise ValueError('Matrix must be over ZZ.') + if not m == self.n: + raise ValueError('Matrix row count must match base module.') + return Submodule(self, B, denom=denom) + + def whole_submodule(self): + """ + Return a submodule equal to this entire module. + + Explanation + =========== + + This is useful when you have a :py:class:`~.PowerBasis` and want to + turn it into a :py:class:`~.Submodule` (in order to use methods + belonging to the latter). + + """ + B = DomainMatrix.eye(self.n, ZZ) + return self.submodule_from_matrix(B) + + def endomorphism_ring(self): + """Form the :py:class:`~.EndomorphismRing` for this module.""" + return EndomorphismRing(self) + + +class PowerBasis(Module): + """The module generated by the powers of an algebraic integer.""" + + def __init__(self, T): + """ + Parameters + ========== + + T : :py:class:`~.Poly`, :py:class:`~.AlgebraicField` + Either (1) the monic, irreducible, univariate polynomial over + :ref:`ZZ`, a root of which is the generator of the power basis, + or (2) an :py:class:`~.AlgebraicField` whose primitive element + is the generator of the power basis. + + """ + K = None + if isinstance(T, AlgebraicField): + K, T = T, T.ext.minpoly_of_element() + # Sometimes incoming Polys are formally over QQ, although all their + # coeffs are integral. We want them to be formally over ZZ. + T = T.set_domain(ZZ) + self.K = K + self.T = T + self._n = T.degree() + self._mult_tab = None + + @property + def number_field(self): + return self.K + + def __repr__(self): + return f'PowerBasis({self.T.as_expr()})' + + def __eq__(self, other): + if isinstance(other, PowerBasis): + return self.T == other.T + return NotImplemented + + @property + def n(self): + return self._n + + def mult_tab(self): + if self._mult_tab is None: + self.compute_mult_tab() + return self._mult_tab + + def compute_mult_tab(self): + theta_pow = AlgIntPowers(self.T) + M = {} + n = self.n + for u in range(n): + M[u] = {} + for v in range(u, n): + M[u][v] = theta_pow[u + v] + self._mult_tab = M + + def represent(self, elt): + r""" + Represent a module element as an integer-linear combination over the + generators of this module. + + See Also + ======== + + .Module.represent + .Submodule.represent + + """ + if elt.module == self and elt.denom == 1: + return elt.column() + else: + raise ClosureFailure('Element not representable in ZZ[theta].') + + def starts_with_unity(self): + return True + + def element_from_rational(self, a): + return self(0) * a + + def element_from_poly(self, f): + """ + Produce an element of this module, representing *f* after reduction mod + our defining minimal polynomial. + + Parameters + ========== + + f : :py:class:`~.Poly` over :ref:`ZZ` in same var as our defining poly. + + Returns + ======= + + :py:class:`~.PowerBasisElement` + + """ + n, k = self.n, f.degree() + if k >= n: + f = f % self.T + if f == 0: + return self.zero() + d, c = dup_clear_denoms(f.rep.to_list(), QQ, convert=True) + c = list(reversed(c)) + ell = len(c) + z = [ZZ(0)] * (n - ell) + col = to_col(c + z) + return self(col, denom=d) + + def _element_from_rep_and_mod(self, rep, mod): + """ + Produce a PowerBasisElement representing a given algebraic number. + + Parameters + ========== + + rep : list of coeffs + Represents the number as polynomial in the primitive element of the + field. + + mod : list of coeffs + Represents the minimal polynomial of the primitive element of the + field. + + Returns + ======= + + :py:class:`~.PowerBasisElement` + + """ + if mod != self.T.rep.to_list(): + raise UnificationFailed('Element does not appear to be in the same field.') + return self.element_from_poly(Poly(rep, self.T.gen)) + + def element_from_ANP(self, a): + """Convert an ANP into a PowerBasisElement. """ + return self._element_from_rep_and_mod(a.to_list(), a.mod_to_list()) + + def element_from_alg_num(self, a): + """Convert an AlgebraicNumber into a PowerBasisElement. """ + return self._element_from_rep_and_mod(a.rep.to_list(), a.minpoly.rep.to_list()) + + +class Submodule(Module, IntegerPowerable): + """A submodule of another module.""" + + def __init__(self, parent, matrix, denom=1, mult_tab=None): + """ + Parameters + ========== + + parent : :py:class:`~.Module` + The module from which this one is derived. + matrix : :py:class:`~.DomainMatrix` over :ref:`ZZ` + The matrix whose columns define this submodule's generators as + linear combinations over the parent's generators. + denom : int, optional (default=1) + Denominator for the coefficients given by the matrix. + mult_tab : dict, ``None``, optional + If already known, the multiplication table for this module may be + supplied. + + """ + self._parent = parent + self._matrix = matrix + self._denom = denom + self._mult_tab = mult_tab + self._n = matrix.shape[1] + self._QQ_matrix = None + self._starts_with_unity = None + self._is_sq_maxrank_HNF = None + + def __repr__(self): + r = 'Submodule' + repr(self.matrix.transpose().to_Matrix().tolist()) + if self.denom > 1: + r += f'/{self.denom}' + return r + + def reduced(self): + """ + Produce a reduced version of this submodule. + + Explanation + =========== + + In the reduced version, it is guaranteed that 1 is the only positive + integer dividing both the submodule's denominator, and every entry in + the submodule's matrix. + + Returns + ======= + + :py:class:`~.Submodule` + + """ + if self.denom == 1: + return self + g = igcd(self.denom, *self.coeffs) + if g == 1: + return self + return type(self)(self.parent, (self.matrix / g).convert_to(ZZ), denom=self.denom // g, mult_tab=self._mult_tab) + + def discard_before(self, r): + """ + Produce a new module by discarding all generators before a given + index *r*. + """ + W = self.matrix[:, r:] + s = self.n - r + M = None + mt = self._mult_tab + if mt is not None: + M = {} + for u in range(s): + M[u] = {} + for v in range(u, s): + M[u][v] = mt[r + u][r + v][r:] + return Submodule(self.parent, W, denom=self.denom, mult_tab=M) + + @property + def n(self): + return self._n + + def mult_tab(self): + if self._mult_tab is None: + self.compute_mult_tab() + return self._mult_tab + + def compute_mult_tab(self): + gens = self.basis_element_pullbacks() + M = {} + n = self.n + for u in range(n): + M[u] = {} + for v in range(u, n): + M[u][v] = self.represent(gens[u] * gens[v]).flat() + self._mult_tab = M + + @property + def parent(self): + return self._parent + + @property + def matrix(self): + return self._matrix + + @property + def coeffs(self): + return self.matrix.flat() + + @property + def denom(self): + return self._denom + + @property + def QQ_matrix(self): + """ + :py:class:`~.DomainMatrix` over :ref:`QQ`, equal to + ``self.matrix / self.denom``, and guaranteed to be dense. + + Explanation + =========== + + Depending on how it is formed, a :py:class:`~.DomainMatrix` may have + an internal representation that is sparse or dense. We guarantee a + dense representation here, so that tests for equivalence of submodules + always come out as expected. + + Examples + ======== + + >>> from sympy.polys import Poly, cyclotomic_poly, ZZ + >>> from sympy.abc import x + >>> from sympy.polys.matrices import DomainMatrix + >>> from sympy.polys.numberfields.modules import PowerBasis + >>> T = Poly(cyclotomic_poly(5, x)) + >>> A = PowerBasis(T) + >>> B = A.submodule_from_matrix(3*DomainMatrix.eye(4, ZZ), denom=6) + >>> C = A.submodule_from_matrix(DomainMatrix.eye(4, ZZ), denom=2) + >>> print(B.QQ_matrix == C.QQ_matrix) + True + + Returns + ======= + + :py:class:`~.DomainMatrix` over :ref:`QQ` + + """ + if self._QQ_matrix is None: + self._QQ_matrix = (self.matrix / self.denom).to_dense() + return self._QQ_matrix + + def starts_with_unity(self): + if self._starts_with_unity is None: + self._starts_with_unity = self(0).equiv(1) + return self._starts_with_unity + + def is_sq_maxrank_HNF(self): + if self._is_sq_maxrank_HNF is None: + self._is_sq_maxrank_HNF = is_sq_maxrank_HNF(self._matrix) + return self._is_sq_maxrank_HNF + + def is_power_basis_submodule(self): + return isinstance(self.parent, PowerBasis) + + def element_from_rational(self, a): + if self.starts_with_unity(): + return self(0) * a + else: + return self.parent.element_from_rational(a) + + def basis_element_pullbacks(self): + """ + Return list of this submodule's basis elements as elements of the + submodule's parent module. + """ + return [e.to_parent() for e in self.basis_elements()] + + def represent(self, elt): + """ + Represent a module element as an integer-linear combination over the + generators of this module. + + See Also + ======== + + .Module.represent + .PowerBasis.represent + + """ + if elt.module == self: + return elt.column() + elif elt.module == self.parent: + try: + # The given element should be a ZZ-linear combination over our + # basis vectors; however, due to the presence of denominators, + # we need to solve over QQ. + A = self.QQ_matrix + b = elt.QQ_col + x = A._solve(b)[0].transpose() + x = x.convert_to(ZZ) + except DMBadInputError: + raise ClosureFailure('Element outside QQ-span of this basis.') + except CoercionFailed: + raise ClosureFailure('Element in QQ-span but not ZZ-span of this basis.') + return x + elif isinstance(self.parent, Submodule): + coeffs_in_parent = self.parent.represent(elt) + parent_element = self.parent(coeffs_in_parent) + return self.represent(parent_element) + else: + raise ClosureFailure('Element outside ancestor chain of this module.') + + def is_compat_submodule(self, other): + return isinstance(other, Submodule) and other.parent == self.parent + + def __eq__(self, other): + if self.is_compat_submodule(other): + return other.QQ_matrix == self.QQ_matrix + return NotImplemented + + def add(self, other, hnf=True, hnf_modulus=None): + """ + Add this :py:class:`~.Submodule` to another. + + Explanation + =========== + + This represents the module generated by the union of the two modules' + sets of generators. + + Parameters + ========== + + other : :py:class:`~.Submodule` + hnf : boolean, optional (default=True) + If ``True``, reduce the matrix of the combined module to its + Hermite Normal Form. + hnf_modulus : :ref:`ZZ`, None, optional + If a positive integer is provided, use this as modulus in the + HNF reduction. See + :py:func:`~sympy.polys.matrices.normalforms.hermite_normal_form`. + + Returns + ======= + + :py:class:`~.Submodule` + + """ + d, e = self.denom, other.denom + m = ilcm(d, e) + a, b = m // d, m // e + B = (a * self.matrix).hstack(b * other.matrix) + if hnf: + B = hermite_normal_form(B, D=hnf_modulus) + return self.parent.submodule_from_matrix(B, denom=m) + + def __add__(self, other): + if self.is_compat_submodule(other): + return self.add(other) + return NotImplemented + + __radd__ = __add__ + + def mul(self, other, hnf=True, hnf_modulus=None): + """ + Multiply this :py:class:`~.Submodule` by a rational number, a + :py:class:`~.ModuleElement`, or another :py:class:`~.Submodule`. + + Explanation + =========== + + To multiply by a rational number or :py:class:`~.ModuleElement` means + to form the submodule whose generators are the products of this + quantity with all the generators of the present submodule. + + To multiply by another :py:class:`~.Submodule` means to form the + submodule whose generators are all the products of one generator from + the one submodule, and one generator from the other. + + Parameters + ========== + + other : int, :ref:`ZZ`, :ref:`QQ`, :py:class:`~.ModuleElement`, :py:class:`~.Submodule` + hnf : boolean, optional (default=True) + If ``True``, reduce the matrix of the product module to its + Hermite Normal Form. + hnf_modulus : :ref:`ZZ`, None, optional + If a positive integer is provided, use this as modulus in the + HNF reduction. See + :py:func:`~sympy.polys.matrices.normalforms.hermite_normal_form`. + + Returns + ======= + + :py:class:`~.Submodule` + + """ + if is_rat(other): + a, b = get_num_denom(other) + if a == b == 1: + return self + else: + return Submodule(self.parent, + self.matrix * a, denom=self.denom * b, + mult_tab=None).reduced() + elif isinstance(other, ModuleElement) and other.module == self.parent: + # The submodule is multiplied by an element of the parent module. + # We presume this means we want a new submodule of the parent module. + gens = [other * e for e in self.basis_element_pullbacks()] + return self.parent.submodule_from_gens(gens, hnf=hnf, hnf_modulus=hnf_modulus) + elif self.is_compat_submodule(other): + # This case usually means you're multiplying ideals, and want another + # ideal, i.e. another submodule of the same parent module. + alphas, betas = self.basis_element_pullbacks(), other.basis_element_pullbacks() + gens = [a * b for a in alphas for b in betas] + return self.parent.submodule_from_gens(gens, hnf=hnf, hnf_modulus=hnf_modulus) + return NotImplemented + + def __mul__(self, other): + return self.mul(other) + + __rmul__ = __mul__ + + def _first_power(self): + return self + + def reduce_element(self, elt): + r""" + If this submodule $B$ has defining matrix $W$ in square, maximal-rank + Hermite normal form, then, given an element $x$ of the parent module + $A$, we produce an element $y \in A$ such that $x - y \in B$, and the + $i$th coordinate of $y$ satisfies $0 \leq y_i < w_{i,i}$. This + representative $y$ is unique, in the sense that every element of + the coset $x + B$ reduces to it under this procedure. + + Explanation + =========== + + In the special case where $A$ is a power basis for a number field $K$, + and $B$ is a submodule representing an ideal $I$, this operation + represents one of a few important ways of reducing an element of $K$ + modulo $I$ to obtain a "small" representative. See [Cohen00]_ Section + 1.4.3. + + Examples + ======== + + >>> from sympy import QQ, Poly, symbols + >>> t = symbols('t') + >>> k = QQ.alg_field_from_poly(Poly(t**3 + t**2 - 2*t + 8)) + >>> Zk = k.maximal_order() + >>> A = Zk.parent + >>> B = (A(2) - 3*A(0))*Zk + >>> B.reduce_element(A(2)) + [3, 0, 0] + + Parameters + ========== + + elt : :py:class:`~.ModuleElement` + An element of this submodule's parent module. + + Returns + ======= + + elt : :py:class:`~.ModuleElement` + An element of this submodule's parent module. + + Raises + ====== + + NotImplementedError + If the given :py:class:`~.ModuleElement` does not belong to this + submodule's parent module. + StructureError + If this submodule's defining matrix is not in square, maximal-rank + Hermite normal form. + + References + ========== + + .. [Cohen00] Cohen, H. *Advanced Topics in Computational Number + Theory.* + + """ + if not elt.module == self.parent: + raise NotImplementedError + if not self.is_sq_maxrank_HNF(): + msg = "Reduction not implemented unless matrix square max-rank HNF" + raise StructureError(msg) + B = self.basis_element_pullbacks() + a = elt + for i in range(self.n - 1, -1, -1): + b = B[i] + q = a.coeffs[i]*b.denom // (b.coeffs[i]*a.denom) + a -= q*b + return a + + +def is_sq_maxrank_HNF(dm): + r""" + Say whether a :py:class:`~.DomainMatrix` is in that special case of Hermite + Normal Form, in which the matrix is also square and of maximal rank. + + Explanation + =========== + + We commonly work with :py:class:`~.Submodule` instances whose matrix is in + this form, and it can be useful to be able to check that this condition is + satisfied. + + For example this is the case with the :py:class:`~.Submodule` ``ZK`` + returned by :py:func:`~sympy.polys.numberfields.basis.round_two`, which + represents the maximal order in a number field, and with ideals formed + therefrom, such as ``2 * ZK``. + + """ + if dm.domain.is_ZZ and dm.is_square and dm.is_upper: + n = dm.shape[0] + for i in range(n): + d = dm[i, i].element + if d <= 0: + return False + for j in range(i + 1, n): + if not (0 <= dm[i, j].element < d): + return False + return True + return False + + +def make_mod_elt(module, col, denom=1): + r""" + Factory function which builds a :py:class:`~.ModuleElement`, but ensures + that it is a :py:class:`~.PowerBasisElement` if the module is a + :py:class:`~.PowerBasis`. + """ + if isinstance(module, PowerBasis): + return PowerBasisElement(module, col, denom=denom) + else: + return ModuleElement(module, col, denom=denom) + + +class ModuleElement(IntegerPowerable): + r""" + Represents an element of a :py:class:`~.Module`. + + NOTE: Should not be constructed directly. Use the + :py:meth:`~.Module.__call__` method or the :py:func:`make_mod_elt()` + factory function instead. + """ + + def __init__(self, module, col, denom=1): + """ + Parameters + ========== + + module : :py:class:`~.Module` + The module to which this element belongs. + col : :py:class:`~.DomainMatrix` over :ref:`ZZ` + Column vector giving the numerators of the coefficients of this + element. + denom : int, optional (default=1) + Denominator for the coefficients of this element. + + """ + self.module = module + self.col = col + self.denom = denom + self._QQ_col = None + + def __repr__(self): + r = str([int(c) for c in self.col.flat()]) + if self.denom > 1: + r += f'/{self.denom}' + return r + + def reduced(self): + """ + Produce a reduced version of this ModuleElement, i.e. one in which the + gcd of the denominator together with all numerator coefficients is 1. + """ + if self.denom == 1: + return self + g = igcd(self.denom, *self.coeffs) + if g == 1: + return self + return type(self)(self.module, + (self.col / g).convert_to(ZZ), + denom=self.denom // g) + + def reduced_mod_p(self, p): + """ + Produce a version of this :py:class:`~.ModuleElement` in which all + numerator coefficients have been reduced mod *p*. + """ + return make_mod_elt(self.module, + self.col.convert_to(FF(p)).convert_to(ZZ), + denom=self.denom) + + @classmethod + def from_int_list(cls, module, coeffs, denom=1): + """ + Make a :py:class:`~.ModuleElement` from a list of ints (instead of a + column vector). + """ + col = to_col(coeffs) + return cls(module, col, denom=denom) + + @property + def n(self): + """The length of this element's column.""" + return self.module.n + + def __len__(self): + return self.n + + def column(self, domain=None): + """ + Get a copy of this element's column, optionally converting to a domain. + """ + if domain is None: + return self.col.copy() + else: + return self.col.convert_to(domain) + + @property + def coeffs(self): + return self.col.flat() + + @property + def QQ_col(self): + """ + :py:class:`~.DomainMatrix` over :ref:`QQ`, equal to + ``self.col / self.denom``, and guaranteed to be dense. + + See Also + ======== + + .Submodule.QQ_matrix + + """ + if self._QQ_col is None: + self._QQ_col = (self.col / self.denom).to_dense() + return self._QQ_col + + def to_parent(self): + """ + Transform into a :py:class:`~.ModuleElement` belonging to the parent of + this element's module. + """ + if not isinstance(self.module, Submodule): + raise ValueError('Not an element of a Submodule.') + return make_mod_elt( + self.module.parent, self.module.matrix * self.col, + denom=self.module.denom * self.denom) + + def to_ancestor(self, anc): + """ + Transform into a :py:class:`~.ModuleElement` belonging to a given + ancestor of this element's module. + + Parameters + ========== + + anc : :py:class:`~.Module` + + """ + if anc == self.module: + return self + else: + return self.to_parent().to_ancestor(anc) + + def over_power_basis(self): + """ + Transform into a :py:class:`~.PowerBasisElement` over our + :py:class:`~.PowerBasis` ancestor. + """ + e = self + while not isinstance(e.module, PowerBasis): + e = e.to_parent() + return e + + def is_compat(self, other): + """ + Test whether other is another :py:class:`~.ModuleElement` with same + module. + """ + return isinstance(other, ModuleElement) and other.module == self.module + + def unify(self, other): + """ + Try to make a compatible pair of :py:class:`~.ModuleElement`, one + equivalent to this one, and one equivalent to the other. + + Explanation + =========== + + We search for the nearest common ancestor module for the pair of + elements, and represent each one there. + + Returns + ======= + + Pair ``(e1, e2)`` + Each ``ei`` is a :py:class:`~.ModuleElement`, they belong to the + same :py:class:`~.Module`, ``e1`` is equivalent to ``self``, and + ``e2`` is equivalent to ``other``. + + Raises + ====== + + UnificationFailed + If ``self`` and ``other`` have no common ancestor module. + + """ + if self.module == other.module: + return self, other + nca = self.module.nearest_common_ancestor(other.module) + if nca is not None: + return self.to_ancestor(nca), other.to_ancestor(nca) + raise UnificationFailed(f"Cannot unify {self} with {other}") + + def __eq__(self, other): + if self.is_compat(other): + return self.QQ_col == other.QQ_col + return NotImplemented + + def equiv(self, other): + """ + A :py:class:`~.ModuleElement` may test as equivalent to a rational + number or another :py:class:`~.ModuleElement`, if they represent the + same algebraic number. + + Explanation + =========== + + This method is intended to check equivalence only in those cases in + which it is easy to test; namely, when *other* is either a + :py:class:`~.ModuleElement` that can be unified with this one (i.e. one + which shares a common :py:class:`~.PowerBasis` ancestor), or else a + rational number (which is easy because every :py:class:`~.PowerBasis` + represents every rational number). + + Parameters + ========== + + other : int, :ref:`ZZ`, :ref:`QQ`, :py:class:`~.ModuleElement` + + Returns + ======= + + bool + + Raises + ====== + + UnificationFailed + If ``self`` and ``other`` do not share a common + :py:class:`~.PowerBasis` ancestor. + + """ + if self == other: + return True + elif isinstance(other, ModuleElement): + a, b = self.unify(other) + return a == b + elif is_rat(other): + if isinstance(self, PowerBasisElement): + return self == self.module(0) * other + else: + return self.over_power_basis().equiv(other) + return False + + def __add__(self, other): + """ + A :py:class:`~.ModuleElement` can be added to a rational number, or to + another :py:class:`~.ModuleElement`. + + Explanation + =========== + + When the other summand is a rational number, it will be converted into + a :py:class:`~.ModuleElement` (belonging to the first ancestor of this + module that starts with unity). + + In all cases, the sum belongs to the nearest common ancestor (NCA) of + the modules of the two summands. If the NCA does not exist, we return + ``NotImplemented``. + """ + if self.is_compat(other): + d, e = self.denom, other.denom + m = ilcm(d, e) + u, v = m // d, m // e + col = to_col([u * a + v * b for a, b in zip(self.coeffs, other.coeffs)]) + return type(self)(self.module, col, denom=m).reduced() + elif isinstance(other, ModuleElement): + try: + a, b = self.unify(other) + except UnificationFailed: + return NotImplemented + return a + b + elif is_rat(other): + return self + self.module.element_from_rational(other) + return NotImplemented + + __radd__ = __add__ + + def __neg__(self): + return self * -1 + + def __sub__(self, other): + return self + (-other) + + def __rsub__(self, other): + return -self + other + + def __mul__(self, other): + """ + A :py:class:`~.ModuleElement` can be multiplied by a rational number, + or by another :py:class:`~.ModuleElement`. + + Explanation + =========== + + When the multiplier is a rational number, the product is computed by + operating directly on the coefficients of this + :py:class:`~.ModuleElement`. + + When the multiplier is another :py:class:`~.ModuleElement`, the product + will belong to the nearest common ancestor (NCA) of the modules of the + two operands, and that NCA must have a multiplication table. If the NCA + does not exist, we return ``NotImplemented``. If the NCA does not have + a mult. table, ``ClosureFailure`` will be raised. + """ + if self.is_compat(other): + M = self.module.mult_tab() + A, B = self.col.flat(), other.col.flat() + n = self.n + C = [0] * n + for u in range(n): + for v in range(u, n): + c = A[u] * B[v] + if v > u: + c += A[v] * B[u] + if c != 0: + R = M[u][v] + for k in range(n): + C[k] += c * R[k] + d = self.denom * other.denom + return self.from_int_list(self.module, C, denom=d) + elif isinstance(other, ModuleElement): + try: + a, b = self.unify(other) + except UnificationFailed: + return NotImplemented + return a * b + elif is_rat(other): + a, b = get_num_denom(other) + if a == b == 1: + return self + else: + return make_mod_elt(self.module, + self.col * a, denom=self.denom * b).reduced() + return NotImplemented + + __rmul__ = __mul__ + + def _zeroth_power(self): + return self.module.one() + + def _first_power(self): + return self + + def __floordiv__(self, a): + if is_rat(a): + a = QQ(a) + return self * (1/a) + elif isinstance(a, ModuleElement): + return self * (1//a) + return NotImplemented + + def __rfloordiv__(self, a): + return a // self.over_power_basis() + + def __mod__(self, m): + r""" + Reduce this :py:class:`~.ModuleElement` mod a :py:class:`~.Submodule`. + + Parameters + ========== + + m : int, :ref:`ZZ`, :ref:`QQ`, :py:class:`~.Submodule` + If a :py:class:`~.Submodule`, reduce ``self`` relative to this. + If an integer or rational, reduce relative to the + :py:class:`~.Submodule` that is our own module times this constant. + + See Also + ======== + + .Submodule.reduce_element + + """ + if is_rat(m): + m = m * self.module.whole_submodule() + if isinstance(m, Submodule) and m.parent == self.module: + return m.reduce_element(self) + return NotImplemented + + +class PowerBasisElement(ModuleElement): + r""" + Subclass for :py:class:`~.ModuleElement` instances whose module is a + :py:class:`~.PowerBasis`. + """ + + @property + def T(self): + """Access the defining polynomial of the :py:class:`~.PowerBasis`.""" + return self.module.T + + def numerator(self, x=None): + """Obtain the numerator as a polynomial over :ref:`ZZ`.""" + x = x or self.T.gen + return Poly(reversed(self.coeffs), x, domain=ZZ) + + def poly(self, x=None): + """Obtain the number as a polynomial over :ref:`QQ`.""" + return self.numerator(x=x) // self.denom + + @property + def is_rational(self): + """Say whether this element represents a rational number.""" + return self.col[1:, :].is_zero_matrix + + @property + def generator(self): + """ + Return a :py:class:`~.Symbol` to be used when expressing this element + as a polynomial. + + If we have an associated :py:class:`~.AlgebraicField` whose primitive + element has an alias symbol, we use that. Otherwise we use the variable + of the minimal polynomial defining the power basis to which we belong. + """ + K = self.module.number_field + return K.ext.alias if K and K.ext.is_aliased else self.T.gen + + def as_expr(self, x=None): + """Create a Basic expression from ``self``. """ + return self.poly(x or self.generator).as_expr() + + def norm(self, T=None): + """Compute the norm of this number.""" + T = T or self.T + x = T.gen + A = self.numerator(x=x) + return T.resultant(A) // self.denom ** self.n + + def inverse(self): + f = self.poly() + f_inv = f.invert(self.T) + return self.module.element_from_poly(f_inv) + + def __rfloordiv__(self, a): + return self.inverse() * a + + def _negative_power(self, e, modulo=None): + return self.inverse() ** abs(e) + + def to_ANP(self): + """Convert to an equivalent :py:class:`~.ANP`. """ + return ANP(list(reversed(self.QQ_col.flat())), QQ.map(self.T.rep.to_list()), QQ) + + def to_alg_num(self): + """ + Try to convert to an equivalent :py:class:`~.AlgebraicNumber`. + + Explanation + =========== + + In general, the conversion from an :py:class:`~.AlgebraicNumber` to a + :py:class:`~.PowerBasisElement` throws away information, because an + :py:class:`~.AlgebraicNumber` specifies a complex embedding, while a + :py:class:`~.PowerBasisElement` does not. However, in some cases it is + possible to convert a :py:class:`~.PowerBasisElement` back into an + :py:class:`~.AlgebraicNumber`, namely when the associated + :py:class:`~.PowerBasis` has a reference to an + :py:class:`~.AlgebraicField`. + + Returns + ======= + + :py:class:`~.AlgebraicNumber` + + Raises + ====== + + StructureError + If the :py:class:`~.PowerBasis` to which this element belongs does + not have an associated :py:class:`~.AlgebraicField`. + + """ + K = self.module.number_field + if K: + return K.to_alg_num(self.to_ANP()) + raise StructureError("No associated AlgebraicField") + + +class ModuleHomomorphism: + r"""A homomorphism from one module to another.""" + + def __init__(self, domain, codomain, mapping): + r""" + Parameters + ========== + + domain : :py:class:`~.Module` + The domain of the mapping. + + codomain : :py:class:`~.Module` + The codomain of the mapping. + + mapping : callable + An arbitrary callable is accepted, but should be chosen so as + to represent an actual module homomorphism. In particular, should + accept elements of *domain* and return elements of *codomain*. + + Examples + ======== + + >>> from sympy import Poly, cyclotomic_poly + >>> from sympy.polys.numberfields.modules import PowerBasis, ModuleHomomorphism + >>> T = Poly(cyclotomic_poly(5)) + >>> A = PowerBasis(T) + >>> B = A.submodule_from_gens([2*A(j) for j in range(4)]) + >>> phi = ModuleHomomorphism(A, B, lambda x: 6*x) + >>> print(phi.matrix()) # doctest: +SKIP + DomainMatrix([[3, 0, 0, 0], [0, 3, 0, 0], [0, 0, 3, 0], [0, 0, 0, 3]], (4, 4), ZZ) + + """ + self.domain = domain + self.codomain = codomain + self.mapping = mapping + + def matrix(self, modulus=None): + r""" + Compute the matrix of this homomorphism. + + Parameters + ========== + + modulus : int, optional + A positive prime number $p$ if the matrix should be reduced mod + $p$. + + Returns + ======= + + :py:class:`~.DomainMatrix` + The matrix is over :ref:`ZZ`, or else over :ref:`GF(p)` if a + modulus was given. + + """ + basis = self.domain.basis_elements() + cols = [self.codomain.represent(self.mapping(elt)) for elt in basis] + if not cols: + return DomainMatrix.zeros((self.codomain.n, 0), ZZ).to_dense() + M = cols[0].hstack(*cols[1:]) + if modulus: + M = M.convert_to(FF(modulus)) + return M + + def kernel(self, modulus=None): + r""" + Compute a Submodule representing the kernel of this homomorphism. + + Parameters + ========== + + modulus : int, optional + A positive prime number $p$ if the kernel should be computed mod + $p$. + + Returns + ======= + + :py:class:`~.Submodule` + This submodule's generators span the kernel of this + homomorphism over :ref:`ZZ`, or else over :ref:`GF(p)` if a + modulus was given. + + """ + M = self.matrix(modulus=modulus) + if modulus is None: + M = M.convert_to(QQ) + # Note: Even when working over a finite field, what we want here is + # the pullback into the integers, so in this case the conversion to ZZ + # below is appropriate. When working over ZZ, the kernel should be a + # ZZ-submodule, so, while the conversion to QQ above was required in + # order for the nullspace calculation to work, conversion back to ZZ + # afterward should always work. + # TODO: + # Watch , which calls + # for fraction-free algorithms. If this is implemented, we can skip + # the conversion to `QQ` above. + K = M.nullspace().convert_to(ZZ).transpose() + return self.domain.submodule_from_matrix(K) + + +class ModuleEndomorphism(ModuleHomomorphism): + r"""A homomorphism from one module to itself.""" + + def __init__(self, domain, mapping): + r""" + Parameters + ========== + + domain : :py:class:`~.Module` + The common domain and codomain of the mapping. + + mapping : callable + An arbitrary callable is accepted, but should be chosen so as + to represent an actual module endomorphism. In particular, should + accept and return elements of *domain*. + + """ + super().__init__(domain, domain, mapping) + + +class InnerEndomorphism(ModuleEndomorphism): + r""" + An inner endomorphism on a module, i.e. the endomorphism corresponding to + multiplication by a fixed element. + """ + + def __init__(self, domain, multiplier): + r""" + Parameters + ========== + + domain : :py:class:`~.Module` + The domain and codomain of the endomorphism. + + multiplier : :py:class:`~.ModuleElement` + The element $a$ defining the mapping as $x \mapsto a x$. + + """ + super().__init__(domain, lambda x: multiplier * x) + self.multiplier = multiplier + + +class EndomorphismRing: + r"""The ring of endomorphisms on a module.""" + + def __init__(self, domain): + """ + Parameters + ========== + + domain : :py:class:`~.Module` + The domain and codomain of the endomorphisms. + + """ + self.domain = domain + + def inner_endomorphism(self, multiplier): + r""" + Form an inner endomorphism belonging to this endomorphism ring. + + Parameters + ========== + + multiplier : :py:class:`~.ModuleElement` + Element $a$ defining the inner endomorphism $x \mapsto a x$. + + Returns + ======= + + :py:class:`~.InnerEndomorphism` + + """ + return InnerEndomorphism(self.domain, multiplier) + + def represent(self, element): + r""" + Represent an element of this endomorphism ring, as a single column + vector. + + Explanation + =========== + + Let $M$ be a module, and $E$ its ring of endomorphisms. Let $N$ be + another module, and consider a homomorphism $\varphi: N \rightarrow E$. + In the event that $\varphi$ is to be represented by a matrix $A$, each + column of $A$ must represent an element of $E$. This is possible when + the elements of $E$ are themselves representable as matrices, by + stacking the columns of such a matrix into a single column. + + This method supports calculating such matrices $A$, by representing + an element of this endomorphism ring first as a matrix, and then + stacking that matrix's columns into a single column. + + Examples + ======== + + Note that in these examples we print matrix transposes, to make their + columns easier to inspect. + + >>> from sympy import Poly, cyclotomic_poly + >>> from sympy.polys.numberfields.modules import PowerBasis + >>> from sympy.polys.numberfields.modules import ModuleHomomorphism + >>> T = Poly(cyclotomic_poly(5)) + >>> M = PowerBasis(T) + >>> E = M.endomorphism_ring() + + Let $\zeta$ be a primitive 5th root of unity, a generator of our field, + and consider the inner endomorphism $\tau$ on the ring of integers, + induced by $\zeta$: + + >>> zeta = M(1) + >>> tau = E.inner_endomorphism(zeta) + >>> tau.matrix().transpose() # doctest: +SKIP + DomainMatrix( + [[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], [-1, -1, -1, -1]], + (4, 4), ZZ) + + The matrix representation of $\tau$ is as expected. The first column + shows that multiplying by $\zeta$ carries $1$ to $\zeta$, the second + column that it carries $\zeta$ to $\zeta^2$, and so forth. + + The ``represent`` method of the endomorphism ring ``E`` stacks these + into a single column: + + >>> E.represent(tau).transpose() # doctest: +SKIP + DomainMatrix( + [[0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1]], + (1, 16), ZZ) + + This is useful when we want to consider a homomorphism $\varphi$ having + ``E`` as codomain: + + >>> phi = ModuleHomomorphism(M, E, lambda x: E.inner_endomorphism(x)) + + and we want to compute the matrix of such a homomorphism: + + >>> phi.matrix().transpose() # doctest: +SKIP + DomainMatrix( + [[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], + [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1], + [0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1, 1, 0, 0, 0], + [0, 0, 0, 1, -1, -1, -1, -1, 1, 0, 0, 0, 0, 1, 0, 0]], + (4, 16), ZZ) + + Note that the stacked matrix of $\tau$ occurs as the second column in + this example. This is because $\zeta$ is the second basis element of + ``M``, and $\varphi(\zeta) = \tau$. + + Parameters + ========== + + element : :py:class:`~.ModuleEndomorphism` belonging to this ring. + + Returns + ======= + + :py:class:`~.DomainMatrix` + Column vector equalling the vertical stacking of all the columns + of the matrix that represents the given *element* as a mapping. + + """ + if isinstance(element, ModuleEndomorphism) and element.domain == self.domain: + M = element.matrix() + # Transform the matrix into a single column, which should reproduce + # the original columns, one after another. + m, n = M.shape + if n == 0: + return M + return M[:, 0].vstack(*[M[:, j] for j in range(1, n)]) + raise NotImplementedError + + +def find_min_poly(alpha, domain, x=None, powers=None): + r""" + Find a polynomial of least degree (not necessarily irreducible) satisfied + by an element of a finitely-generated ring with unity. + + Examples + ======== + + For the $n$th cyclotomic field, $n$ an odd prime, consider the quadratic + equation whose roots are the two periods of length $(n-1)/2$. Article 356 + of Gauss tells us that we should get $x^2 + x - (n-1)/4$ or + $x^2 + x + (n+1)/4$ according to whether $n$ is 1 or 3 mod 4, respectively. + + >>> from sympy import Poly, cyclotomic_poly, primitive_root, QQ + >>> from sympy.abc import x + >>> from sympy.polys.numberfields.modules import PowerBasis, find_min_poly + >>> n = 13 + >>> g = primitive_root(n) + >>> C = PowerBasis(Poly(cyclotomic_poly(n, x))) + >>> ee = [g**(2*k+1) % n for k in range((n-1)//2)] + >>> eta = sum(C(e) for e in ee) + >>> print(find_min_poly(eta, QQ, x=x).as_expr()) + x**2 + x - 3 + >>> n = 19 + >>> g = primitive_root(n) + >>> C = PowerBasis(Poly(cyclotomic_poly(n, x))) + >>> ee = [g**(2*k+2) % n for k in range((n-1)//2)] + >>> eta = sum(C(e) for e in ee) + >>> print(find_min_poly(eta, QQ, x=x).as_expr()) + x**2 + x + 5 + + Parameters + ========== + + alpha : :py:class:`~.ModuleElement` + The element whose min poly is to be found, and whose module has + multiplication and starts with unity. + + domain : :py:class:`~.Domain` + The desired domain of the polynomial. + + x : :py:class:`~.Symbol`, optional + The desired variable for the polynomial. + + powers : list, optional + If desired, pass an empty list. The powers of *alpha* (as + :py:class:`~.ModuleElement` instances) from the zeroth up to the degree + of the min poly will be recorded here, as we compute them. + + Returns + ======= + + :py:class:`~.Poly`, ``None`` + The minimal polynomial for alpha, or ``None`` if no polynomial could be + found over the desired domain. + + Raises + ====== + + MissingUnityError + If the module to which alpha belongs does not start with unity. + ClosureFailure + If the module to which alpha belongs is not closed under + multiplication. + + """ + R = alpha.module + if not R.starts_with_unity(): + raise MissingUnityError("alpha must belong to finitely generated ring with unity.") + if powers is None: + powers = [] + one = R(0) + powers.append(one) + powers_matrix = one.column(domain=domain) + ak = alpha + m = None + for k in range(1, R.n + 1): + powers.append(ak) + ak_col = ak.column(domain=domain) + try: + X = powers_matrix._solve(ak_col)[0] + except DMBadInputError: + # This means alpha^k still isn't in the domain-span of the lower powers. + powers_matrix = powers_matrix.hstack(ak_col) + ak *= alpha + else: + # alpha^k is in the domain-span of the lower powers, so we have found a + # minimal-degree poly for alpha. + coeffs = [1] + [-c for c in reversed(X.to_list_flat())] + x = x or Dummy('x') + if domain.is_FF: + m = Poly(coeffs, x, modulus=domain.mod) + else: + m = Poly(coeffs, x, domain=domain) + break + return m diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/primes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/primes.py new file mode 100644 index 0000000000000000000000000000000000000000..8f28f13d94f33ed59cded8eabd05e9cf7d0f103f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/primes.py @@ -0,0 +1,784 @@ +"""Prime ideals in number fields. """ + +from sympy.polys.polytools import Poly +from sympy.polys.domains.finitefield import FF +from sympy.polys.domains.rationalfield import QQ +from sympy.polys.domains.integerring import ZZ +from sympy.polys.matrices.domainmatrix import DomainMatrix +from sympy.polys.polyerrors import CoercionFailed +from sympy.polys.polyutils import IntegerPowerable +from sympy.utilities.decorator import public +from .basis import round_two, nilradical_mod_p +from .exceptions import StructureError +from .modules import ModuleEndomorphism, find_min_poly +from .utilities import coeff_search, supplement_a_subspace + + +def _check_formal_conditions_for_maximal_order(submodule): + r""" + Several functions in this module accept an argument which is to be a + :py:class:`~.Submodule` representing the maximal order in a number field, + such as returned by the :py:func:`~sympy.polys.numberfields.basis.round_two` + algorithm. + + We do not attempt to check that the given ``Submodule`` actually represents + a maximal order, but we do check a basic set of formal conditions that the + ``Submodule`` must satisfy, at a minimum. The purpose is to catch an + obviously ill-formed argument. + """ + prefix = 'The submodule representing the maximal order should ' + cond = None + if not submodule.is_power_basis_submodule(): + cond = 'be a direct submodule of a power basis.' + elif not submodule.starts_with_unity(): + cond = 'have 1 as its first generator.' + elif not submodule.is_sq_maxrank_HNF(): + cond = 'have square matrix, of maximal rank, in Hermite Normal Form.' + if cond is not None: + raise StructureError(prefix + cond) + + +class PrimeIdeal(IntegerPowerable): + r""" + A prime ideal in a ring of algebraic integers. + """ + + def __init__(self, ZK, p, alpha, f, e=None): + """ + Parameters + ========== + + ZK : :py:class:`~.Submodule` + The maximal order where this ideal lives. + p : int + The rational prime this ideal divides. + alpha : :py:class:`~.PowerBasisElement` + Such that the ideal is equal to ``p*ZK + alpha*ZK``. + f : int + The inertia degree. + e : int, ``None``, optional + The ramification index, if already known. If ``None``, we will + compute it here. + + """ + _check_formal_conditions_for_maximal_order(ZK) + self.ZK = ZK + self.p = p + self.alpha = alpha + self.f = f + self._test_factor = None + self.e = e if e is not None else self.valuation(p * ZK) + + def __str__(self): + if self.is_inert: + return f'({self.p})' + return f'({self.p}, {self.alpha.as_expr()})' + + @property + def is_inert(self): + """ + Say whether the rational prime we divide is inert, i.e. stays prime in + our ring of integers. + """ + return self.f == self.ZK.n + + def repr(self, field_gen=None, just_gens=False): + """ + Print a representation of this prime ideal. + + Examples + ======== + + >>> from sympy import cyclotomic_poly, QQ + >>> from sympy.abc import x, zeta + >>> T = cyclotomic_poly(7, x) + >>> K = QQ.algebraic_field((T, zeta)) + >>> P = K.primes_above(11) + >>> print(P[0].repr()) + [ (11, x**3 + 5*x**2 + 4*x - 1) e=1, f=3 ] + >>> print(P[0].repr(field_gen=zeta)) + [ (11, zeta**3 + 5*zeta**2 + 4*zeta - 1) e=1, f=3 ] + >>> print(P[0].repr(field_gen=zeta, just_gens=True)) + (11, zeta**3 + 5*zeta**2 + 4*zeta - 1) + + Parameters + ========== + + field_gen : :py:class:`~.Symbol`, ``None``, optional (default=None) + The symbol to use for the generator of the field. This will appear + in our representation of ``self.alpha``. If ``None``, we use the + variable of the defining polynomial of ``self.ZK``. + just_gens : bool, optional (default=False) + If ``True``, just print the "(p, alpha)" part, showing "just the + generators" of the prime ideal. Otherwise, print a string of the + form "[ (p, alpha) e=..., f=... ]", giving the ramification index + and inertia degree, along with the generators. + + """ + field_gen = field_gen or self.ZK.parent.T.gen + p, alpha, e, f = self.p, self.alpha, self.e, self.f + alpha_rep = str(alpha.numerator(x=field_gen).as_expr()) + if alpha.denom > 1: + alpha_rep = f'({alpha_rep})/{alpha.denom}' + gens = f'({p}, {alpha_rep})' + if just_gens: + return gens + return f'[ {gens} e={e}, f={f} ]' + + def __repr__(self): + return self.repr() + + def as_submodule(self): + r""" + Represent this prime ideal as a :py:class:`~.Submodule`. + + Explanation + =========== + + The :py:class:`~.PrimeIdeal` class serves to bundle information about + a prime ideal, such as its inertia degree, ramification index, and + two-generator representation, as well as to offer helpful methods like + :py:meth:`~.PrimeIdeal.valuation` and + :py:meth:`~.PrimeIdeal.test_factor`. + + However, in order to be added and multiplied by other ideals or + rational numbers, it must first be converted into a + :py:class:`~.Submodule`, which is a class that supports these + operations. + + In many cases, the user need not perform this conversion deliberately, + since it is automatically performed by the arithmetic operator methods + :py:meth:`~.PrimeIdeal.__add__` and :py:meth:`~.PrimeIdeal.__mul__`. + + Raising a :py:class:`~.PrimeIdeal` to a non-negative integer power is + also supported. + + Examples + ======== + + >>> from sympy import Poly, cyclotomic_poly, prime_decomp + >>> T = Poly(cyclotomic_poly(7)) + >>> P0 = prime_decomp(7, T)[0] + >>> print(P0**6 == 7*P0.ZK) + True + + Note that, on both sides of the equation above, we had a + :py:class:`~.Submodule`. In the next equation we recall that adding + ideals yields their GCD. This time, we need a deliberate conversion + to :py:class:`~.Submodule` on the right: + + >>> print(P0 + 7*P0.ZK == P0.as_submodule()) + True + + Returns + ======= + + :py:class:`~.Submodule` + Will be equal to ``self.p * self.ZK + self.alpha * self.ZK``. + + See Also + ======== + + __add__ + __mul__ + + """ + M = self.p * self.ZK + self.alpha * self.ZK + # Pre-set expensive boolean properties whose value we already know: + M._starts_with_unity = False + M._is_sq_maxrank_HNF = True + return M + + def __eq__(self, other): + if isinstance(other, PrimeIdeal): + return self.as_submodule() == other.as_submodule() + return NotImplemented + + def __add__(self, other): + """ + Convert to a :py:class:`~.Submodule` and add to another + :py:class:`~.Submodule`. + + See Also + ======== + + as_submodule + + """ + return self.as_submodule() + other + + __radd__ = __add__ + + def __mul__(self, other): + """ + Convert to a :py:class:`~.Submodule` and multiply by another + :py:class:`~.Submodule` or a rational number. + + See Also + ======== + + as_submodule + + """ + return self.as_submodule() * other + + __rmul__ = __mul__ + + def _zeroth_power(self): + return self.ZK + + def _first_power(self): + return self + + def test_factor(self): + r""" + Compute a test factor for this prime ideal. + + Explanation + =========== + + Write $\mathfrak{p}$ for this prime ideal, $p$ for the rational prime + it divides. Then, for computing $\mathfrak{p}$-adic valuations it is + useful to have a number $\beta \in \mathbb{Z}_K$ such that + $p/\mathfrak{p} = p \mathbb{Z}_K + \beta \mathbb{Z}_K$. + + Essentially, this is the same as the number $\Psi$ (or the "reagent") + from Kummer's 1847 paper (*Ueber die Zerlegung...*, Crelle vol. 35) in + which ideal divisors were invented. + """ + if self._test_factor is None: + self._test_factor = _compute_test_factor(self.p, [self.alpha], self.ZK) + return self._test_factor + + def valuation(self, I): + r""" + Compute the $\mathfrak{p}$-adic valuation of integral ideal I at this + prime ideal. + + Parameters + ========== + + I : :py:class:`~.Submodule` + + See Also + ======== + + prime_valuation + + """ + return prime_valuation(I, self) + + def reduce_element(self, elt): + """ + Reduce a :py:class:`~.PowerBasisElement` to a "small representative" + modulo this prime ideal. + + Parameters + ========== + + elt : :py:class:`~.PowerBasisElement` + The element to be reduced. + + Returns + ======= + + :py:class:`~.PowerBasisElement` + The reduced element. + + See Also + ======== + + reduce_ANP + reduce_alg_num + .Submodule.reduce_element + + """ + return self.as_submodule().reduce_element(elt) + + def reduce_ANP(self, a): + """ + Reduce an :py:class:`~.ANP` to a "small representative" modulo this + prime ideal. + + Parameters + ========== + + elt : :py:class:`~.ANP` + The element to be reduced. + + Returns + ======= + + :py:class:`~.ANP` + The reduced element. + + See Also + ======== + + reduce_element + reduce_alg_num + .Submodule.reduce_element + + """ + elt = self.ZK.parent.element_from_ANP(a) + red = self.reduce_element(elt) + return red.to_ANP() + + def reduce_alg_num(self, a): + """ + Reduce an :py:class:`~.AlgebraicNumber` to a "small representative" + modulo this prime ideal. + + Parameters + ========== + + elt : :py:class:`~.AlgebraicNumber` + The element to be reduced. + + Returns + ======= + + :py:class:`~.AlgebraicNumber` + The reduced element. + + See Also + ======== + + reduce_element + reduce_ANP + .Submodule.reduce_element + + """ + elt = self.ZK.parent.element_from_alg_num(a) + red = self.reduce_element(elt) + return a.field_element(list(reversed(red.QQ_col.flat()))) + + +def _compute_test_factor(p, gens, ZK): + r""" + Compute the test factor for a :py:class:`~.PrimeIdeal` $\mathfrak{p}$. + + Parameters + ========== + + p : int + The rational prime $\mathfrak{p}$ divides + + gens : list of :py:class:`PowerBasisElement` + A complete set of generators for $\mathfrak{p}$ over *ZK*, EXCEPT that + an element equivalent to rational *p* can and should be omitted (since + it has no effect except to waste time). + + ZK : :py:class:`~.Submodule` + The maximal order where the prime ideal $\mathfrak{p}$ lives. + + Returns + ======= + + :py:class:`~.PowerBasisElement` + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* + (See Proposition 4.8.15.) + + """ + _check_formal_conditions_for_maximal_order(ZK) + E = ZK.endomorphism_ring() + matrices = [E.inner_endomorphism(g).matrix(modulus=p) for g in gens] + B = DomainMatrix.zeros((0, ZK.n), FF(p)).vstack(*matrices) + # A nonzero element of the nullspace of B will represent a + # lin comb over the omegas which (i) is not a multiple of p + # (since it is nonzero over FF(p)), while (ii) is such that + # its product with each g in gens _is_ a multiple of p (since + # B represents multiplication by these generators). Theory + # predicts that such an element must exist, so nullspace should + # be non-trivial. + x = B.nullspace()[0, :].transpose() + beta = ZK.parent(ZK.matrix * x.convert_to(ZZ), denom=ZK.denom) + return beta + + +@public +def prime_valuation(I, P): + r""" + Compute the *P*-adic valuation for an integral ideal *I*. + + Examples + ======== + + >>> from sympy import QQ + >>> from sympy.polys.numberfields import prime_valuation + >>> K = QQ.cyclotomic_field(5) + >>> P = K.primes_above(5) + >>> ZK = K.maximal_order() + >>> print(prime_valuation(25*ZK, P[0])) + 8 + + Parameters + ========== + + I : :py:class:`~.Submodule` + An integral ideal whose valuation is desired. + + P : :py:class:`~.PrimeIdeal` + The prime at which to compute the valuation. + + Returns + ======= + + int + + See Also + ======== + + .PrimeIdeal.valuation + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* + (See Algorithm 4.8.17.) + + """ + p, ZK = P.p, P.ZK + n, W, d = ZK.n, ZK.matrix, ZK.denom + + A = W.convert_to(QQ).inv() * I.matrix * d / I.denom + # Although A must have integer entries, given that I is an integral ideal, + # as a DomainMatrix it will still be over QQ, so we convert back: + A = A.convert_to(ZZ) + D = A.det() + if D % p != 0: + return 0 + + beta = P.test_factor() + + f = d ** n // W.det() + need_complete_test = (f % p == 0) + v = 0 + while True: + # Entering the loop, the cols of A represent lin combs of omegas. + # Turn them into lin combs of thetas: + A = W * A + # And then one column at a time... + for j in range(n): + c = ZK.parent(A[:, j], denom=d) + c *= beta + # ...turn back into lin combs of omegas, after multiplying by beta: + c = ZK.represent(c).flat() + for i in range(n): + A[i, j] = c[i] + if A[n - 1, n - 1].element % p != 0: + break + A = A / p + # As noted above, domain converts to QQ even when division goes evenly. + # So must convert back, even when we don't "need_complete_test". + if need_complete_test: + # In this case, having a non-integer entry is actually just our + # halting condition. + try: + A = A.convert_to(ZZ) + except CoercionFailed: + break + else: + # In this case theory says we should not have any non-integer entries. + A = A.convert_to(ZZ) + v += 1 + return v + + +def _two_elt_rep(gens, ZK, p, f=None, Np=None): + r""" + Given a set of *ZK*-generators of a prime ideal, compute a set of just two + *ZK*-generators for the same ideal, one of which is *p* itself. + + Parameters + ========== + + gens : list of :py:class:`PowerBasisElement` + Generators for the prime ideal over *ZK*, the ring of integers of the + field $K$. + + ZK : :py:class:`~.Submodule` + The maximal order in $K$. + + p : int + The rational prime divided by the prime ideal. + + f : int, optional + The inertia degree of the prime ideal, if known. + + Np : int, optional + The norm $p^f$ of the prime ideal, if known. + NOTE: There is no reason to supply both *f* and *Np*. Either one will + save us from having to compute the norm *Np* ourselves. If both are known, + *Np* is preferred since it saves one exponentiation. + + Returns + ======= + + :py:class:`~.PowerBasisElement` representing a single algebraic integer + alpha such that the prime ideal is equal to ``p*ZK + alpha*ZK``. + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* + (See Algorithm 4.7.10.) + + """ + _check_formal_conditions_for_maximal_order(ZK) + pb = ZK.parent + T = pb.T + # Detect the special cases in which either (a) all generators are multiples + # of p, or (b) there are no generators (so `all` is vacuously true): + if all((g % p).equiv(0) for g in gens): + return pb.zero() + + if Np is None: + if f is not None: + Np = p**f + else: + Np = abs(pb.submodule_from_gens(gens).matrix.det()) + + omega = ZK.basis_element_pullbacks() + beta = [p*om for om in omega[1:]] # note: we omit omega[0] == 1 + beta += gens + search = coeff_search(len(beta), 1) + for c in search: + alpha = sum(ci*betai for ci, betai in zip(c, beta)) + # Note: It may be tempting to reduce alpha mod p here, to try to work + # with smaller numbers, but must not do that, as it can result in an + # infinite loop! E.g. try factoring 2 in Q(sqrt(-7)). + n = alpha.norm(T) // Np + if n % p != 0: + # Now can reduce alpha mod p. + return alpha % p + + +def _prime_decomp_easy_case(p, ZK): + r""" + Compute the decomposition of rational prime *p* in the ring of integers + *ZK* (given as a :py:class:`~.Submodule`), in the "easy case", i.e. the + case where *p* does not divide the index of $\theta$ in *ZK*, where + $\theta$ is the generator of the ``PowerBasis`` of which *ZK* is a + ``Submodule``. + """ + T = ZK.parent.T + T_bar = Poly(T, modulus=p) + lc, fl = T_bar.factor_list() + if len(fl) == 1 and fl[0][1] == 1: + return [PrimeIdeal(ZK, p, ZK.parent.zero(), ZK.n, 1)] + return [PrimeIdeal(ZK, p, + ZK.parent.element_from_poly(Poly(t, domain=ZZ)), + t.degree(), e) + for t, e in fl] + + +def _prime_decomp_compute_kernel(I, p, ZK): + r""" + Parameters + ========== + + I : :py:class:`~.Module` + An ideal of ``ZK/pZK``. + p : int + The rational prime being factored. + ZK : :py:class:`~.Submodule` + The maximal order. + + Returns + ======= + + Pair ``(N, G)``, where: + + ``N`` is a :py:class:`~.Module` representing the kernel of the map + ``a |--> a**p - a`` on ``(O/pO)/I``, guaranteed to be a module with + unity. + + ``G`` is a :py:class:`~.Module` representing a basis for the separable + algebra ``A = O/I`` (see Cohen). + + """ + W = I.matrix + n, r = W.shape + # Want to take the Fp-basis given by the columns of I, adjoin (1, 0, ..., 0) + # (which we know is not already in there since I is a basis for a prime ideal) + # and then supplement this with additional columns to make an invertible n x n + # matrix. This will then represent a full basis for ZK, whose first r columns + # are pullbacks of the basis for I. + if r == 0: + B = W.eye(n, ZZ) + else: + B = W.hstack(W.eye(n, ZZ)[:, 0]) + if B.shape[1] < n: + B = supplement_a_subspace(B.convert_to(FF(p))).convert_to(ZZ) + + G = ZK.submodule_from_matrix(B) + # Must compute G's multiplication table _before_ discarding the first r + # columns. (See Step 9 in Alg 6.2.9 in Cohen, where the betas are actually + # needed in order to represent each product of gammas. However, once we've + # found the representations, then we can ignore the betas.) + G.compute_mult_tab() + G = G.discard_before(r) + + phi = ModuleEndomorphism(G, lambda x: x**p - x) + N = phi.kernel(modulus=p) + assert N.starts_with_unity() + return N, G + + +def _prime_decomp_maximal_ideal(I, p, ZK): + r""" + We have reached the case where we have a maximal (hence prime) ideal *I*, + which we know because the quotient ``O/I`` is a field. + + Parameters + ========== + + I : :py:class:`~.Module` + An ideal of ``O/pO``. + p : int + The rational prime being factored. + ZK : :py:class:`~.Submodule` + The maximal order. + + Returns + ======= + + :py:class:`~.PrimeIdeal` instance representing this prime + + """ + m, n = I.matrix.shape + f = m - n + G = ZK.matrix * I.matrix + gens = [ZK.parent(G[:, j], denom=ZK.denom) for j in range(G.shape[1])] + alpha = _two_elt_rep(gens, ZK, p, f=f) + return PrimeIdeal(ZK, p, alpha, f) + + +def _prime_decomp_split_ideal(I, p, N, G, ZK): + r""" + Perform the step in the prime decomposition algorithm where we have determined + the quotient ``ZK/I`` is _not_ a field, and we want to perform a non-trivial + factorization of *I* by locating an idempotent element of ``ZK/I``. + """ + assert I.parent == ZK and G.parent is ZK and N.parent is G + # Since ZK/I is not a field, the kernel computed in the previous step contains + # more than just the prime field Fp, and our basis N for the nullspace therefore + # contains at least a second column (which represents an element outside Fp). + # Let alpha be such an element: + alpha = N(1).to_parent() + assert alpha.module is G + + alpha_powers = [] + m = find_min_poly(alpha, FF(p), powers=alpha_powers) + # TODO (future work): + # We don't actually need full factorization, so might use a faster method + # to just break off a single non-constant factor m1? + lc, fl = m.factor_list() + m1 = fl[0][0] + m2 = m.quo(m1) + U, V, g = m1.gcdex(m2) + # Sanity check: theory says m is squarefree, so m1, m2 should be coprime: + assert g == 1 + E = list(reversed(Poly(U * m1, domain=ZZ).rep.to_list())) + eps1 = sum(E[i]*alpha_powers[i] for i in range(len(E))) + eps2 = 1 - eps1 + idemps = [eps1, eps2] + factors = [] + for eps in idemps: + e = eps.to_parent() + assert e.module is ZK + D = I.matrix.convert_to(FF(p)).hstack(*[ + (e * om).column(domain=FF(p)) for om in ZK.basis_elements() + ]) + W = D.columnspace().convert_to(ZZ) + H = ZK.submodule_from_matrix(W) + factors.append(H) + return factors + + +@public +def prime_decomp(p, T=None, ZK=None, dK=None, radical=None): + r""" + Compute the decomposition of rational prime *p* in a number field. + + Explanation + =========== + + Ordinarily this should be accessed through the + :py:meth:`~.AlgebraicField.primes_above` method of an + :py:class:`~.AlgebraicField`. + + Examples + ======== + + >>> from sympy import Poly, QQ + >>> from sympy.abc import x, theta + >>> T = Poly(x ** 3 + x ** 2 - 2 * x + 8) + >>> K = QQ.algebraic_field((T, theta)) + >>> print(K.primes_above(2)) + [[ (2, x**2 + 1) e=1, f=1 ], [ (2, (x**2 + 3*x + 2)/2) e=1, f=1 ], + [ (2, (3*x**2 + 3*x)/2) e=1, f=1 ]] + + Parameters + ========== + + p : int + The rational prime whose decomposition is desired. + + T : :py:class:`~.Poly`, optional + Monic irreducible polynomial defining the number field $K$ in which to + factor. NOTE: at least one of *T* or *ZK* must be provided. + + ZK : :py:class:`~.Submodule`, optional + The maximal order for $K$, if already known. + NOTE: at least one of *T* or *ZK* must be provided. + + dK : int, optional + The discriminant of the field $K$, if already known. + + radical : :py:class:`~.Submodule`, optional + The nilradical mod *p* in the integers of $K$, if already known. + + Returns + ======= + + List of :py:class:`~.PrimeIdeal` instances. + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* + (See Algorithm 6.2.9.) + + """ + if T is None and ZK is None: + raise ValueError('At least one of T or ZK must be provided.') + if ZK is not None: + _check_formal_conditions_for_maximal_order(ZK) + if T is None: + T = ZK.parent.T + radicals = {} + if dK is None or ZK is None: + ZK, dK = round_two(T, radicals=radicals) + dT = T.discriminant() + f_squared = dT // dK + if f_squared % p != 0: + return _prime_decomp_easy_case(p, ZK) + radical = radical or radicals.get(p) or nilradical_mod_p(ZK, p) + stack = [radical] + primes = [] + while stack: + I = stack.pop() + N, G = _prime_decomp_compute_kernel(I, p, ZK) + if N.n == 1: + P = _prime_decomp_maximal_ideal(I, p, ZK) + primes.append(P) + else: + I1, I2 = _prime_decomp_split_ideal(I, p, N, G, ZK) + stack.extend([I1, I2]) + return primes diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/resolvent_lookup.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/resolvent_lookup.py new file mode 100644 index 0000000000000000000000000000000000000000..71812c0d7aec6501039eefe4f3602b1916628071 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/resolvent_lookup.py @@ -0,0 +1,456 @@ +"""Lookup table for Galois resolvents for polys of degree 4 through 6. """ +# This table was generated by a call to +# `sympy.polys.numberfields.galois_resolvents.generate_lambda_lookup()`. +# The entire job took 543.23s. +# Of this, Case (6, 1) took 539.03s. +# The final polynomial of Case (6, 1) alone took 455.09s. +resolvent_coeff_lambdas = { + (4, 0): [ + lambda s1, s2, s3, s4: (-2*s1*s2 + 6*s3), + lambda s1, s2, s3, s4: (2*s1**3*s3 + s1**2*s2**2 + s1**2*s4 - 17*s1*s2*s3 + 2*s2**3 - 8*s2*s4 + 24*s3**2), + lambda s1, s2, s3, s4: (-2*s1**5*s4 - 2*s1**4*s2*s3 + 10*s1**3*s2*s4 + 8*s1**3*s3**2 + 10*s1**2*s2**2*s3 - +12*s1**2*s3*s4 - 2*s1*s2**4 - 54*s1*s2*s3**2 + 32*s1*s4**2 + 8*s2**3*s3 - 32*s2*s3*s4 ++ 56*s3**3), + lambda s1, s2, s3, s4: (2*s1**6*s2*s4 + s1**6*s3**2 - 5*s1**5*s3*s4 - 11*s1**4*s2**2*s4 - 13*s1**4*s2*s3**2 ++ 7*s1**4*s4**2 + 3*s1**3*s2**3*s3 + 30*s1**3*s2*s3*s4 + 22*s1**3*s3**3 + 10*s1**2*s2**3*s4 ++ 33*s1**2*s2**2*s3**2 - 72*s1**2*s2*s4**2 - 36*s1**2*s3**2*s4 - 13*s1*s2**4*s3 + +48*s1*s2**2*s3*s4 - 116*s1*s2*s3**3 + 144*s1*s3*s4**2 + s2**6 - 12*s2**4*s4 + 22*s2**3*s3**2 ++ 48*s2**2*s4**2 - 120*s2*s3**2*s4 + 96*s3**4 - 64*s4**3), + lambda s1, s2, s3, s4: (-2*s1**8*s3*s4 - s1**7*s4**2 + 22*s1**6*s2*s3*s4 + 2*s1**6*s3**3 - 2*s1**5*s2**3*s4 +- s1**5*s2**2*s3**2 - 29*s1**5*s3**2*s4 - 60*s1**4*s2**2*s3*s4 - 19*s1**4*s2*s3**3 ++ 38*s1**4*s3*s4**2 + 9*s1**3*s2**4*s4 + 10*s1**3*s2**3*s3**2 + 24*s1**3*s2**2*s4**2 ++ 134*s1**3*s2*s3**2*s4 + 28*s1**3*s3**4 + 16*s1**3*s4**3 - s1**2*s2**5*s3 - 4*s1**2*s2**3*s3*s4 ++ 34*s1**2*s2**2*s3**3 - 288*s1**2*s2*s3*s4**2 - 104*s1**2*s3**3*s4 - 19*s1*s2**4*s3**2 ++ 120*s1*s2**2*s3**2*s4 - 128*s1*s2*s3**4 + 336*s1*s3**2*s4**2 + 2*s2**6*s3 - 24*s2**4*s3*s4 ++ 28*s2**3*s3**3 + 96*s2**2*s3*s4**2 - 176*s2*s3**3*s4 + 96*s3**5 - 128*s3*s4**3), + lambda s1, s2, s3, s4: (s1**10*s4**2 - 11*s1**8*s2*s4**2 - 2*s1**8*s3**2*s4 + s1**7*s2**2*s3*s4 + 15*s1**7*s3*s4**2 ++ 45*s1**6*s2**2*s4**2 + 17*s1**6*s2*s3**2*s4 + s1**6*s3**4 - 5*s1**6*s4**3 - 12*s1**5*s2**3*s3*s4 +- 133*s1**5*s2*s3*s4**2 - 22*s1**5*s3**3*s4 + s1**4*s2**5*s4 - 76*s1**4*s2**3*s4**2 +- 6*s1**4*s2**2*s3**2*s4 - 12*s1**4*s2*s3**4 + 32*s1**4*s2*s4**3 + 128*s1**4*s3**2*s4**2 ++ 29*s1**3*s2**4*s3*s4 + 2*s1**3*s2**3*s3**3 + 344*s1**3*s2**2*s3*s4**2 + 48*s1**3*s2*s3**3*s4 ++ 16*s1**3*s3**5 - 48*s1**3*s3*s4**3 - 4*s1**2*s2**6*s4 + 32*s1**2*s2**4*s4**2 - 134*s1**2*s2**3*s3**2*s4 ++ 36*s1**2*s2**2*s3**4 - 64*s1**2*s2**2*s4**3 - 648*s1**2*s2*s3**2*s4**2 - 48*s1**2*s3**4*s4 ++ 16*s1*s2**5*s3*s4 - 12*s1*s2**4*s3**3 - 128*s1*s2**3*s3*s4**2 + 296*s1*s2**2*s3**3*s4 +- 96*s1*s2*s3**5 + 256*s1*s2*s3*s4**3 + 416*s1*s3**3*s4**2 + s2**6*s3**2 - 28*s2**4*s3**2*s4 ++ 16*s2**3*s3**4 + 176*s2**2*s3**2*s4**2 - 224*s2*s3**4*s4 + 64*s3**6 - 320*s3**2*s4**3) + ], + (4, 1): [ + lambda s1, s2, s3, s4: (-s2), + lambda s1, s2, s3, s4: (s1*s3 - 4*s4), + lambda s1, s2, s3, s4: (-s1**2*s4 + 4*s2*s4 - s3**2) + ], + (5, 1): [ + lambda s1, s2, s3, s4, s5: (-2*s1*s3 + 8*s4), + lambda s1, s2, s3, s4, s5: (-8*s1**3*s5 + 2*s1**2*s2*s4 + s1**2*s3**2 + 30*s1*s2*s5 - 14*s1*s3*s4 - 6*s2**2*s4 ++ 2*s2*s3**2 - 50*s3*s5 + 40*s4**2), + lambda s1, s2, s3, s4, s5: (16*s1**4*s3*s5 - 2*s1**4*s4**2 - 2*s1**3*s2**2*s5 - 2*s1**3*s2*s3*s4 - 44*s1**3*s4*s5 +- 66*s1**2*s2*s3*s5 + 21*s1**2*s2*s4**2 + 6*s1**2*s3**2*s4 - 50*s1**2*s5**2 + 9*s1*s2**3*s5 ++ 5*s1*s2**2*s3*s4 - 2*s1*s2*s3**3 + 190*s1*s2*s4*s5 + 120*s1*s3**2*s5 - 80*s1*s3*s4**2 +- 15*s2**2*s3*s5 - 40*s2**2*s4**2 + 21*s2*s3**2*s4 + 125*s2*s5**2 - 2*s3**4 - 400*s3*s4*s5 ++ 160*s4**3), + lambda s1, s2, s3, s4, s5: (16*s1**6*s5**2 - 8*s1**5*s2*s4*s5 - 8*s1**5*s3**2*s5 + 2*s1**5*s3*s4**2 + 2*s1**4*s2**2*s3*s5 ++ s1**4*s2**2*s4**2 - 120*s1**4*s2*s5**2 + 68*s1**4*s3*s4*s5 - 8*s1**4*s4**3 + 46*s1**3*s2**2*s4*s5 ++ 28*s1**3*s2*s3**2*s5 - 19*s1**3*s2*s3*s4**2 + 250*s1**3*s3*s5**2 - 144*s1**3*s4**2*s5 +- 9*s1**2*s2**3*s3*s5 - 6*s1**2*s2**3*s4**2 + 3*s1**2*s2**2*s3**2*s4 + 225*s1**2*s2**2*s5**2 +- 354*s1**2*s2*s3*s4*s5 + 76*s1**2*s2*s4**3 - 70*s1**2*s3**3*s5 + 41*s1**2*s3**2*s4**2 +- 200*s1**2*s4*s5**2 - 54*s1*s2**3*s4*s5 + 45*s1*s2**2*s3**2*s5 + 30*s1*s2**2*s3*s4**2 +- 19*s1*s2*s3**3*s4 - 875*s1*s2*s3*s5**2 + 640*s1*s2*s4**2*s5 + 2*s1*s3**5 + 630*s1*s3**2*s4*s5 +- 264*s1*s3*s4**3 + 9*s2**4*s4**2 - 6*s2**3*s3**2*s4 + s2**2*s3**4 + 90*s2**2*s3*s4*s5 +- 136*s2**2*s4**3 - 50*s2*s3**3*s5 + 76*s2*s3**2*s4**2 + 500*s2*s4*s5**2 - 8*s3**4*s4 ++ 625*s3**2*s5**2 - 1400*s3*s4**2*s5 + 400*s4**4), + lambda s1, s2, s3, s4, s5: (-32*s1**7*s3*s5**2 + 8*s1**7*s4**2*s5 + 8*s1**6*s2**2*s5**2 + 8*s1**6*s2*s3*s4*s5 +- 2*s1**6*s2*s4**3 + 48*s1**6*s4*s5**2 - 2*s1**5*s2**3*s4*s5 + 264*s1**5*s2*s3*s5**2 +- 94*s1**5*s2*s4**2*s5 - 24*s1**5*s3**2*s4*s5 + 6*s1**5*s3*s4**3 - 56*s1**5*s5**3 +- 66*s1**4*s2**3*s5**2 - 50*s1**4*s2**2*s3*s4*s5 + 19*s1**4*s2**2*s4**3 + 8*s1**4*s2*s3**3*s5 +- 2*s1**4*s2*s3**2*s4**2 - 318*s1**4*s2*s4*s5**2 - 352*s1**4*s3**2*s5**2 + 166*s1**4*s3*s4**2*s5 ++ 3*s1**4*s4**4 + 15*s1**3*s2**4*s4*s5 - 2*s1**3*s2**3*s3**2*s5 - s1**3*s2**3*s3*s4**2 +- 574*s1**3*s2**2*s3*s5**2 + 347*s1**3*s2**2*s4**2*s5 + 194*s1**3*s2*s3**2*s4*s5 - +89*s1**3*s2*s3*s4**3 + 350*s1**3*s2*s5**3 - 8*s1**3*s3**4*s5 + 4*s1**3*s3**3*s4**2 ++ 1090*s1**3*s3*s4*s5**2 - 364*s1**3*s4**3*s5 + 162*s1**2*s2**4*s5**2 + 33*s1**2*s2**3*s3*s4*s5 +- 51*s1**2*s2**3*s4**3 - 32*s1**2*s2**2*s3**3*s5 + 28*s1**2*s2**2*s3**2*s4**2 + 305*s1**2*s2**2*s4*s5**2 +- 2*s1**2*s2*s3**4*s4 + 1340*s1**2*s2*s3**2*s5**2 - 901*s1**2*s2*s3*s4**2*s5 + 76*s1**2*s2*s4**4 +- 234*s1**2*s3**3*s4*s5 + 102*s1**2*s3**2*s4**3 - 750*s1**2*s3*s5**3 - 550*s1**2*s4**2*s5**2 +- 27*s1*s2**5*s4*s5 + 9*s1*s2**4*s3**2*s5 + 3*s1*s2**4*s3*s4**2 - s1*s2**3*s3**3*s4 ++ 180*s1*s2**3*s3*s5**2 - 366*s1*s2**3*s4**2*s5 - 231*s1*s2**2*s3**2*s4*s5 + 212*s1*s2**2*s3*s4**3 +- 375*s1*s2**2*s5**3 + 112*s1*s2*s3**4*s5 - 89*s1*s2*s3**3*s4**2 - 3075*s1*s2*s3*s4*s5**2 ++ 1640*s1*s2*s4**3*s5 + 6*s1*s3**5*s4 - 850*s1*s3**3*s5**2 + 1220*s1*s3**2*s4**2*s5 +- 384*s1*s3*s4**4 + 2500*s1*s4*s5**3 - 108*s2**5*s5**2 + 117*s2**4*s3*s4*s5 + 32*s2**4*s4**3 +- 31*s2**3*s3**3*s5 - 51*s2**3*s3**2*s4**2 + 525*s2**3*s4*s5**2 + 19*s2**2*s3**4*s4 +- 325*s2**2*s3**2*s5**2 + 260*s2**2*s3*s4**2*s5 - 256*s2**2*s4**4 - 2*s2*s3**6 + 105*s2*s3**3*s4*s5 ++ 76*s2*s3**2*s4**3 + 625*s2*s3*s5**3 - 500*s2*s4**2*s5**2 - 58*s3**5*s5 + 3*s3**4*s4**2 ++ 2750*s3**2*s4*s5**2 - 2400*s3*s4**3*s5 + 512*s4**5 - 3125*s5**4), + lambda s1, s2, s3, s4, s5: (16*s1**8*s3**2*s5**2 - 8*s1**8*s3*s4**2*s5 + s1**8*s4**4 - 8*s1**7*s2**2*s3*s5**2 ++ 2*s1**7*s2**2*s4**2*s5 - 48*s1**7*s3*s4*s5**2 + 12*s1**7*s4**3*s5 + s1**6*s2**4*s5**2 ++ 12*s1**6*s2**2*s4*s5**2 - 144*s1**6*s2*s3**2*s5**2 + 88*s1**6*s2*s3*s4**2*s5 - 13*s1**6*s2*s4**4 ++ 56*s1**6*s3*s5**3 + 86*s1**6*s4**2*s5**2 + 72*s1**5*s2**3*s3*s5**2 - 22*s1**5*s2**3*s4**2*s5 +- 4*s1**5*s2**2*s3**2*s4*s5 + s1**5*s2**2*s3*s4**3 - 14*s1**5*s2**2*s5**3 + 304*s1**5*s2*s3*s4*s5**2 +- 148*s1**5*s2*s4**3*s5 + 152*s1**5*s3**3*s5**2 - 54*s1**5*s3**2*s4**2*s5 + 5*s1**5*s3*s4**4 +- 468*s1**5*s4*s5**3 - 9*s1**4*s2**5*s5**2 + s1**4*s2**4*s3*s4*s5 - 76*s1**4*s2**3*s4*s5**2 ++ 370*s1**4*s2**2*s3**2*s5**2 - 287*s1**4*s2**2*s3*s4**2*s5 + 65*s1**4*s2**2*s4**4 +- 28*s1**4*s2*s3**3*s4*s5 + 5*s1**4*s2*s3**2*s4**3 - 200*s1**4*s2*s3*s5**3 - 294*s1**4*s2*s4**2*s5**2 ++ 8*s1**4*s3**5*s5 - 2*s1**4*s3**4*s4**2 - 676*s1**4*s3**2*s4*s5**2 + 180*s1**4*s3*s4**3*s5 ++ 17*s1**4*s4**5 + 625*s1**4*s5**4 - 210*s1**3*s2**4*s3*s5**2 + 76*s1**3*s2**4*s4**2*s5 ++ 43*s1**3*s2**3*s3**2*s4*s5 - 15*s1**3*s2**3*s3*s4**3 + 50*s1**3*s2**3*s5**3 - 6*s1**3*s2**2*s3**4*s5 ++ 2*s1**3*s2**2*s3**3*s4**2 - 397*s1**3*s2**2*s3*s4*s5**2 + 514*s1**3*s2**2*s4**3*s5 +- 700*s1**3*s2*s3**3*s5**2 + 447*s1**3*s2*s3**2*s4**2*s5 - 118*s1**3*s2*s3*s4**4 + +2300*s1**3*s2*s4*s5**3 - 12*s1**3*s3**4*s4*s5 + 6*s1**3*s3**3*s4**3 + 250*s1**3*s3**2*s5**3 ++ 1470*s1**3*s3*s4**2*s5**2 - 276*s1**3*s4**4*s5 + 27*s1**2*s2**6*s5**2 - 9*s1**2*s2**5*s3*s4*s5 ++ s1**2*s2**5*s4**3 + s1**2*s2**4*s3**3*s5 + 141*s1**2*s2**4*s4*s5**2 - 185*s1**2*s2**3*s3**2*s5**2 ++ 168*s1**2*s2**3*s3*s4**2*s5 - 128*s1**2*s2**3*s4**4 + 93*s1**2*s2**2*s3**3*s4*s5 ++ 19*s1**2*s2**2*s3**2*s4**3 - 125*s1**2*s2**2*s3*s5**3 - 610*s1**2*s2**2*s4**2*s5**2 +- 36*s1**2*s2*s3**5*s5 + 5*s1**2*s2*s3**4*s4**2 + 1995*s1**2*s2*s3**2*s4*s5**2 - 1174*s1**2*s2*s3*s4**3*s5 +- 16*s1**2*s2*s4**5 - 3125*s1**2*s2*s5**4 + 375*s1**2*s3**4*s5**2 - 172*s1**2*s3**3*s4**2*s5 ++ 82*s1**2*s3**2*s4**4 - 3500*s1**2*s3*s4*s5**3 - 1450*s1**2*s4**3*s5**2 + 198*s1*s2**5*s3*s5**2 +- 78*s1*s2**5*s4**2*s5 - 95*s1*s2**4*s3**2*s4*s5 + 44*s1*s2**4*s3*s4**3 + 25*s1*s2**3*s3**4*s5 +- 15*s1*s2**3*s3**3*s4**2 + 15*s1*s2**3*s3*s4*s5**2 - 384*s1*s2**3*s4**3*s5 + s1*s2**2*s3**5*s4 ++ 525*s1*s2**2*s3**3*s5**2 - 528*s1*s2**2*s3**2*s4**2*s5 + 384*s1*s2**2*s3*s4**4 - +1750*s1*s2**2*s4*s5**3 - 29*s1*s2*s3**4*s4*s5 - 118*s1*s2*s3**3*s4**3 + 625*s1*s2*s3**2*s5**3 +- 850*s1*s2*s3*s4**2*s5**2 + 1760*s1*s2*s4**4*s5 + 38*s1*s3**6*s5 + 5*s1*s3**5*s4**2 +- 2050*s1*s3**3*s4*s5**2 + 780*s1*s3**2*s4**3*s5 - 192*s1*s3*s4**5 + 3125*s1*s3*s5**4 ++ 7500*s1*s4**2*s5**3 - 27*s2**7*s5**2 + 18*s2**6*s3*s4*s5 - 4*s2**6*s4**3 - 4*s2**5*s3**3*s5 ++ s2**5*s3**2*s4**2 - 99*s2**5*s4*s5**2 - 150*s2**4*s3**2*s5**2 + 196*s2**4*s3*s4**2*s5 ++ 48*s2**4*s4**4 + 12*s2**3*s3**3*s4*s5 - 128*s2**3*s3**2*s4**3 + 1200*s2**3*s4**2*s5**2 +- 12*s2**2*s3**5*s5 + 65*s2**2*s3**4*s4**2 - 725*s2**2*s3**2*s4*s5**2 - 160*s2**2*s3*s4**3*s5 +- 192*s2**2*s4**5 + 3125*s2**2*s5**4 - 13*s2*s3**6*s4 - 125*s2*s3**4*s5**2 + 590*s2*s3**3*s4**2*s5 +- 16*s2*s3**2*s4**4 - 1250*s2*s3*s4*s5**3 - 2000*s2*s4**3*s5**2 + s3**8 - 124*s3**5*s4*s5 ++ 17*s3**4*s4**3 + 3250*s3**2*s4**2*s5**2 - 1600*s3*s4**4*s5 + 256*s4**6 - 9375*s4*s5**4) + ], + (6, 1): [ + lambda s1, s2, s3, s4, s5, s6: (8*s1*s5 - 2*s2*s4 - 18*s6), + lambda s1, s2, s3, s4, s5, s6: (-50*s1**2*s4*s6 + 40*s1**2*s5**2 + 30*s1*s2*s3*s6 - 14*s1*s2*s4*s5 - 6*s1*s3**2*s5 ++ 2*s1*s3*s4**2 - 30*s1*s5*s6 - 8*s2**3*s6 + 2*s2**2*s3*s5 + s2**2*s4**2 + 114*s2*s4*s6 +- 50*s2*s5**2 - 54*s3**2*s6 + 30*s3*s4*s5 - 8*s4**3 - 135*s6**2), + lambda s1, s2, s3, s4, s5, s6: (125*s1**3*s3*s6**2 - 400*s1**3*s4*s5*s6 + 160*s1**3*s5**3 - 50*s1**2*s2**2*s6**2 + +190*s1**2*s2*s3*s5*s6 + 120*s1**2*s2*s4**2*s6 - 80*s1**2*s2*s4*s5**2 - 15*s1**2*s3**2*s4*s6 +- 40*s1**2*s3**2*s5**2 + 21*s1**2*s3*s4**2*s5 - 2*s1**2*s4**4 + 900*s1**2*s4*s6**2 +- 80*s1**2*s5**2*s6 - 44*s1*s2**3*s5*s6 - 66*s1*s2**2*s3*s4*s6 + 21*s1*s2**2*s3*s5**2 ++ 6*s1*s2**2*s4**2*s5 + 9*s1*s2*s3**3*s6 + 5*s1*s2*s3**2*s4*s5 - 2*s1*s2*s3*s4**3 +- 990*s1*s2*s3*s6**2 + 920*s1*s2*s4*s5*s6 - 400*s1*s2*s5**3 - 135*s1*s3**2*s5*s6 - +126*s1*s3*s4**2*s6 + 190*s1*s3*s4*s5**2 - 44*s1*s4**3*s5 - 2070*s1*s5*s6**2 + 16*s2**4*s4*s6 +- 2*s2**4*s5**2 - 2*s2**3*s3**2*s6 - 2*s2**3*s3*s4*s5 + 304*s2**3*s6**2 - 126*s2**2*s3*s5*s6 +- 232*s2**2*s4**2*s6 + 120*s2**2*s4*s5**2 + 198*s2*s3**2*s4*s6 - 15*s2*s3**2*s5**2 +- 66*s2*s3*s4**2*s5 + 16*s2*s4**4 - 1440*s2*s4*s6**2 + 900*s2*s5**2*s6 - 27*s3**4*s6 ++ 9*s3**3*s4*s5 - 2*s3**2*s4**3 + 1350*s3**2*s6**2 - 990*s3*s4*s5*s6 + 125*s3*s5**3 ++ 304*s4**3*s6 - 50*s4**2*s5**2 + 3240*s6**3), + lambda s1, s2, s3, s4, s5, s6: (500*s1**4*s3*s5*s6**2 + 625*s1**4*s4**2*s6**2 - 1400*s1**4*s4*s5**2*s6 + 400*s1**4*s5**4 +- 200*s1**3*s2**2*s5*s6**2 - 875*s1**3*s2*s3*s4*s6**2 + 640*s1**3*s2*s3*s5**2*s6 + +630*s1**3*s2*s4**2*s5*s6 - 264*s1**3*s2*s4*s5**3 + 90*s1**3*s3**2*s4*s5*s6 - 136*s1**3*s3**2*s5**3 +- 50*s1**3*s3*s4**3*s6 + 76*s1**3*s3*s4**2*s5**2 - 1125*s1**3*s3*s6**3 - 8*s1**3*s4**4*s5 ++ 2550*s1**3*s4*s5*s6**2 - 200*s1**3*s5**3*s6 + 250*s1**2*s2**3*s4*s6**2 - 144*s1**2*s2**3*s5**2*s6 ++ 225*s1**2*s2**2*s3**2*s6**2 - 354*s1**2*s2**2*s3*s4*s5*s6 + 76*s1**2*s2**2*s3*s5**3 +- 70*s1**2*s2**2*s4**3*s6 + 41*s1**2*s2**2*s4**2*s5**2 + 450*s1**2*s2**2*s6**3 - 54*s1**2*s2*s3**3*s5*s6 ++ 45*s1**2*s2*s3**2*s4**2*s6 + 30*s1**2*s2*s3**2*s4*s5**2 - 19*s1**2*s2*s3*s4**3*s5 +- 2880*s1**2*s2*s3*s5*s6**2 + 2*s1**2*s2*s4**5 - 3480*s1**2*s2*s4**2*s6**2 + 4692*s1**2*s2*s4*s5**2*s6 +- 1400*s1**2*s2*s5**4 + 9*s1**2*s3**4*s5**2 - 6*s1**2*s3**3*s4**2*s5 + s1**2*s3**2*s4**4 ++ 1485*s1**2*s3**2*s4*s6**2 - 522*s1**2*s3**2*s5**2*s6 - 1257*s1**2*s3*s4**2*s5*s6 ++ 640*s1**2*s3*s4*s5**3 + 218*s1**2*s4**4*s6 - 144*s1**2*s4**3*s5**2 + 1350*s1**2*s4*s6**3 +- 5175*s1**2*s5**2*s6**2 - 120*s1*s2**4*s3*s6**2 + 68*s1*s2**4*s4*s5*s6 - 8*s1*s2**4*s5**3 ++ 46*s1*s2**3*s3**2*s5*s6 + 28*s1*s2**3*s3*s4**2*s6 - 19*s1*s2**3*s3*s4*s5**2 + 868*s1*s2**3*s5*s6**2 +- 9*s1*s2**2*s3**3*s4*s6 - 6*s1*s2**2*s3**3*s5**2 + 3*s1*s2**2*s3**2*s4**2*s5 + 2484*s1*s2**2*s3*s4*s6**2 +- 1257*s1*s2**2*s3*s5**2*s6 - 1356*s1*s2**2*s4**2*s5*s6 + 630*s1*s2**2*s4*s5**3 - +891*s1*s2*s3**3*s6**2 + 882*s1*s2*s3**2*s4*s5*s6 + 90*s1*s2*s3**2*s5**3 + 84*s1*s2*s3*s4**3*s6 +- 354*s1*s2*s3*s4**2*s5**2 + 3240*s1*s2*s3*s6**3 + 68*s1*s2*s4**4*s5 - 4392*s1*s2*s4*s5*s6**2 ++ 2550*s1*s2*s5**3*s6 + 54*s1*s3**4*s5*s6 - 54*s1*s3**3*s4**2*s6 - 54*s1*s3**3*s4*s5**2 ++ 46*s1*s3**2*s4**3*s5 + 2727*s1*s3**2*s5*s6**2 - 8*s1*s3*s4**5 + 756*s1*s3*s4**2*s6**2 +- 2880*s1*s3*s4*s5**2*s6 + 500*s1*s3*s5**4 + 868*s1*s4**3*s5*s6 - 200*s1*s4**2*s5**3 ++ 8100*s1*s5*s6**3 + 16*s2**6*s6**2 - 8*s2**5*s3*s5*s6 - 8*s2**5*s4**2*s6 + 2*s2**5*s4*s5**2 ++ 2*s2**4*s3**2*s4*s6 + s2**4*s3**2*s5**2 - 688*s2**4*s4*s6**2 + 218*s2**4*s5**2*s6 ++ 234*s2**3*s3**2*s6**2 + 84*s2**3*s3*s4*s5*s6 - 50*s2**3*s3*s5**3 + 168*s2**3*s4**3*s6 +- 70*s2**3*s4**2*s5**2 - 1224*s2**3*s6**3 - 54*s2**2*s3**3*s5*s6 - 144*s2**2*s3**2*s4**2*s6 ++ 45*s2**2*s3**2*s4*s5**2 + 28*s2**2*s3*s4**3*s5 + 756*s2**2*s3*s5*s6**2 - 8*s2**2*s4**5 ++ 4320*s2**2*s4**2*s6**2 - 3480*s2**2*s4*s5**2*s6 + 625*s2**2*s5**4 + 27*s2*s3**4*s4*s6 +- 9*s2*s3**3*s4**2*s5 + 2*s2*s3**2*s4**4 - 4752*s2*s3**2*s4*s6**2 + 1485*s2*s3**2*s5**2*s6 ++ 2484*s2*s3*s4**2*s5*s6 - 875*s2*s3*s4*s5**3 - 688*s2*s4**4*s6 + 250*s2*s4**3*s5**2 +- 4536*s2*s4*s6**3 + 1350*s2*s5**2*s6**2 + 972*s3**4*s6**2 - 891*s3**3*s4*s5*s6 + +234*s3**2*s4**3*s6 + 225*s3**2*s4**2*s5**2 - 1944*s3**2*s6**3 - 120*s3*s4**4*s5 + +3240*s3*s4*s5*s6**2 - 1125*s3*s5**3*s6 + 16*s4**6 - 1224*s4**3*s6**2 + 450*s4**2*s5**2*s6), + lambda s1, s2, s3, s4, s5, s6: (-3125*s1**6*s6**4 + 2500*s1**5*s2*s5*s6**3 + 625*s1**5*s3*s4*s6**3 - 500*s1**5*s3*s5**2*s6**2 ++ 2750*s1**5*s4**2*s5*s6**2 - 2400*s1**5*s4*s5**3*s6 + 512*s1**5*s5**5 - 750*s1**4*s2**2*s4*s6**3 +- 550*s1**4*s2**2*s5**2*s6**2 - 375*s1**4*s2*s3**2*s6**3 - 3075*s1**4*s2*s3*s4*s5*s6**2 ++ 1640*s1**4*s2*s3*s5**3*s6 - 850*s1**4*s2*s4**3*s6**2 + 1220*s1**4*s2*s4**2*s5**2*s6 +- 384*s1**4*s2*s4*s5**4 + 22500*s1**4*s2*s6**4 + 525*s1**4*s3**3*s5*s6**2 - 325*s1**4*s3**2*s4**2*s6**2 ++ 260*s1**4*s3**2*s4*s5**2*s6 - 256*s1**4*s3**2*s5**4 + 105*s1**4*s3*s4**3*s5*s6 + +76*s1**4*s3*s4**2*s5**3 + 375*s1**4*s3*s5*s6**3 - 58*s1**4*s4**5*s6 + 3*s1**4*s4**4*s5**2 +- 12750*s1**4*s4**2*s6**3 + 3700*s1**4*s4*s5**2*s6**2 + 640*s1**4*s5**4*s6 + 350*s1**3*s2**3*s3*s6**3 ++ 1090*s1**3*s2**3*s4*s5*s6**2 - 364*s1**3*s2**3*s5**3*s6 + 305*s1**3*s2**2*s3**2*s5*s6**2 ++ 1340*s1**3*s2**2*s3*s4**2*s6**2 - 901*s1**3*s2**2*s3*s4*s5**2*s6 + 76*s1**3*s2**2*s3*s5**4 +- 234*s1**3*s2**2*s4**3*s5*s6 + 102*s1**3*s2**2*s4**2*s5**3 - 16650*s1**3*s2**2*s5*s6**3 ++ 180*s1**3*s2*s3**3*s4*s6**2 - 366*s1**3*s2*s3**3*s5**2*s6 - 231*s1**3*s2*s3**2*s4**2*s5*s6 ++ 212*s1**3*s2*s3**2*s4*s5**3 + 112*s1**3*s2*s3*s4**4*s6 - 89*s1**3*s2*s3*s4**3*s5**2 ++ 10950*s1**3*s2*s3*s4*s6**3 + 1555*s1**3*s2*s3*s5**2*s6**2 + 6*s1**3*s2*s4**5*s5 +- 9540*s1**3*s2*s4**2*s5*s6**2 + 9016*s1**3*s2*s4*s5**3*s6 - 2400*s1**3*s2*s5**5 - +108*s1**3*s3**5*s6**2 + 117*s1**3*s3**4*s4*s5*s6 + 32*s1**3*s3**4*s5**3 - 31*s1**3*s3**3*s4**3*s6 +- 51*s1**3*s3**3*s4**2*s5**2 - 2025*s1**3*s3**3*s6**3 + 19*s1**3*s3**2*s4**4*s5 + +2955*s1**3*s3**2*s4*s5*s6**2 - 1436*s1**3*s3**2*s5**3*s6 - 2*s1**3*s3*s4**6 + 2770*s1**3*s3*s4**3*s6**2 +- 5123*s1**3*s3*s4**2*s5**2*s6 + 1640*s1**3*s3*s4*s5**4 - 40500*s1**3*s3*s6**4 + 914*s1**3*s4**4*s5*s6 +- 364*s1**3*s4**3*s5**3 + 53550*s1**3*s4*s5*s6**3 - 17930*s1**3*s5**3*s6**2 - 56*s1**2*s2**5*s6**3 +- 318*s1**2*s2**4*s3*s5*s6**2 - 352*s1**2*s2**4*s4**2*s6**2 + 166*s1**2*s2**4*s4*s5**2*s6 ++ 3*s1**2*s2**4*s5**4 - 574*s1**2*s2**3*s3**2*s4*s6**2 + 347*s1**2*s2**3*s3**2*s5**2*s6 ++ 194*s1**2*s2**3*s3*s4**2*s5*s6 - 89*s1**2*s2**3*s3*s4*s5**3 - 8*s1**2*s2**3*s4**4*s6 ++ 4*s1**2*s2**3*s4**3*s5**2 + 560*s1**2*s2**3*s4*s6**3 + 3662*s1**2*s2**3*s5**2*s6**2 ++ 162*s1**2*s2**2*s3**4*s6**2 + 33*s1**2*s2**2*s3**3*s4*s5*s6 - 51*s1**2*s2**2*s3**3*s5**3 +- 32*s1**2*s2**2*s3**2*s4**3*s6 + 28*s1**2*s2**2*s3**2*s4**2*s5**2 + 270*s1**2*s2**2*s3**2*s6**3 +- 2*s1**2*s2**2*s3*s4**4*s5 + 4872*s1**2*s2**2*s3*s4*s5*s6**2 - 5123*s1**2*s2**2*s3*s5**3*s6 ++ 2144*s1**2*s2**2*s4**3*s6**2 - 2812*s1**2*s2**2*s4**2*s5**2*s6 + 1220*s1**2*s2**2*s4*s5**4 +- 37800*s1**2*s2**2*s6**4 - 27*s1**2*s2*s3**5*s5*s6 + 9*s1**2*s2*s3**4*s4**2*s6 + +3*s1**2*s2*s3**4*s4*s5**2 - s1**2*s2*s3**3*s4**3*s5 - 3078*s1**2*s2*s3**3*s5*s6**2 +- 4014*s1**2*s2*s3**2*s4**2*s6**2 + 5412*s1**2*s2*s3**2*s4*s5**2*s6 + 260*s1**2*s2*s3**2*s5**4 +- 310*s1**2*s2*s3*s4**3*s5*s6 - 901*s1**2*s2*s3*s4**2*s5**3 - 3780*s1**2*s2*s3*s5*s6**3 ++ 166*s1**2*s2*s4**4*s5**2 + 40320*s1**2*s2*s4**2*s6**3 - 25344*s1**2*s2*s4*s5**2*s6**2 ++ 3700*s1**2*s2*s5**4*s6 + 918*s1**2*s3**4*s4*s6**2 + 27*s1**2*s3**4*s5**2*s6 - 342*s1**2*s3**3*s4**2*s5*s6 +- 366*s1**2*s3**3*s4*s5**3 + 32*s1**2*s3**2*s4**4*s6 + 347*s1**2*s3**2*s4**3*s5**2 +- 4590*s1**2*s3**2*s4*s6**3 + 594*s1**2*s3**2*s5**2*s6**2 - 94*s1**2*s3*s4**5*s5 + +3618*s1**2*s3*s4**2*s5*s6**2 + 1555*s1**2*s3*s4*s5**3*s6 - 500*s1**2*s3*s5**5 + 8*s1**2*s4**7 +- 7192*s1**2*s4**4*s6**2 + 3662*s1**2*s4**3*s5**2*s6 - 550*s1**2*s4**2*s5**4 - 48600*s1**2*s4*s6**4 ++ 1080*s1**2*s5**2*s6**3 + 48*s1*s2**6*s5*s6**2 + 264*s1*s2**5*s3*s4*s6**2 - 94*s1*s2**5*s3*s5**2*s6 +- 24*s1*s2**5*s4**2*s5*s6 + 6*s1*s2**5*s4*s5**3 - 66*s1*s2**4*s3**3*s6**2 - 50*s1*s2**4*s3**2*s4*s5*s6 ++ 19*s1*s2**4*s3**2*s5**3 + 8*s1*s2**4*s3*s4**3*s6 - 2*s1*s2**4*s3*s4**2*s5**2 - 552*s1*s2**4*s3*s6**3 +- 2560*s1*s2**4*s4*s5*s6**2 + 914*s1*s2**4*s5**3*s6 + 15*s1*s2**3*s3**4*s5*s6 - 2*s1*s2**3*s3**3*s4**2*s6 +- s1*s2**3*s3**3*s4*s5**2 + 1602*s1*s2**3*s3**2*s5*s6**2 - 608*s1*s2**3*s3*s4**2*s6**2 +- 310*s1*s2**3*s3*s4*s5**2*s6 + 105*s1*s2**3*s3*s5**4 + 600*s1*s2**3*s4**3*s5*s6 - +234*s1*s2**3*s4**2*s5**3 + 31368*s1*s2**3*s5*s6**3 + 756*s1*s2**2*s3**3*s4*s6**2 - +342*s1*s2**2*s3**3*s5**2*s6 + 216*s1*s2**2*s3**2*s4**2*s5*s6 - 231*s1*s2**2*s3**2*s4*s5**3 +- 192*s1*s2**2*s3*s4**4*s6 + 194*s1*s2**2*s3*s4**3*s5**2 - 39096*s1*s2**2*s3*s4*s6**3 ++ 3618*s1*s2**2*s3*s5**2*s6**2 - 24*s1*s2**2*s4**5*s5 + 9408*s1*s2**2*s4**2*s5*s6**2 +- 9540*s1*s2**2*s4*s5**3*s6 + 2750*s1*s2**2*s5**5 - 162*s1*s2*s3**5*s6**2 - 378*s1*s2*s3**4*s4*s5*s6 ++ 117*s1*s2*s3**4*s5**3 + 150*s1*s2*s3**3*s4**3*s6 + 33*s1*s2*s3**3*s4**2*s5**2 + +10044*s1*s2*s3**3*s6**3 - 50*s1*s2*s3**2*s4**4*s5 - 8640*s1*s2*s3**2*s4*s5*s6**2 + +2955*s1*s2*s3**2*s5**3*s6 + 8*s1*s2*s3*s4**6 + 6144*s1*s2*s3*s4**3*s6**2 + 4872*s1*s2*s3*s4**2*s5**2*s6 +- 3075*s1*s2*s3*s4*s5**4 + 174960*s1*s2*s3*s6**4 - 2560*s1*s2*s4**4*s5*s6 + 1090*s1*s2*s4**3*s5**3 +- 148824*s1*s2*s4*s5*s6**3 + 53550*s1*s2*s5**3*s6**2 + 81*s1*s3**6*s5*s6 - 27*s1*s3**5*s4**2*s6 +- 27*s1*s3**5*s4*s5**2 + 15*s1*s3**4*s4**3*s5 + 2430*s1*s3**4*s5*s6**2 - 2*s1*s3**3*s4**5 +- 2052*s1*s3**3*s4**2*s6**2 - 3078*s1*s3**3*s4*s5**2*s6 + 525*s1*s3**3*s5**4 + 1602*s1*s3**2*s4**3*s5*s6 ++ 305*s1*s3**2*s4**2*s5**3 + 18144*s1*s3**2*s5*s6**3 - 104*s1*s3*s4**5*s6 - 318*s1*s3*s4**4*s5**2 +- 33696*s1*s3*s4**2*s6**3 - 3780*s1*s3*s4*s5**2*s6**2 + 375*s1*s3*s5**4*s6 + 48*s1*s4**6*s5 ++ 31368*s1*s4**3*s5*s6**2 - 16650*s1*s4**2*s5**3*s6 + 2500*s1*s4*s5**5 + 77760*s1*s5*s6**4 +- 32*s2**7*s4*s6**2 + 8*s2**7*s5**2*s6 + 8*s2**6*s3**2*s6**2 + 8*s2**6*s3*s4*s5*s6 +- 2*s2**6*s3*s5**3 + 96*s2**6*s6**3 - 2*s2**5*s3**3*s5*s6 - 104*s2**5*s3*s5*s6**2 ++ 416*s2**5*s4**2*s6**2 - 58*s2**5*s5**4 - 312*s2**4*s3**2*s4*s6**2 + 32*s2**4*s3**2*s5**2*s6 +- 192*s2**4*s3*s4**2*s5*s6 + 112*s2**4*s3*s4*s5**3 - 8*s2**4*s4**3*s5**2 + 4224*s2**4*s4*s6**3 +- 7192*s2**4*s5**2*s6**2 + 54*s2**3*s3**4*s6**2 + 150*s2**3*s3**3*s4*s5*s6 - 31*s2**3*s3**3*s5**3 +- 32*s2**3*s3**2*s4**2*s5**2 - 864*s2**3*s3**2*s6**3 + 8*s2**3*s3*s4**4*s5 + 6144*s2**3*s3*s4*s5*s6**2 ++ 2770*s2**3*s3*s5**3*s6 - 4032*s2**3*s4**3*s6**2 + 2144*s2**3*s4**2*s5**2*s6 - 850*s2**3*s4*s5**4 +- 16416*s2**3*s6**4 - 27*s2**2*s3**5*s5*s6 + 9*s2**2*s3**4*s4*s5**2 - 2*s2**2*s3**3*s4**3*s5 +- 2052*s2**2*s3**3*s5*s6**2 + 2376*s2**2*s3**2*s4**2*s6**2 - 4014*s2**2*s3**2*s4*s5**2*s6 +- 325*s2**2*s3**2*s5**4 - 608*s2**2*s3*s4**3*s5*s6 + 1340*s2**2*s3*s4**2*s5**3 - 33696*s2**2*s3*s5*s6**3 ++ 416*s2**2*s4**5*s6 - 352*s2**2*s4**4*s5**2 - 6048*s2**2*s4**2*s6**3 + 40320*s2**2*s4*s5**2*s6**2 +- 12750*s2**2*s5**4*s6 - 324*s2*s3**4*s4*s6**2 + 918*s2*s3**4*s5**2*s6 + 756*s2*s3**3*s4**2*s5*s6 ++ 180*s2*s3**3*s4*s5**3 - 312*s2*s3**2*s4**4*s6 - 574*s2*s3**2*s4**3*s5**2 + 43416*s2*s3**2*s4*s6**3 +- 4590*s2*s3**2*s5**2*s6**2 + 264*s2*s3*s4**5*s5 - 39096*s2*s3*s4**2*s5*s6**2 + 10950*s2*s3*s4*s5**3*s6 ++ 625*s2*s3*s5**5 - 32*s2*s4**7 + 4224*s2*s4**4*s6**2 + 560*s2*s4**3*s5**2*s6 - 750*s2*s4**2*s5**4 ++ 85536*s2*s4*s6**4 - 48600*s2*s5**2*s6**3 - 162*s3**5*s4*s5*s6 - 108*s3**5*s5**3 ++ 54*s3**4*s4**3*s6 + 162*s3**4*s4**2*s5**2 - 11664*s3**4*s6**3 - 66*s3**3*s4**4*s5 ++ 10044*s3**3*s4*s5*s6**2 - 2025*s3**3*s5**3*s6 + 8*s3**2*s4**6 - 864*s3**2*s4**3*s6**2 ++ 270*s3**2*s4**2*s5**2*s6 - 375*s3**2*s4*s5**4 - 163296*s3**2*s6**4 - 552*s3*s4**4*s5*s6 ++ 350*s3*s4**3*s5**3 + 174960*s3*s4*s5*s6**3 - 40500*s3*s5**3*s6**2 + 96*s4**6*s6 +- 56*s4**5*s5**2 - 16416*s4**3*s6**3 - 37800*s4**2*s5**2*s6**2 + 22500*s4*s5**4*s6 +- 3125*s5**6 - 93312*s6**5), + lambda s1, s2, s3, s4, s5, s6: (-9375*s1**7*s5*s6**4 + 3125*s1**6*s2*s4*s6**4 + 7500*s1**6*s2*s5**2*s6**3 + 3125*s1**6*s3**2*s6**4 +- 1250*s1**6*s3*s4*s5*s6**3 - 2000*s1**6*s3*s5**3*s6**2 + 3250*s1**6*s4**2*s5**2*s6**2 +- 1600*s1**6*s4*s5**4*s6 + 256*s1**6*s5**6 + 40625*s1**6*s6**5 - 3125*s1**5*s2**2*s3*s6**4 +- 3500*s1**5*s2**2*s4*s5*s6**3 - 1450*s1**5*s2**2*s5**3*s6**2 - 1750*s1**5*s2*s3**2*s5*s6**3 ++ 625*s1**5*s2*s3*s4**2*s6**3 - 850*s1**5*s2*s3*s4*s5**2*s6**2 + 1760*s1**5*s2*s3*s5**4*s6 +- 2050*s1**5*s2*s4**3*s5*s6**2 + 780*s1**5*s2*s4**2*s5**3*s6 - 192*s1**5*s2*s4*s5**5 ++ 35000*s1**5*s2*s5*s6**4 + 1200*s1**5*s3**3*s5**2*s6**2 - 725*s1**5*s3**2*s4**2*s5*s6**2 +- 160*s1**5*s3**2*s4*s5**3*s6 - 192*s1**5*s3**2*s5**5 - 125*s1**5*s3*s4**4*s6**2 + +590*s1**5*s3*s4**3*s5**2*s6 - 16*s1**5*s3*s4**2*s5**4 - 20625*s1**5*s3*s4*s6**4 + +17250*s1**5*s3*s5**2*s6**3 - 124*s1**5*s4**5*s5*s6 + 17*s1**5*s4**4*s5**3 - 20250*s1**5*s4**2*s5*s6**3 ++ 1900*s1**5*s4*s5**3*s6**2 + 1344*s1**5*s5**5*s6 + 625*s1**4*s2**4*s6**4 + 2300*s1**4*s2**3*s3*s5*s6**3 ++ 250*s1**4*s2**3*s4**2*s6**3 + 1470*s1**4*s2**3*s4*s5**2*s6**2 - 276*s1**4*s2**3*s5**4*s6 +- 125*s1**4*s2**2*s3**2*s4*s6**3 - 610*s1**4*s2**2*s3**2*s5**2*s6**2 + 1995*s1**4*s2**2*s3*s4**2*s5*s6**2 +- 1174*s1**4*s2**2*s3*s4*s5**3*s6 - 16*s1**4*s2**2*s3*s5**5 + 375*s1**4*s2**2*s4**4*s6**2 +- 172*s1**4*s2**2*s4**3*s5**2*s6 + 82*s1**4*s2**2*s4**2*s5**4 - 7750*s1**4*s2**2*s4*s6**4 +- 46650*s1**4*s2**2*s5**2*s6**3 + 15*s1**4*s2*s3**3*s4*s5*s6**2 - 384*s1**4*s2*s3**3*s5**3*s6 ++ 525*s1**4*s2*s3**2*s4**3*s6**2 - 528*s1**4*s2*s3**2*s4**2*s5**2*s6 + 384*s1**4*s2*s3**2*s4*s5**4 +- 10125*s1**4*s2*s3**2*s6**4 - 29*s1**4*s2*s3*s4**4*s5*s6 - 118*s1**4*s2*s3*s4**3*s5**3 ++ 36700*s1**4*s2*s3*s4*s5*s6**3 + 2410*s1**4*s2*s3*s5**3*s6**2 + 38*s1**4*s2*s4**6*s6 ++ 5*s1**4*s2*s4**5*s5**2 + 5550*s1**4*s2*s4**3*s6**3 - 10040*s1**4*s2*s4**2*s5**2*s6**2 ++ 5800*s1**4*s2*s4*s5**4*s6 - 1600*s1**4*s2*s5**6 - 292500*s1**4*s2*s6**5 - 99*s1**4*s3**5*s5*s6**2 +- 150*s1**4*s3**4*s4**2*s6**2 + 196*s1**4*s3**4*s4*s5**2*s6 + 48*s1**4*s3**4*s5**4 ++ 12*s1**4*s3**3*s4**3*s5*s6 - 128*s1**4*s3**3*s4**2*s5**3 - 6525*s1**4*s3**3*s5*s6**3 +- 12*s1**4*s3**2*s4**5*s6 + 65*s1**4*s3**2*s4**4*s5**2 + 225*s1**4*s3**2*s4**2*s6**3 ++ 80*s1**4*s3**2*s4*s5**2*s6**2 - 13*s1**4*s3*s4**6*s5 + 5145*s1**4*s3*s4**3*s5*s6**2 +- 6746*s1**4*s3*s4**2*s5**3*s6 + 1760*s1**4*s3*s4*s5**5 - 103500*s1**4*s3*s5*s6**4 ++ s1**4*s4**8 + 954*s1**4*s4**5*s6**2 + 449*s1**4*s4**4*s5**2*s6 - 276*s1**4*s4**3*s5**4 ++ 70125*s1**4*s4**2*s6**4 + 58900*s1**4*s4*s5**2*s6**3 - 23310*s1**4*s5**4*s6**2 - +468*s1**3*s2**5*s5*s6**3 - 200*s1**3*s2**4*s3*s4*s6**3 - 294*s1**3*s2**4*s3*s5**2*s6**2 +- 676*s1**3*s2**4*s4**2*s5*s6**2 + 180*s1**3*s2**4*s4*s5**3*s6 + 17*s1**3*s2**4*s5**5 ++ 50*s1**3*s2**3*s3**3*s6**3 - 397*s1**3*s2**3*s3**2*s4*s5*s6**2 + 514*s1**3*s2**3*s3**2*s5**3*s6 +- 700*s1**3*s2**3*s3*s4**3*s6**2 + 447*s1**3*s2**3*s3*s4**2*s5**2*s6 - 118*s1**3*s2**3*s3*s4*s5**4 ++ 11700*s1**3*s2**3*s3*s6**4 - 12*s1**3*s2**3*s4**4*s5*s6 + 6*s1**3*s2**3*s4**3*s5**3 ++ 10360*s1**3*s2**3*s4*s5*s6**3 + 11404*s1**3*s2**3*s5**3*s6**2 + 141*s1**3*s2**2*s3**4*s5*s6**2 +- 185*s1**3*s2**2*s3**3*s4**2*s6**2 + 168*s1**3*s2**2*s3**3*s4*s5**2*s6 - 128*s1**3*s2**2*s3**3*s5**4 ++ 93*s1**3*s2**2*s3**2*s4**3*s5*s6 + 19*s1**3*s2**2*s3**2*s4**2*s5**3 + 5895*s1**3*s2**2*s3**2*s5*s6**3 +- 36*s1**3*s2**2*s3*s4**5*s6 + 5*s1**3*s2**2*s3*s4**4*s5**2 - 12020*s1**3*s2**2*s3*s4**2*s6**3 +- 5698*s1**3*s2**2*s3*s4*s5**2*s6**2 - 6746*s1**3*s2**2*s3*s5**4*s6 + 5064*s1**3*s2**2*s4**3*s5*s6**2 +- 762*s1**3*s2**2*s4**2*s5**3*s6 + 780*s1**3*s2**2*s4*s5**5 + 93900*s1**3*s2**2*s5*s6**4 ++ 198*s1**3*s2*s3**5*s4*s6**2 - 78*s1**3*s2*s3**5*s5**2*s6 - 95*s1**3*s2*s3**4*s4**2*s5*s6 ++ 44*s1**3*s2*s3**4*s4*s5**3 + 25*s1**3*s2*s3**3*s4**4*s6 - 15*s1**3*s2*s3**3*s4**3*s5**2 ++ 1935*s1**3*s2*s3**3*s4*s6**3 - 2808*s1**3*s2*s3**3*s5**2*s6**2 + s1**3*s2*s3**2*s4**5*s5 +- 4844*s1**3*s2*s3**2*s4**2*s5*s6**2 + 8996*s1**3*s2*s3**2*s4*s5**3*s6 - 160*s1**3*s2*s3**2*s5**5 +- 3616*s1**3*s2*s3*s4**4*s6**2 + 500*s1**3*s2*s3*s4**3*s5**2*s6 - 1174*s1**3*s2*s3*s4**2*s5**4 ++ 72900*s1**3*s2*s3*s4*s6**4 - 55665*s1**3*s2*s3*s5**2*s6**3 + 128*s1**3*s2*s4**5*s5*s6 ++ 180*s1**3*s2*s4**4*s5**3 + 16240*s1**3*s2*s4**2*s5*s6**3 - 9330*s1**3*s2*s4*s5**3*s6**2 ++ 1900*s1**3*s2*s5**5*s6 - 27*s1**3*s3**7*s6**2 + 18*s1**3*s3**6*s4*s5*s6 - 4*s1**3*s3**6*s5**3 +- 4*s1**3*s3**5*s4**3*s6 + s1**3*s3**5*s4**2*s5**2 + 54*s1**3*s3**5*s6**3 + 1143*s1**3*s3**4*s4*s5*s6**2 +- 820*s1**3*s3**4*s5**3*s6 + 923*s1**3*s3**3*s4**3*s6**2 + 57*s1**3*s3**3*s4**2*s5**2*s6 +- 384*s1**3*s3**3*s4*s5**4 + 29700*s1**3*s3**3*s6**4 - 547*s1**3*s3**2*s4**4*s5*s6 ++ 514*s1**3*s3**2*s4**3*s5**3 - 10305*s1**3*s3**2*s4*s5*s6**3 - 7405*s1**3*s3**2*s5**3*s6**2 ++ 108*s1**3*s3*s4**6*s6 - 148*s1**3*s3*s4**5*s5**2 - 11360*s1**3*s3*s4**3*s6**3 + +22209*s1**3*s3*s4**2*s5**2*s6**2 + 2410*s1**3*s3*s4*s5**4*s6 - 2000*s1**3*s3*s5**6 ++ 432000*s1**3*s3*s6**5 + 12*s1**3*s4**7*s5 - 22624*s1**3*s4**4*s5*s6**2 + 11404*s1**3*s4**3*s5**3*s6 +- 1450*s1**3*s4**2*s5**5 - 242100*s1**3*s4*s5*s6**4 + 58430*s1**3*s5**3*s6**3 + 56*s1**2*s2**6*s4*s6**3 ++ 86*s1**2*s2**6*s5**2*s6**2 - 14*s1**2*s2**5*s3**2*s6**3 + 304*s1**2*s2**5*s3*s4*s5*s6**2 +- 148*s1**2*s2**5*s3*s5**3*s6 + 152*s1**2*s2**5*s4**3*s6**2 - 54*s1**2*s2**5*s4**2*s5**2*s6 ++ 5*s1**2*s2**5*s4*s5**4 - 2472*s1**2*s2**5*s6**4 - 76*s1**2*s2**4*s3**3*s5*s6**2 ++ 370*s1**2*s2**4*s3**2*s4**2*s6**2 - 287*s1**2*s2**4*s3**2*s4*s5**2*s6 + 65*s1**2*s2**4*s3**2*s5**4 +- 28*s1**2*s2**4*s3*s4**3*s5*s6 + 5*s1**2*s2**4*s3*s4**2*s5**3 - 8092*s1**2*s2**4*s3*s5*s6**3 ++ 8*s1**2*s2**4*s4**5*s6 - 2*s1**2*s2**4*s4**4*s5**2 + 1096*s1**2*s2**4*s4**2*s6**3 +- 5144*s1**2*s2**4*s4*s5**2*s6**2 + 449*s1**2*s2**4*s5**4*s6 - 210*s1**2*s2**3*s3**4*s4*s6**2 ++ 76*s1**2*s2**3*s3**4*s5**2*s6 + 43*s1**2*s2**3*s3**3*s4**2*s5*s6 - 15*s1**2*s2**3*s3**3*s4*s5**3 +- 6*s1**2*s2**3*s3**2*s4**4*s6 + 2*s1**2*s2**3*s3**2*s4**3*s5**2 + 1962*s1**2*s2**3*s3**2*s4*s6**3 ++ 3181*s1**2*s2**3*s3**2*s5**2*s6**2 + 1684*s1**2*s2**3*s3*s4**2*s5*s6**2 + 500*s1**2*s2**3*s3*s4*s5**3*s6 ++ 590*s1**2*s2**3*s3*s5**5 - 168*s1**2*s2**3*s4**4*s6**2 - 494*s1**2*s2**3*s4**3*s5**2*s6 +- 172*s1**2*s2**3*s4**2*s5**4 - 22080*s1**2*s2**3*s4*s6**4 + 58894*s1**2*s2**3*s5**2*s6**3 ++ 27*s1**2*s2**2*s3**6*s6**2 - 9*s1**2*s2**2*s3**5*s4*s5*s6 + s1**2*s2**2*s3**5*s5**3 ++ s1**2*s2**2*s3**4*s4**3*s6 - 486*s1**2*s2**2*s3**4*s6**3 + 1071*s1**2*s2**2*s3**3*s4*s5*s6**2 ++ 57*s1**2*s2**2*s3**3*s5**3*s6 + 2262*s1**2*s2**2*s3**2*s4**3*s6**2 - 2742*s1**2*s2**2*s3**2*s4**2*s5**2*s6 +- 528*s1**2*s2**2*s3**2*s4*s5**4 - 29160*s1**2*s2**2*s3**2*s6**4 + 772*s1**2*s2**2*s3*s4**4*s5*s6 ++ 447*s1**2*s2**2*s3*s4**3*s5**3 - 96732*s1**2*s2**2*s3*s4*s5*s6**3 + 22209*s1**2*s2**2*s3*s5**3*s6**2 +- 160*s1**2*s2**2*s4**6*s6 - 54*s1**2*s2**2*s4**5*s5**2 - 7992*s1**2*s2**2*s4**3*s6**3 ++ 8634*s1**2*s2**2*s4**2*s5**2*s6**2 - 10040*s1**2*s2**2*s4*s5**4*s6 + 3250*s1**2*s2**2*s5**6 ++ 529200*s1**2*s2**2*s6**5 - 351*s1**2*s2*s3**5*s5*s6**2 - 1215*s1**2*s2*s3**4*s4**2*s6**2 +- 360*s1**2*s2*s3**4*s4*s5**2*s6 + 196*s1**2*s2*s3**4*s5**4 + 741*s1**2*s2*s3**3*s4**3*s5*s6 ++ 168*s1**2*s2*s3**3*s4**2*s5**3 + 11718*s1**2*s2*s3**3*s5*s6**3 - 106*s1**2*s2*s3**2*s4**5*s6 +- 287*s1**2*s2*s3**2*s4**4*s5**2 + 22572*s1**2*s2*s3**2*s4**2*s6**3 - 8892*s1**2*s2*s3**2*s4*s5**2*s6**2 ++ 80*s1**2*s2*s3**2*s5**4*s6 + 88*s1**2*s2*s3*s4**6*s5 + 22144*s1**2*s2*s3*s4**3*s5*s6**2 +- 5698*s1**2*s2*s3*s4**2*s5**3*s6 - 850*s1**2*s2*s3*s4*s5**5 + 169560*s1**2*s2*s3*s5*s6**4 +- 8*s1**2*s2*s4**8 + 3032*s1**2*s2*s4**5*s6**2 - 5144*s1**2*s2*s4**4*s5**2*s6 + 1470*s1**2*s2*s4**3*s5**4 +- 249480*s1**2*s2*s4**2*s6**4 - 105390*s1**2*s2*s4*s5**2*s6**3 + 58900*s1**2*s2*s5**4*s6**2 ++ 162*s1**2*s3**6*s4*s6**2 + 216*s1**2*s3**6*s5**2*s6 - 216*s1**2*s3**5*s4**2*s5*s6 +- 78*s1**2*s3**5*s4*s5**3 + 36*s1**2*s3**4*s4**4*s6 + 76*s1**2*s3**4*s4**3*s5**2 - +3564*s1**2*s3**4*s4*s6**3 + 8802*s1**2*s3**4*s5**2*s6**2 - 22*s1**2*s3**3*s4**5*s5 +- 11475*s1**2*s3**3*s4**2*s5*s6**2 - 2808*s1**2*s3**3*s4*s5**3*s6 + 1200*s1**2*s3**3*s5**5 ++ 2*s1**2*s3**2*s4**7 + 222*s1**2*s3**2*s4**4*s6**2 + 3181*s1**2*s3**2*s4**3*s5**2*s6 +- 610*s1**2*s3**2*s4**2*s5**4 - 165240*s1**2*s3**2*s4*s6**4 + 118260*s1**2*s3**2*s5**2*s6**3 ++ 572*s1**2*s3*s4**5*s5*s6 - 294*s1**2*s3*s4**4*s5**3 - 32616*s1**2*s3*s4**2*s5*s6**3 +- 55665*s1**2*s3*s4*s5**3*s6**2 + 17250*s1**2*s3*s5**5*s6 - 232*s1**2*s4**7*s6 + 86*s1**2*s4**6*s5**2 ++ 48408*s1**2*s4**4*s6**3 + 58894*s1**2*s4**3*s5**2*s6**2 - 46650*s1**2*s4**2*s5**4*s6 ++ 7500*s1**2*s4*s5**6 - 129600*s1**2*s4*s6**5 + 41040*s1**2*s5**2*s6**4 - 48*s1*s2**7*s4*s5*s6**2 ++ 12*s1*s2**7*s5**3*s6 + 12*s1*s2**6*s3**2*s5*s6**2 - 144*s1*s2**6*s3*s4**2*s6**2 ++ 88*s1*s2**6*s3*s4*s5**2*s6 - 13*s1*s2**6*s3*s5**4 + 1680*s1*s2**6*s5*s6**3 + 72*s1*s2**5*s3**3*s4*s6**2 +- 22*s1*s2**5*s3**3*s5**2*s6 - 4*s1*s2**5*s3**2*s4**2*s5*s6 + s1*s2**5*s3**2*s4*s5**3 +- 144*s1*s2**5*s3*s4*s6**3 + 572*s1*s2**5*s3*s5**2*s6**2 + 736*s1*s2**5*s4**2*s5*s6**2 ++ 128*s1*s2**5*s4*s5**3*s6 - 124*s1*s2**5*s5**5 - 9*s1*s2**4*s3**5*s6**2 + s1*s2**4*s3**4*s4*s5*s6 ++ 36*s1*s2**4*s3**3*s6**3 - 2028*s1*s2**4*s3**2*s4*s5*s6**2 - 547*s1*s2**4*s3**2*s5**3*s6 +- 480*s1*s2**4*s3*s4**3*s6**2 + 772*s1*s2**4*s3*s4**2*s5**2*s6 - 29*s1*s2**4*s3*s4*s5**4 ++ 6336*s1*s2**4*s3*s6**4 - 12*s1*s2**4*s4**3*s5**3 + 4368*s1*s2**4*s4*s5*s6**3 - 22624*s1*s2**4*s5**3*s6**2 ++ 441*s1*s2**3*s3**4*s5*s6**2 + 336*s1*s2**3*s3**3*s4**2*s6**2 + 741*s1*s2**3*s3**3*s4*s5**2*s6 ++ 12*s1*s2**3*s3**3*s5**4 - 868*s1*s2**3*s3**2*s4**3*s5*s6 + 93*s1*s2**3*s3**2*s4**2*s5**3 ++ 11016*s1*s2**3*s3**2*s5*s6**3 + 176*s1*s2**3*s3*s4**5*s6 - 28*s1*s2**3*s3*s4**4*s5**2 ++ 14784*s1*s2**3*s3*s4**2*s6**3 + 22144*s1*s2**3*s3*s4*s5**2*s6**2 + 5145*s1*s2**3*s3*s5**4*s6 +- 11344*s1*s2**3*s4**3*s5*s6**2 + 5064*s1*s2**3*s4**2*s5**3*s6 - 2050*s1*s2**3*s4*s5**5 +- 346896*s1*s2**3*s5*s6**4 - 54*s1*s2**2*s3**5*s4*s6**2 - 216*s1*s2**2*s3**5*s5**2*s6 ++ 324*s1*s2**2*s3**4*s4**2*s5*s6 - 95*s1*s2**2*s3**4*s4*s5**3 - 80*s1*s2**2*s3**3*s4**4*s6 ++ 43*s1*s2**2*s3**3*s4**3*s5**2 - 12204*s1*s2**2*s3**3*s4*s6**3 - 11475*s1*s2**2*s3**3*s5**2*s6**2 +- 4*s1*s2**2*s3**2*s4**5*s5 - 3888*s1*s2**2*s3**2*s4**2*s5*s6**2 - 4844*s1*s2**2*s3**2*s4*s5**3*s6 +- 725*s1*s2**2*s3**2*s5**5 - 1312*s1*s2**2*s3*s4**4*s6**2 + 1684*s1*s2**2*s3*s4**3*s5**2*s6 ++ 1995*s1*s2**2*s3*s4**2*s5**4 + 139104*s1*s2**2*s3*s4*s6**4 - 32616*s1*s2**2*s3*s5**2*s6**3 ++ 736*s1*s2**2*s4**5*s5*s6 - 676*s1*s2**2*s4**4*s5**3 + 131040*s1*s2**2*s4**2*s5*s6**3 ++ 16240*s1*s2**2*s4*s5**3*s6**2 - 20250*s1*s2**2*s5**5*s6 - 27*s1*s2*s3**6*s4*s5*s6 ++ 18*s1*s2*s3**6*s5**3 + 9*s1*s2*s3**5*s4**3*s6 - 9*s1*s2*s3**5*s4**2*s5**2 + 1944*s1*s2*s3**5*s6**3 ++ s1*s2*s3**4*s4**4*s5 + 6156*s1*s2*s3**4*s4*s5*s6**2 + 1143*s1*s2*s3**4*s5**3*s6 ++ 324*s1*s2*s3**3*s4**3*s6**2 + 1071*s1*s2*s3**3*s4**2*s5**2*s6 + 15*s1*s2*s3**3*s4*s5**4 +- 7776*s1*s2*s3**3*s6**4 - 2028*s1*s2*s3**2*s4**4*s5*s6 - 397*s1*s2*s3**2*s4**3*s5**3 ++ 112860*s1*s2*s3**2*s4*s5*s6**3 - 10305*s1*s2*s3**2*s5**3*s6**2 + 336*s1*s2*s3*s4**6*s6 ++ 304*s1*s2*s3*s4**5*s5**2 - 68976*s1*s2*s3*s4**3*s6**3 - 96732*s1*s2*s3*s4**2*s5**2*s6**2 ++ 36700*s1*s2*s3*s4*s5**4*s6 - 1250*s1*s2*s3*s5**6 - 1477440*s1*s2*s3*s6**5 - 48*s1*s2*s4**7*s5 ++ 4368*s1*s2*s4**4*s5*s6**2 + 10360*s1*s2*s4**3*s5**3*s6 - 3500*s1*s2*s4**2*s5**5 ++ 935280*s1*s2*s4*s5*s6**4 - 242100*s1*s2*s5**3*s6**3 - 972*s1*s3**6*s5*s6**2 - 351*s1*s3**5*s4*s5**2*s6 +- 99*s1*s3**5*s5**4 + 441*s1*s3**4*s4**3*s5*s6 + 141*s1*s3**4*s4**2*s5**3 - 36936*s1*s3**4*s5*s6**3 +- 84*s1*s3**3*s4**5*s6 - 76*s1*s3**3*s4**4*s5**2 + 17496*s1*s3**3*s4**2*s6**3 + 11718*s1*s3**3*s4*s5**2*s6**2 +- 6525*s1*s3**3*s5**4*s6 + 12*s1*s3**2*s4**6*s5 + 11016*s1*s3**2*s4**3*s5*s6**2 + +5895*s1*s3**2*s4**2*s5**3*s6 - 1750*s1*s3**2*s4*s5**5 - 252720*s1*s3**2*s5*s6**4 - +2544*s1*s3*s4**5*s6**2 - 8092*s1*s3*s4**4*s5**2*s6 + 2300*s1*s3*s4**3*s5**4 + 536544*s1*s3*s4**2*s6**4 ++ 169560*s1*s3*s4*s5**2*s6**3 - 103500*s1*s3*s5**4*s6**2 + 1680*s1*s4**6*s5*s6 - 468*s1*s4**5*s5**3 +- 346896*s1*s4**3*s5*s6**3 + 93900*s1*s4**2*s5**3*s6**2 + 35000*s1*s4*s5**5*s6 - 9375*s1*s5**7 ++ 108864*s1*s5*s6**5 + 16*s2**8*s4**2*s6**2 - 8*s2**8*s4*s5**2*s6 + s2**8*s5**4 - +8*s2**7*s3**2*s4*s6**2 + 2*s2**7*s3**2*s5**2*s6 - 96*s2**7*s4*s6**3 - 232*s2**7*s5**2*s6**2 ++ s2**6*s3**4*s6**2 + 24*s2**6*s3**2*s6**3 + 336*s2**6*s3*s4*s5*s6**2 + 108*s2**6*s3*s5**3*s6 +- 32*s2**6*s4**3*s6**2 - 160*s2**6*s4**2*s5**2*s6 + 38*s2**6*s4*s5**4 + 144*s2**6*s6**4 +- 84*s2**5*s3**3*s5*s6**2 + 8*s2**5*s3**2*s4**2*s6**2 - 106*s2**5*s3**2*s4*s5**2*s6 +- 12*s2**5*s3**2*s5**4 + 176*s2**5*s3*s4**3*s5*s6 - 36*s2**5*s3*s4**2*s5**3 - 2544*s2**5*s3*s5*s6**3 +- 32*s2**5*s4**5*s6 + 8*s2**5*s4**4*s5**2 - 3072*s2**5*s4**2*s6**3 + 3032*s2**5*s4*s5**2*s6**2 ++ 954*s2**5*s5**4*s6 + 36*s2**4*s3**4*s5**2*s6 - 80*s2**4*s3**3*s4**2*s5*s6 + 25*s2**4*s3**3*s4*s5**3 ++ 16*s2**4*s3**2*s4**4*s6 - 6*s2**4*s3**2*s4**3*s5**2 + 2520*s2**4*s3**2*s4*s6**3 ++ 222*s2**4*s3**2*s5**2*s6**2 - 1312*s2**4*s3*s4**2*s5*s6**2 - 3616*s2**4*s3*s4*s5**3*s6 +- 125*s2**4*s3*s5**5 + 1296*s2**4*s4**4*s6**2 - 168*s2**4*s4**3*s5**2*s6 + 375*s2**4*s4**2*s5**4 ++ 19296*s2**4*s4*s6**4 + 48408*s2**4*s5**2*s6**3 + 9*s2**3*s3**5*s4*s5*s6 - 4*s2**3*s3**5*s5**3 +- 2*s2**3*s3**4*s4**3*s6 + s2**3*s3**4*s4**2*s5**2 - 432*s2**3*s3**4*s6**3 + 324*s2**3*s3**3*s4*s5*s6**2 ++ 923*s2**3*s3**3*s5**3*s6 - 752*s2**3*s3**2*s4**3*s6**2 + 2262*s2**3*s3**2*s4**2*s5**2*s6 ++ 525*s2**3*s3**2*s4*s5**4 - 9936*s2**3*s3**2*s6**4 - 480*s2**3*s3*s4**4*s5*s6 - 700*s2**3*s3*s4**3*s5**3 +- 68976*s2**3*s3*s4*s5*s6**3 - 11360*s2**3*s3*s5**3*s6**2 - 32*s2**3*s4**6*s6 + 152*s2**3*s4**5*s5**2 ++ 6912*s2**3*s4**3*s6**3 - 7992*s2**3*s4**2*s5**2*s6**2 + 5550*s2**3*s4*s5**4*s6 - +29376*s2**3*s6**5 + 108*s2**2*s3**4*s4**2*s6**2 - 1215*s2**2*s3**4*s4*s5**2*s6 - 150*s2**2*s3**4*s5**4 ++ 336*s2**2*s3**3*s4**3*s5*s6 - 185*s2**2*s3**3*s4**2*s5**3 + 17496*s2**2*s3**3*s5*s6**3 ++ 8*s2**2*s3**2*s4**5*s6 + 370*s2**2*s3**2*s4**4*s5**2 - 864*s2**2*s3**2*s4**2*s6**3 ++ 22572*s2**2*s3**2*s4*s5**2*s6**2 + 225*s2**2*s3**2*s5**4*s6 - 144*s2**2*s3*s4**6*s5 ++ 14784*s2**2*s3*s4**3*s5*s6**2 - 12020*s2**2*s3*s4**2*s5**3*s6 + 625*s2**2*s3*s4*s5**5 ++ 536544*s2**2*s3*s5*s6**4 + 16*s2**2*s4**8 - 3072*s2**2*s4**5*s6**2 + 1096*s2**2*s4**4*s5**2*s6 ++ 250*s2**2*s4**3*s5**4 - 93744*s2**2*s4**2*s6**4 - 249480*s2**2*s4*s5**2*s6**3 + +70125*s2**2*s5**4*s6**2 + 162*s2*s3**6*s5**2*s6 - 54*s2*s3**5*s4**2*s5*s6 + 198*s2*s3**5*s4*s5**3 +- 210*s2*s3**4*s4**3*s5**2 - 3564*s2*s3**4*s5**2*s6**2 + 72*s2*s3**3*s4**5*s5 - 12204*s2*s3**3*s4**2*s5*s6**2 ++ 1935*s2*s3**3*s4*s5**3*s6 - 8*s2*s3**2*s4**7 + 2520*s2*s3**2*s4**4*s6**2 + 1962*s2*s3**2*s4**3*s5**2*s6 +- 125*s2*s3**2*s4**2*s5**4 - 178848*s2*s3**2*s4*s6**4 - 165240*s2*s3**2*s5**2*s6**3 +- 144*s2*s3*s4**5*s5*s6 - 200*s2*s3*s4**4*s5**3 + 139104*s2*s3*s4**2*s5*s6**3 + 72900*s2*s3*s4*s5**3*s6**2 +- 20625*s2*s3*s5**5*s6 - 96*s2*s4**7*s6 + 56*s2*s4**6*s5**2 + 19296*s2*s4**4*s6**3 +- 22080*s2*s4**3*s5**2*s6**2 - 7750*s2*s4**2*s5**4*s6 + 3125*s2*s4*s5**6 + 248832*s2*s4*s6**5 +- 129600*s2*s5**2*s6**4 - 27*s3**7*s5**3 + 27*s3**6*s4**2*s5**2 - 9*s3**5*s4**4*s5 ++ 1944*s3**5*s4*s5*s6**2 + 54*s3**5*s5**3*s6 + s3**4*s4**6 - 432*s3**4*s4**3*s6**2 +- 486*s3**4*s4**2*s5**2*s6 + 46656*s3**4*s6**4 + 36*s3**3*s4**4*s5*s6 + 50*s3**3*s4**3*s5**3 +- 7776*s3**3*s4*s5*s6**3 + 29700*s3**3*s5**3*s6**2 + 24*s3**2*s4**6*s6 - 14*s3**2*s4**5*s5**2 +- 9936*s3**2*s4**3*s6**3 - 29160*s3**2*s4**2*s5**2*s6**2 - 10125*s3**2*s4*s5**4*s6 ++ 3125*s3**2*s5**6 + 1026432*s3**2*s6**5 + 6336*s3*s4**4*s5*s6**2 + 11700*s3*s4**3*s5**3*s6 +- 3125*s3*s4**2*s5**5 - 1477440*s3*s4*s5*s6**4 + 432000*s3*s5**3*s6**3 + 144*s4**6*s6**2 +- 2472*s4**5*s5**2*s6 + 625*s4**4*s5**4 - 29376*s4**3*s6**4 + 529200*s4**2*s5**2*s6**3 +- 292500*s4*s5**4*s6**2 + 40625*s5**6*s6 - 186624*s6**6) + ], + (6, 2): [ + lambda s1, s2, s3, s4, s5, s6: (-s3), + lambda s1, s2, s3, s4, s5, s6: (-s1*s5 + s2*s4 - 9*s6), + lambda s1, s2, s3, s4, s5, s6: (s1*s2*s6 + 2*s1*s3*s5 - s1*s4**2 - s2**2*s5 + 6*s3*s6 + s4*s5), + lambda s1, s2, s3, s4, s5, s6: (s1**2*s4*s6 - s1**2*s5**2 - 3*s1*s2*s3*s6 + s1*s2*s4*s5 + 9*s1*s5*s6 + s2**3*s6 - +9*s2*s4*s6 + s2*s5**2 + 3*s3**2*s6 - 3*s3*s4*s5 + s4**3 + 27*s6**2), + lambda s1, s2, s3, s4, s5, s6: (-2*s1**3*s6**2 + 2*s1**2*s2*s5*s6 + 2*s1**2*s3*s4*s6 - s1**2*s3*s5**2 - s1*s2**2*s4*s6 +- 3*s1*s2*s6**2 - 16*s1*s3*s5*s6 + 4*s1*s4**2*s6 + 2*s1*s4*s5**2 + 4*s2**2*s5*s6 + +s2*s3*s4*s6 + 2*s2*s3*s5**2 - s2*s4**2*s5 - 9*s3*s6**2 - 3*s4*s5*s6 - 2*s5**3), + lambda s1, s2, s3, s4, s5, s6: (s1**3*s3*s6**2 - 3*s1**3*s4*s5*s6 + s1**3*s5**3 - s1**2*s2**2*s6**2 + s1**2*s2*s3*s5*s6 +- 2*s1**2*s4*s6**2 + 6*s1**2*s5**2*s6 + 16*s1*s2*s3*s6**2 - 3*s1*s2*s5**3 - s1*s3**2*s5*s6 +- 2*s1*s3*s4**2*s6 + s1*s3*s4*s5**2 - 30*s1*s5*s6**2 - 4*s2**3*s6**2 - 2*s2**2*s3*s5*s6 ++ s2**2*s4**2*s6 + 18*s2*s4*s6**2 - 2*s2*s5**2*s6 - 15*s3**2*s6**2 + 16*s3*s4*s5*s6 ++ s3*s5**3 - 4*s4**3*s6 - s4**2*s5**2 - 27*s6**3), + lambda s1, s2, s3, s4, s5, s6: (s1**4*s5*s6**2 + 2*s1**3*s2*s4*s6**2 - s1**3*s2*s5**2*s6 - s1**3*s3**2*s6**2 + 9*s1**3*s6**3 +- 14*s1**2*s2*s5*s6**2 - 11*s1**2*s3*s4*s6**2 + 6*s1**2*s3*s5**2*s6 + 3*s1**2*s4**2*s5*s6 +- s1**2*s4*s5**3 + 3*s1*s2**2*s5**2*s6 + 3*s1*s2*s3**2*s6**2 - s1*s2*s3*s4*s5*s6 + +39*s1*s3*s5*s6**2 - 14*s1*s4*s5**2*s6 + s1*s5**4 - 11*s2*s3*s5**2*s6 + 2*s2*s4*s5**3 +- 3*s3**3*s6**2 + 3*s3**2*s4*s5*s6 - s3**2*s5**3 + 9*s5**3*s6), + lambda s1, s2, s3, s4, s5, s6: (-s1**4*s2*s6**3 + s1**4*s3*s5*s6**2 - 4*s1**3*s3*s6**3 + 10*s1**3*s4*s5*s6**2 - 4*s1**3*s5**3*s6 ++ 8*s1**2*s2**2*s6**3 - 8*s1**2*s2*s3*s5*s6**2 - 2*s1**2*s2*s4**2*s6**2 + s1**2*s2*s4*s5**2*s6 ++ s1**2*s3**2*s4*s6**2 - 6*s1**2*s4*s6**3 - 7*s1**2*s5**2*s6**2 - 24*s1*s2*s3*s6**3 +- 4*s1*s2*s4*s5*s6**2 + 10*s1*s2*s5**3*s6 + 8*s1*s3**2*s5*s6**2 + 8*s1*s3*s4**2*s6**2 +- 8*s1*s3*s4*s5**2*s6 + s1*s3*s5**4 + 36*s1*s5*s6**3 + 8*s2**2*s3*s5*s6**2 - 2*s2**2*s4*s5**2*s6 +- 2*s2*s3**2*s4*s6**2 + s2*s3**2*s5**2*s6 - 6*s2*s5**2*s6**2 + 18*s3**2*s6**3 - 24*s3*s4*s5*s6**2 +- 4*s3*s5**3*s6 + 8*s4**2*s5**2*s6 - s4*s5**4), + lambda s1, s2, s3, s4, s5, s6: (-s1**5*s4*s6**3 - 2*s1**4*s5*s6**3 + 3*s1**3*s2*s5**2*s6**2 + 3*s1**3*s3**2*s6**3 +- s1**3*s3*s4*s5*s6**2 - 8*s1**3*s6**4 + 16*s1**2*s2*s5*s6**3 + 8*s1**2*s3*s4*s6**3 +- 6*s1**2*s3*s5**2*s6**2 - 8*s1**2*s4**2*s5*s6**2 + 3*s1**2*s4*s5**3*s6 - 8*s1*s2**2*s5**2*s6**2 +- 8*s1*s2*s3**2*s6**3 + 8*s1*s2*s3*s4*s5*s6**2 - s1*s2*s3*s5**3*s6 - s1*s3**3*s5*s6**2 +- 24*s1*s3*s5*s6**3 + 16*s1*s4*s5**2*s6**2 - 2*s1*s5**4*s6 + 8*s2*s3*s5**2*s6**2 - +s2*s5**5 + 8*s3**3*s6**3 - 8*s3**2*s4*s5*s6**2 + 3*s3**2*s5**3*s6 - 8*s5**3*s6**2), + lambda s1, s2, s3, s4, s5, s6: (s1**6*s6**4 - 4*s1**4*s2*s6**4 - 2*s1**4*s3*s5*s6**3 + s1**4*s4**2*s6**3 + 8*s1**3*s3*s6**4 +- 4*s1**3*s4*s5*s6**3 + 2*s1**3*s5**3*s6**2 + 8*s1**2*s2*s3*s5*s6**3 - 2*s1**2*s2*s4*s5**2*s6**2 +- 2*s1**2*s3**2*s4*s6**3 + s1**2*s3**2*s5**2*s6**2 - 4*s1*s2*s5**3*s6**2 - 12*s1*s3**2*s5*s6**3 ++ 8*s1*s3*s4*s5**2*s6**2 - 2*s1*s3*s5**4*s6 + s2**2*s5**4*s6 - 2*s2*s3**2*s5**2*s6**2 ++ s3**4*s6**3 + 8*s3*s5**3*s6**2 - 4*s4*s5**4*s6 + s5**6) + ], +} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/subfield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/subfield.py new file mode 100644 index 0000000000000000000000000000000000000000..c56d0662e4a38b4c0fcaa385c2e0166490354790 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/subfield.py @@ -0,0 +1,516 @@ +r""" +Functions in ``polys.numberfields.subfield`` solve the "Subfield Problem" and +allied problems, for algebraic number fields. + +Following Cohen (see [Cohen93]_ Section 4.5), we can define the main problem as +follows: + +* **Subfield Problem:** + + Given two number fields $\mathbb{Q}(\alpha)$, $\mathbb{Q}(\beta)$ + via the minimal polynomials for their generators $\alpha$ and $\beta$, decide + whether one field is isomorphic to a subfield of the other. + +From a solution to this problem flow solutions to the following problems as +well: + +* **Primitive Element Problem:** + + Given several algebraic numbers + $\alpha_1, \ldots, \alpha_m$, compute a single algebraic number $\theta$ + such that $\mathbb{Q}(\alpha_1, \ldots, \alpha_m) = \mathbb{Q}(\theta)$. + +* **Field Isomorphism Problem:** + + Decide whether two number fields + $\mathbb{Q}(\alpha)$, $\mathbb{Q}(\beta)$ are isomorphic. + +* **Field Membership Problem:** + + Given two algebraic numbers $\alpha$, + $\beta$, decide whether $\alpha \in \mathbb{Q}(\beta)$, and if so write + $\alpha = f(\beta)$ for some $f(x) \in \mathbb{Q}[x]$. +""" + +from sympy.core.add import Add +from sympy.core.numbers import AlgebraicNumber +from sympy.core.singleton import S +from sympy.core.symbol import Dummy +from sympy.core.sympify import sympify, _sympify +from sympy.ntheory import sieve +from sympy.polys.densetools import dup_eval +from sympy.polys.domains import QQ +from sympy.polys.numberfields.minpoly import _choose_factor, minimal_polynomial +from sympy.polys.polyerrors import IsomorphismFailed +from sympy.polys.polytools import Poly, PurePoly, factor_list +from sympy.utilities import public + +from mpmath import MPContext + + +def is_isomorphism_possible(a, b): + """Necessary but not sufficient test for isomorphism. """ + n = a.minpoly.degree() + m = b.minpoly.degree() + + if m % n != 0: + return False + + if n == m: + return True + + da = a.minpoly.discriminant() + db = b.minpoly.discriminant() + + i, k, half = 1, m//n, db//2 + + while True: + p = sieve[i] + P = p**k + + if P > half: + break + + if ((da % p) % 2) and not (db % P): + return False + + i += 1 + + 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: + raise NotImplementedError("PSLQ doesn't support complex coefficients") + + f = a.minpoly + g = b.minpoly.replace(f.gen) + + n, m, prev = 100, b.minpoly.degree(), None + ctx = MPContext() + + for i in range(1, 5): + A = a.root.evalf(n) + B = b.root.evalf(n) + + basis = [1, B] + [ B**i for i in range(2, m) ] + [-A] + + ctx.dps = n + coeffs = ctx.pslq(basis, maxcoeff=10**10, maxsteps=1000) + + if coeffs is None: + # PSLQ can't find an integer linear combination. Give up. + break + + if coeffs != prev: + prev = coeffs + else: + # Increasing precision didn't produce anything new. Give up. + break + + # We have + # c0 + c1*B + c2*B^2 + ... + cm-1*B^(m-1) - cm*A ~ 0. + # So bring cm*A to the other side, and divide through by cm, + # for an approximate representation of A as a polynomial in B. + # (We know cm != 0 since `b.minpoly` is irreducible.) + coeffs = [S(c)/coeffs[-1] for c in coeffs[:-1]] + + # Throw away leading zeros. + while not coeffs[-1]: + coeffs.pop() + + coeffs = list(reversed(coeffs)) + h = Poly(coeffs, f.gen, domain='QQ') + + # We only have A ~ h(B). We must check whether the relation is exact. + if f.compose(h).rem(g).is_zero: + # Now we know that h(b) is in fact equal to _some conjugate of_ a. + # But from the very precise approximation A ~ h(B) we can assume + # the conjugate is a itself. + return coeffs + else: + n *= 2 + + return None + + +def field_isomorphism_factor(a, b): + """Construct field isomorphism via factorization. """ + _, factors = factor_list(a.minpoly, extension=b) + for f, _ in factors: + if f.degree() == 1: + # Any linear factor f(x) represents some conjugate of a in QQ(b). + # We want to know whether this linear factor represents a itself. + # Let f = x - c + c = -f.rep.TC() + # Write c as polynomial in b + coeffs = c.to_sympy_list() + d, terms = len(coeffs) - 1, [] + for i, coeff in enumerate(coeffs): + terms.append(coeff*b.root**(d - i)) + r = Add(*terms) + # Check whether we got the number a + if a.minpoly.same_root(r, a): + return coeffs + + # If none of the linear factors represented a in QQ(b), then in fact a is + # not an element of QQ(b). + return None + + +@public +def field_isomorphism(a, b, *, fast=True): + r""" + Find an embedding of one number field into another. + + Explanation + =========== + + This function looks for an isomorphism from $\mathbb{Q}(a)$ onto some + subfield of $\mathbb{Q}(b)$. Thus, it solves the Subfield Problem. + + Examples + ======== + + >>> from sympy import sqrt, field_isomorphism, I + >>> print(field_isomorphism(3, sqrt(2))) # doctest: +SKIP + [3] + >>> print(field_isomorphism( I*sqrt(3), I*sqrt(3)/2)) # doctest: +SKIP + [2, 0] + + Parameters + ========== + + a : :py:class:`~.Expr` + Any expression representing an algebraic number. + b : :py:class:`~.Expr` + Any expression representing an algebraic number. + fast : boolean, optional (default=True) + If ``True``, we first attempt a potentially faster way of computing the + isomorphism, falling back on a slower method if this fails. If + ``False``, we go directly to the slower method, which is guaranteed to + return a result. + + Returns + ======= + + List of rational numbers, or None + If $\mathbb{Q}(a)$ is not isomorphic to some subfield of + $\mathbb{Q}(b)$, then return ``None``. Otherwise, return a list of + rational numbers representing an element of $\mathbb{Q}(b)$ to which + $a$ may be mapped, in order to define a monomorphism, i.e. an + isomorphism from $\mathbb{Q}(a)$ to some subfield of $\mathbb{Q}(b)$. + The elements of the list are the coefficients of falling powers of $b$. + + """ + a, b = sympify(a), sympify(b) + + if not a.is_AlgebraicNumber: + a = AlgebraicNumber(a) + + if not b.is_AlgebraicNumber: + b = AlgebraicNumber(b) + + a = a.to_primitive_element() + b = b.to_primitive_element() + + if a == b: + return a.coeffs() + + n = a.minpoly.degree() + m = b.minpoly.degree() + + if n == 1: + return [a.root] + + if m % n != 0: + return None + + if fast: + try: + result = field_isomorphism_pslq(a, b) + + if result is not None: + return result + except NotImplementedError: + pass + + return field_isomorphism_factor(a, b) + + +def _switch_domain(g, K): + # An algebraic relation f(a, b) = 0 over Q can also be written + # g(b) = 0 where g is in Q(a)[x] and h(a) = 0 where h is in Q(b)[x]. + # This function transforms g into h where Q(b) = K. + frep = g.rep.inject() + hrep = frep.eject(K, front=True) + + return g.new(hrep, g.gens[0]) + + +def _linsolve(p): + # Compute root of linear polynomial. + c, d = p.rep.to_list() + return -d/c + + +@public +def primitive_element(extension, x=None, *, ex=False, polys=False): + r""" + Find a single generator for a number field given by several generators. + + Explanation + =========== + + The basic problem is this: Given several algebraic numbers + $\alpha_1, \alpha_2, \ldots, \alpha_n$, find a single algebraic number + $\theta$ such that + $\mathbb{Q}(\alpha_1, \alpha_2, \ldots, \alpha_n) = \mathbb{Q}(\theta)$. + + This function actually guarantees that $\theta$ will be a linear + combination of the $\alpha_i$, with non-negative integer coefficients. + + Furthermore, if desired, this function will tell you how to express each + $\alpha_i$ as a $\mathbb{Q}$-linear combination of the powers of $\theta$. + + Examples + ======== + + >>> from sympy import primitive_element, sqrt, S, minpoly, simplify + >>> from sympy.abc import x + >>> f, lincomb, reps = primitive_element([sqrt(2), sqrt(3)], x, ex=True) + + Then ``lincomb`` tells us the primitive element as a linear combination of + the given generators ``sqrt(2)`` and ``sqrt(3)``. + + >>> print(lincomb) + [1, 1] + + This means the primtiive element is $\sqrt{2} + \sqrt{3}$. + Meanwhile ``f`` is the minimal polynomial for this primitive element. + + >>> print(f) + x**4 - 10*x**2 + 1 + >>> print(minpoly(sqrt(2) + sqrt(3), x)) + x**4 - 10*x**2 + 1 + + Finally, ``reps`` (which was returned only because we set keyword arg + ``ex=True``) tells us how to recover each of the generators $\sqrt{2}$ and + $\sqrt{3}$ as $\mathbb{Q}$-linear combinations of the powers of the + primitive element $\sqrt{2} + \sqrt{3}$. + + >>> print([S(r) for r in reps[0]]) + [1/2, 0, -9/2, 0] + >>> theta = sqrt(2) + sqrt(3) + >>> print(simplify(theta**3/2 - 9*theta/2)) + sqrt(2) + >>> print([S(r) for r in reps[1]]) + [-1/2, 0, 11/2, 0] + >>> print(simplify(-theta**3/2 + 11*theta/2)) + sqrt(3) + + Parameters + ========== + + extension : list of :py:class:`~.Expr` + Each expression must represent an algebraic number $\alpha_i$. + x : :py:class:`~.Symbol`, optional (default=None) + The desired symbol to appear in the computed minimal polynomial for the + primitive element $\theta$. If ``None``, we use a dummy symbol. + ex : boolean, optional (default=False) + If and only if ``True``, compute the representation of each $\alpha_i$ + as a $\mathbb{Q}$-linear combination over the powers of $\theta$. + polys : boolean, optional (default=False) + If ``True``, return the minimal polynomial as a :py:class:`~.Poly`. + Otherwise return it as an :py:class:`~.Expr`. + + Returns + ======= + + Pair (f, coeffs) or triple (f, coeffs, reps), where: + ``f`` is the minimal polynomial for the primitive element. + ``coeffs`` gives the primitive element as a linear combination of the + given generators. + ``reps`` is present if and only if argument ``ex=True`` was passed, + and is a list of lists of rational numbers. Each list gives the + coefficients of falling powers of the primitive element, to recover + one of the original, given generators. + + """ + if not extension: + raise ValueError("Cannot compute primitive element for empty extension") + extension = [_sympify(ext) for ext in extension] + + if x is not None: + x, cls = sympify(x), Poly + else: + x, cls = Dummy('x'), PurePoly + + def _canonicalize(f): + _, f = f.primitive() + if f.LC() < 0: + f = -f + return f + + if not ex: + gen, coeffs = extension[0], [1] + g = minimal_polynomial(gen, x, polys=True) + for ext in extension[1:]: + if ext.is_Rational: + coeffs.append(0) + continue + _, factors = factor_list(g, extension=ext) + g = _choose_factor(factors, x, gen) + [s], _, g = g.sqf_norm() + gen += s*ext + coeffs.append(s) + + g = _canonicalize(g) + if not polys: + return g.as_expr(), coeffs + else: + return cls(g), coeffs + + gen, coeffs = extension[0], [1] + f = minimal_polynomial(gen, x, polys=True) + K = QQ.algebraic_field((f, gen)) # incrementally constructed field + reps = [K.unit] # representations of extension elements in K + for ext in extension[1:]: + if ext.is_Rational: + coeffs.append(0) # rational ext is not included in the expression of a primitive element + reps.append(K.convert(ext)) # but it is included in reps + continue + p = minimal_polynomial(ext, x, polys=True) + L = QQ.algebraic_field((p, ext)) + _, factors = factor_list(f, domain=L) + f = _choose_factor(factors, x, gen) + [s], g, f = f.sqf_norm() + gen += s*ext + coeffs.append(s) + K = QQ.algebraic_field((f, gen)) + h = _switch_domain(g, K) + erep = _linsolve(h.gcd(p)) # ext as element of K + ogen = K.unit - s*erep # old gen as element of K + reps = [dup_eval(_.to_list(), ogen, K) for _ in reps] + [erep] + + if K.ext.root.is_Rational: # all extensions are rational + H = [K.convert(_).rep for _ in extension] + coeffs = [0]*len(extension) + f = cls(x, domain=QQ) + else: + H = [_.to_list() for _ in reps] + + f = _canonicalize(f) + if not polys: + return f.as_expr(), coeffs, H + else: + return f, coeffs, H + + +@public +def to_number_field(extension, theta=None, *, gen=None, alias=None): + r""" + Express one algebraic number in the field generated by another. + + Explanation + =========== + + Given two algebraic numbers $\eta, \theta$, this function either expresses + $\eta$ as an element of $\mathbb{Q}(\theta)$, or else raises an exception + if $\eta \not\in \mathbb{Q}(\theta)$. + + This function is essentially just a convenience, utilizing + :py:func:`~.field_isomorphism` (our solution of the Subfield Problem) to + solve this, the Field Membership Problem. + + As an additional convenience, this function allows you to pass a list of + algebraic numbers $\alpha_1, \alpha_2, \ldots, \alpha_n$ instead of $\eta$. + It then computes $\eta$ for you, as a solution of the Primitive Element + Problem, using :py:func:`~.primitive_element` on the list of $\alpha_i$. + + Examples + ======== + + >>> from sympy import sqrt, to_number_field + >>> eta = sqrt(2) + >>> theta = sqrt(2) + sqrt(3) + >>> a = to_number_field(eta, theta) + >>> print(type(a)) + + >>> a.root + sqrt(2) + sqrt(3) + >>> print(a) + sqrt(2) + >>> a.coeffs() + [1/2, 0, -9/2, 0] + + We get an :py:class:`~.AlgebraicNumber`, whose ``.root`` is $\theta$, whose + value is $\eta$, and whose ``.coeffs()`` show how to write $\eta$ as a + $\mathbb{Q}$-linear combination in falling powers of $\theta$. + + Parameters + ========== + + extension : :py:class:`~.Expr` or list of :py:class:`~.Expr` + Either the algebraic number that is to be expressed in the other field, + or else a list of algebraic numbers, a primitive element for which is + to be expressed in the other field. + theta : :py:class:`~.Expr`, None, optional (default=None) + If an :py:class:`~.Expr` representing an algebraic number, behavior is + as described under **Explanation**. If ``None``, then this function + reduces to a shorthand for calling :py:func:`~.primitive_element` on + ``extension`` and turning the computed primitive element into an + :py:class:`~.AlgebraicNumber`. + gen : :py:class:`~.Symbol`, None, optional (default=None) + If provided, this will be used as the generator symbol for the minimal + polynomial in the returned :py:class:`~.AlgebraicNumber`. + alias : str, :py:class:`~.Symbol`, None, optional (default=None) + If provided, this will be used as the alias symbol for the returned + :py:class:`~.AlgebraicNumber`. + + Returns + ======= + + AlgebraicNumber + Belonging to $\mathbb{Q}(\theta)$ and equaling $\eta$. + + Raises + ====== + + IsomorphismFailed + If $\eta \not\in \mathbb{Q}(\theta)$. + + See Also + ======== + + field_isomorphism + primitive_element + + """ + if hasattr(extension, '__iter__'): + extension = list(extension) + else: + extension = [extension] + + if len(extension) == 1 and isinstance(extension[0], tuple): + return AlgebraicNumber(extension[0], alias=alias) + + minpoly, coeffs = primitive_element(extension, gen, polys=True) + root = sum(coeff*ext for coeff, ext in zip(coeffs, extension)) + + if theta is None: + return AlgebraicNumber((minpoly, root), alias=alias) + else: + theta = sympify(theta) + + if not theta.is_AlgebraicNumber: + theta = AlgebraicNumber(theta, gen=gen, alias=alias) + + coeffs = field_isomorphism(root, theta) + + if coeffs is not None: + return AlgebraicNumber(theta, coeffs, alias=alias) + else: + raise IsomorphismFailed( + "%s is not in a subfield of %s" % (root, theta.root)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2f53fa49bb41a1a287d4b4d5b17217f43c3cc2ac Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_basis.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_basis.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb48368820b0f7f4faa71b60e779bd9523db6900 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_basis.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_galoisgroups.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_galoisgroups.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba754cec98495366adafbfcbcc5ec8b21c2d7cad Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_galoisgroups.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_minpoly.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_minpoly.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7dccc3254d7311add47d081745cf11e01b090b5a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_minpoly.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_modules.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_modules.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8d94d4c5b6f604d2e8a3612b4c85f623a2883a60 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_modules.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_numbers.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_numbers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..09a58c0344095c5afdeac350dc99767b513982e6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_numbers.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_primes.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_primes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9dfdca2116acc295eba37448500fefc0f0e39625 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_primes.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_subfield.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_subfield.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2253c544f2ff0227543700cc551d467ea6d74282 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_subfield.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_utilities.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_utilities.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b645f60235cb98e0d893b3037fc3b644ede6fe05 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/__pycache__/test_utilities.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_basis.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_basis.py new file mode 100644 index 0000000000000000000000000000000000000000..c0ed017936cc5c24da63ac02ceca0480f1945feb --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_basis.py @@ -0,0 +1,85 @@ +from sympy.abc import x +from sympy.core import S +from sympy.core.numbers import AlgebraicNumber +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.polys import Poly, cyclotomic_poly +from sympy.polys.domains import QQ +from sympy.polys.matrices import DomainMatrix, DM +from sympy.polys.numberfields.basis import round_two +from sympy.testing.pytest import raises + + +def test_round_two(): + # Poly must be irreducible, and over ZZ or QQ: + raises(ValueError, lambda: round_two(Poly(x ** 2 - 1))) + raises(ValueError, lambda: round_two(Poly(x ** 2 + sqrt(2)))) + + # Test on many fields: + cases = ( + # A couple of cyclotomic fields: + (cyclotomic_poly(5), DomainMatrix.eye(4, QQ), 125), + (cyclotomic_poly(7), DomainMatrix.eye(6, QQ), -16807), + # A couple of quadratic fields (one 1 mod 4, one 3 mod 4): + (x ** 2 - 5, DM([[1, (1, 2)], [0, (1, 2)]], QQ), 5), + (x ** 2 - 7, DM([[1, 0], [0, 1]], QQ), 28), + # Dedekind's example of a field with 2 as essential disc divisor: + (x ** 3 + x ** 2 - 2 * x + 8, DM([[1, 0, 0], [0, 1, 0], [0, (1, 2), (1, 2)]], QQ).transpose(), -503), + # A bunch of cubics with various forms for F -- all of these require + # second or third enlargements. (Five of them require a third, while the rest require just a second.) + # F = 2^2 + (x**3 + 3 * x**2 - 4 * x + 4, DM([((1, 2), (1, 4), (1, 4)), (0, (1, 2), (1, 2)), (0, 0, 1)], QQ).transpose(), -83), + # F = 2^2 * 3 + (x**3 + 3 * x**2 + 3 * x - 3, DM([((1, 2), 0, (1, 2)), (0, 1, 0), (0, 0, 1)], QQ).transpose(), -108), + # F = 2^3 + (x**3 + 5 * x**2 - x + 3, DM([((1, 4), 0, (3, 4)), (0, (1, 2), (1, 2)), (0, 0, 1)], QQ).transpose(), -31), + # F = 2^2 * 5 + (x**3 + 5 * x**2 - 5 * x - 5, DM([((1, 2), 0, (1, 2)), (0, 1, 0), (0, 0, 1)], QQ).transpose(), 1300), + # F = 3^2 + (x**3 + 3 * x**2 + 5, DM([((1, 3), (1, 3), (1, 3)), (0, 1, 0), (0, 0, 1)], QQ).transpose(), -135), + # F = 3^3 + (x**3 + 6 * x**2 + 3 * x - 1, DM([((1, 3), (1, 3), (1, 3)), (0, 1, 0), (0, 0, 1)], QQ).transpose(), 81), + # F = 2^2 * 3^2 + (x**3 + 6 * x**2 + 4, DM([((1, 3), (2, 3), (1, 3)), (0, 1, 0), (0, 0, (1, 2))], QQ).transpose(), -108), + # F = 2^3 * 7 + (x**3 + 7 * x**2 + 7 * x - 7, DM([((1, 4), 0, (3, 4)), (0, (1, 2), (1, 2)), (0, 0, 1)], QQ).transpose(), 49), + # F = 2^2 * 13 + (x**3 + 7 * x**2 - x + 5, DM([((1, 2), 0, (1, 2)), (0, 1, 0), (0, 0, 1)], QQ).transpose(), -2028), + # F = 2^4 + (x**3 + 7 * x**2 - 5 * x + 5, DM([((1, 4), 0, (3, 4)), (0, (1, 2), (1, 2)), (0, 0, 1)], QQ).transpose(), -140), + # F = 5^2 + (x**3 + 4 * x**2 - 3 * x + 7, DM([((1, 5), (4, 5), (4, 5)), (0, 1, 0), (0, 0, 1)], QQ).transpose(), -175), + # F = 7^2 + (x**3 + 8 * x**2 + 5 * x - 1, DM([((1, 7), (6, 7), (2, 7)), (0, 1, 0), (0, 0, 1)], QQ).transpose(), 49), + # F = 2 * 5 * 7 + (x**3 + 8 * x**2 - 2 * x + 6, DM([(1, 0, 0), (0, 1, 0), (0, 0, 1)], QQ).transpose(), -14700), + # F = 2^2 * 3 * 5 + (x**3 + 6 * x**2 - 3 * x + 8, DM([(1, 0, 0), (0, (1, 4), (1, 4)), (0, 0, 1)], QQ).transpose(), -675), + # F = 2 * 3^2 * 7 + (x**3 + 9 * x**2 + 6 * x - 8, DM([(1, 0, 0), (0, (1, 2), (1, 2)), (0, 0, 1)], QQ).transpose(), 3969), + # F = 2^2 * 3^2 * 7 + (x**3 + 15 * x**2 - 9 * x + 13, DM([((1, 6), (1, 3), (1, 6)), (0, 1, 0), (0, 0, 1)], QQ).transpose(), -5292), + # Polynomial need not be monic + (5*x**3 + 5*x**2 - 10 * x + 40, DM([[1, 0, 0], [0, 1, 0], [0, (1, 2), (1, 2)]], QQ).transpose(), -503), + # Polynomial can have non-integer rational coeffs + (QQ(5, 3)*x**3 + QQ(5, 3)*x**2 - QQ(10, 3)*x + QQ(40, 3), DM([[1, 0, 0], [0, 1, 0], [0, (1, 2), (1, 2)]], QQ).transpose(), -503), + ) + for f, B_exp, d_exp in cases: + K = QQ.alg_field_from_poly(f) + B = K.maximal_order().QQ_matrix + d = K.discriminant() + assert d == d_exp + # The computed basis need not equal the expected one, but their quotient + # must be unimodular: + assert (B.inv()*B_exp).det()**2 == 1 + + +def test_AlgebraicField_integral_basis(): + alpha = AlgebraicNumber(sqrt(5), alias='alpha') + k = QQ.algebraic_field(alpha) + B0 = k.integral_basis() + B1 = k.integral_basis(fmt='sympy') + B2 = k.integral_basis(fmt='alg') + assert B0 == [k([1]), k([S.Half, S.Half])] + assert B1 == [1, S.Half + alpha/2] + assert B2 == [k.ext.field_element([1]), + k.ext.field_element([S.Half, S.Half])] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_galoisgroups.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_galoisgroups.py new file mode 100644 index 0000000000000000000000000000000000000000..e4cb3d51bcdfad7764b3f6f62dbd2049e466e9e1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_galoisgroups.py @@ -0,0 +1,143 @@ +"""Tests for computing Galois groups. """ + +from sympy.abc import x +from sympy.combinatorics.galois import ( + S1TransitiveSubgroups, S2TransitiveSubgroups, S3TransitiveSubgroups, + S4TransitiveSubgroups, S5TransitiveSubgroups, S6TransitiveSubgroups, +) +from sympy.polys.domains.rationalfield import QQ +from sympy.polys.numberfields.galoisgroups import ( + tschirnhausen_transformation, + galois_group, + _galois_group_degree_4_root_approx, + _galois_group_degree_5_hybrid, +) +from sympy.polys.numberfields.subfield import field_isomorphism +from sympy.polys.polytools import Poly +from sympy.testing.pytest import raises + + +def test_tschirnhausen_transformation(): + for T in [ + Poly(x**2 - 2), + Poly(x**2 + x + 1), + Poly(x**4 + 1), + Poly(x**4 - x**3 + x**2 - x + 1), + ]: + _, U = tschirnhausen_transformation(T) + assert U.degree() == T.degree() + assert U.is_monic + assert U.is_irreducible + K = QQ.alg_field_from_poly(T) + L = QQ.alg_field_from_poly(U) + assert field_isomorphism(K.ext, L.ext) is not None + + +# Test polys are from: +# Cohen, H. *A Course in Computational Algebraic Number Theory*. +test_polys_by_deg = { + # Degree 1 + 1: [ + (x, S1TransitiveSubgroups.S1, True) + ], + # Degree 2 + 2: [ + (x**2 + x + 1, S2TransitiveSubgroups.S2, False) + ], + # Degree 3 + 3: [ + (x**3 + x**2 - 2*x - 1, S3TransitiveSubgroups.A3, True), + (x**3 + 2, S3TransitiveSubgroups.S3, False), + ], + # Degree 4 + 4: [ + (x**4 + x**3 + x**2 + x + 1, S4TransitiveSubgroups.C4, False), + (x**4 + 1, S4TransitiveSubgroups.V, True), + (x**4 - 2, S4TransitiveSubgroups.D4, False), + (x**4 + 8*x + 12, S4TransitiveSubgroups.A4, True), + (x**4 + x + 1, S4TransitiveSubgroups.S4, False), + ], + # Degree 5 + 5: [ + (x**5 + x**4 - 4*x**3 - 3*x**2 + 3*x + 1, S5TransitiveSubgroups.C5, True), + (x**5 - 5*x + 12, S5TransitiveSubgroups.D5, True), + (x**5 + 2, S5TransitiveSubgroups.M20, False), + (x**5 + 20*x + 16, S5TransitiveSubgroups.A5, True), + (x**5 - x + 1, S5TransitiveSubgroups.S5, False), + ], + # Degree 6 + 6: [ + (x**6 + x**5 + x**4 + x**3 + x**2 + x + 1, S6TransitiveSubgroups.C6, False), + (x**6 + 108, S6TransitiveSubgroups.S3, False), + (x**6 + 2, S6TransitiveSubgroups.D6, False), + (x**6 - 3*x**2 - 1, S6TransitiveSubgroups.A4, True), + (x**6 + 3*x**3 + 3, S6TransitiveSubgroups.G18, False), + (x**6 - 3*x**2 + 1, S6TransitiveSubgroups.A4xC2, False), + (x**6 - 4*x**2 - 1, S6TransitiveSubgroups.S4p, True), + (x**6 - 3*x**5 + 6*x**4 - 7*x**3 + 2*x**2 + x - 4, S6TransitiveSubgroups.S4m, False), + (x**6 + 2*x**3 - 2, S6TransitiveSubgroups.G36m, False), + (x**6 + 2*x**2 + 2, S6TransitiveSubgroups.S4xC2, False), + (x**6 + 10*x**5 + 55*x**4 + 140*x**3 + 175*x**2 + 170*x + 25, S6TransitiveSubgroups.PSL2F5, True), + (x**6 + 10*x**5 + 55*x**4 + 140*x**3 + 175*x**2 - 3019*x + 25, S6TransitiveSubgroups.PGL2F5, False), + (x**6 + 6*x**4 + 2*x**3 + 9*x**2 + 6*x - 4, S6TransitiveSubgroups.G36p, True), + (x**6 + 2*x**4 + 2*x**3 + x**2 + 2*x + 2, S6TransitiveSubgroups.G72, False), + (x**6 + 24*x - 20, S6TransitiveSubgroups.A6, True), + (x**6 + x + 1, S6TransitiveSubgroups.S6, False), + ], +} + + +def test_galois_group(): + """ + Try all the test polys. + """ + for deg in range(1, 7): + polys = test_polys_by_deg[deg] + for T, G, alt in polys: + assert galois_group(T, by_name=True) == (G, alt) + + +def test_galois_group_degree_out_of_bounds(): + raises(ValueError, lambda: galois_group(Poly(0, x))) + raises(ValueError, lambda: galois_group(Poly(1, x))) + raises(ValueError, lambda: galois_group(Poly(x ** 7 + 1))) + + +def test_galois_group_not_by_name(): + """ + Check at least one polynomial of each supported degree, to see that + conversion from name to group works. + """ + for deg in range(1, 7): + T, G_name, _ = test_polys_by_deg[deg][0] + G, _ = galois_group(T) + assert G == G_name.get_perm_group() + + +def test_galois_group_not_monic_over_ZZ(): + """ + Check that we can work with polys that are not monic over ZZ. + """ + for deg in range(1, 7): + T, G, alt = test_polys_by_deg[deg][0] + assert galois_group(T/2, by_name=True) == (G, alt) + + +def test__galois_group_degree_4_root_approx(): + for T, G, alt in test_polys_by_deg[4]: + assert _galois_group_degree_4_root_approx(Poly(T)) == (G, alt) + + +def test__galois_group_degree_5_hybrid(): + for T, G, alt in test_polys_by_deg[5]: + assert _galois_group_degree_5_hybrid(Poly(T)) == (G, alt) + + +def test_AlgebraicField_galois_group(): + k = QQ.alg_field_from_poly(Poly(x**4 + 1)) + G, _ = k.galois_group(by_name=True) + assert G == S4TransitiveSubgroups.V + + k = QQ.alg_field_from_poly(Poly(x**4 - 2)) + G, _ = k.galois_group(by_name=True) + assert G == S4TransitiveSubgroups.D4 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_minpoly.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_minpoly.py new file mode 100644 index 0000000000000000000000000000000000000000..792e5ad6e136bb00abda0b0739b2fff4fd41937b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_minpoly.py @@ -0,0 +1,490 @@ +"""Tests for minimal polynomials. """ + +from sympy.core.function import expand +from sympy.core import (GoldenRatio, TribonacciConstant) +from sympy.core.numbers import (AlgebraicNumber, I, Rational, oo, pi) +from sympy.core.power import Pow +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import (cbrt, sqrt) +from sympy.functions.elementary.trigonometric import (cos, sin, tan) +from sympy.ntheory.generate import nextprime +from sympy.polys.polytools import Poly +from sympy.polys.rootoftools import CRootOf +from sympy.solvers.solveset import nonlinsolve +from sympy.geometry import Circle, intersection +from sympy.testing.pytest import raises, slow +from sympy.sets.sets import FiniteSet +from sympy.geometry.point import Point2D +from sympy.polys.numberfields.minpoly import ( + minimal_polynomial, + _choose_factor, + _minpoly_op_algebraic_element, + _separate_sq, + _minpoly_groebner, +) +from sympy.polys.partfrac import apart +from sympy.polys.polyerrors import ( + NotAlgebraic, + GeneratorsError, +) + +from sympy.polys.domains import QQ +from sympy.polys.rootoftools import rootof +from sympy.polys.polytools import degree + +from sympy.abc import x, y, z + +Q = Rational + + +def test_minimal_polynomial(): + assert minimal_polynomial(-7, x) == x + 7 + assert minimal_polynomial(-1, x) == x + 1 + assert minimal_polynomial( 0, x) == x + assert minimal_polynomial( 1, x) == x - 1 + assert minimal_polynomial( 7, x) == x - 7 + + assert minimal_polynomial(sqrt(2), x) == x**2 - 2 + assert minimal_polynomial(sqrt(5), x) == x**2 - 5 + assert minimal_polynomial(sqrt(6), x) == x**2 - 6 + + assert minimal_polynomial(2*sqrt(2), x) == x**2 - 8 + 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(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(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(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 + + 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 + + raises(NotAlgebraic, lambda: minimal_polynomial(oo, x)) + raises(NotAlgebraic, lambda: minimal_polynomial(2**y, x)) + raises(NotAlgebraic, lambda: minimal_polynomial(sin(1), x)) + + assert minimal_polynomial(sqrt(2)).dummy_eq(x**2 - 2) + assert minimal_polynomial(sqrt(2), x) == x**2 - 2 + + assert minimal_polynomial(sqrt(2), polys=True) == Poly(x**2 - 2) + assert minimal_polynomial(sqrt(2), x, polys=True) == Poly(x**2 - 2, domain='QQ') + assert minimal_polynomial(sqrt(2), x, polys=True, compose=False) == Poly(x**2 - 2, domain='QQ') + + a = AlgebraicNumber(sqrt(2)) + b = AlgebraicNumber(sqrt(3)) + + assert minimal_polynomial(a, x) == x**2 - 2 + assert minimal_polynomial(b, x) == x**2 - 3 + + assert minimal_polynomial(a, x, polys=True) == Poly(x**2 - 2, domain='QQ') + assert minimal_polynomial(b, x, polys=True) == Poly(x**2 - 3, domain='QQ') + + 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 + + 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 + + # issue 5994 + 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 = (sqrt(5)*sqrt(I)/(5*sqrt(1 + 125*I)) + + 25*sqrt(5)/(I**Q(5,2)*(1 + 125*I)**Q(3,2)) + + 3125*sqrt(5)/(I**Q(11,2)*(1 + 125*I)**Q(3,2)) + + 5*I*sqrt(1 - I/125)) + mp = minimal_polynomial(ex, x) + assert mp == 25*x**4 + 5000*x**2 + 250016 + + 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 + + # minimal polynomial of I + assert minimal_polynomial(I, x, domain=QQ.algebraic_field(I)) == x - I + K = QQ.algebraic_field(I*(sqrt(2) + 1)) + assert minimal_polynomial(I, x, domain=K) == x - I + assert minimal_polynomial(I, x, domain=QQ) == x**2 + 1 + assert minimal_polynomial(I, x, domain='QQ(y)') == x**2 + 1 + + #issue 11553 + assert minimal_polynomial(GoldenRatio, x) == x**2 - x - 1 + assert minimal_polynomial(TribonacciConstant + 3, x) == x**3 - 10*x**2 + 32*x - 34 + assert minimal_polynomial(GoldenRatio, x, domain=QQ.algebraic_field(sqrt(5))) == \ + 2*x - sqrt(5) - 1 + assert minimal_polynomial(TribonacciConstant, x, domain=QQ.algebraic_field(cbrt(19 - 3*sqrt(33)))) == \ + 48*x - 19*(19 - 3*sqrt(33))**Rational(2, 3) - 3*sqrt(33)*(19 - 3*sqrt(33))**Rational(2, 3) \ + - 16*(19 - 3*sqrt(33))**Rational(1, 3) - 16 + + # AlgebraicNumber with an alias. + # Wester H24 + phi = AlgebraicNumber(S.GoldenRatio.expand(func=True), alias='phi') + assert minimal_polynomial(phi, x) == x**2 - x - 1 + + +def test_issue_26903(): + p1 = nextprime(10**16) # greater than 10**15 + p2 = nextprime(p1) + assert sqrt(p1**2*p2).is_Pow # square not extracted + zero = sqrt(p1**2*p2) - p1*sqrt(p2) + assert minimal_polynomial(zero, x) == x + assert minimal_polynomial(sqrt(2) - zero, x) == x**2 - 2 + + +def test_issue_8353(): + assert minimal_polynomial(exp(3*I*pi, evaluate=False), x) == x + 1 + assert minimal_polynomial(Pow(8, S(1)/3, evaluate=False), x + ) == x - 2 + + +def test_minimal_polynomial_issue_19732(): + # https://github.com/sympy/sympy/issues/19732 + expr = (-280898097948878450887044002323982963174671632174995451265117559518123750720061943079105185551006003416773064305074191140286225850817291393988597615/(-488144716373031204149459129212782509078221364279079444636386844223983756114492222145074506571622290776245390771587888364089507840000000*sqrt(238368341569)*sqrt(S(11918417078450)/63568729 + - 24411360*sqrt(238368341569)/63568729) + + 238326799225996604451373809274348704114327860564921529846705817404208077866956345381951726531296652901169111729944612727047670549086208000000*sqrt(S(11918417078450)/63568729 + - 24411360*sqrt(238368341569)/63568729)) - + 180561807339168676696180573852937120123827201075968945871075967679148461189459480842956689723484024031016208588658753107/(-59358007109636562851035004992802812513575019937126272896569856090962677491318275291141463850327474176000000*sqrt(238368341569)*sqrt(S(11918417078450)/63568729 + - 24411360*sqrt(238368341569)/63568729) + + 28980348180319251787320809875930301310576055074938369007463004788921613896002936637780993064387310446267596800000*sqrt(S(11918417078450)/63568729 + - 24411360*sqrt(238368341569)/63568729))) + poly = (2151288870990266634727173620565483054187142169311153766675688628985237817262915166497766867289157986631135400926544697981091151416655364879773546003475813114962656742744975460025956167152918469472166170500512008351638710934022160294849059721218824490226159355197136265032810944357335461128949781377875451881300105989490353140886315677977149440000000000000000000000*x**4 + - 5773274155644072033773937864114266313663195672820501581692669271302387257492905909558846459600429795784309388968498783843631580008547382703258503404023153694528041873101120067477617592651525155101107144042679962433039557235772239171616433004024998230222455940044709064078962397144550855715640331680262171410099614469231080995436488414164502751395405398078353242072696360734131090111239998110773292915337556205692674790561090109440000000000000*x**2 + + 211295968822207088328287206509522887719741955693091053353263782924470627623790749534705683380138972642560898936171035770539616881000369889020398551821767092685775598633794696371561234818461806577723412581353857653829324364446419444210520602157621008010129702779407422072249192199762604318993590841636967747488049176548615614290254356975376588506729604345612047361483789518445332415765213187893207704958013682516462853001964919444736320672860140355089) + assert minimal_polynomial(expr, x) == poly + + +def test_minimal_polynomial_hi_prec(): + p = 1/sqrt(1 - 9*sqrt(2) + 7*sqrt(3) + Rational(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.core.add import Add + from sympy.core.function import 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 6868 + 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 5888 + 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(I*pi*Rational(2, 7)), x) + assert mp == x**6 + x**5 + x**4 + x**3 + x**2 + x + 1 + mp = minimal_polynomial(exp(I*pi*Rational(2, 15)), x) + assert mp == x**8 - x**7 + x**5 - x**4 + x**3 - x + 1 + mp = minimal_polynomial(cos(pi*Rational(2, 7)), x) + assert mp == 8*x**3 + 4*x**2 - 4*x - 1 + mp = minimal_polynomial(sin(pi*Rational(2, 7)), x) + ex = (5*cos(pi*Rational(2, 7)) - 7)/(9*cos(pi/7) - 5*cos(pi*Rational(3, 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(pi*Rational(2, 15)), x) == \ + 256*x**8 - 448*x**6 + 224*x**4 - 32*x**2 + 1 + assert minimal_polynomial(sin(pi*Rational(5, 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 + + ex = rootof(x**3 +x*4 + 1, 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 + assert minimal_polynomial(sin(pi/21), x) == 4096*x**12 - 11264*x**10 + \ + 11264*x**8 - 4992*x**6 + 960*x**4 - 64*x**2 + 1 + assert minimal_polynomial(cos(pi/9), x) == 8*x**3 - 6*x - 1 + + ex = 2**Rational(1, 3)*exp(2*I*pi/3) + 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(1.618*I*pi), x)) + raises(NotAlgebraic, lambda: minimal_polynomial(exp(I*pi*sqrt(2)), x)) + + # issue 5934 + 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 + + ex = tan(pi/5, evaluate=False) + mp = minimal_polynomial(ex, x) + assert mp == x**4 - 10*x**2 + 5 + assert mp.subs(x, tan(pi/5)).is_zero + + ex = tan(pi/6, evaluate=False) + mp = minimal_polynomial(ex, x) + assert mp == 3*x**2 - 1 + assert mp.subs(x, tan(pi/6)).is_zero + + ex = tan(pi/10, evaluate=False) + mp = minimal_polynomial(ex, x) + assert mp == 5*x**4 - 10*x**2 + 1 + assert mp.subs(x, tan(pi/10)).is_zero + + raises(NotAlgebraic, lambda: minimal_polynomial(tan(pi*sqrt(2)), x)) + + +def test_minpoly_issue_7113(): + # see discussion in https://github.com/sympy/sympy/pull/2234 + from sympy.simplify.simplify import nsimplify + r = nsimplify(pi, tolerance=0.000000001) + mp = minimal_polynomial(r, x) + assert mp == 1768292677839237920489538677417507171630859375*x**109 - \ + 2734577732179183863586489182929671773182898498218854181690460140337930774573792597743853652058046464 + + +def test_minpoly_issue_23677(): + r1 = CRootOf(4000000*x**3 - 239960000*x**2 + 4782399900*x - 31663998001, 0) + r2 = CRootOf(4000000*x**3 - 239960000*x**2 + 4782399900*x - 31663998001, 1) + num = (7680000000000000000*r1**4*r2**4 - 614323200000000000000*r1**4*r2**3 + + 18458112576000000000000*r1**4*r2**2 - 246896663036160000000000*r1**4*r2 + + 1240473830323209600000000*r1**4 - 614323200000000000000*r1**3*r2**4 + - 1476464424954240000000000*r1**3*r2**2 - 99225501687553535904000000*r1**3 + + 18458112576000000000000*r1**2*r2**4 - 1476464424954240000000000*r1**2*r2**3 + - 593391458458356671712000000*r1**2*r2 + 2981354896834339226880720000*r1**2 + - 246896663036160000000000*r1*r2**4 - 593391458458356671712000000*r1*r2**2 + - 39878756418031796275267195200*r1 + 1240473830323209600000000*r2**4 + - 99225501687553535904000000*r2**3 + 2981354896834339226880720000*r2**2 - + 39878756418031796275267195200*r2 + 200361370275616536577343808012) + mp = (x**3 + 59426520028417434406408556687919*x**2 + + 1161475464966574421163316896737773190861975156439163671112508400*x + + 7467465541178623874454517208254940823818304424383315270991298807299003671748074773558707779600) + assert minimal_polynomial(num, x) == mp + + +def test_minpoly_issue_7574(): + ex = -(-1)**Rational(1, 3) + (-1)**Rational(2,3) + assert minimal_polynomial(ex, x) == x + 1 + + +def test_choose_factor(): + # Test that this does not enter an infinite loop: + bad_factors = [Poly(x-2, x), Poly(x+2, x)] + raises(NotImplementedError, lambda: _choose_factor(bad_factors, x, sqrt(3))) + + +def test_minpoly_fraction_field(): + assert minimal_polynomial(1/x, y) == -x*y + 1 + assert minimal_polynomial(1 / (x + 1), y) == (x + 1)*y - 1 + + assert minimal_polynomial(sqrt(x), y) == y**2 - x + assert minimal_polynomial(sqrt(x + 1), y) == y**2 - x - 1 + assert minimal_polynomial(sqrt(x) / x, y) == x*y**2 - 1 + assert minimal_polynomial(sqrt(2) * sqrt(x), y) == y**2 - 2 * x + assert minimal_polynomial(sqrt(2) + sqrt(x), y) == \ + y**4 + (-2*x - 4)*y**2 + x**2 - 4*x + 4 + + assert minimal_polynomial(x**Rational(1,3), y) == y**3 - x + assert minimal_polynomial(x**Rational(1,3) + sqrt(x), y) == \ + y**6 - 3*x*y**4 - 2*x*y**3 + 3*x**2*y**2 - 6*x**2*y - x**3 + x**2 + + assert minimal_polynomial(sqrt(x) / z, y) == z**2*y**2 - x + assert minimal_polynomial(sqrt(x) / (z + 1), y) == (z**2 + 2*z + 1)*y**2 - x + + assert minimal_polynomial(1/x, y, polys=True) == Poly(-x*y + 1, y, domain='ZZ(x)') + assert minimal_polynomial(1 / (x + 1), y, polys=True) == \ + Poly((x + 1)*y - 1, y, domain='ZZ(x)') + assert minimal_polynomial(sqrt(x), y, polys=True) == Poly(y**2 - x, y, domain='ZZ(x)') + assert minimal_polynomial(sqrt(x) / z, y, polys=True) == \ + Poly(z**2*y**2 - x, y, domain='ZZ(x, z)') + + # this is (sqrt(1 + x**3)/x).integrate(x).diff(x) - sqrt(1 + x**3)/x + a = sqrt(x)/sqrt(1 + x**(-3)) - sqrt(x**3 + 1)/x + 1/(x**Rational(5, 2)* \ + (1 + x**(-3))**Rational(3, 2)) + 1/(x**Rational(11, 2)*(1 + x**(-3))**Rational(3, 2)) + + assert minimal_polynomial(a, y) == y + + raises(NotAlgebraic, lambda: minimal_polynomial(exp(x), y)) + raises(GeneratorsError, lambda: minimal_polynomial(sqrt(x), x)) + raises(GeneratorsError, lambda: minimal_polynomial(sqrt(x) - y, x)) + raises(NotImplementedError, lambda: minimal_polynomial(sqrt(x), y, compose=False)) + +@slow +def test_minpoly_fraction_field_slow(): + assert minimal_polynomial(minimal_polynomial(sqrt(x**Rational(1,5) - 1), + y).subs(y, sqrt(x**Rational(1,5) - 1)), z) == z + +def test_minpoly_domain(): + assert minimal_polynomial(sqrt(2), x, domain=QQ.algebraic_field(sqrt(2))) == \ + x - sqrt(2) + assert minimal_polynomial(sqrt(8), x, domain=QQ.algebraic_field(sqrt(2))) == \ + x - 2*sqrt(2) + assert minimal_polynomial(sqrt(Rational(3,2)), x, + domain=QQ.algebraic_field(sqrt(2))) == 2*x**2 - 3 + + raises(NotAlgebraic, lambda: minimal_polynomial(y, x, domain=QQ)) + + +def test_issue_14831(): + a = -2*sqrt(2)*sqrt(12*sqrt(2) + 17) + assert minimal_polynomial(a, x) == x**2 + 16*x - 8 + e = (-3*sqrt(12*sqrt(2) + 17) + 12*sqrt(2) + + 17 - 2*sqrt(2)*sqrt(12*sqrt(2) + 17)) + assert minimal_polynomial(e, x) == x + + +def test_issue_18248(): + assert nonlinsolve([x*y**3-sqrt(2)/3, x*y**6-4/(9*(sqrt(3)))],x,y) == \ + FiniteSet((sqrt(3)/2, sqrt(6)/3), (sqrt(3)/2, -sqrt(6)/6 - sqrt(2)*I/2), + (sqrt(3)/2, -sqrt(6)/6 + sqrt(2)*I/2)) + + +def test_issue_13230(): + c1 = Circle(Point2D(3, sqrt(5)), 5) + c2 = Circle(Point2D(4, sqrt(7)), 6) + assert intersection(c1, c2) == [Point2D(-1 + (-sqrt(7) + sqrt(5))*(-2*sqrt(7)/29 + + 9*sqrt(5)/29 + sqrt(196*sqrt(35) + 1941)/29), -2*sqrt(7)/29 + 9*sqrt(5)/29 + + sqrt(196*sqrt(35) + 1941)/29), Point2D(-1 + (-sqrt(7) + sqrt(5))*(-sqrt(196*sqrt(35) + + 1941)/29 - 2*sqrt(7)/29 + 9*sqrt(5)/29), -sqrt(196*sqrt(35) + 1941)/29 - 2*sqrt(7)/29 + 9*sqrt(5)/29)] + +def test_issue_19760(): + e = 1/(sqrt(1 + sqrt(2)) - sqrt(2)*sqrt(1 + sqrt(2))) + 1 + mp_expected = x**4 - 4*x**3 + 4*x**2 - 2 + + for comp in (True, False): + mp = Poly(minimal_polynomial(e, compose=comp)) + assert mp(x) == mp_expected, "minimal_polynomial(e, compose=%s) = %s; %s expected" % (comp, mp(x), mp_expected) + + +def test_issue_20163(): + assert apart(1/(x**6+1), extension=[sqrt(3), I]) == \ + (sqrt(3) + I)/(2*x + sqrt(3) + I)/6 + \ + (sqrt(3) - I)/(2*x + sqrt(3) - I)/6 - \ + (sqrt(3) - I)/(2*x - sqrt(3) + I)/6 - \ + (sqrt(3) + I)/(2*x - sqrt(3) - I)/6 + \ + I/(x + I)/6 - I/(x - I)/6 + + +def test_issue_22559(): + alpha = AlgebraicNumber(sqrt(2)) + assert minimal_polynomial(alpha**3, x) == x**2 - 8 + + +def test_issue_22561(): + a = AlgebraicNumber(sqrt(2) + sqrt(3), [S(1) / 2, 0, S(-9) / 2, 0], gen=x) + assert a.as_expr() == sqrt(2) + assert minimal_polynomial(a, x) == x**2 - 2 + assert minimal_polynomial(a**3, x) == x**2 - 8 + + +def test_separate_sq_not_impl(): + raises(NotImplementedError, lambda: _separate_sq(x**(S(1)/3) + x)) + + +def test_minpoly_op_algebraic_element_not_impl(): + raises(NotImplementedError, + lambda: _minpoly_op_algebraic_element(Pow, sqrt(2), sqrt(3), x, QQ)) + + +def test_minpoly_groebner(): + assert _minpoly_groebner(S(2)/3, x, Poly) == 3*x - 2 + assert _minpoly_groebner( + (sqrt(2) + 3)*(sqrt(2) + 1), x, Poly) == x**2 - 10*x - 7 + assert _minpoly_groebner((sqrt(2) + 3)**(S(1)/3)*(sqrt(2) + 1)**(S(1)/3), + x, Poly) == x**6 - 10*x**3 - 7 + assert _minpoly_groebner((sqrt(2) + 3)**(-S(1)/3)*(sqrt(2) + 1)**(S(1)/3), + x, Poly) == 7*x**6 - 2*x**3 - 1 + raises(NotAlgebraic, lambda: _minpoly_groebner(pi**2, x, Poly)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_modules.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_modules.py new file mode 100644 index 0000000000000000000000000000000000000000..f3c61c98e33d3c78e79eeed45efcfa1f74478645 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_modules.py @@ -0,0 +1,752 @@ +from sympy.abc import x, zeta +from sympy.polys import Poly, cyclotomic_poly +from sympy.polys.domains import FF, QQ, ZZ +from sympy.polys.matrices import DomainMatrix, DM +from sympy.polys.numberfields.exceptions import ( + ClosureFailure, MissingUnityError, StructureError +) +from sympy.polys.numberfields.modules import ( + Module, ModuleElement, ModuleEndomorphism, PowerBasis, PowerBasisElement, + find_min_poly, is_sq_maxrank_HNF, make_mod_elt, to_col, +) +from sympy.polys.numberfields.utilities import is_int +from sympy.polys.polyerrors import UnificationFailed +from sympy.testing.pytest import raises + + +def test_to_col(): + c = [1, 2, 3, 4] + m = to_col(c) + assert m.domain.is_ZZ + assert m.shape == (4, 1) + assert m.flat() == c + + +def test_Module_NotImplemented(): + M = Module() + raises(NotImplementedError, lambda: M.n) + raises(NotImplementedError, lambda: M.mult_tab()) + raises(NotImplementedError, lambda: M.represent(None)) + raises(NotImplementedError, lambda: M.starts_with_unity()) + raises(NotImplementedError, lambda: M.element_from_rational(QQ(2, 3))) + + +def test_Module_ancestors(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + C = B.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) + D = B.submodule_from_matrix(5 * DomainMatrix.eye(4, ZZ)) + assert C.ancestors(include_self=True) == [A, B, C] + assert D.ancestors(include_self=True) == [A, B, D] + assert C.power_basis_ancestor() == A + assert C.nearest_common_ancestor(D) == B + M = Module() + assert M.power_basis_ancestor() is None + + +def test_Module_compat_col(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + col = to_col([1, 2, 3, 4]) + row = col.transpose() + assert A.is_compat_col(col) is True + assert A.is_compat_col(row) is False + assert A.is_compat_col(1) is False + assert A.is_compat_col(DomainMatrix.eye(3, ZZ)[:, 0]) is False + assert A.is_compat_col(DomainMatrix.eye(4, QQ)[:, 0]) is False + assert A.is_compat_col(DomainMatrix.eye(4, ZZ)[:, 0]) is True + + +def test_Module_call(): + T = Poly(cyclotomic_poly(5, x)) + B = PowerBasis(T) + assert B(0).col.flat() == [1, 0, 0, 0] + assert B(1).col.flat() == [0, 1, 0, 0] + col = DomainMatrix.eye(4, ZZ)[:, 2] + assert B(col).col == col + raises(ValueError, lambda: B(-1)) + + +def test_Module_starts_with_unity(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + assert A.starts_with_unity() is True + assert B.starts_with_unity() is False + + +def test_Module_basis_elements(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + basis = B.basis_elements() + bp = B.basis_element_pullbacks() + for i, (e, p) in enumerate(zip(basis, bp)): + c = [0] * 4 + assert e.module == B + assert p.module == A + c[i] = 1 + assert e == B(to_col(c)) + c[i] = 2 + assert p == A(to_col(c)) + + +def test_Module_zero(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + assert A.zero().col.flat() == [0, 0, 0, 0] + assert A.zero().module == A + assert B.zero().col.flat() == [0, 0, 0, 0] + assert B.zero().module == B + + +def test_Module_one(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + assert A.one().col.flat() == [1, 0, 0, 0] + assert A.one().module == A + assert B.one().col.flat() == [1, 0, 0, 0] + assert B.one().module == A + + +def test_Module_element_from_rational(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + rA = A.element_from_rational(QQ(22, 7)) + rB = B.element_from_rational(QQ(22, 7)) + assert rA.coeffs == [22, 0, 0, 0] + assert rA.denom == 7 + assert rA.module == A + assert rB.coeffs == [22, 0, 0, 0] + assert rB.denom == 7 + assert rB.module == A + + +def test_Module_submodule_from_gens(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + gens = [2*A(0), 2*A(1), 6*A(0), 6*A(1)] + B = A.submodule_from_gens(gens) + # Because the 3rd and 4th generators do not add anything new, we expect + # the cols of the matrix of B to just reproduce the first two gens: + M = gens[0].column().hstack(gens[1].column()) + assert B.matrix == M + # At least one generator must be provided: + raises(ValueError, lambda: A.submodule_from_gens([])) + # All generators must belong to A: + raises(ValueError, lambda: A.submodule_from_gens([3*A(0), B(0)])) + + +def test_Module_submodule_from_matrix(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + e = B(to_col([1, 2, 3, 4])) + f = e.to_parent() + assert f.col.flat() == [2, 4, 6, 8] + # Matrix must be over ZZ: + raises(ValueError, lambda: A.submodule_from_matrix(DomainMatrix.eye(4, QQ))) + # Number of rows of matrix must equal number of generators of module A: + raises(ValueError, lambda: A.submodule_from_matrix(2 * DomainMatrix.eye(5, ZZ))) + + +def test_Module_whole_submodule(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.whole_submodule() + e = B(to_col([1, 2, 3, 4])) + f = e.to_parent() + assert f.col.flat() == [1, 2, 3, 4] + e0, e1, e2, e3 = B(0), B(1), B(2), B(3) + assert e2 * e3 == e0 + assert e3 ** 2 == e1 + + +def test_PowerBasis_repr(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + assert repr(A) == 'PowerBasis(x**4 + x**3 + x**2 + x + 1)' + + +def test_PowerBasis_eq(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = PowerBasis(T) + assert A == B + + +def test_PowerBasis_mult_tab(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + M = A.mult_tab() + exp = {0: {0: [1, 0, 0, 0], 1: [0, 1, 0, 0], 2: [0, 0, 1, 0], 3: [0, 0, 0, 1]}, + 1: {1: [0, 0, 1, 0], 2: [0, 0, 0, 1], 3: [-1, -1, -1, -1]}, + 2: {2: [-1, -1, -1, -1], 3: [1, 0, 0, 0]}, + 3: {3: [0, 1, 0, 0]}} + # We get the table we expect: + assert M == exp + # And all entries are of expected type: + assert all(is_int(c) for u in M for v in M[u] for c in M[u][v]) + + +def test_PowerBasis_represent(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + col = to_col([1, 2, 3, 4]) + a = A(col) + assert A.represent(a) == col + b = A(col, denom=2) + raises(ClosureFailure, lambda: A.represent(b)) + + +def test_PowerBasis_element_from_poly(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + f = Poly(1 + 2*x) + g = Poly(x**4) + h = Poly(0, x) + assert A.element_from_poly(f).coeffs == [1, 2, 0, 0] + assert A.element_from_poly(g).coeffs == [-1, -1, -1, -1] + assert A.element_from_poly(h).coeffs == [0, 0, 0, 0] + + +def test_PowerBasis_element__conversions(): + k = QQ.cyclotomic_field(5) + L = QQ.cyclotomic_field(7) + B = PowerBasis(k) + + # ANP --> PowerBasisElement + a = k([QQ(1, 2), QQ(1, 3), 5, 7]) + e = B.element_from_ANP(a) + assert e.coeffs == [42, 30, 2, 3] + assert e.denom == 6 + + # PowerBasisElement --> ANP + assert e.to_ANP() == a + + # Cannot convert ANP from different field + d = L([QQ(1, 2), QQ(1, 3), 5, 7]) + raises(UnificationFailed, lambda: B.element_from_ANP(d)) + + # AlgebraicNumber --> PowerBasisElement + alpha = k.to_alg_num(a) + eps = B.element_from_alg_num(alpha) + assert eps.coeffs == [42, 30, 2, 3] + assert eps.denom == 6 + + # PowerBasisElement --> AlgebraicNumber + assert eps.to_alg_num() == alpha + + # Cannot convert AlgebraicNumber from different field + delta = L.to_alg_num(d) + raises(UnificationFailed, lambda: B.element_from_alg_num(delta)) + + # When we don't know the field: + C = PowerBasis(k.ext.minpoly) + # Can convert from AlgebraicNumber: + eps = C.element_from_alg_num(alpha) + assert eps.coeffs == [42, 30, 2, 3] + assert eps.denom == 6 + # But can't convert back: + raises(StructureError, lambda: eps.to_alg_num()) + + +def test_Submodule_repr(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ), denom=3) + assert repr(B) == 'Submodule[[2, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0], [0, 0, 0, 2]]/3' + + +def test_Submodule_reduced(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + C = A.submodule_from_matrix(6 * DomainMatrix.eye(4, ZZ), denom=3) + D = C.reduced() + assert D.denom == 1 and D == C == B + + +def test_Submodule_discard_before(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + B.compute_mult_tab() + C = B.discard_before(2) + assert C.parent == B.parent + assert B.is_sq_maxrank_HNF() and not C.is_sq_maxrank_HNF() + assert C.matrix == B.matrix[:, 2:] + assert C.mult_tab() == {0: {0: [-2, -2], 1: [0, 0]}, 1: {1: [0, 0]}} + + +def test_Submodule_QQ_matrix(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + C = A.submodule_from_matrix(6 * DomainMatrix.eye(4, ZZ), denom=3) + assert C.QQ_matrix == B.QQ_matrix + + +def test_Submodule_represent(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + C = B.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) + a0 = A(to_col([6, 12, 18, 24])) + a1 = A(to_col([2, 4, 6, 8])) + a2 = A(to_col([1, 3, 5, 7])) + + b1 = B.represent(a1) + assert b1.flat() == [1, 2, 3, 4] + + c0 = C.represent(a0) + assert c0.flat() == [1, 2, 3, 4] + + Y = A.submodule_from_matrix(DomainMatrix([ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + ], (3, 4), ZZ).transpose()) + + U = Poly(cyclotomic_poly(7, x)) + Z = PowerBasis(U) + z0 = Z(to_col([1, 2, 3, 4, 5, 6])) + + raises(ClosureFailure, lambda: Y.represent(A(3))) + raises(ClosureFailure, lambda: B.represent(a2)) + raises(ClosureFailure, lambda: B.represent(z0)) + + +def test_Submodule_is_compat_submodule(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) + D = C.submodule_from_matrix(5 * DomainMatrix.eye(4, ZZ)) + assert B.is_compat_submodule(C) is True + assert B.is_compat_submodule(A) is False + assert B.is_compat_submodule(D) is False + + +def test_Submodule_eq(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + C = A.submodule_from_matrix(6 * DomainMatrix.eye(4, ZZ), denom=3) + assert C == B + + +def test_Submodule_add(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(DomainMatrix([ + [4, 0, 0, 0], + [0, 4, 0, 0], + ], (2, 4), ZZ).transpose(), denom=6) + C = A.submodule_from_matrix(DomainMatrix([ + [0, 10, 0, 0], + [0, 0, 7, 0], + ], (2, 4), ZZ).transpose(), denom=15) + D = A.submodule_from_matrix(DomainMatrix([ + [20, 0, 0, 0], + [ 0, 20, 0, 0], + [ 0, 0, 14, 0], + ], (3, 4), ZZ).transpose(), denom=30) + assert B + C == D + + U = Poly(cyclotomic_poly(7, x)) + Z = PowerBasis(U) + Y = Z.submodule_from_gens([Z(0), Z(1)]) + raises(TypeError, lambda: B + Y) + + +def test_Submodule_mul(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + C = A.submodule_from_matrix(DomainMatrix([ + [0, 10, 0, 0], + [0, 0, 7, 0], + ], (2, 4), ZZ).transpose(), denom=15) + C1 = A.submodule_from_matrix(DomainMatrix([ + [0, 20, 0, 0], + [0, 0, 14, 0], + ], (2, 4), ZZ).transpose(), denom=3) + C2 = A.submodule_from_matrix(DomainMatrix([ + [0, 0, 10, 0], + [0, 0, 0, 7], + ], (2, 4), ZZ).transpose(), denom=15) + C3_unred = A.submodule_from_matrix(DomainMatrix([ + [0, 0, 100, 0], + [0, 0, 0, 70], + [0, 0, 0, 70], + [-49, -49, -49, -49] + ], (4, 4), ZZ).transpose(), denom=225) + C3 = A.submodule_from_matrix(DomainMatrix([ + [4900, 4900, 0, 0], + [4410, 4410, 10, 0], + [2107, 2107, 7, 7] + ], (3, 4), ZZ).transpose(), denom=225) + assert C * 1 == C + assert C ** 1 == C + assert C * 10 == C1 + assert C * A(1) == C2 + assert C.mul(C, hnf=False) == C3_unred + assert C * C == C3 + assert C ** 2 == C3 + + +def test_Submodule_reduce_element(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.whole_submodule() + b = B(to_col([90, 84, 80, 75]), denom=120) + + C = B.submodule_from_matrix(DomainMatrix.eye(4, ZZ), denom=2) + b_bar_expected = B(to_col([30, 24, 20, 15]), denom=120) + b_bar = C.reduce_element(b) + assert b_bar == b_bar_expected + + C = B.submodule_from_matrix(DomainMatrix.eye(4, ZZ), denom=4) + b_bar_expected = B(to_col([0, 24, 20, 15]), denom=120) + b_bar = C.reduce_element(b) + assert b_bar == b_bar_expected + + C = B.submodule_from_matrix(DomainMatrix.eye(4, ZZ), denom=8) + b_bar_expected = B(to_col([0, 9, 5, 0]), denom=120) + b_bar = C.reduce_element(b) + assert b_bar == b_bar_expected + + a = A(to_col([1, 2, 3, 4])) + raises(NotImplementedError, lambda: C.reduce_element(a)) + + C = B.submodule_from_matrix(DomainMatrix([ + [5, 4, 3, 2], + [0, 8, 7, 6], + [0, 0,11,12], + [0, 0, 0, 1] + ], (4, 4), ZZ).transpose()) + raises(StructureError, lambda: C.reduce_element(b)) + + +def test_is_HNF(): + M = DM([ + [3, 2, 1], + [0, 2, 1], + [0, 0, 1] + ], ZZ) + M1 = DM([ + [3, 2, 1], + [0, -2, 1], + [0, 0, 1] + ], ZZ) + M2 = DM([ + [3, 2, 3], + [0, 2, 1], + [0, 0, 1] + ], ZZ) + assert is_sq_maxrank_HNF(M) is True + assert is_sq_maxrank_HNF(M1) is False + assert is_sq_maxrank_HNF(M2) is False + + +def test_make_mod_elt(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + col = to_col([1, 2, 3, 4]) + eA = make_mod_elt(A, col) + eB = make_mod_elt(B, col) + assert isinstance(eA, PowerBasisElement) + assert not isinstance(eB, PowerBasisElement) + + +def test_ModuleElement_repr(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + e = A(to_col([1, 2, 3, 4]), denom=2) + assert repr(e) == '[1, 2, 3, 4]/2' + + +def test_ModuleElement_reduced(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + e = A(to_col([2, 4, 6, 8]), denom=2) + f = e.reduced() + assert f.denom == 1 and f == e + + +def test_ModuleElement_reduced_mod_p(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + e = A(to_col([20, 40, 60, 80])) + f = e.reduced_mod_p(7) + assert f.coeffs == [-1, -2, -3, 3] + + +def test_ModuleElement_from_int_list(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + c = [1, 2, 3, 4] + assert ModuleElement.from_int_list(A, c).coeffs == c + + +def test_ModuleElement_len(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + e = A(0) + assert len(e) == 4 + + +def test_ModuleElement_column(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + e = A(0) + col1 = e.column() + assert col1 == e.col and col1 is not e.col + col2 = e.column(domain=FF(5)) + assert col2.domain.is_FF + + +def test_ModuleElement_QQ_col(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + e = A(to_col([1, 2, 3, 4]), denom=1) + f = A(to_col([3, 6, 9, 12]), denom=3) + assert e.QQ_col == f.QQ_col + + +def test_ModuleElement_to_ancestors(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + C = B.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) + D = C.submodule_from_matrix(5 * DomainMatrix.eye(4, ZZ)) + eD = D(0) + eC = eD.to_parent() + eB = eD.to_ancestor(B) + eA = eD.over_power_basis() + assert eC.module is C and eC.coeffs == [5, 0, 0, 0] + assert eB.module is B and eB.coeffs == [15, 0, 0, 0] + assert eA.module is A and eA.coeffs == [30, 0, 0, 0] + + a = A(0) + raises(ValueError, lambda: a.to_parent()) + + +def test_ModuleElement_compatibility(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + C = B.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) + D = B.submodule_from_matrix(5 * DomainMatrix.eye(4, ZZ)) + assert C(0).is_compat(C(1)) is True + assert C(0).is_compat(D(0)) is False + u, v = C(0).unify(D(0)) + assert u.module is B and v.module is B + assert C(C.represent(u)) == C(0) and D(D.represent(v)) == D(0) + + u, v = C(0).unify(C(1)) + assert u == C(0) and v == C(1) + + U = Poly(cyclotomic_poly(7, x)) + Z = PowerBasis(U) + raises(UnificationFailed, lambda: C(0).unify(Z(1))) + + +def test_ModuleElement_eq(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + e = A(to_col([1, 2, 3, 4]), denom=1) + f = A(to_col([3, 6, 9, 12]), denom=3) + assert e == f + + U = Poly(cyclotomic_poly(7, x)) + Z = PowerBasis(U) + assert e != Z(0) + assert e != 3.14 + + +def test_ModuleElement_equiv(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + e = A(to_col([1, 2, 3, 4]), denom=1) + f = A(to_col([3, 6, 9, 12]), denom=3) + assert e.equiv(f) + + C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) + g = C(to_col([1, 2, 3, 4]), denom=1) + h = A(to_col([3, 6, 9, 12]), denom=1) + assert g.equiv(h) + assert C(to_col([5, 0, 0, 0]), denom=7).equiv(QQ(15, 7)) + + U = Poly(cyclotomic_poly(7, x)) + Z = PowerBasis(U) + raises(UnificationFailed, lambda: e.equiv(Z(0))) + + assert e.equiv(3.14) is False + + +def test_ModuleElement_add(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) + e = A(to_col([1, 2, 3, 4]), denom=6) + f = A(to_col([5, 6, 7, 8]), denom=10) + g = C(to_col([1, 1, 1, 1]), denom=2) + assert e + f == A(to_col([10, 14, 18, 22]), denom=15) + assert e - f == A(to_col([-5, -4, -3, -2]), denom=15) + assert e + g == A(to_col([10, 11, 12, 13]), denom=6) + assert e + QQ(7, 10) == A(to_col([26, 10, 15, 20]), denom=30) + assert g + QQ(7, 10) == A(to_col([22, 15, 15, 15]), denom=10) + + U = Poly(cyclotomic_poly(7, x)) + Z = PowerBasis(U) + raises(TypeError, lambda: e + Z(0)) + raises(TypeError, lambda: e + 3.14) + + +def test_ModuleElement_mul(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) + e = A(to_col([0, 2, 0, 0]), denom=3) + f = A(to_col([0, 0, 0, 7]), denom=5) + g = C(to_col([0, 0, 0, 1]), denom=2) + h = A(to_col([0, 0, 3, 1]), denom=7) + assert e * f == A(to_col([-14, -14, -14, -14]), denom=15) + assert e * g == A(to_col([-1, -1, -1, -1])) + assert e * h == A(to_col([-2, -2, -2, 4]), denom=21) + assert e * QQ(6, 5) == A(to_col([0, 4, 0, 0]), denom=5) + assert (g * QQ(10, 21)).equiv(A(to_col([0, 0, 0, 5]), denom=7)) + assert e // QQ(6, 5) == A(to_col([0, 5, 0, 0]), denom=9) + + U = Poly(cyclotomic_poly(7, x)) + Z = PowerBasis(U) + raises(TypeError, lambda: e * Z(0)) + raises(TypeError, lambda: e * 3.14) + raises(TypeError, lambda: e // 3.14) + raises(ZeroDivisionError, lambda: e // 0) + + +def test_ModuleElement_div(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) + e = A(to_col([0, 2, 0, 0]), denom=3) + f = A(to_col([0, 0, 0, 7]), denom=5) + g = C(to_col([1, 1, 1, 1])) + assert e // f == 10*A(3)//21 + assert e // g == -2*A(2)//9 + assert 3 // g == -A(1) + + +def test_ModuleElement_pow(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) + e = A(to_col([0, 2, 0, 0]), denom=3) + g = C(to_col([0, 0, 0, 1]), denom=2) + assert e ** 3 == A(to_col([0, 0, 0, 8]), denom=27) + assert g ** 2 == C(to_col([0, 3, 0, 0]), denom=4) + assert e ** 0 == A(to_col([1, 0, 0, 0])) + assert g ** 0 == A(to_col([1, 0, 0, 0])) + assert e ** 1 == e + assert g ** 1 == g + + +def test_ModuleElement_mod(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + e = A(to_col([1, 15, 8, 0]), denom=2) + assert e % 7 == A(to_col([1, 1, 8, 0]), denom=2) + assert e % QQ(1, 2) == A.zero() + assert e % QQ(1, 3) == A(to_col([1, 1, 0, 0]), denom=6) + + B = A.submodule_from_gens([A(0), 5*A(1), 3*A(2), A(3)]) + assert e % B == A(to_col([1, 5, 2, 0]), denom=2) + + C = B.whole_submodule() + raises(TypeError, lambda: e % C) + + +def test_PowerBasisElement_polys(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + e = A(to_col([1, 15, 8, 0]), denom=2) + assert e.numerator(x=zeta) == Poly(8 * zeta ** 2 + 15 * zeta + 1, domain=ZZ) + assert e.poly(x=zeta) == Poly(4 * zeta ** 2 + QQ(15, 2) * zeta + QQ(1, 2), domain=QQ) + + +def test_PowerBasisElement_norm(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + lam = A(to_col([1, -1, 0, 0])) + assert lam.norm() == 5 + + +def test_PowerBasisElement_inverse(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + e = A(to_col([1, 1, 1, 1])) + assert 2 // e == -2*A(1) + assert e ** -3 == -A(3) + + +def test_ModuleHomomorphism_matrix(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + phi = ModuleEndomorphism(A, lambda a: a ** 2) + M = phi.matrix() + assert M == DomainMatrix([ + [1, 0, -1, 0], + [0, 0, -1, 1], + [0, 1, -1, 0], + [0, 0, -1, 0] + ], (4, 4), ZZ) + + +def test_ModuleHomomorphism_kernel(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + phi = ModuleEndomorphism(A, lambda a: a ** 5) + N = phi.kernel() + assert N.n == 3 + + +def test_EndomorphismRing_represent(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + R = A.endomorphism_ring() + phi = R.inner_endomorphism(A(1)) + col = R.represent(phi) + assert col.transpose() == DomainMatrix([ + [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1] + ], (1, 16), ZZ) + + B = A.submodule_from_matrix(DomainMatrix.zeros((4, 0), ZZ)) + S = B.endomorphism_ring() + psi = S.inner_endomorphism(A(1)) + col = S.represent(psi) + assert col == DomainMatrix([], (0, 0), ZZ) + + raises(NotImplementedError, lambda: R.represent(3.14)) + + +def test_find_min_poly(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + powers = [] + m = find_min_poly(A(1), QQ, x=x, powers=powers) + assert m == Poly(T, domain=QQ) + assert len(powers) == 5 + + # powers list need not be passed + m = find_min_poly(A(1), QQ, x=x) + assert m == Poly(T, domain=QQ) + + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + raises(MissingUnityError, lambda: find_min_poly(B(1), QQ)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_numbers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_numbers.py new file mode 100644 index 0000000000000000000000000000000000000000..f8f350719cc740901a29d03e45ae9f3978446f31 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_numbers.py @@ -0,0 +1,202 @@ +"""Tests on algebraic numbers. """ + +from sympy.core.containers import Tuple +from sympy.core.numbers import (AlgebraicNumber, I, Rational) +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.polys.polytools import Poly +from sympy.polys.numberfields.subfield import to_number_field +from sympy.polys.polyclasses import DMP +from sympy.polys.domains import QQ +from sympy.polys.rootoftools import CRootOf +from sympy.abc import x, y + + +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.root == root + assert a.alias is None + assert a.minpoly == minpoly + assert a.is_number + + assert a.is_aliased is False + + assert a.coeffs() == [S.One, S.Zero] + 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.root == root + assert a.alias == Symbol('y') + assert a.minpoly == minpoly + assert a.is_number + + 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.root == root + assert a.alias == Symbol('y') + assert a.minpoly == minpoly + assert a.is_number + + assert a.is_aliased is True + + assert AlgebraicNumber(sqrt(2), []).rep == DMP([], QQ) + assert AlgebraicNumber(sqrt(2), ()).rep == DMP([], QQ) + assert AlgebraicNumber(sqrt(2), (0, 0)).rep == DMP([], QQ) + + assert AlgebraicNumber(sqrt(2), [8]).rep == DMP([QQ(8)], QQ) + assert AlgebraicNumber(sqrt(2), [Rational(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), [Rational(7, 9), Rational(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) + + a = AlgebraicNumber(AlgebraicNumber(root, gen=x), [1, 2]) + + 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_number + + assert a.is_aliased is False + + assert a.coeffs() == [S.One, S(2)] + assert a.native_coeffs() == [QQ(1), QQ(2)] + + a = AlgebraicNumber((minpoly, root), [1, 2]) + + 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_number + + assert a.is_aliased is False + + a = AlgebraicNumber((Poly(minpoly), root), [1, 2]) + + 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_number + + 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) + + a = AlgebraicNumber(sqrt(2)) + b = AlgebraicNumber(sqrt(2)) + + assert a == b + + c = AlgebraicNumber(sqrt(2), gen=x) + + assert a == b + assert a == c + + a = AlgebraicNumber(sqrt(2), [1, 2]) + b = AlgebraicNumber(sqrt(2), [1, 3]) + + assert a != b and a != sqrt(2) + 3 + + assert (a == x) is False and (a != x) is True + + a = AlgebraicNumber(sqrt(2), [1, 0]) + b = AlgebraicNumber(sqrt(2), [1, 0], alias=y) + + assert a.as_poly(x) == Poly(x, domain='QQ') + assert b.as_poly() == Poly(y, domain='QQ') + + assert a.as_expr() == sqrt(2) + assert a.as_expr(x) == x + 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) + + p = a.as_poly() + + assert p == Poly(2*p.gen + 3) + + assert a.as_poly(x) == Poly(2*x + 3, domain='QQ') + assert b.as_poly() == Poly(2*y + 3, domain='QQ') + + 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)) + assert a.args == b.args == (sqrt(2), Tuple(1, 0)) + b = AlgebraicNumber(sqrt(2), alias='alpha') + assert b.args == (sqrt(2), Tuple(1, 0), Symbol('alpha')) + + a = AlgebraicNumber(sqrt(2), [1, 2, 3]) + assert a.args == (sqrt(2), Tuple(1, 2, 3)) + + a = AlgebraicNumber(sqrt(2), [1, 2], "alpha") + b = AlgebraicNumber(a) + c = AlgebraicNumber(a, alias="gamma") + assert a == b + assert c.alias.name == "gamma" + + a = AlgebraicNumber(sqrt(2) + sqrt(3), [S(1)/2, 0, S(-9)/2, 0]) + b = AlgebraicNumber(a, [1, 0, 0]) + assert b.root == a.root + assert a.to_root() == sqrt(2) + assert b.to_root() == 2 + + a = AlgebraicNumber(2) + assert a.is_primitive_element is True + + +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) + + 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) + + 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) + + a = AlgebraicNumber(sqrt(3)/2, [Rational(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) + + +def test_AlgebraicNumber_to_root(): + assert AlgebraicNumber(sqrt(2)).to_root() == sqrt(2) + + zeta5_squared = AlgebraicNumber(CRootOf(x**5 - 1, 4), coeffs=[1, 0, 0]) + assert zeta5_squared.to_root() == CRootOf(x**4 + x**3 + x**2 + x + 1, 1) + + zeta3_squared = AlgebraicNumber(CRootOf(x**3 - 1, 2), coeffs=[1, 0, 0]) + assert zeta3_squared.to_root() == -S(1)/2 - sqrt(3)*I/2 + assert zeta3_squared.to_root(radicals=False) == CRootOf(x**2 + x + 1, 0) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_primes.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_primes.py new file mode 100644 index 0000000000000000000000000000000000000000..f121d60d272fe65345de773748828a8a67eb0028 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_primes.py @@ -0,0 +1,296 @@ +from math import prod + +from sympy import QQ, ZZ +from sympy.abc import x, theta +from sympy.ntheory import factorint +from sympy.ntheory.residue_ntheory import n_order +from sympy.polys import Poly, cyclotomic_poly +from sympy.polys.matrices import DomainMatrix +from sympy.polys.numberfields.basis import round_two +from sympy.polys.numberfields.exceptions import StructureError +from sympy.polys.numberfields.modules import PowerBasis, to_col +from sympy.polys.numberfields.primes import ( + prime_decomp, _two_elt_rep, + _check_formal_conditions_for_maximal_order, +) +from sympy.testing.pytest import raises + + +def test_check_formal_conditions_for_maximal_order(): + T = Poly(cyclotomic_poly(5, x)) + A = PowerBasis(T) + B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ)) + C = B.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ)) + D = A.submodule_from_matrix(DomainMatrix.eye(4, ZZ)[:, :-1]) + # Is a direct submodule of a power basis, but lacks 1 as first generator: + raises(StructureError, lambda: _check_formal_conditions_for_maximal_order(B)) + # Is not a direct submodule of a power basis: + raises(StructureError, lambda: _check_formal_conditions_for_maximal_order(C)) + # Is direct submod of pow basis, and starts with 1, but not sq/max rank/HNF: + raises(StructureError, lambda: _check_formal_conditions_for_maximal_order(D)) + + +def test_two_elt_rep(): + ell = 7 + T = Poly(cyclotomic_poly(ell)) + ZK, dK = round_two(T) + for p in [29, 13, 11, 5]: + P = prime_decomp(p, T) + for Pi in P: + # We have Pi in two-element representation, and, because we are + # looking at a cyclotomic field, this was computed by the "easy" + # method that just factors T mod p. We will now convert this to + # a set of Z-generators, then convert that back into a two-element + # rep. The latter need not be identical to the two-elt rep we + # already have, but it must have the same HNF. + H = p*ZK + Pi.alpha*ZK + gens = H.basis_element_pullbacks() + # Note: we could supply f = Pi.f, but prefer to test behavior without it. + b = _two_elt_rep(gens, ZK, p) + if b != Pi.alpha: + H2 = p*ZK + b*ZK + assert H2 == H + + +def test_valuation_at_prime_ideal(): + p = 7 + T = Poly(cyclotomic_poly(p)) + ZK, dK = round_two(T) + P = prime_decomp(p, T, dK=dK, ZK=ZK) + assert len(P) == 1 + P0 = P[0] + v = P0.valuation(p*ZK) + assert v == P0.e + # Test easy 0 case: + assert P0.valuation(5*ZK) == 0 + + +def test_decomp_1(): + # All prime decompositions in cyclotomic fields are in the "easy case," + # since the index is unity. + # Here we check the ramified prime. + T = Poly(cyclotomic_poly(7)) + raises(ValueError, lambda: prime_decomp(7)) + P = prime_decomp(7, T) + assert len(P) == 1 + P0 = P[0] + assert P0.e == 6 + assert P0.f == 1 + # Test powers: + assert P0**0 == P0.ZK + assert P0**1 == P0 + assert P0**6 == 7 * P0.ZK + + +def test_decomp_2(): + # More easy cyclotomic cases, but here we check unramified primes. + ell = 7 + T = Poly(cyclotomic_poly(ell)) + for p in [29, 13, 11, 5]: + f_exp = n_order(p, ell) + g_exp = (ell - 1) // f_exp + P = prime_decomp(p, T) + assert len(P) == g_exp + for Pi in P: + assert Pi.e == 1 + assert Pi.f == f_exp + + +def test_decomp_3(): + T = Poly(x ** 2 - 35) + rad = {} + ZK, dK = round_two(T, radicals=rad) + # 35 is 3 mod 4, so field disc is 4*5*7, and theory says each of the + # rational primes 2, 5, 7 should be the square of a prime ideal. + for p in [2, 5, 7]: + P = prime_decomp(p, T, dK=dK, ZK=ZK, radical=rad.get(p)) + assert len(P) == 1 + assert P[0].e == 2 + assert P[0]**2 == p*ZK + + +def test_decomp_4(): + T = Poly(x ** 2 - 21) + rad = {} + ZK, dK = round_two(T, radicals=rad) + # 21 is 1 mod 4, so field disc is 3*7, and theory says the + # rational primes 3, 7 should be the square of a prime ideal. + for p in [3, 7]: + P = prime_decomp(p, T, dK=dK, ZK=ZK, radical=rad.get(p)) + assert len(P) == 1 + assert P[0].e == 2 + assert P[0]**2 == p*ZK + + +def test_decomp_5(): + # Here is our first test of the "hard case" of prime decomposition. + # We work in a quadratic extension Q(sqrt(d)) where d is 1 mod 4, and + # we consider the factorization of the rational prime 2, which divides + # the index. + # Theory says the form of p's factorization depends on the residue of + # d mod 8, so we consider both cases, d = 1 mod 8 and d = 5 mod 8. + for d in [-7, -3]: + T = Poly(x ** 2 - d) + rad = {} + ZK, dK = round_two(T, radicals=rad) + p = 2 + P = prime_decomp(p, T, dK=dK, ZK=ZK, radical=rad.get(p)) + if d % 8 == 1: + assert len(P) == 2 + assert all(P[i].e == 1 and P[i].f == 1 for i in range(2)) + assert prod(Pi**Pi.e for Pi in P) == p * ZK + else: + assert d % 8 == 5 + assert len(P) == 1 + assert P[0].e == 1 + assert P[0].f == 2 + assert P[0].as_submodule() == p * ZK + + +def test_decomp_6(): + # Another case where 2 divides the index. This is Dedekind's example of + # an essential discriminant divisor. (See Cohen, Exercise 6.10.) + T = Poly(x ** 3 + x ** 2 - 2 * x + 8) + rad = {} + ZK, dK = round_two(T, radicals=rad) + p = 2 + P = prime_decomp(p, T, dK=dK, ZK=ZK, radical=rad.get(p)) + assert len(P) == 3 + assert all(Pi.e == Pi.f == 1 for Pi in P) + assert prod(Pi**Pi.e for Pi in P) == p*ZK + + +def test_decomp_7(): + # Try working through an AlgebraicField + T = Poly(x ** 3 + x ** 2 - 2 * x + 8) + K = QQ.alg_field_from_poly(T) + p = 2 + P = K.primes_above(p) + ZK = K.maximal_order() + assert len(P) == 3 + assert all(Pi.e == Pi.f == 1 for Pi in P) + assert prod(Pi**Pi.e for Pi in P) == p*ZK + + +def test_decomp_8(): + # This time we consider various cubics, and try factoring all primes + # dividing the index. + cases = ( + x ** 3 + 3 * x ** 2 - 4 * x + 4, + x ** 3 + 3 * x ** 2 + 3 * x - 3, + x ** 3 + 5 * x ** 2 - x + 3, + x ** 3 + 5 * x ** 2 - 5 * x - 5, + x ** 3 + 3 * x ** 2 + 5, + x ** 3 + 6 * x ** 2 + 3 * x - 1, + x ** 3 + 6 * x ** 2 + 4, + x ** 3 + 7 * x ** 2 + 7 * x - 7, + x ** 3 + 7 * x ** 2 - x + 5, + x ** 3 + 7 * x ** 2 - 5 * x + 5, + x ** 3 + 4 * x ** 2 - 3 * x + 7, + x ** 3 + 8 * x ** 2 + 5 * x - 1, + x ** 3 + 8 * x ** 2 - 2 * x + 6, + x ** 3 + 6 * x ** 2 - 3 * x + 8, + x ** 3 + 9 * x ** 2 + 6 * x - 8, + x ** 3 + 15 * x ** 2 - 9 * x + 13, + ) + def display(T, p, radical, P, I, J): + """Useful for inspection, when running test manually.""" + print('=' * 20) + print(T, p, radical) + for Pi in P: + print(f' ({Pi!r})') + print("I: ", I) + print("J: ", J) + print(f'Equal: {I == J}') + inspect = False + for g in cases: + T = Poly(g) + rad = {} + ZK, dK = round_two(T, radicals=rad) + dT = T.discriminant() + f_squared = dT // dK + F = factorint(f_squared) + for p in F: + radical = rad.get(p) + P = prime_decomp(p, T, dK=dK, ZK=ZK, radical=radical) + I = prod(Pi**Pi.e for Pi in P) + J = p * ZK + if inspect: + display(T, p, radical, P, I, J) + assert I == J + + +def test_PrimeIdeal_eq(): + # `==` should fail on objects of different types, so even a completely + # inert PrimeIdeal should test unequal to the rational prime it divides. + T = Poly(cyclotomic_poly(7)) + P0 = prime_decomp(5, T)[0] + assert P0.f == 6 + assert P0.as_submodule() == 5 * P0.ZK + assert P0 != 5 + + +def test_PrimeIdeal_add(): + T = Poly(cyclotomic_poly(7)) + P0 = prime_decomp(7, T)[0] + # Adding ideals computes their GCD, so adding the ramified prime dividing + # 7 to 7 itself should reproduce this prime (as a submodule). + assert P0 + 7 * P0.ZK == P0.as_submodule() + + +def test_str(): + # Without alias: + k = QQ.alg_field_from_poly(Poly(x**2 + 7)) + frp = k.primes_above(2)[0] + assert str(frp) == '(2, 3*_x/2 + 1/2)' + + frp = k.primes_above(3)[0] + assert str(frp) == '(3)' + + # With alias: + k = QQ.alg_field_from_poly(Poly(x ** 2 + 7), alias='alpha') + frp = k.primes_above(2)[0] + assert str(frp) == '(2, 3*alpha/2 + 1/2)' + + frp = k.primes_above(3)[0] + assert str(frp) == '(3)' + + +def test_repr(): + T = Poly(x**2 + 7) + ZK, dK = round_two(T) + P = prime_decomp(2, T, dK=dK, ZK=ZK) + assert repr(P[0]) == '[ (2, (3*x + 1)/2) e=1, f=1 ]' + assert P[0].repr(field_gen=theta) == '[ (2, (3*theta + 1)/2) e=1, f=1 ]' + assert P[0].repr(field_gen=theta, just_gens=True) == '(2, (3*theta + 1)/2)' + + +def test_PrimeIdeal_reduce(): + k = QQ.alg_field_from_poly(Poly(x ** 3 + x ** 2 - 2 * x + 8)) + Zk = k.maximal_order() + P = k.primes_above(2) + frp = P[2] + + # reduce_element + a = Zk.parent(to_col([23, 20, 11]), denom=6) + a_bar_expected = Zk.parent(to_col([11, 5, 2]), denom=6) + a_bar = frp.reduce_element(a) + assert a_bar == a_bar_expected + + # reduce_ANP + a = k([QQ(11, 6), QQ(20, 6), QQ(23, 6)]) + a_bar_expected = k([QQ(2, 6), QQ(5, 6), QQ(11, 6)]) + a_bar = frp.reduce_ANP(a) + assert a_bar == a_bar_expected + + # reduce_alg_num + a = k.to_alg_num(a) + a_bar_expected = k.to_alg_num(a_bar_expected) + a_bar = frp.reduce_alg_num(a) + assert a_bar == a_bar_expected + + +def test_issue_23402(): + k = QQ.alg_field_from_poly(Poly(x ** 3 + x ** 2 - 2 * x + 8)) + P = k.primes_above(3) + assert P[0].alpha.equiv(0) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_subfield.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_subfield.py new file mode 100644 index 0000000000000000000000000000000000000000..b152dd684aa20034f9233eedb1866aac2639b5f9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_subfield.py @@ -0,0 +1,317 @@ +"""Tests for the subfield problem and allied problems. """ + +from sympy.core.numbers import (AlgebraicNumber, I, pi, Rational) +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.external.gmpy import MPQ +from sympy.polys.numberfields.subfield import ( + is_isomorphism_possible, + field_isomorphism_pslq, + field_isomorphism, + primitive_element, + to_number_field, +) +from sympy.polys.domains import QQ +from sympy.polys.polyerrors import IsomorphismFailed +from sympy.polys.polytools import Poly +from sympy.polys.rootoftools import CRootOf +from sympy.testing.pytest import raises + +from sympy.abc import x + +Q = Rational + + +def test_field_isomorphism_pslq(): + a = AlgebraicNumber(I) + b = AlgebraicNumber(I*sqrt(3)) + + raises(NotImplementedError, lambda: field_isomorphism_pslq(a, b)) + + 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)) + + assert field_isomorphism_pslq(a, a) == [1, 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) is None + assert field_isomorphism_pslq(b, b) == [1, 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) is None + assert field_isomorphism_pslq(c, b) is None + assert field_isomorphism_pslq(c, c) == [1, 0] + 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(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) + + 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] + + 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) == [ Rational(6, 35), 0] + assert field_isomorphism(-2*I*sqrt(3)/7, 5*I*sqrt(3)/3) == [Rational(-6, 35), 0] + + assert field_isomorphism( 2*I*sqrt(3)/7, -5*I*sqrt(3)/3) == [Rational(-6, 35), 0] + assert field_isomorphism(-2*I*sqrt(3)/7, -5*I*sqrt(3)/3) == [ Rational(6, 35), 0] + + assert field_isomorphism( + 2*I*sqrt(3)/7 + 27, 5*I*sqrt(3)/3) == [ Rational(6, 35), 27] + assert field_isomorphism( + -2*I*sqrt(3)/7 + 27, 5*I*sqrt(3)/3) == [Rational(-6, 35), 27] + + assert field_isomorphism( + 2*I*sqrt(3)/7 + 27, -5*I*sqrt(3)/3) == [Rational(-6, 35), 27] + assert field_isomorphism( + -2*I*sqrt(3)/7 + 27, -5*I*sqrt(3)/3) == [ Rational(6, 35), 27] + + p = AlgebraicNumber( sqrt(2) + sqrt(3)) + q = AlgebraicNumber(-sqrt(2) + sqrt(3)) + r = AlgebraicNumber( sqrt(2) - sqrt(3)) + s = AlgebraicNumber(-sqrt(2) - sqrt(3)) + + pos_coeffs = [ S.Half, S.Zero, Rational(-9, 2), S.Zero] + neg_coeffs = [Rational(-1, 2), S.Zero, Rational(9, 2), S.Zero] + + a = AlgebraicNumber(sqrt(2)) + + 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 + assert field_isomorphism(a, r, fast=True) == pos_coeffs + assert field_isomorphism(a, s, fast=True) == neg_coeffs + + assert field_isomorphism(a, p, fast=False) == pos_coeffs + assert field_isomorphism(a, q, fast=False) == neg_coeffs + assert field_isomorphism(a, r, fast=False) == pos_coeffs + assert field_isomorphism(a, s, fast=False) == neg_coeffs + + a = AlgebraicNumber(-sqrt(2)) + + 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 + assert field_isomorphism(a, r, fast=True) == neg_coeffs + assert field_isomorphism(a, s, fast=True) == pos_coeffs + + assert field_isomorphism(a, p, fast=False) == neg_coeffs + assert field_isomorphism(a, q, fast=False) == pos_coeffs + assert field_isomorphism(a, r, fast=False) == neg_coeffs + assert field_isomorphism(a, s, fast=False) == pos_coeffs + + pos_coeffs = [ S.Half, S.Zero, Rational(-11, 2), S.Zero] + neg_coeffs = [Rational(-1, 2), S.Zero, Rational(11, 2), S.Zero] + + a = AlgebraicNumber(sqrt(3)) + + 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 + assert field_isomorphism(a, r, fast=True) == pos_coeffs + assert field_isomorphism(a, s, fast=True) == pos_coeffs + + assert field_isomorphism(a, p, fast=False) == neg_coeffs + assert field_isomorphism(a, q, fast=False) == neg_coeffs + assert field_isomorphism(a, r, fast=False) == pos_coeffs + assert field_isomorphism(a, s, fast=False) == pos_coeffs + + a = AlgebraicNumber(-sqrt(3)) + + 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 + assert field_isomorphism(a, r, fast=True) == neg_coeffs + assert field_isomorphism(a, s, fast=True) == neg_coeffs + + assert field_isomorphism(a, p, fast=False) == pos_coeffs + assert field_isomorphism(a, q, fast=False) == pos_coeffs + assert field_isomorphism(a, r, fast=False) == neg_coeffs + assert field_isomorphism(a, s, fast=False) == neg_coeffs + + pos_coeffs = [ Rational(3, 2), S.Zero, Rational(-33, 2), -S(8)] + neg_coeffs = [Rational(-3, 2), S.Zero, Rational(33, 2), -S(8)] + + a = AlgebraicNumber(3*sqrt(3) - 8) + + 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 + assert field_isomorphism(a, r, fast=True) == pos_coeffs + assert field_isomorphism(a, s, fast=True) == pos_coeffs + + assert field_isomorphism(a, p, fast=False) == neg_coeffs + assert field_isomorphism(a, q, fast=False) == neg_coeffs + 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) + + pos_1_coeffs = [ S.Half, S.Zero, Rational(-5, 2), S.One] + neg_5_coeffs = [Rational(-5, 2), S.Zero, Rational(49, 2), S.One] + pos_5_coeffs = [ Rational(5, 2), S.Zero, Rational(-49, 2), S.One] + neg_1_coeffs = [Rational(-1, 2), S.Zero, Rational(5, 2), S.One] + + 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 + assert field_isomorphism(a, r, fast=True) == pos_5_coeffs + assert field_isomorphism(a, s, fast=True) == neg_1_coeffs + + assert field_isomorphism(a, p, fast=False) == pos_1_coeffs + assert field_isomorphism(a, q, fast=False) == neg_5_coeffs + assert field_isomorphism(a, r, fast=False) == pos_5_coeffs + assert field_isomorphism(a, s, fast=False) == neg_1_coeffs + + a = AlgebraicNumber(sqrt(2)) + b = AlgebraicNumber(sqrt(3)) + c = AlgebraicNumber(sqrt(7)) + + assert is_isomorphism_possible(a, b) is True + assert is_isomorphism_possible(b, a) is True + + 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 + + assert field_isomorphism(sqrt(2), sqrt(3), fast=False) is None + assert field_isomorphism(sqrt(3), sqrt(2), fast=False) is None + + a = AlgebraicNumber(sqrt(2)) + b = AlgebraicNumber(2 ** (S(1) / 3)) + + assert is_isomorphism_possible(a, b) is False + assert field_isomorphism(a, b) is None + + +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)], x, polys=True) == (Poly(x**2 - 2, domain='QQ'), [1]) + assert primitive_element([sqrt( + 2), sqrt(3)], x, polys=True) == (Poly(x**4 - 10*x**2 + 1, domain='QQ'), [1, 1]) + + 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]]) + + assert primitive_element( + [sqrt(2)], x, ex=True, polys=True) == (Poly(x**2 - 2, domain='QQ'), [1], [[1, 0]]) + assert primitive_element([sqrt(2), sqrt(3)], x, ex=True, polys=True) == \ + (Poly(x**4 - 10*x**2 + 1, domain='QQ'), [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)) + + # Issue 14117 + a, b = I*sqrt(2*sqrt(2) + 3), I*sqrt(-2*sqrt(2) + 3) + assert primitive_element([a, b, I], x) == (x**4 + 6*x**2 + 1, [1, 0, 0]) + + assert primitive_element([sqrt(2), 0], x) == (x**2 - 2, [1, 0]) + assert primitive_element([0, sqrt(2)], x) == (x**2 - 2, [1, 1]) + assert primitive_element([sqrt(2), 0], x, ex=True) == (x**2 - 2, [1, 0], [[MPQ(1,1), MPQ(0,1)], []]) + assert primitive_element([0, sqrt(2)], x, ex=True) == (x**2 - 2, [1, 1], [[], [MPQ(1,1), MPQ(0,1)]]) + + +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)) + + a = AlgebraicNumber(sqrt(2) + sqrt(3), [S.Half, S.Zero, Rational(-9, 2), S.Zero]) + + 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_issue_22561(): + a = to_number_field(sqrt(2), sqrt(2) + sqrt(3)) + b = to_number_field(sqrt(2), sqrt(2) + sqrt(5)) + assert field_isomorphism(a, b) == [1, 0] + + +def test_issue_22736(): + a = CRootOf(x**4 + x**3 + x**2 + x + 1, -1) + a._reset() + b = exp(2*I*pi/5) + assert field_isomorphism(a, b) == [1, 0] + + +def test_issue_27798(): + # https://github.com/sympy/sympy/issues/27798 + a, b = CRootOf(49*x**3 - 49*x**2 + 14*x - 1, 2), CRootOf(49*x**3 - 49*x**2 + 14*x - 1, 0) + assert primitive_element([a, b], polys=True)[0].primitive()[0] == 1 + assert primitive_element([a, b], polys=True, ex=True)[0].primitive()[0] == 1 + + f1, f2 = QQ.algebraic_field(a), QQ.algebraic_field(b) + f3 = f1.unify(f2) + assert f3.mod.primitive()[0] == 1 + assert Poly(x, x, domain=f1) + Poly(x, x, domain=f2) == Poly(2*x, x, domain=f3) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_utilities.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..134853ef0c88045ef9cc7e215bb98db37041e63a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/tests/test_utilities.py @@ -0,0 +1,113 @@ +from sympy.abc import x +from sympy.core.numbers import (I, Rational) +from sympy.core.singleton import S +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.polys import Poly, cyclotomic_poly +from sympy.polys.domains import FF, QQ +from sympy.polys.matrices import DomainMatrix, DM +from sympy.polys.matrices.exceptions import DMRankError +from sympy.polys.numberfields.utilities import ( + AlgIntPowers, coeff_search, extract_fundamental_discriminant, + isolate, supplement_a_subspace, +) +from sympy.printing.lambdarepr import IntervalPrinter +from sympy.testing.pytest import raises + + +def test_AlgIntPowers_01(): + T = Poly(cyclotomic_poly(5)) + zeta_pow = AlgIntPowers(T) + raises(ValueError, lambda: zeta_pow[-1]) + for e in range(10): + a = e % 5 + if a < 4: + c = zeta_pow[e] + assert c[a] == 1 and all(c[i] == 0 for i in range(4) if i != a) + else: + assert zeta_pow[e] == [-1] * 4 + + +def test_AlgIntPowers_02(): + T = Poly(x**3 + 2*x**2 + 3*x + 4) + m = 7 + theta_pow = AlgIntPowers(T, m) + for e in range(10): + computed = theta_pow[e] + coeffs = (Poly(x)**e % T + Poly(x**3)).rep.to_list()[1:] + expected = [c % m for c in reversed(coeffs)] + assert computed == expected + + +def test_coeff_search(): + C = [] + search = coeff_search(2, 1) + for i, c in enumerate(search): + C.append(c) + if i == 12: + break + assert C == [[1, 1], [1, 0], [1, -1], [0, 1], [2, 2], [2, 1], [2, 0], [2, -1], [2, -2], [1, 2], [1, -2], [0, 2], [3, 3]] + + +def test_extract_fundamental_discriminant(): + # To extract, integer must be 0 or 1 mod 4. + raises(ValueError, lambda: extract_fundamental_discriminant(2)) + raises(ValueError, lambda: extract_fundamental_discriminant(3)) + # Try many cases, of different forms: + cases = ( + (0, {}, {0: 1}), + (1, {}, {}), + (8, {2: 3}, {}), + (-8, {2: 3, -1: 1}, {}), + (12, {2: 2, 3: 1}, {}), + (36, {}, {2: 1, 3: 1}), + (45, {5: 1}, {3: 1}), + (48, {2: 2, 3: 1}, {2: 1}), + (1125, {5: 1}, {3: 1, 5: 1}), + ) + for a, D_expected, F_expected in cases: + D, F = extract_fundamental_discriminant(a) + assert D == D_expected + assert F == F_expected + + +def test_supplement_a_subspace_1(): + M = DM([[1, 7, 0], [2, 3, 4]], QQ).transpose() + + # First supplement over QQ: + B = supplement_a_subspace(M) + assert B[:, :2] == M + assert B[:, 2] == DomainMatrix.eye(3, QQ).to_dense()[:, 0] + + # Now supplement over FF(7): + M = M.convert_to(FF(7)) + B = supplement_a_subspace(M) + assert B[:, :2] == M + # When we work mod 7, first col of M goes to [1, 0, 0], + # so the supplementary vector cannot equal this, as it did + # when we worked over QQ. Instead, we get the second std basis vector: + assert B[:, 2] == DomainMatrix.eye(3, FF(7)).to_dense()[:, 1] + + +def test_supplement_a_subspace_2(): + M = DM([[1, 0, 0], [2, 0, 0]], QQ).transpose() + with raises(DMRankError): + supplement_a_subspace(M) + + +def test_IntervalPrinter(): + ip = IntervalPrinter() + assert ip.doprint(x**Rational(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.Half) == (S.Half, S.Half) + + assert isolate(sqrt(2)) == (1, 2) + assert isolate(-sqrt(2)) == (-2, -1) + + assert isolate(sqrt(2), eps=Rational(1, 100)) == (Rational(24, 17), Rational(17, 12)) + assert isolate(-sqrt(2), eps=Rational(1, 100)) == (Rational(-17, 12), Rational(-24, 17)) + + raises(NotImplementedError, lambda: isolate(I)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/utilities.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..fe583efb440f02f1b16c38fb7d03621c1f97e83d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/numberfields/utilities.py @@ -0,0 +1,474 @@ +"""Utilities for algebraic number theory. """ + +from sympy.core.sympify import sympify +from sympy.ntheory.factor_ import factorint +from sympy.polys.domains.rationalfield import QQ +from sympy.polys.domains.integerring import ZZ +from sympy.polys.matrices.exceptions import DMRankError +from sympy.polys.numberfields.minpoly import minpoly +from sympy.printing.lambdarepr import IntervalPrinter +from sympy.utilities.decorator import public +from sympy.utilities.lambdify import lambdify + +from mpmath import mp + + +def is_rat(c): + r""" + Test whether an argument is of an acceptable type to be used as a rational + number. + + Explanation + =========== + + Returns ``True`` on any argument of type ``int``, :ref:`ZZ`, or :ref:`QQ`. + + See Also + ======== + + is_int + + """ + # ``c in QQ`` is too accepting (e.g. ``3.14 in QQ`` is ``True``), + # ``QQ.of_type(c)`` is too demanding (e.g. ``QQ.of_type(3)`` is ``False``). + # + # Meanwhile, if gmpy2 is installed then ``ZZ.of_type()`` accepts only + # ``mpz``, not ``int``, so we need another clause to ensure ``int`` is + # accepted. + return isinstance(c, int) or ZZ.of_type(c) or QQ.of_type(c) + + +def is_int(c): + r""" + Test whether an argument is of an acceptable type to be used as an integer. + + Explanation + =========== + + Returns ``True`` on any argument of type ``int`` or :ref:`ZZ`. + + See Also + ======== + + is_rat + + """ + # If gmpy2 is installed then ``ZZ.of_type()`` accepts only + # ``mpz``, not ``int``, so we need another clause to ensure ``int`` is + # accepted. + return isinstance(c, int) or ZZ.of_type(c) + + +def get_num_denom(c): + r""" + Given any argument on which :py:func:`~.is_rat` is ``True``, return the + numerator and denominator of this number. + + See Also + ======== + + is_rat + + """ + r = QQ(c) + return r.numerator, r.denominator + + +@public +def extract_fundamental_discriminant(a): + r""" + Extract a fundamental discriminant from an integer *a*. + + Explanation + =========== + + Given any rational integer *a* that is 0 or 1 mod 4, write $a = d f^2$, + where $d$ is either 1 or a fundamental discriminant, and return a pair + of dictionaries ``(D, F)`` giving the prime factorizations of $d$ and $f$ + respectively, in the same format returned by :py:func:`~.factorint`. + + A fundamental discriminant $d$ is different from unity, and is either + 1 mod 4 and squarefree, or is 0 mod 4 and such that $d/4$ is squarefree + and 2 or 3 mod 4. This is the same as being the discriminant of some + quadratic field. + + Examples + ======== + + >>> from sympy.polys.numberfields.utilities import extract_fundamental_discriminant + >>> print(extract_fundamental_discriminant(-432)) + ({3: 1, -1: 1}, {2: 2, 3: 1}) + + For comparison: + + >>> from sympy import factorint + >>> print(factorint(-432)) + {2: 4, 3: 3, -1: 1} + + Parameters + ========== + + a: int, must be 0 or 1 mod 4 + + Returns + ======= + + Pair ``(D, F)`` of dictionaries. + + Raises + ====== + + ValueError + If *a* is not 0 or 1 mod 4. + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* + (See Prop. 5.1.3) + + """ + if a % 4 not in [0, 1]: + raise ValueError('To extract fundamental discriminant, number must be 0 or 1 mod 4.') + if a == 0: + return {}, {0: 1} + if a == 1: + return {}, {} + a_factors = factorint(a) + D = {} + F = {} + # First pass: just make d squarefree, and a/d a perfect square. + # We'll count primes (and units! i.e. -1) that are 3 mod 4 and present in d. + num_3_mod_4 = 0 + for p, e in a_factors.items(): + if e % 2 == 1: + D[p] = 1 + if p % 4 == 3: + num_3_mod_4 += 1 + if e >= 3: + F[p] = (e - 1) // 2 + else: + F[p] = e // 2 + # Second pass: if d is cong. to 2 or 3 mod 4, then we must steal away + # another factor of 4 from f**2 and give it to d. + even = 2 in D + if even or num_3_mod_4 % 2 == 1: + e2 = F[2] + assert e2 > 0 + if e2 == 1: + del F[2] + else: + F[2] = e2 - 1 + D[2] = 3 if even else 2 + return D, F + + +@public +class AlgIntPowers: + r""" + Compute the powers of an algebraic integer. + + Explanation + =========== + + Given an algebraic integer $\theta$ by its monic irreducible polynomial + ``T`` over :ref:`ZZ`, this class computes representations of arbitrarily + high powers of $\theta$, as :ref:`ZZ`-linear combinations over + $\{1, \theta, \ldots, \theta^{n-1}\}$, where $n = \deg(T)$. + + The representations are computed using the linear recurrence relations for + powers of $\theta$, derived from the polynomial ``T``. See [1], Sec. 4.2.2. + + Optionally, the representations may be reduced with respect to a modulus. + + Examples + ======== + + >>> from sympy import Poly, cyclotomic_poly + >>> from sympy.polys.numberfields.utilities import AlgIntPowers + >>> T = Poly(cyclotomic_poly(5)) + >>> zeta_pow = AlgIntPowers(T) + >>> print(zeta_pow[0]) + [1, 0, 0, 0] + >>> print(zeta_pow[1]) + [0, 1, 0, 0] + >>> print(zeta_pow[4]) # doctest: +SKIP + [-1, -1, -1, -1] + >>> print(zeta_pow[24]) # doctest: +SKIP + [-1, -1, -1, -1] + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory.* + + """ + + def __init__(self, T, modulus=None): + """ + Parameters + ========== + + T : :py:class:`~.Poly` + The monic irreducible polynomial over :ref:`ZZ` defining the + algebraic integer. + + modulus : int, None, optional + If not ``None``, all representations will be reduced w.r.t. this. + + """ + self.T = T + self.modulus = modulus + self.n = T.degree() + self.powers_n_and_up = [[-c % self for c in reversed(T.rep.to_list())][:-1]] + self.max_so_far = self.n + + def red(self, exp): + return exp if self.modulus is None else exp % self.modulus + + def __rmod__(self, other): + return self.red(other) + + def compute_up_through(self, e): + m = self.max_so_far + if e <= m: return + n = self.n + r = self.powers_n_and_up + c = r[0] + for k in range(m+1, e+1): + b = r[k-1-n][n-1] + r.append( + [c[0]*b % self] + [ + (r[k-1-n][i-1] + c[i]*b) % self for i in range(1, n) + ] + ) + self.max_so_far = e + + def get(self, e): + n = self.n + if e < 0: + raise ValueError('Exponent must be non-negative.') + elif e < n: + return [1 if i == e else 0 for i in range(n)] + else: + self.compute_up_through(e) + return self.powers_n_and_up[e - n] + + def __getitem__(self, item): + return self.get(item) + + +@public +def coeff_search(m, R): + r""" + Generate coefficients for searching through polynomials. + + Explanation + =========== + + Lead coeff is always non-negative. Explore all combinations with coeffs + bounded in absolute value before increasing the bound. Skip the all-zero + list, and skip any repeats. See examples. + + Examples + ======== + + >>> from sympy.polys.numberfields.utilities import coeff_search + >>> cs = coeff_search(2, 1) + >>> C = [next(cs) for i in range(13)] + >>> print(C) + [[1, 1], [1, 0], [1, -1], [0, 1], [2, 2], [2, 1], [2, 0], [2, -1], [2, -2], + [1, 2], [1, -2], [0, 2], [3, 3]] + + Parameters + ========== + + m : int + Length of coeff list. + R : int + Initial max abs val for coeffs (will increase as search proceeds). + + Returns + ======= + + generator + Infinite generator of lists of coefficients. + + """ + R0 = R + c = [R] * m + while True: + if R == R0 or R in c or -R in c: + yield c[:] + j = m - 1 + while c[j] == -R: + j -= 1 + c[j] -= 1 + for i in range(j + 1, m): + c[i] = R + for j in range(m): + if c[j] != 0: + break + else: + R += 1 + c = [R] * m + + +def supplement_a_subspace(M): + r""" + Extend a basis for a subspace to a basis for the whole space. + + Explanation + =========== + + Given an $n \times r$ matrix *M* of rank $r$ (so $r \leq n$), this function + computes an invertible $n \times n$ matrix $B$ such that the first $r$ + columns of $B$ equal *M*. + + This operation can be interpreted as a way of extending a basis for a + subspace, to give a basis for the whole space. + + To be precise, suppose you have an $n$-dimensional vector space $V$, with + basis $\{v_1, v_2, \ldots, v_n\}$, and an $r$-dimensional subspace $W$ of + $V$, spanned by a basis $\{w_1, w_2, \ldots, w_r\}$, where the $w_j$ are + given as linear combinations of the $v_i$. If the columns of *M* represent + the $w_j$ as such linear combinations, then the columns of the matrix $B$ + computed by this function give a new basis $\{u_1, u_2, \ldots, u_n\}$ for + $V$, again relative to the $\{v_i\}$ basis, and such that $u_j = w_j$ + for $1 \leq j \leq r$. + + Examples + ======== + + Note: The function works in terms of columns, so in these examples we + print matrix transposes in order to make the columns easier to inspect. + + >>> from sympy.polys.matrices import DM + >>> from sympy import QQ, FF + >>> from sympy.polys.numberfields.utilities import supplement_a_subspace + >>> M = DM([[1, 7, 0], [2, 3, 4]], QQ).transpose() + >>> print(supplement_a_subspace(M).to_Matrix().transpose()) + Matrix([[1, 7, 0], [2, 3, 4], [1, 0, 0]]) + + >>> M2 = M.convert_to(FF(7)) + >>> print(M2.to_Matrix().transpose()) + Matrix([[1, 0, 0], [2, 3, -3]]) + >>> print(supplement_a_subspace(M2).to_Matrix().transpose()) + Matrix([[1, 0, 0], [2, 3, -3], [0, 1, 0]]) + + Parameters + ========== + + M : :py:class:`~.DomainMatrix` + The columns give the basis for the subspace. + + Returns + ======= + + :py:class:`~.DomainMatrix` + This matrix is invertible and its first $r$ columns equal *M*. + + Raises + ====== + + DMRankError + If *M* was not of maximal rank. + + References + ========== + + .. [1] Cohen, H. *A Course in Computational Algebraic Number Theory* + (See Sec. 2.3.2.) + + """ + n, r = M.shape + # Let In be the n x n identity matrix. + # Form the augmented matrix [M | In] and compute RREF. + Maug = M.hstack(M.eye(n, M.domain)) + R, pivots = Maug.rref() + if pivots[:r] != tuple(range(r)): + raise DMRankError('M was not of maximal rank') + # Let J be the n x r matrix equal to the first r columns of In. + # Since M is of rank r, RREF reduces [M | In] to [J | A], where A is the product of + # elementary matrices Ei corresp. to the row ops performed by RREF. Since the Ei are + # invertible, so is A. Let B = A^(-1). + A = R[:, r:] + B = A.inv() + # Then B is the desired matrix. It is invertible, since B^(-1) == A. + # And A * [M | In] == [J | A] + # => A * M == J + # => M == B * J == the first r columns of B. + return B + + +@public +def isolate(alg, eps=None, fast=False): + """ + Find a rational isolating interval for a real algebraic number. + + Examples + ======== + + >>> from sympy import isolate, sqrt, Rational + >>> print(isolate(sqrt(2))) # doctest: +SKIP + (1, 2) + >>> print(isolate(sqrt(2), eps=Rational(1, 100))) + (24/17, 17/12) + + Parameters + ========== + + alg : str, int, :py:class:`~.Expr` + The algebraic number to be isolated. Must be a real number, to use this + particular function. However, see also :py:meth:`.Poly.intervals`, + which isolates complex roots when you pass ``all=True``. + eps : positive element of :ref:`QQ`, None, optional (default=None) + Precision to be passed to :py:meth:`.Poly.refine_root` + fast : boolean, optional (default=False) + Say whether fast refinement procedure should be used. + (Will be passed to :py:meth:`.Poly.refine_root`.) + + Returns + ======= + + Pair of rational numbers defining an isolating interval for the given + algebraic number. + + See Also + ======== + + .Poly.intervals + + """ + alg = sympify(alg) + + if alg.is_Rational: + return (alg, alg) + elif not alg.is_real: + raise NotImplementedError( + "complex algebraic numbers are not supported") + + func = lambdify((), alg, modules="mpmath", printer=IntervalPrinter()) + + poly = minpoly(alg, polys=True) + intervals = poly.intervals(sqf=True) + + dps, done = mp.dps, False + + try: + while not done: + alg = func() + + for a, b in intervals: + if a <= alg.a and alg.b <= b: + done = True + break + else: + mp.dps *= 2 + finally: + mp.dps = dps + + if eps is not None: + a, b = poly.refine_root(a, b, eps=eps, fast=fast) + + return (a, b) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6ca9ad1d46775084fe588dd1234d7210b96d0a7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_appellseqs.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_appellseqs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0eb5e8be71ee011be0b1079a9cce3a07d1b06fa2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_appellseqs.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_constructor.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_constructor.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b5ecacaddb8dcc091c1e5b446f226e40954a9a2b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_constructor.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_densearith.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_densearith.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a2185e8e5d0494432135d2a26fd05ce31285af81 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_densearith.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_densebasic.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_densebasic.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87121347dbfb4e86bf992dceaae73e6fd347e4c3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_densebasic.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_densetools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_densetools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7e3531c982187926dd813b671520659b64c88b5 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_densetools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_dispersion.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_dispersion.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e9f335b4107f730a234473628e3b71e8ccd2a094 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_dispersion.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_distributedmodules.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_distributedmodules.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b484e79c4c1994c9c606712d521526235794af6f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_distributedmodules.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_euclidtools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_euclidtools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..80929f8d4d9d2210564d24402aee4aa8d1ccc10f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_euclidtools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_factortools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_factortools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..470e528178dcc907c4a0636a18557de1187f387d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_factortools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_fields.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_fields.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e11cbc4a9122e6128eadcec270904d25fe0af4fe Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_fields.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_galoistools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_galoistools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2cb67098d560b8c1607fade27364cf550023afb2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_galoistools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_groebnertools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_groebnertools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b6ecb3f242e8d4f5231357178bba1f16d65c7279 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_groebnertools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_heuristicgcd.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_heuristicgcd.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e4ff779b049e15714b73525d2357ae5a0c4645d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_heuristicgcd.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_hypothesis.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_hypothesis.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..91d554770101947cf5d4c1c0017adbb6dc30b762 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_hypothesis.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_injections.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_injections.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27cf0f85f11d098dd6dba60ede37eef6443fc0b2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_injections.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_modulargcd.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_modulargcd.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6a067068cc0fd84eda9553a87f43dd531daf7c41 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_modulargcd.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_monomials.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_monomials.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..718c59d0135573b49f02ffdfc193f9173b480bfe Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_monomials.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_multivariate_resultants.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_multivariate_resultants.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..62b2c7b92c3a2b12efa53be2fea294d3e8122533 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_multivariate_resultants.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_orderings.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_orderings.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bd9e3b0517c6fc8582a5cdc27e444105b20b1a4b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_orderings.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_orthopolys.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_orthopolys.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d968283246741a94f60db26516727863c8f2ac05 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_orthopolys.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_partfrac.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_partfrac.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fcffbd71e3ca0eeb8af5249706a4bfdd9be08535 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_partfrac.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyclasses.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyclasses.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87f883343fb413fb4cae7640c2a709a9444717ad Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyclasses.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyfuncs.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyfuncs.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9b0e8ee1673411f83f03ec1901d6234e3b91322 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyfuncs.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polymatrix.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polymatrix.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8137a1666217166450ff0e292c44053fafd2cbd9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polymatrix.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyoptions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyoptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5fa2f69cce76b29ad7c9572f7ec86c3b7af982ae Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyoptions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyroots.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyroots.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1fe02888baf785d910dff21dc7cce4e1ccb1c9f3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyroots.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyutils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyutils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..833afe76e7604d93b2acea18296eb2fcf0c55c1c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_polyutils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_puiseux.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_puiseux.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a66cfdac91110710ddb1e9d8beaaccda10557c9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_puiseux.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_pythonrational.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_pythonrational.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ef22766c398c4595680d7aa6a26fe5d916f6759 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_pythonrational.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_rationaltools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_rationaltools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43c21817799b3b8bfb239dce7dc53ce195cb7158 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_rationaltools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_ring_series.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_ring_series.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d7b11e0c4e5264a655aea2feb44c11da37a99ea1 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_ring_series.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_rootisolation.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_rootisolation.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f803d348e2fffe316ea3501c866418d0e82a1eac Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_rootisolation.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_rootoftools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_rootoftools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8c8cc8d0c8d433bfa9f7981fcfcdd154edc1e343 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_rootoftools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_solvers.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_solvers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fe7f3cfa2c0915204dc832d0b55f444dd61491e4 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_solvers.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_specialpolys.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_specialpolys.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..62c2618e6d9ff06fd492474c2f499309eaebad62 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_specialpolys.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_sqfreetools.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_sqfreetools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..704a1b54be99aae99691621f9f7d8d2bda93c9fd Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_sqfreetools.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_subresultants_qq_zz.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_subresultants_qq_zz.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca1eab9a7022ff5225283701a3eb8a5eb0aeb09f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/__pycache__/test_subresultants_qq_zz.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_appellseqs.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_appellseqs.py new file mode 100644 index 0000000000000000000000000000000000000000..f4718a2da272ac6f36a968572dc246ebc699e5c4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_appellseqs.py @@ -0,0 +1,91 @@ +"""Tests for efficient functions for generating Appell sequences.""" +from sympy.core.numbers import Rational as Q +from sympy.polys.polytools import Poly +from sympy.testing.pytest import raises +from sympy.polys.appellseqs import (bernoulli_poly, bernoulli_c_poly, + euler_poly, genocchi_poly, andre_poly) +from sympy.abc import x + +def test_bernoulli_poly(): + raises(ValueError, lambda: bernoulli_poly(-1, x)) + assert bernoulli_poly(1, x, polys=True) == Poly(x - Q(1,2)) + + assert bernoulli_poly(0, x) == 1 + assert bernoulli_poly(1, x) == x - Q(1,2) + assert bernoulli_poly(2, x) == x**2 - x + Q(1,6) + assert bernoulli_poly(3, x) == x**3 - Q(3,2)*x**2 + Q(1,2)*x + assert bernoulli_poly(4, x) == x**4 - 2*x**3 + x**2 - Q(1,30) + assert bernoulli_poly(5, x) == x**5 - Q(5,2)*x**4 + Q(5,3)*x**3 - Q(1,6)*x + assert bernoulli_poly(6, x) == x**6 - 3*x**5 + Q(5,2)*x**4 - Q(1,2)*x**2 + Q(1,42) + + assert bernoulli_poly(1).dummy_eq(x - Q(1,2)) + assert bernoulli_poly(1, polys=True) == Poly(x - Q(1,2)) + +def test_bernoulli_c_poly(): + raises(ValueError, lambda: bernoulli_c_poly(-1, x)) + assert bernoulli_c_poly(1, x, polys=True) == Poly(x, domain='QQ') + + assert bernoulli_c_poly(0, x) == 1 + assert bernoulli_c_poly(1, x) == x + assert bernoulli_c_poly(2, x) == x**2 - Q(1,3) + assert bernoulli_c_poly(3, x) == x**3 - x + assert bernoulli_c_poly(4, x) == x**4 - 2*x**2 + Q(7,15) + assert bernoulli_c_poly(5, x) == x**5 - Q(10,3)*x**3 + Q(7,3)*x + assert bernoulli_c_poly(6, x) == x**6 - 5*x**4 + 7*x**2 - Q(31,21) + + assert bernoulli_c_poly(1).dummy_eq(x) + assert bernoulli_c_poly(1, polys=True) == Poly(x, domain='QQ') + + assert 2**8 * bernoulli_poly(8, (x+1)/2).expand() == bernoulli_c_poly(8, x) + assert 2**9 * bernoulli_poly(9, (x+1)/2).expand() == bernoulli_c_poly(9, x) + +def test_genocchi_poly(): + raises(ValueError, lambda: genocchi_poly(-1, x)) + assert genocchi_poly(2, x, polys=True) == Poly(-2*x + 1) + + assert genocchi_poly(0, x) == 0 + assert genocchi_poly(1, x) == -1 + assert genocchi_poly(2, x) == 1 - 2*x + assert genocchi_poly(3, x) == 3*x - 3*x**2 + assert genocchi_poly(4, x) == -1 + 6*x**2 - 4*x**3 + assert genocchi_poly(5, x) == -5*x + 10*x**3 - 5*x**4 + assert genocchi_poly(6, x) == 3 - 15*x**2 + 15*x**4 - 6*x**5 + + assert genocchi_poly(2).dummy_eq(-2*x + 1) + assert genocchi_poly(2, polys=True) == Poly(-2*x + 1) + + assert 2 * (bernoulli_poly(8, x) - bernoulli_c_poly(8, x)) == genocchi_poly(8, x) + assert 2 * (bernoulli_poly(9, x) - bernoulli_c_poly(9, x)) == genocchi_poly(9, x) + +def test_euler_poly(): + raises(ValueError, lambda: euler_poly(-1, x)) + assert euler_poly(1, x, polys=True) == Poly(x - Q(1,2)) + + assert euler_poly(0, x) == 1 + assert euler_poly(1, x) == x - Q(1,2) + assert euler_poly(2, x) == x**2 - x + assert euler_poly(3, x) == x**3 - Q(3,2)*x**2 + Q(1,4) + assert euler_poly(4, x) == x**4 - 2*x**3 + x + assert euler_poly(5, x) == x**5 - Q(5,2)*x**4 + Q(5,2)*x**2 - Q(1,2) + assert euler_poly(6, x) == x**6 - 3*x**5 + 5*x**3 - 3*x + + assert euler_poly(1).dummy_eq(x - Q(1,2)) + assert euler_poly(1, polys=True) == Poly(x - Q(1,2)) + + assert genocchi_poly(9, x) == euler_poly(8, x) * -9 + assert genocchi_poly(10, x) == euler_poly(9, x) * -10 + +def test_andre_poly(): + raises(ValueError, lambda: andre_poly(-1, x)) + assert andre_poly(1, x, polys=True) == Poly(x) + + assert andre_poly(0, x) == 1 + assert andre_poly(1, x) == x + assert andre_poly(2, x) == x**2 - 1 + assert andre_poly(3, x) == x**3 - 3*x + assert andre_poly(4, x) == x**4 - 6*x**2 + 5 + assert andre_poly(5, x) == x**5 - 10*x**3 + 25*x + assert andre_poly(6, x) == x**6 - 15*x**4 + 75*x**2 - 61 + + assert andre_poly(1).dummy_eq(x) + assert andre_poly(1, polys=True) == Poly(x) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_constructor.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_constructor.py new file mode 100644 index 0000000000000000000000000000000000000000..b02d8a4b360dd09b993bbed80cdec307d09908fc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_constructor.py @@ -0,0 +1,236 @@ +"""Tests for tools for constructing domains for expressions. """ + +from sympy.testing.pytest import tooslow + +from sympy.polys.constructor import construct_domain +from sympy.polys.domains import ZZ, QQ, ZZ_I, QQ_I, RR, CC, EX +from sympy.polys.domains.realfield import RealField +from sympy.polys.domains.complexfield import ComplexField + +from sympy.core import (Catalan, GoldenRatio) +from sympy.core.numbers import (E, Float, I, Rational, pi) +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin +from sympy import rootof + +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([S.One, S(2), S(3)]) == (ZZ, [ZZ(1), ZZ(2), ZZ(3)]) + assert construct_domain([S.One, S(2), S(3)], field=True) == (QQ, [QQ(1), QQ(2), QQ(3)]) + + assert construct_domain([S.Half, S(2)]) == (QQ, [QQ(1, 2), QQ(2)]) + result = construct_domain([3.14, 1, S.Half]) + assert isinstance(result[0], RealField) + assert result[1] == [RR(3.14), RR(1.0), RR(0.5)] + + result = construct_domain([3.14, I, S.Half]) + assert isinstance(result[0], ComplexField) + assert result[1] == [CC(3.14), CC(1.0j), CC(0.5)] + + assert construct_domain([1.0+I]) == (CC, [CC(1.0, 1.0)]) + assert construct_domain([2.0+3.0*I]) == (CC, [CC(2.0, 3.0)]) + + assert construct_domain([1, I]) == (ZZ_I, [ZZ_I(1, 0), ZZ_I(0, 1)]) + assert construct_domain([1, I/2]) == (QQ_I, [QQ_I(1, 0), QQ_I(0, S.Half)]) + + 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([x, sqrt(x)]) == (EX, [EX(x), EX(sqrt(x))]) + assert construct_domain([x, sqrt(x), sqrt(y)]) == (EX, [EX(x), EX(sqrt(x)), EX(sqrt(y))]) + + alg = QQ.algebraic_field(sqrt(2)) + + assert construct_domain([7, S.Half, sqrt(2)], extension=True) == \ + (alg, [alg.convert(7), alg.convert(S.Half), alg.convert(sqrt(2))]) + + 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))]) + + dom = ZZ[x] + + assert construct_domain([2*x, 3]) == \ + (dom, [dom.convert(2*x), dom.convert(3)]) + + dom = ZZ[x, y] + + assert construct_domain([2*x, 3*y]) == \ + (dom, [dom.convert(2*x), dom.convert(3*y)]) + + dom = QQ[x] + + assert construct_domain([x/2, 3]) == \ + (dom, [dom.convert(x/2), dom.convert(3)]) + + dom = QQ[x, y] + + assert construct_domain([x/2, 3*y]) == \ + (dom, [dom.convert(x/2), dom.convert(3*y)]) + + dom = ZZ_I[x] + + assert construct_domain([2*x, I]) == \ + (dom, [dom.convert(2*x), dom.convert(I)]) + + dom = ZZ_I[x, y] + + assert construct_domain([2*x, I*y]) == \ + (dom, [dom.convert(2*x), dom.convert(I*y)]) + + dom = QQ_I[x] + + assert construct_domain([x/2, I]) == \ + (dom, [dom.convert(x/2), dom.convert(I)]) + + dom = QQ_I[x, y] + + assert construct_domain([x/2, I*y]) == \ + (dom, [dom.convert(x/2), dom.convert(I*y)]) + + dom = RR[x] + + assert construct_domain([x/2, 3.5]) == \ + (dom, [dom.convert(x/2), dom.convert(3.5)]) + + dom = RR[x, y] + + assert construct_domain([x/2, 3.5*y]) == \ + (dom, [dom.convert(x/2), dom.convert(3.5*y)]) + + dom = CC[x] + + assert construct_domain([I*x/2, 3.5]) == \ + (dom, [dom.convert(I*x/2), dom.convert(3.5)]) + + dom = CC[x, y] + + assert construct_domain([I*x/2, 3.5*y]) == \ + (dom, [dom.convert(I*x/2), dom.convert(3.5*y)]) + + dom = CC[x] + + assert construct_domain([x/2, I*3.5]) == \ + (dom, [dom.convert(x/2), dom.convert(I*3.5)]) + + dom = CC[x, y] + + assert construct_domain([x/2, I*3.5*y]) == \ + (dom, [dom.convert(x/2), dom.convert(I*3.5*y)]) + + dom = ZZ.frac_field(x) + + assert construct_domain([2/x, 3]) == \ + (dom, [dom.convert(2/x), dom.convert(3)]) + + dom = ZZ.frac_field(x, y) + + assert construct_domain([2/x, 3*y]) == \ + (dom, [dom.convert(2/x), dom.convert(3*y)]) + + dom = RR.frac_field(x) + + assert construct_domain([2/x, 3.5]) == \ + (dom, [dom.convert(2/x), dom.convert(3.5)]) + + dom = RR.frac_field(x, y) + + assert construct_domain([2/x, 3.5*y]) == \ + (dom, [dom.convert(2/x), dom.convert(3.5*y)]) + + dom = RealField(prec=336)[x] + + assert construct_domain([pi.evalf(100)*x]) == \ + (dom, [dom.convert(pi.evalf(100)*x)]) + + assert construct_domain(2) == (ZZ, ZZ(2)) + assert construct_domain(S(2)/3) == (QQ, QQ(2, 3)) + assert construct_domain(Rational(2, 3)) == (QQ, QQ(2, 3)) + + assert construct_domain({}) == (ZZ, {}) + + +def test_complex_exponential(): + w = exp(-I*2*pi/3, evaluate=False) + alg = QQ.algebraic_field(w) + assert construct_domain([w**2, w, 1], extension=True) == ( + alg, + [alg.convert(w**2), + alg.convert(w), + alg.convert(1)] + ) + + +def test_rootof(): + r1 = rootof(x**3 + x + 1, 0) + r2 = rootof(x**3 + x + 1, 1) + K1 = QQ.algebraic_field(r1) + K2 = QQ.algebraic_field(r2) + assert construct_domain([r1]) == (EX, [EX(r1)]) + assert construct_domain([r2]) == (EX, [EX(r2)]) + assert construct_domain([r1, r2]) == (EX, [EX(r1), EX(r2)]) + + assert construct_domain([r1], extension=True) == ( + K1, [K1.from_sympy(r1)]) + assert construct_domain([r2], extension=True) == ( + K2, [K2.from_sympy(r2)]) + + +@tooslow +def test_rootof_primitive_element(): + r1 = rootof(x**3 + x + 1, 0) + r2 = rootof(x**3 + x + 1, 1) + K12 = QQ.algebraic_field(r1 + r2) + assert construct_domain([r1, r2], extension=True) == ( + K12, [K12.from_sympy(r1), K12.from_sympy(r2)]) + + +def test_composite_option(): + assert construct_domain({(1,): sin(y)}, composite=False) == \ + (EX, {(1,): EX(sin(y))}) + + assert construct_domain({(1,): y}, composite=False) == \ + (EX, {(1,): EX(y)}) + + assert construct_domain({(1, 1): 1}, composite=False) == \ + (ZZ, {(1, 1): 1}) + + assert construct_domain({(1, 0): y}, composite=False) == \ + (EX, {(1, 0): EX(y)}) + + +def test_precision(): + f1 = Float("1.01") + f2 = Float("1.0000000000000000000001") + for u in [1, 1e-2, 1e-6, 1e-13, 1e-14, 1e-16, 1e-20, 1e-100, 1e-300, + f1, f2]: + result = construct_domain([u]) + v = float(result[1][0]) + assert abs(u - v) / u < 1e-14 # Test relative accuracy + + result = construct_domain([f1]) + y = result[1][0] + assert y-1 > 1e-50 + + result = construct_domain([f2]) + y = result[1][0] + assert y-1 > 1e-50 + + +def test_issue_11538(): + for n in [E, pi, Catalan]: + assert construct_domain(n)[0] == ZZ[n] + assert construct_domain(x + n)[0] == ZZ[x, n] + assert construct_domain(GoldenRatio)[0] == EX + assert construct_domain(x + GoldenRatio)[0] == EX diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_densearith.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_densearith.py new file mode 100644 index 0000000000000000000000000000000000000000..ebb29d50867ad578274ed11c766e0515d8e4da35 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_densearith.py @@ -0,0 +1,1007 @@ +"""Tests for dense recursive polynomials' arithmetics. """ + +from sympy.external.gmpy import GROUND_TYPES + +from sympy.polys.densebasic import ( + dup_normal, dmp_normal, +) + +from sympy.polys.densearith import ( + dup_add_term, dmp_add_term, + dup_sub_term, dmp_sub_term, + dup_mul_term, dmp_mul_term, + dup_add_ground, dmp_add_ground, + dup_sub_ground, dmp_sub_ground, + dup_mul_ground, dmp_mul_ground, + dup_quo_ground, dmp_quo_ground, + dup_exquo_ground, dmp_exquo_ground, + dup_lshift, dup_rshift, + dup_abs, dmp_abs, + dup_neg, dmp_neg, + dup_add, dmp_add, + dup_sub, dmp_sub, + dup_mul, dmp_mul, + dup_sqr, dmp_sqr, + dup_pow, dmp_pow, + dup_add_mul, dmp_add_mul, + dup_sub_mul, dmp_sub_mul, + dup_pdiv, dup_prem, dup_pquo, dup_pexquo, + dmp_pdiv, dmp_prem, dmp_pquo, dmp_pexquo, + dup_rr_div, dmp_rr_div, + dup_ff_div, dmp_ff_div, + dup_div, dup_rem, dup_quo, dup_exquo, + dmp_div, dmp_rem, dmp_quo, dmp_exquo, + dup_max_norm, dmp_max_norm, + dup_l1_norm, dmp_l1_norm, + dup_l2_norm_squared, dmp_l2_norm_squared, + dup_expand, dmp_expand, +) + +from sympy.polys.polyerrors import ( + ExactQuotientFailed, +) + +from sympy.polys.specialpolys import f_polys, Symbol, Poly +from sympy.polys.domains import FF, ZZ, QQ, CC + +from sympy.testing.pytest import raises + +x = Symbol('x') + +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) + + assert dup_add_term(f, ZZ(0), 0, ZZ) == dup_normal([], ZZ) + + assert dup_add_term(f, ZZ(1), 0, ZZ) == dup_normal([1], ZZ) + 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) + + 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) + assert dup_add_term(f, ZZ(1), 2, ZZ) == dup_normal([2, 1, 1], ZZ) + + 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), 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(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) + + assert dup_sub_term(f, ZZ(0), 0, ZZ) == dup_normal([], ZZ) + + assert dup_sub_term(f, ZZ(1), 0, ZZ) == dup_normal([-1], ZZ) + 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) + + 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), 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(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) + + assert dup_mul_term(f, ZZ(0), 3, ZZ) == dup_normal([], 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) + + +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(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([[]], [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)], [], []] + + +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 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 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 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) + + 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) + + +def test_dmp_mul_ground(): + assert dmp_mul_ground(f_0, ZZ(2), 2, ZZ) == [ + [[ZZ(2), ZZ(4), ZZ(6)], [ZZ(4)]], + [[ZZ(6)]], + [[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)]] + ] + + +def test_dup_quo_ground(): + 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) + + 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(3), ZZ) == dup_normal([2, 0, 2], ZZ) + + 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)] + + +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)) + + f = dup_normal([], ZZ) + + assert dup_exquo_ground(f, ZZ(3), ZZ) == dup_normal([], 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) + + 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)] + + +def test_dmp_quo_ground(): + 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_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) + + 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) + + +def test_dup_lshift(): + assert dup_lshift([], 3, ZZ) == [] + 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] + + +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([], 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)] + + +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([[[]]], 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)]]] + + +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([], 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)] + + +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([[[]]], 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)]]] + + +def test_dup_add(): + assert dup_add([], [], ZZ) == [] + assert dup_add([ZZ(1)], [], ZZ) == [ZZ(1)] + assert dup_add([], [ZZ(1)], ZZ) == [ZZ(1)] + 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(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(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)] + + +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([[[]]], [[[]]], 2, ZZ) == [[[]]] + assert dmp_add([[[ZZ(1)]]], [[[]]], 2, ZZ) == [[[ZZ(1)]]] + assert dmp_add([[[]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(1)]]] + assert dmp_add([[[ZZ(2)]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(3)]]] + 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)]]] + + +def test_dup_sub(): + assert dup_sub([], [], ZZ) == [] + assert dup_sub([ZZ(1)], [], ZZ) == [ZZ(1)] + assert dup_sub([], [ZZ(1)], ZZ) == [ZZ(-1)] + 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(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, 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)] + + +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([[[]]], [[[]]], 2, ZZ) == [[[]]] + assert dmp_sub([[[ZZ(1)]]], [[[]]], 2, ZZ) == [[[ZZ(1)]]] + assert dmp_sub([[[]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(-1)]]] + assert dmp_sub([[[ZZ(2)]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(1)]]] + 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)]]] + + +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 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 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) == [] + assert dup_mul([], [ZZ(1)], ZZ) == [] + assert dup_mul([ZZ(1)], [], ZZ) == [] + assert dup_mul([ZZ(1)], [ZZ(1)], ZZ) == [ZZ(1)] + 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(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) + + 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)] + + p1 = dup_normal([79, -1, 78, -94, -10, 11, 32, -19, 78, 2, -89, 30, 73, 42, + 85, 77, 83, -30, -34, -2, 95, -81, 37, -49, -46, -58, -16, 37, 35, -11, + -57, -15, -31, 67, -20, 27, 76, 2, 70, 67, -65, 65, -26, -93, -44, -12, + -92, 57, -90, -57, -11, -67, -98, -69, 97, -41, 89, 33, 89, -50, 81, + -31, 60, -27, 43, 29, -77, 44, 21, -91, 32, -57, 33, 3, 53, -51, -38, + -99, -84, 23, -50, 66, -100, 1, -75, -25, 27, -60, 98, -51, -87, 6, 8, + 78, -28, -95, -88, 12, -35, 26, -9, 16, -92, 55, -7, -86, 68, -39, -46, + 84, 94, 45, 60, 92, 68, -75, -74, -19, 8, 75, 78, 91, 57, 34, 14, -3, + -49, 65, 78, -18, 6, -29, -80, -98, 17, 13, 58, 21, 20, 9, 37, 7, -30, + -53, -20, 34, 67, -42, 89, -22, 73, 43, -6, 5, 51, -8, -15, -52, -22, + -58, -72, -3, 43, -92, 82, 83, -2, -13, -23, -60, 16, -94, -8, -28, + -95, -72, 63, -90, 76, 6, -43, -100, -59, 76, 3, 3, 46, -85, 75, 62, + -71, -76, 88, 97, -72, -1, 30, -64, 72, -48, 14, -78, 58, 63, -91, 24, + -87, -27, -80, -100, -44, 98, 70, 100, -29, -38, 11, 77, 100, 52, 86, + 65, -5, -42, -81, -38, -42, 43, -2, -70, -63, -52], ZZ) + p2 = dup_normal([65, -19, -47, 1, 90, 81, -15, -34, 25, -75, 9, -83, 50, -5, + -44, 31, 1, 70, -7, 78, 74, 80, 85, 65, 21, 41, 66, 19, -40, 63, -21, + -27, 32, 69, 83, 34, -35, 14, 81, 57, -75, 32, -67, -89, -100, -61, 46, + 84, -78, -29, -50, -94, -24, -32, -68, -16, 100, -7, -72, -89, 35, 82, + 58, 81, -92, 62, 5, -47, -39, -58, -72, -13, 84, 44, 55, -25, 48, -54, + -31, -56, -11, -50, -84, 10, 67, 17, 13, -14, 61, 76, -64, -44, -40, + -96, 11, -11, -94, 2, 6, 27, -6, 68, -54, 66, -74, -14, -1, -24, -73, + 96, 89, -11, -89, 56, -53, 72, -43, 96, 25, 63, -31, 29, 68, 83, 91, + -93, -19, -38, -40, 40, -12, -19, -79, 44, 100, -66, -29, -77, 62, 39, + -8, 11, -97, 14, 87, 64, 21, -18, 13, 15, -59, -75, -99, -88, 57, 54, + 56, -67, 6, -63, -59, -14, 28, 87, -20, -39, 84, -91, -2, 49, -75, 11, + -24, -95, 36, 66, 5, 25, -72, -40, 86, 90, 37, -33, 57, -35, 29, -18, + 4, -79, 64, -17, -27, 21, 29, -5, -44, -87, -24, 52, 78, 11, -23, -53, + 36, 42, 21, -68, 94, -91, -51, -21, 51, -76, 72, 31, 24, -48, -80, -9, + 37, -47, -6, -8, -63, -91, 79, -79, -100, 38, -20, 38, 100, 83, -90, + 87, 63, -36, 82, -19, 18, -98, -38, 26, 98, -70, 79, 92, 12, 12, 70, + 74, 36, 48, -13, 31, 31, -47, -71, -12, -64, 36, -42, 32, -86, 60, 83, + 70, 55, 0, 1, 29, -35, 8, -82, 8, -73, -46, -50, 43, 48, -5, -86, -72, + 44, -90, 19, 19, 5, -20, 97, -13, -66, -5, 5, -69, 64, -30, 41, 51, 36, + 13, -99, -61, 94, -12, 74, 98, 68, 24, 46, -97, -87, -6, -27, 82, 62, + -11, -77, 86, 66, -47, -49, -50, 13, 18, 89, -89, 46, -80, 13, 98, -35, + -36, -25, 12, 20, 26, -52, 79, 27, 79, 100, 8, 62, -58, -28, 37], ZZ) + res = dup_normal([5135, -1566, 1376, -7466, 4579, 11710, 8001, -7183, + -3737, -7439, 345, -10084, 24522, -1201, 1070, -10245, 9582, 9264, + 1903, 23312, 18953, 10037, -15268, -5450, 6442, -6243, -3777, 5110, + 10936, -16649, -6022, 16255, 31300, 24818, 31922, 32760, 7854, 27080, + 15766, 29596, 7139, 31945, -19810, 465, -38026, -3971, 9641, 465, + -19375, 5524, -30112, -11960, -12813, 13535, 30670, 5925, -43725, + -14089, 11503, -22782, 6371, 43881, 37465, -33529, -33590, -39798, + -37854, -18466, -7908, -35825, -26020, -36923, -11332, -5699, 25166, + -3147, 19885, 12962, -20659, -1642, 27723, -56331, -24580, -11010, + -20206, 20087, -23772, -16038, 38580, 20901, -50731, 32037, -4299, + 26508, 18038, -28357, 31846, -7405, -20172, -15894, 2096, 25110, + -45786, 45918, -55333, -31928, -49428, -29824, -58796, -24609, -15408, + 69, -35415, -18439, 10123, -20360, -65949, 33356, -20333, 26476, + -32073, 33621, 930, 28803, -42791, 44716, 38164, 12302, -1739, 11421, + 73385, -7613, 14297, 38155, -414, 77587, 24338, -21415, 29367, 42639, + 13901, -288, 51027, -11827, 91260, 43407, 88521, -15186, 70572, -12049, + 5090, -12208, -56374, 15520, -623, -7742, 50825, 11199, -14894, 40892, + 59591, -31356, -28696, -57842, -87751, -33744, -28436, -28945, -40287, + 37957, -35638, 33401, -61534, 14870, 40292, 70366, -10803, 102290, + -71719, -85251, 7902, -22409, 75009, 99927, 35298, -1175, -762, -34744, + -10587, -47574, -62629, -19581, -43659, -54369, -32250, -39545, 15225, + -24454, 11241, -67308, -30148, 39929, 37639, 14383, -73475, -77636, + -81048, -35992, 41601, -90143, 76937, -8112, 56588, 9124, -40094, + -32340, 13253, 10898, -51639, 36390, 12086, -1885, 100714, -28561, + -23784, -18735, 18916, 16286, 10742, -87360, -13697, 10689, -19477, + -29770, 5060, 20189, -8297, 112407, 47071, 47743, 45519, -4109, 17468, + -68831, 78325, -6481, -21641, -19459, 30919, 96115, 8607, 53341, 32105, + -16211, 23538, 57259, -76272, -40583, 62093, 38511, -34255, -40665, + -40604, -37606, -15274, 33156, -13885, 103636, 118678, -14101, -92682, + -100791, 2634, 63791, 98266, 19286, -34590, -21067, -71130, 25380, + -40839, -27614, -26060, 52358, -15537, 27138, -6749, 36269, -33306, + 13207, -91084, -5540, -57116, 69548, 44169, -57742, -41234, -103327, + -62904, -8566, 41149, -12866, 71188, 23980, 1838, 58230, 73950, 5594, + 43113, -8159, -15925, 6911, 85598, -75016, -16214, -62726, -39016, + 8618, -63882, -4299, 23182, 49959, 49342, -3238, -24913, -37138, 78361, + 32451, 6337, -11438, -36241, -37737, 8169, -3077, -24829, 57953, 53016, + -31511, -91168, 12599, -41849, 41576, 55275, -62539, 47814, -62319, + 12300, -32076, -55137, -84881, -27546, 4312, -3433, -54382, 113288, + -30157, 74469, 18219, 79880, -2124, 98911, 17655, -33499, -32861, + 47242, -37393, 99765, 14831, -44483, 10800, -31617, -52710, 37406, + 22105, 29704, -20050, 13778, 43683, 36628, 8494, 60964, -22644, 31550, + -17693, 33805, -124879, -12302, 19343, 20400, -30937, -21574, -34037, + -33380, 56539, -24993, -75513, -1527, 53563, 65407, -101, 53577, 37991, + 18717, -23795, -8090, -47987, -94717, 41967, 5170, -14815, -94311, + 17896, -17734, -57718, -774, -38410, 24830, 29682, 76480, 58802, + -46416, -20348, -61353, -68225, -68306, 23822, -31598, 42972, 36327, + 28968, -65638, -21638, 24354, -8356, 26777, 52982, -11783, -44051, + -26467, -44721, -28435, -53265, -25574, -2669, 44155, 22946, -18454, + -30718, -11252, 58420, 8711, 67447, 4425, 41749, 67543, 43162, 11793, + -41907, 20477, -13080, 6559, -6104, -13244, 42853, 42935, 29793, 36730, + -28087, 28657, 17946, 7503, 7204, 21491, -27450, -24241, -98156, + -18082, -42613, -24928, 10775, -14842, -44127, 55910, 14777, 31151, -2194, + 39206, -2100, -4211, 11827, -8918, -19471, 72567, 36447, -65590, -34861, + -17147, -45303, 9025, -7333, -35473, 11101, 11638, 3441, 6626, -41800, + 9416, 13679, 33508, 40502, -60542, 16358, 8392, -43242, -35864, -34127, + -48721, 35878, 30598, 28630, 20279, -19983, -14638, -24455, -1851, -11344, + 45150, 42051, 26034, -28889, -32382, -3527, -14532, 22564, -22346, 477, + 11706, 28338, -25972, -9185, -22867, -12522, 32120, -4424, 11339, -33913, + -7184, 5101, -23552, -17115, -31401, -6104, 21906, 25708, 8406, 6317, + -7525, 5014, 20750, 20179, 22724, 11692, 13297, 2493, -253, -16841, -17339, + -6753, -4808, 2976, -10881, -10228, -13816, -12686, 1385, 2316, 2190, -875, + -1924], ZZ) + + assert dup_mul(p1, p2, ZZ) == res + + p1 = dup_normal([83, -61, -86, -24, 12, 43, -88, -9, 42, 55, -66, 74, 95, + -25, -12, 68, -99, 4, 45, 6, -15, -19, 78, 65, -55, 47, -13, 17, 86, + 81, -58, -27, 50, -40, -24, 39, -41, -92, 75, 90, -1, 40, -15, -27, + -35, 68, 70, -64, -40, 78, -88, -58, -39, 69, 46, 12, 28, -94, -37, + -50, -80, -96, -61, 25, 1, 71, 4, 12, 48, 4, 34, -47, -75, 5, 48, 82, + 88, 23, 98, 35, 17, -10, 48, -61, -95, 47, 65, -19, -66, -57, -6, -51, + -42, -89, 66, -13, 18, 37, 90, -23, 72, 96, -53, 0, 40, -73, -52, -68, + 32, -25, -53, 79, -52, 18, 44, 73, -81, 31, -90, 70, 3, 36, 48, 76, + -24, -44, 23, 98, -4, 73, 69, 88, -70, 14, -68, 94, -78, -15, -64, -97, + -70, -35, 65, 88, 49, -53, -7, 12, -45, -7, 59, -94, 99, -2, 67, -60, + -71, 29, -62, -77, 1, 51, 17, 80, -20, -47, -19, 24, -9, 39, -23, 21, + -84, 10, 84, 56, -17, -21, -66, 85, 70, 46, -51, -22, -95, 78, -60, + -96, -97, -45, 72, 35, 30, -61, -92, -93, -60, -61, 4, -4, -81, -73, + 46, 53, -11, 26, 94, 45, 14, -78, 55, 84, -68, 98, 60, 23, 100, -63, + 68, 96, -16, 3, 56, 21, -58, 62, -67, 66, 85, 41, -79, -22, 97, -67, + 82, 82, -96, -20, -7, 48, -67, 48, -9, -39, 78], ZZ) + p2 = dup_normal([52, 88, 76, 66, 9, -64, 46, -20, -28, 69, 60, 96, -36, + -92, -30, -11, -35, 35, 55, 63, -92, -7, 25, -58, 74, 55, -6, 4, 47, + -92, -65, 67, -45, 74, -76, 59, -6, 69, 39, 24, -71, -7, 39, -45, 60, + -68, 98, 97, -79, 17, 4, 94, -64, 68, -100, -96, -2, 3, 22, 96, 54, + -77, -86, 67, 6, 57, 37, 40, 89, -78, 64, -94, -45, -92, 57, 87, -26, + 36, 19, 97, 25, 77, -87, 24, 43, -5, 35, 57, 83, 71, 35, 63, 61, 96, + -22, 8, -1, 96, 43, 45, 94, -93, 36, 71, -41, -99, 85, -48, 59, 52, + -17, 5, 87, -16, -68, -54, 76, -18, 100, 91, -42, -70, -66, -88, -12, + 1, 95, -82, 52, 43, -29, 3, 12, 72, -99, -43, -32, -93, -51, 16, -20, + -12, -11, 5, 33, -38, 93, -5, -74, 25, 74, -58, 93, 59, -63, -86, 63, + -20, -4, -74, -73, -95, 29, -28, 93, -91, -2, -38, -62, 77, -58, -85, + -28, 95, 38, 19, -69, 86, 94, 25, -2, -4, 47, 34, -59, 35, -48, 29, + -63, -53, 34, 29, 66, 73, 6, 92, -84, 89, 15, 81, 93, 97, 51, -72, -78, + 25, 60, 90, -45, 39, 67, -84, -62, 57, 26, -32, -56, -14, -83, 76, 5, + -2, 99, -100, 28, 46, 94, -7, 53, -25, 16, -23, -36, 89, -78, -63, 31, + 1, 84, -99, -52, 76, 48, 90, -76, 44, -19, 54, -36, -9, -73, -100, -69, + 31, 42, 25, -39, 76, -26, -8, -14, 51, 3, 37, 45, 2, -54, 13, -34, -92, + 17, -25, -65, 53, -63, 30, 4, -70, -67, 90, 52, 51, 18, -3, 31, -45, + -9, 59, 63, -87, 22, -32, 29, -38, 21, 36, -82, 27, -11], ZZ) + res = dup_normal([4316, 4132, -3532, -7974, -11303, -10069, 5484, -3330, + -5874, 7734, 4673, 11327, -9884, -8031, 17343, 21035, -10570, -9285, + 15893, 3780, -14083, 8819, 17592, 10159, 7174, -11587, 8598, -16479, + 3602, 25596, 9781, 12163, 150, 18749, -21782, -12307, 27578, -2757, + -12573, 12565, 6345, -18956, 19503, -15617, 1443, -16778, 36851, 23588, + -28474, 5749, 40695, -7521, -53669, -2497, -18530, 6770, 57038, 3926, + -6927, -15399, 1848, -64649, -27728, 3644, 49608, 15187, -8902, -9480, + -7398, -40425, 4824, 23767, -7594, -6905, 33089, 18786, 12192, 24670, + 31114, 35334, -4501, -14676, 7107, -59018, -21352, 20777, 19661, 20653, + 33754, -885, -43758, 6269, 51897, -28719, -97488, -9527, 13746, 11644, + 17644, -21720, 23782, -10481, 47867, 20752, 33810, -1875, 39918, -7710, + -40840, 19808, -47075, 23066, 46616, 25201, 9287, 35436, -1602, 9645, + -11978, 13273, 15544, 33465, 20063, 44539, 11687, 27314, -6538, -37467, + 14031, 32970, -27086, 41323, 29551, 65910, -39027, -37800, -22232, + 8212, 46316, -28981, -55282, 50417, -44929, -44062, 73879, 37573, + -2596, -10877, -21893, -133218, -33707, -25753, -9531, 17530, 61126, + 2748, -56235, 43874, -10872, -90459, -30387, 115267, -7264, -44452, + 122626, 14839, -599, 10337, 57166, -67467, -54957, 63669, 1202, 18488, + 52594, 7205, -97822, 612, 78069, -5403, -63562, 47236, 36873, -154827, + -26188, 82427, -39521, 5628, 7416, 5276, -53095, 47050, 26121, -42207, + 79021, -13035, 2499, -66943, 29040, -72355, -23480, 23416, -12885, + -44225, -42688, -4224, 19858, 55299, 15735, 11465, 101876, -39169, + 51786, 14723, 43280, -68697, 16410, 92295, 56767, 7183, 111850, 4550, + 115451, -38443, -19642, -35058, 10230, 93829, 8925, 63047, 3146, 29250, + 8530, 5255, -98117, -115517, -76817, -8724, 41044, 1312, -35974, 79333, + -28567, 7547, -10580, -24559, -16238, 10794, -3867, 24848, 57770, + -51536, -35040, 71033, 29853, 62029, -7125, -125585, -32169, -47907, + 156811, -65176, -58006, -15757, -57861, 11963, 30225, -41901, -41681, + 31310, 27982, 18613, 61760, 60746, -59096, 33499, 30097, -17997, 24032, + 56442, -83042, 23747, -20931, -21978, -158752, -9883, -73598, -7987, + -7333, -125403, -116329, 30585, 53281, 51018, -29193, 88575, 8264, + -40147, -16289, 113088, 12810, -6508, 101552, -13037, 34440, -41840, + 101643, 24263, 80532, 61748, 65574, 6423, -20672, 6591, -10834, -71716, + 86919, -92626, 39161, 28490, 81319, 46676, 106720, 43530, 26998, 57456, + -8862, 60989, 13982, 3119, -2224, 14743, 55415, -49093, -29303, 28999, + 1789, 55953, -84043, -7780, -65013, 57129, -47251, 61484, 61994, + -78361, -82778, 22487, -26894, 9756, -74637, -15519, -4360, 30115, + 42433, 35475, 15286, 69768, 21509, -20214, 78675, -21163, 13596, 11443, + -10698, -53621, -53867, -24155, 64500, -42784, -33077, -16500, 873, + -52788, 14546, -38011, 36974, -39849, -34029, -94311, 83068, -50437, + -26169, -46746, 59185, 42259, -101379, -12943, 30089, -59086, 36271, + 22723, -30253, -52472, -70826, -23289, 3331, -31687, 14183, -857, + -28627, 35246, -51284, 5636, -6933, 66539, 36654, 50927, 24783, 3457, + 33276, 45281, 45650, -4938, -9968, -22590, 47995, 69229, 5214, -58365, + -17907, -14651, 18668, 18009, 12649, -11851, -13387, 20339, 52472, + -1087, -21458, -68647, 52295, 15849, 40608, 15323, 25164, -29368, + 10352, -7055, 7159, 21695, -5373, -54849, 101103, -24963, -10511, + 33227, 7659, 41042, -69588, 26718, -20515, 6441, 38135, -63, 24088, + -35364, -12785, -18709, 47843, 48533, -48575, 17251, -19394, 32878, + -9010, -9050, 504, -12407, 28076, -3429, 25324, -4210, -26119, 752, + -29203, 28251, -11324, -32140, -3366, -25135, 18702, -31588, -7047, + -24267, 49987, -14975, -33169, 37744, -7720, -9035, 16964, -2807, -421, + 14114, -17097, -13662, 40628, -12139, -9427, 5369, 17551, -13232, -16211, + 9804, -7422, 2677, 28635, -8280, -4906, 2908, -22558, 5604, 12459, 8756, + -3980, -4745, -18525, 7913, 5970, -16457, 20230, -6247, -13812, 2505, + 11899, 1409, -15094, 22540, -18863, 137, 11123, -4516, 2290, -8594, 12150, + -10380, 3005, 5235, -7350, 2535, -858], ZZ) + + assert dup_mul(p1, p2, ZZ) == res + + +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) + + assert dmp_mul([[[]]], [[[]]], 2, ZZ) == [[[]]] + assert dmp_mul([[[ZZ(1)]]], [[[]]], 2, ZZ) == [[[]]] + assert dmp_mul([[[]]], [[[ZZ(1)]]], 2, ZZ) == [[[]]] + assert dmp_mul([[[ZZ(2)]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(2)]]] + 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)]]] + + K = FF(6) + + 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([], 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)] + + 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) + + K = FF(9) + + 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([[[]]], 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)]]] + + K = FF(9) + + assert dmp_sqr([[K(3)], [K(4)]], 1, K) == [[K(6)], [K(7)]] + + +def test_dup_pow(): + assert dup_pow([], 0, ZZ) == [ZZ(1)] + assert dup_pow([], 0, QQ) == [QQ(1)] + + assert dup_pow([], 1, ZZ) == [] + assert dup_pow([], 7, ZZ) == [] + + assert dup_pow([ZZ(1)], 0, ZZ) == [ZZ(1)] + assert dup_pow([ZZ(1)], 1, ZZ) == [ZZ(1)] + assert dup_pow([ZZ(1)], 7, ZZ) == [ZZ(1)] + + assert dup_pow([ZZ(3)], 0, ZZ) == [ZZ(1)] + 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)] + + 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) + + +def test_dmp_pow(): + assert dmp_pow([[]], 0, 1, ZZ) == [[ZZ(1)]] + assert dmp_pow([[]], 0, 1, QQ) == [[QQ(1)]] + + assert dmp_pow([[]], 1, 1, ZZ) == [[]] + assert dmp_pow([[]], 7, 1, ZZ) == [[]] + + assert dmp_pow([[ZZ(1)]], 0, 1, ZZ) == [[ZZ(1)]] + 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)]] + + 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) + + q = dup_normal([15, 14], ZZ) + r = dup_normal([52, 111], ZZ) + + assert dup_pdiv(f, g, ZZ) == (q, r) + assert dup_pquo(f, g, ZZ) == q + assert dup_prem(f, g, ZZ) == r + + raises(ExactQuotientFailed, lambda: dup_pexquo(f, g, ZZ)) + + 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) + + assert dup_pdiv(f, g, QQ) == (q, r) + assert dup_pquo(f, g, QQ) == q + assert dup_prem(f, g, QQ) == r + + 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) + + q = dmp_normal([[1], [1, 0]], 1, ZZ) + r = dmp_normal([[2, 0, 0]], 1, ZZ) + + assert dmp_pdiv(f, g, 1, ZZ) == (q, r) + assert dmp_pquo(f, g, 1, ZZ) == q + assert dmp_prem(f, g, 1, ZZ) == r + + 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) + + q = dmp_normal([[2], [2, 0]], 1, ZZ) + r = dmp_normal([[8, 0, 0]], 1, ZZ) + + assert dmp_pdiv(f, g, 1, ZZ) == (q, r) + assert dmp_pquo(f, g, 1, ZZ) == q + assert dmp_prem(f, g, 1, ZZ) == r + + raises(ExactQuotientFailed, lambda: dmp_pexquo(f, g, 1, ZZ)) + + +def test_dup_rr_div(): + 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) + + 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)) + + 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) + + 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) + + 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)) + + 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)] + + assert dup_ff_div(f, g, QQ) == (q, r) + +def test_dup_ff_div_gmpy2(): + if GROUND_TYPES != 'gmpy2': + return + + from gmpy2 import mpq + from sympy.polys.domains import GMPYRationalField + K = GMPYRationalField() + + f = [mpq(1,3), mpq(3,2)] + g = [mpq(2,1)] + assert dmp_ff_div(f, g, 0, K) == ([mpq(1,6), mpq(3,4)], []) + + f = [mpq(1,2), mpq(1,3), mpq(1,4), mpq(1,5)] + g = [mpq(-1,1), mpq(1,1), mpq(-1,1)] + assert dmp_ff_div(f, g, 0, K) == ([mpq(-1,2), mpq(-5,6)], [mpq(7,12), mpq(-19,30)]) + +def test_dmp_ff_div(): + 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) + + 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) + + 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) + + 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] + + assert dup_div(f, g, ZZ) == (q, r) + assert dup_quo(f, g, ZZ) == q + assert dup_rem(f, g, ZZ) == r + + 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] + + assert dup_div(f, g, ZZ) == (q, r) + assert dup_quo(f, g, ZZ) == q + assert dup_rem(f, g, ZZ) == r + + 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] + + assert dmp_div(f, g, 0, ZZ) == (q, r) + assert dmp_quo(f, g, 0, ZZ) == q + assert dmp_rem(f, g, 0, ZZ) == r + + raises(ExactQuotientFailed, lambda: dmp_exquo(f, g, 0, ZZ)) + + 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 + assert dmp_rem(f, g, 2, ZZ) == r + + 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 + + +def test_dmp_max_norm(): + assert dmp_max_norm([[[]]], 2, ZZ) == 0 + assert dmp_max_norm([[[1]]], 2, ZZ) == 1 + + 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 + + +def test_dmp_l1_norm(): + assert dmp_l1_norm([[[]]], 2, ZZ) == 0 + assert dmp_l1_norm([[[1]]], 2, ZZ) == 1 + + assert dmp_l1_norm(f_0, 2, ZZ) == 31 + + +def test_dup_l2_norm_squared(): + assert dup_l2_norm_squared([], ZZ) == 0 + assert dup_l2_norm_squared([1], ZZ) == 1 + assert dup_l2_norm_squared([1, 4, 2, 3], ZZ) == 30 + + +def test_dmp_l2_norm_squared(): + assert dmp_l2_norm_squared([[[]]], 2, ZZ) == 0 + assert dmp_l2_norm_squared([[[1]]], 2, ZZ) == 1 + assert dmp_l2_norm_squared(f_0, 2, ZZ) == 111 + + +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) + + +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) + +def test_dup_mul_poly(): + p = Poly(18786186952704.0*x**165 + 9.31746684052255e+31*x**82, x, domain='RR') + px = Poly(18786186952704.0*x**166 + 9.31746684052255e+31*x**83, x, domain='RR') + + assert p * x == px + assert p.set_domain(QQ) * x == px.set_domain(QQ) + assert p.set_domain(CC) * x == px.set_domain(CC) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_densebasic.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_densebasic.py new file mode 100644 index 0000000000000000000000000000000000000000..43386d86d0e6ec7b20d3962d8063aa6402165f9a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_densebasic.py @@ -0,0 +1,730 @@ +"""Tests for dense recursive polynomials' basic tools. """ + +from sympy.polys.densebasic import ( + ninf, + dup_LC, dmp_LC, + dup_TC, dmp_TC, + dmp_ground_LC, dmp_ground_TC, + dmp_true_LT, + dup_degree, dmp_degree, + dmp_degree_in, dmp_degree_list, + dup_strip, dmp_strip, + dmp_validate, + dup_reverse, + dup_copy, dmp_copy, + dup_normal, dmp_normal, + dup_convert, dmp_convert, + dup_from_sympy, dmp_from_sympy, + dup_nth, dmp_nth, dmp_ground_nth, + dmp_zero_p, dmp_zero, + dmp_one_p, dmp_one, + dmp_ground_p, dmp_ground, + dmp_negative_p, dmp_positive_p, + dmp_zeros, dmp_grounds, + dup_from_dict, dup_from_raw_dict, + dup_to_dict, dup_to_raw_dict, + dmp_from_dict, dmp_to_dict, + dmp_swap, dmp_permute, + dmp_nest, dmp_raise, + dup_deflate, dmp_deflate, + dup_multi_deflate, dmp_multi_deflate, + dup_inflate, dmp_inflate, + dmp_exclude, dmp_include, + dmp_inject, dmp_eject, + dup_terms_gcd, dmp_terms_gcd, + dmp_list_terms, dmp_apply_pairs, + dup_slice, + dup_random, +) + +from sympy.polys.specialpolys import f_polys +from sympy.polys.domains import ZZ, QQ +from sympy.polys.rings import ring + +from sympy.core.singleton import S +from sympy.testing.pytest import raises + +from sympy.core.numbers import oo + +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 + + +def test_dup_TC(): + assert dup_TC([], ZZ) == 0 + 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([[[]]], ZZ) == [[]] + 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([[[]]], ZZ) == [[]] + 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, ZZ) == 0 + 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, ZZ) == 0 + 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) + + +def test_dup_degree(): + assert ninf == float('-inf') + assert dup_degree([]) is ninf + assert dup_degree([1]) == 0 + assert dup_degree([1, 0]) == 1 + assert dup_degree([1, 0, 0, 0, 1]) == 4 + + +def test_dmp_degree(): + assert dmp_degree([[]], 1) is ninf + assert dmp_degree([[[]]], 2) is ninf + + assert dmp_degree([[1]], 1) == 0 + assert dmp_degree([[2], [1]], 1) == 1 + + +def test_dmp_degree_in(): + assert dmp_degree_in([[[]]], 0, 2) is ninf + assert dmp_degree_in([[[]]], 1, 2) is ninf + assert dmp_degree_in([[[]]], 2, 2) is ninf + + assert dmp_degree_in([[[1]]], 0, 2) == 0 + assert dmp_degree_in([[[1]]], 1, 2) == 0 + assert dmp_degree_in([[[1]]], 2, 2) == 0 + + assert dmp_degree_in(f_4, 0, 2) == 9 + assert dmp_degree_in(f_4, 1, 2) == 12 + assert dmp_degree_in(f_4, 2, 2) == 8 + + assert dmp_degree_in(f_6, 0, 2) == 4 + assert dmp_degree_in(f_6, 1, 2) == 4 + assert dmp_degree_in(f_6, 2, 2) == 6 + assert dmp_degree_in(f_6, 3, 3) == 3 + + raises(IndexError, lambda: dmp_degree_in([[1]], -5, 1)) + + +def test_dmp_degree_list(): + assert dmp_degree_list([[[[ ]]]], 3) == (-oo, -oo, -oo, -oo) + assert dmp_degree_list([[[[1]]]], 3) == ( 0, 0, 0, 0) + + assert dmp_degree_list(f_0, 2) == (2, 2, 2) + assert dmp_degree_list(f_1, 2) == (3, 3, 3) + assert dmp_degree_list(f_2, 2) == (5, 3, 3) + assert dmp_degree_list(f_3, 2) == (5, 4, 7) + assert dmp_degree_list(f_4, 2) == (9, 12, 8) + 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([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] + + +def test_dmp_strip(): + assert dmp_strip([0, 1, 0], 0) == [1, 0] + + assert dmp_strip([[]], 1) == [[]] + assert dmp_strip([[], []], 1) == [[]] + assert dmp_strip([[], [], []], 1) == [[]] + + assert dmp_strip([[[]]], 2) == [[[]]] + assert dmp_strip([[[]], [[]]], 2) == [[[]]] + assert dmp_strip([[[]], [[]], [[]]], 2) == [[[]]] + + assert dmp_strip([[[1]]], 2) == [[[1]]] + 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([[[]]]) == ([[[]]], 2) + assert dmp_validate([[0], [], [0], [1], [0]]) == ([[1], []], 1) + + 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] + + +def test_dup_copy(): + 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)]] + 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)] + + +def test_dmp_normal(): + 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 = [K0(1), K0(2), K0(0), K0(3)] + + assert dup_convert(f, K0, K1) == \ + [ZZ(1), ZZ(2), ZZ(0), ZZ(3)] + + +def test_dmp_convert(): + K0, K1 = ZZ['x'], ZZ + + f = [[K0(1)], [K0(2)], [], [K0(3)]] + + assert dmp_convert(f, 1, K0, K1) == \ + [[ZZ(1)], [ZZ(2)], [], [ZZ(3)]] + + +def test_dup_from_sympy(): + assert dup_from_sympy([S.One, S(2)], ZZ) == \ + [ZZ(1), ZZ(2)] + assert dup_from_sympy([S.Half, S(3)], QQ) == \ + [QQ(1, 2), QQ(3, 1)] + + +def test_dmp_from_sympy(): + assert dmp_from_sympy([[S.One, S(2)], [S.Zero]], 1, ZZ) == \ + [[ZZ(1), ZZ(2)], []] + assert dmp_from_sympy([[S.Half, 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], 9, ZZ) == 0 + + 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]], 9, 1, ZZ) == [] + + raises(IndexError, lambda: dmp_nth([[3], [4], [5]], -1, 1, ZZ)) + + +def test_dmp_ground_nth(): + assert dmp_ground_nth([[]], (0, 0), 1, ZZ) == 0 + 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 + + raises(IndexError, lambda: dmp_ground_nth([[3], [4], [5]], (2, -1), 1, ZZ)) + + +def test_dmp_zero_p(): + 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 + + +def test_dmp_zero(): + assert dmp_zero(0) == [] + assert dmp_zero(2) == [[[]]] + + +def test_dmp_one_p(): + 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) 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(2)]]], 3, 2) is False + assert dmp_ground_p([[[ZZ(3)], []]], 3, 2) is False + + assert dmp_ground_p([], None, 0) is True + assert dmp_ground_p([[]], None, 1) is 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(3)], []]], None, 2) is False + + +def test_dmp_ground(): + assert dmp_ground(ZZ(0), 2) == [[[]]] + + 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) == [[], [], [], []] + + assert dmp_zeros(0, 2, ZZ) == [] + assert dmp_zeros(1, 2, ZZ) == [[[[]]]] + assert dmp_zeros(2, 2, ZZ) == [[[[]]], [[[]]]] + assert dmp_zeros(3, 2, ZZ) == [[[[]]], [[[]]], [[[]]]] + + assert dmp_zeros(3, -1, ZZ) == [0, 0, 0] + + +def test_dmp_grounds(): + assert dmp_grounds(ZZ(7), 0, 2) == [] + + assert dmp_grounds(ZZ(7), 1, 2) == [[[[7]]]] + assert dmp_grounds(ZZ(7), 2, 2) == [[[[7]]], [[[7]]]] + assert dmp_grounds(ZZ(7), 3, 2) == [[[[7]]], [[[7]]], [[[7]]]] + + assert dmp_grounds(ZZ(7), 3, -1) == [7, 7, 7] + + +def test_dmp_negative_p(): + 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) 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) == [] + assert dup_from_dict({}, ZZ) == [] + + assert dup_to_raw_dict([]) == {} + assert dup_to_dict([]) == {} + + 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] + g = {8: 3, 5: 2, 0: 8} + h = {(8,): 3, (5,): 2, (0,): 8} + + assert dup_from_raw_dict(g, ZZ) == f + assert dup_from_dict(h, ZZ) == f + + assert dup_to_raw_dict(f) == g + assert dup_to_dict(f) == h + + R, x,y = ring("x,y", ZZ) + K = R.to_domain() + + f = [R(3), R(0), R(2), R(0), R(0), R(8)] + g = {5: R(3), 3: R(2), 0: R(8)} + h = {(5,): R(3), (3,): R(2), (0,): R(8)} + + assert dup_from_raw_dict(g, K) == f + assert dup_from_dict(h, K) == f + + 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)} + + 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) + + assert dmp_swap(f, 1, 1, 1, ZZ) == f + + assert dmp_swap(f, 0, 1, 1, ZZ) == g + assert dmp_swap(g, 0, 1, 1, ZZ) == f + + 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) + + assert dmp_permute(f, [0, 1], 1, ZZ) == f + assert dmp_permute(g, [0, 1], 1, ZZ) == g + + 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]]] + + assert dmp_nest([[1]], 0, ZZ) == [[1]] + 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]]]] + + +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(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) == \ + (7, [1, 1]) + 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) == \ + (1, [1, 0, 0, 1, 0, 0, 0, 0]) + 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) == \ + (8, [1, 0]) + 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) == \ + (1, [1, 0]) + + +def test_dmp_deflate(): + assert dmp_deflate([[]], 1, ZZ) == ((1, 1), [[]]) + assert dmp_deflate([[2]], 1, ZZ) == ((1, 1), [[2]]) + + f = [[1, 0, 0], [], [1, 0], [], [1]] + + 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, 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) == \ + ((1, 1), ([[]],)) + assert dmp_multi_deflate(([[]], [[]]), 1, ZZ) == \ + ((1, 1), ([[]], [[]])) + + assert dmp_multi_deflate(([[1]], [[]]), 1, ZZ) == \ + ((1, 1), ([[1]], [[]])) + assert dmp_multi_deflate(([[1]], [[2]]), 1, ZZ) == \ + ((1, 1), ([[1]], [[2]])) + assert dmp_multi_deflate(([[1]], [[2, 0]]), 1, ZZ) == \ + ((1, 1), ([[1]], [[2, 0]])) + + 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, 0, 0], [1, 0, 4, 0, 1]), 0, ZZ) == \ + ((2,), ([2, 0], [1, 4, 1])) + + f = [[1, 0, 0], [], [1, 0], [], [1]] + g = [[1, 0, 1, 0], [], [1]] + + assert dmp_multi_deflate((f,), 1, ZZ) == \ + ((2, 1), ([[1, 0, 0], [1, 0], [1]],)) + + assert dmp_multi_deflate((f, g), 1, ZZ) == \ + ((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] + + raises(IndexError, lambda: dup_inflate([1, 2, 3], 0, ZZ)) + + +def test_dmp_inflate(): + assert dmp_inflate([1], (3,), 0, ZZ) == [1] + + 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([[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]], 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) + + +def test_dmp_include(): + 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, 1], 0, ZZ) == [[[1, 2, 3]]] + assert dmp_include([1, 2, 3], [1, 2], 0, ZZ) == [[[1]], [[2]], [[3]]] + + +def test_dmp_inject(): + R, x,y = ring("x,y", ZZ) + K = R.to_domain() + + assert dmp_inject([], 0, K) == ([[[]]], 2) + assert dmp_inject([[]], 1, K) == ([[[[]]]], 3) + + assert dmp_inject([R(1)], 0, K) == ([[[1]]], 2) + assert dmp_inject([[R(1)]], 1, K) == ([[[[1]]]], 3) + + assert dmp_inject([R(1), 2*x + 3*y + 4], 0, K) == ([[[1]], [[2], [3, 4]]], 2) + + f = [3*x**2 + 7*x*y + 5*y**2, 2*x, R(0), x*y**2 + 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(): + R, x,y = ring("x,y", ZZ) + K = R.to_domain() + + assert dmp_eject([[[]]], 2, K) == [] + assert dmp_eject([[[[]]]], 3, K) == [[]] + + assert dmp_eject([[[1]]], 2, K) == [R(1)] + assert dmp_eject([[[[1]]]], 3, K) == [[R(1)]] + + assert dmp_eject([[[1]], [[2], [3, 4]]], 2, K) == [R(1), 2*x + 3*y + 4] + + f = [3*x**2 + 7*x*y + 5*y**2, 2*x, R(0), x*y**2 + 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]) + + +def test_dmp_terms_gcd(): + 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]], 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([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) == \ + [((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)] + + 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)] + + +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([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) == [[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, 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([1, 2], 0, 3, ZZ) == [1, 2] + + g = [1, 0, 0, 2] + + assert dup_slice(g, 0, 3, ZZ) == [2] + + +def test_dup_random(): + f = dup_random(0, -10, 10, ZZ) + + assert dup_degree(f) == 0 + assert all(-10 <= c <= 10 for c in f) + + f = dup_random(1, -20, 20, ZZ) + + assert dup_degree(f) == 1 + assert all(-20 <= c <= 20 for c in f) + + f = dup_random(2, -30, 30, ZZ) + + assert dup_degree(f) == 2 + assert all(-30 <= c <= 30 for c in f) + + f = dup_random(3, -40, 40, ZZ) + + assert dup_degree(f) == 3 + assert all(-40 <= c <= 40 for c in f) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_densetools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_densetools.py new file mode 100644 index 0000000000000000000000000000000000000000..b4bebd2a6f061a13a7d34b7689c696456310f62e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_densetools.py @@ -0,0 +1,714 @@ +"""Tests for dense recursive polynomials' tools. """ + +from sympy.polys.densebasic import ( + dup_normal, dmp_normal, + dup_from_raw_dict, + dmp_convert, dmp_swap, +) + +from sympy.polys.densearith import dmp_mul_ground + +from sympy.polys.densetools import ( + dup_clear_denoms, dmp_clear_denoms, + dup_integrate, dmp_integrate, dmp_integrate_in, + dup_diff, dmp_diff, dmp_diff_in, + dup_eval, dmp_eval, dmp_eval_in, + dmp_eval_tail, dmp_diff_eval_in, + dup_trunc, dmp_trunc, dmp_ground_trunc, + dup_monic, dmp_ground_monic, + dup_content, dmp_ground_content, + dup_primitive, dmp_ground_primitive, + dup_extract, dmp_ground_extract, + dup_real_imag, + dup_mirror, dup_scale, dup_shift, dmp_shift, + dup_transform, + dup_compose, dmp_compose, + dup_decompose, + dmp_lift, + dup_sign_variations, + dup_revert, dmp_revert, +) +from sympy.polys.polyclasses import ANP + +from sympy.polys.polyerrors import ( + MultivariatePolynomialError, + ExactQuotientFailed, + NotReversible, + DomainError, +) + +from sympy.polys.specialpolys import f_polys + +from sympy.polys.domains import FF, ZZ, QQ, ZZ_I, QQ_I, EX, RR +from sympy.polys.rings import ring + +from sympy.core.numbers import I +from sympy.core.singleton import S +from sympy.functions.elementary.trigonometric import sin + +from sympy.abc import x +from sympy.testing.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), 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) + + 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([QQ(1)], 2, 0, QQ) == [QQ(1, 2), QQ(0), QQ(0)] + + 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)], [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) + 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) + 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) + 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) + + raises(IndexError, lambda: dmp_integrate_in(f, 1, -1, 3, QQ)) + raises(IndexError, lambda: dmp_integrate_in(f, 1, 4, 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) == [170, 306, 448, -2415, 138, 380, 0, 0, 24, 3] + 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) + + 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, 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) == [] + assert dmp_diff([[]], 1, 1, ZZ) == [[]] + assert dmp_diff([[[]]], 1, 2, ZZ) == [[[]]] + + assert dmp_diff([[[1], [2]]], 1, 2, ZZ) == [[[]]] + + 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(f_6, 0, 3, ZZ) == f_6 + assert dmp_diff(f_6, 1, 3, ZZ) == [[[[8460]], [[]]], + [[[135, 0, 0], [], [], [-135, 0, 0]]], + [[[]]], + [[[-423]], [[-47]], [[]], [[141], [], [94, 0], []], [[]]]] + 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) + + +def test_dmp_diff_in(): + assert dmp_diff_in(f_6, 2, 1, 3, ZZ) == \ + dmp_swap(dmp_diff(dmp_swap(f_6, 0, 1, 3, ZZ), 2, 3, ZZ), 0, 1, 3, ZZ) + assert dmp_diff_in(f_6, 3, 1, 3, ZZ) == \ + dmp_swap(dmp_diff(dmp_swap(f_6, 0, 1, 3, ZZ), 3, 3, ZZ), 0, 1, 3, ZZ) + assert dmp_diff_in(f_6, 2, 2, 3, ZZ) == \ + dmp_swap(dmp_diff(dmp_swap(f_6, 0, 2, 3, ZZ), 2, 3, ZZ), 0, 2, 3, ZZ) + 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) + + raises(IndexError, lambda: dmp_diff_in(f_6, 1, -1, 3, ZZ)) + raises(IndexError, lambda: dmp_diff_in(f_6, 1, 4, 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 + + +def test_dmp_eval(): + assert dmp_eval([], 3, 0, ZZ) == 0 + + 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]]], 3, 2, ZZ) == [[1]] + assert dmp_eval([[[1, 2]]], 3, 2, ZZ) == [[1, 2]] + + 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) + + f = [[[int(45)]], [[]], [[]], [[int(-9)], [-1], [], [int(3), int(0), int(10), int(0)]]] + + assert dmp_eval_in(f, -2, 2, 2, ZZ) == \ + [[45], [], [], [-9, -1, 0, -44]] + + raises(IndexError, lambda: dmp_eval_in(f_6, ZZ(1), -1, 3, ZZ)) + raises(IndexError, lambda: dmp_eval_in(f_6, ZZ(1), 4, 3, ZZ)) + + +def test_dmp_eval_tail(): + assert dmp_eval_tail([[]], [1], 1, ZZ) == [] + assert dmp_eval_tail([[[]]], [1], 2, ZZ) == [[]] + assert dmp_eval_tail([[[]]], [1, 2], 2, ZZ) == [] + + 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, [-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_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) + + assert dmp_diff_eval_in(f_6, 2, 7, 0, 3, ZZ) == \ + dmp_eval(dmp_diff(f_6, 2, 3, ZZ), 7, 3, ZZ) + + raises(IndexError, lambda: dmp_diff_eval_in(f_6, 1, ZZ(1), 4, 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)] + + 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)] + + 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] + + R = ZZ_I + assert dup_trunc([R(3), R(4), R(5)], R(3), R) == [R(1), R(-1)] + + K = FF(5) + assert dup_trunc([K(3), K(4), K(5)], K(3), K) == [K(1), K(0)] + + +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]] + + +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) + + +def test_dup_monic(): + assert dup_monic([3, 6, 9], ZZ) == [1, 2, 3] + + 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)] + + +def test_dmp_ground_monic(): + assert dmp_ground_monic([3, 6, 9], 0, 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)) + + 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)]] + + +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([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([[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(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(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(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(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(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(f_6, 3, ZZ) == ZZ(1) + 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([], 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(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([ZZ(1)], 0, ZZ) == (ZZ(1), [ZZ(1)]) + + 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(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(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(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(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(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(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([[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)]]) + + +def test_dup_extract(): + f = dup_normal([2930944, 0, 2198208, 0, 549552, 0, 45796], ZZ) + g = dup_normal([17585664, 0, 8792832, 0, 1099104, 0], ZZ) + + F = dup_normal([64, 0, 48, 0, 12, 0, 1], ZZ) + G = dup_normal([384, 0, 192, 0, 24, 0], ZZ) + + assert dup_extract(f, g, ZZ) == (45796, F, G) + + +def test_dmp_ground_extract(): + 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) + G = dmp_normal([[384], [], [192], [], [24], []], 1, ZZ) + + 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, 2, 3], ZZ) == ([[1], [2], [-1, 0, 3]], [[2, 0], [2, 0]]) + + assert dup_real_imag([ZZ(1), ZZ(0), ZZ(1), ZZ(3)], ZZ) == ( + [[ZZ(1)], [], [ZZ(-3), ZZ(0), ZZ(1)], [ZZ(3)]], + [[ZZ(3), ZZ(0)], [], [ZZ(-1), ZZ(0), ZZ(1), ZZ(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] + + +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] + + +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] + + +def test_dmp_shift(): + assert dmp_shift([ZZ(1), ZZ(2)], [ZZ(1)], 0, ZZ) == [ZZ(1), ZZ(3)] + + assert dmp_shift([[]], [ZZ(1), ZZ(2)], 1, ZZ) == [[]] + + xy = [[ZZ(1), ZZ(0)], []] # x*y + x1y2 = [[ZZ(1), ZZ(2)], [ZZ(1), ZZ(2)]] # (x+1)*(y+2) + assert dmp_shift(xy, [ZZ(1), ZZ(2)], 1, ZZ) == x1y2 + + +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([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], [], 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, -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([[[]]], [[[]]], 2, ZZ) == [[[]]] + assert dmp_compose([[[]]], [[[1]]], 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]], [[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], [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, 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]] + + 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]] + + 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]] + + 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]] + + R, t = ring("t", ZZ) + f = [6*t**2 - 42, + 48*t**2 + 96, + 144*t**2 + 648*t + 288, + 624*t**2 + 864*t + 384, + 108*t**3 + 312*t**2 + 432*t + 192] + + assert dup_decompose(f, R.to_domain()) == [f] + + +def test_dmp_lift(): + q = [QQ(1, 1), QQ(0, 1), QQ(1, 1)] + + f_a = [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_lift = QQ.map([1, 0, 0, 0, 0, 0, 1, 34, 289]) + + assert dmp_lift(f_a, 0, QQ.algebraic_field(I)) == f_lift + + f_g = [QQ_I(1), QQ_I(0), QQ_I(0), QQ_I(0, 1), QQ_I(0, 17)] + + assert dmp_lift(f_g, 0, QQ_I) == f_lift + + 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, 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 + + +def test_dup_clear_denoms(): + assert dup_clear_denoms([], QQ, ZZ) == (ZZ(1), []) + + 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(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( + [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)]) + + F = RR.frac_field(x) + result = dup_clear_denoms([F(8.48717/(8.0089*x + 2.83)), F(0.0)], F) + assert str(result) == "(x + 0.353356890459364, [1.05971731448763, 0.0])" + +def test_dmp_clear_denoms(): + assert dmp_clear_denoms([[]], 1, QQ, ZZ) == (ZZ(1), [[]]) + + 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( + [[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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_dispersion.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_dispersion.py new file mode 100644 index 0000000000000000000000000000000000000000..ad56b7bebd73c38e037085d36625a41729c0369a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_dispersion.py @@ -0,0 +1,95 @@ +from sympy.core import Symbol, S, oo +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.polys import poly +from sympy.polys.dispersion import dispersion, dispersionset + + +def test_dispersion(): + x = Symbol("x") + a = Symbol("a") + + fp = poly(S.Zero, x) + assert sorted(dispersionset(fp)) == [0] + + fp = poly(S(2), x) + assert sorted(dispersionset(fp)) == [0] + + fp = poly(x + 1, x) + assert sorted(dispersionset(fp)) == [0] + assert dispersion(fp) == 0 + + fp = poly((x + 1)*(x + 2), x) + assert sorted(dispersionset(fp)) == [0, 1] + assert dispersion(fp) == 1 + + fp = poly(x*(x + 3), x) + assert sorted(dispersionset(fp)) == [0, 3] + assert dispersion(fp) == 3 + + fp = poly((x - 3)*(x + 3), x) + assert sorted(dispersionset(fp)) == [0, 6] + assert dispersion(fp) == 6 + + fp = poly(x**4 - 3*x**2 + 1, x) + gp = fp.shift(-3) + assert sorted(dispersionset(fp, gp)) == [2, 3, 4] + assert dispersion(fp, gp) == 4 + assert sorted(dispersionset(gp, fp)) == [] + assert dispersion(gp, fp) is -oo + + fp = poly(x*(3*x**2+a)*(x-2536)*(x**3+a), x) + gp = fp.as_expr().subs(x, x-345).as_poly(x) + assert sorted(dispersionset(fp, gp)) == [345, 2881] + assert sorted(dispersionset(gp, fp)) == [2191] + + gp = poly((x-2)**2*(x-3)**3*(x-5)**3, x) + assert sorted(dispersionset(gp)) == [0, 1, 2, 3] + assert sorted(dispersionset(gp, (gp+4)**2)) == [1, 2] + + fp = poly(x*(x+2)*(x-1), x) + assert sorted(dispersionset(fp)) == [0, 1, 2, 3] + + fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ') + gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ') + assert sorted(dispersionset(fp, gp)) == [2] + assert sorted(dispersionset(gp, fp)) == [1, 4] + + # There are some difficulties if we compute over Z[a] + # and alpha happens to lie in Z[a] instead of simply Z. + # Hence we can not decide if alpha is indeed integral + # in general. + + fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x) + assert sorted(dispersionset(fp)) == [0, 1] + + # For any specific value of a, the dispersion is 3*a + # but the algorithm can not find this in general. + # This is the point where the resultant based Ansatz + # is superior to the current one. + fp = poly(a**2*x**3 + (a**3 + a**2 + a + 1)*x, x) + gp = fp.as_expr().subs(x, x - 3*a).as_poly(x) + assert sorted(dispersionset(fp, gp)) == [] + + fpa = fp.as_expr().subs(a, 2).as_poly(x) + gpa = gp.as_expr().subs(a, 2).as_poly(x) + assert sorted(dispersionset(fpa, gpa)) == [6] + + # Work with Expr instead of Poly + f = (x + 1)*(x + 2) + assert sorted(dispersionset(f)) == [0, 1] + assert dispersion(f) == 1 + + f = x**4 - 3*x**2 + 1 + g = x**4 - 12*x**3 + 51*x**2 - 90*x + 55 + assert sorted(dispersionset(f, g)) == [2, 3, 4] + assert dispersion(f, g) == 4 + + # Work with Expr and specify a generator + f = (x + 1)*(x + 2) + assert sorted(dispersionset(f, None, x)) == [0, 1] + assert dispersion(f, None, x) == 1 + + f = x**4 - 3*x**2 + 1 + g = x**4 - 12*x**3 + 51*x**2 - 90*x + 55 + assert sorted(dispersionset(f, g, x)) == [2, 3, 4] + assert dispersion(f, g, x) == 4 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_distributedmodules.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_distributedmodules.py new file mode 100644 index 0000000000000000000000000000000000000000..c95672f99f878f3def660aadec901afbde9adf8b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_distributedmodules.py @@ -0,0 +1,208 @@ +"""Tests for sparse distributed modules. """ + +from sympy.polys.distributedmodules import ( + sdm_monomial_mul, sdm_monomial_deg, sdm_monomial_divides, + sdm_add, sdm_LM, sdm_LT, sdm_mul_term, sdm_zero, sdm_deg, + sdm_LC, sdm_from_dict, + sdm_spoly, sdm_ecart, sdm_nf_mora, sdm_groebner, + sdm_from_vector, sdm_to_vector, sdm_monomial_lcm +) + +from sympy.polys.orderings import lex, grlex, InverseOrder +from sympy.polys.domains import QQ + +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 + assert sdm_monomial_divides((5, 1, 1), (5, 2, 1)) is True + + assert sdm_monomial_divides((1, 0, 0), (2, 0, 0)) is False + 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)} + assert sdm_from_dict(dic, grlex) == \ + [((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))] + +# 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))] + assert sdm_add([((1, 1, 1), QQ(1))], [((1, 1, 1), QQ(-1))], lex, QQ) == [] + assert sdm_add([((1, 0, 0), QQ(1))], [((1, 0, 0), QQ(2))], lex, QQ) == \ + [((1, 0, 0), QQ(3))] + 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) == [] + assert sdm_mul_term([((1, 0, 0), QQ(1))], ((1, 0), QQ(1)), lex, QQ) == \ + [((1, 1, 0), QQ(1))] + f = [((2, 0, 1), QQ(4)), ((1, 1, 0), QQ(3))] + 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))] + h = [((1, 2, 3), QQ(1))] + 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) + 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) + (id0, id1, id2) = [sdm_from_dict({(i, 0, 0, 0): QQ(1)}, grlex) + for i in range(3)] + + assert sdm_nf_mora(f, [f1, f2], grlex, QQ, phantom=(id0, [id1, id2])) == \ + ([((1, 0, 2, 1), QQ(1)), ((1, 0, 0, 3), QQ(1)), ((1, 1, 1, 0), QQ(1)), + ((1, 1, 0, 1), QQ(1))], + [((1, 1, 0, 1), QQ(-1)), ((0, 0, 0, 0), QQ(1))]) + assert sdm_nf_mora(f, [f2, f1], grlex, QQ, phantom=(id0, [id2, id1])) == \ + ([((1, 0, 2, 1), QQ(1)), ((1, 0, 0, 3), QQ(1)), ((1, 1, 1, 0), QQ(1))], + [((2, 1, 0, 1), QQ(-1)), ((2, 0, 1, 1), QQ(-1)), ((0, 0, 0, 0), QQ(1))]) + + f = sdm_from_vector([x*z, y**2 + y*z - z, y], lex, QQ, gens=[x, y, z]) + 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) == \ + [((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_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) + return sdm_nf_mora(sdm_from_vector([f], lex, QQ, gens=gens), + G, lex, QQ) == sdm_zero() + + assert contains([x, y], x) + assert contains([x, y], x + y) + 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) + + # 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) + + +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) + return sdm_nf_mora(sdm_from_vector([f], lex, QQ, gens=gens), + G, lex, QQ) == sdm_zero() + assert contains([x, y], x) + assert contains([x, y], x + y) + 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) + + +def test_uncovered_line(): + gens = [x, y] + f1 = sdm_zero() + f2 = sdm_from_vector([x, 0], lex, QQ, gens=gens) + f3 = sdm_from_vector([0, y], lex, QQ, gens=gens) + + 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) + f2 = sdm_from_vector([0, x - 2], grlex, QQ, gens=gens) + assert len(sdm_groebner([f1, f2], sdm_nf_mora, grlex, QQ)) == 2 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_euclidtools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_euclidtools.py new file mode 100644 index 0000000000000000000000000000000000000000..3061be73f987163951a5836ff50125d29abc60c7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_euclidtools.py @@ -0,0 +1,712 @@ +"""Tests for Euclidean algorithms, GCDs, LCMs and polynomial remainder sequences. """ + +from sympy.polys.rings import ring +from sympy.polys.domains import ZZ, QQ, RR + +from sympy.polys.specialpolys import ( + f_polys, + dmp_fateman_poly_F_1, + dmp_fateman_poly_F_2, + dmp_fateman_poly_F_3) + +f_0, f_1, f_2, f_3, f_4, f_5, f_6 = f_polys() + +def test_dup_gcdex(): + 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 + + assert R.dup_half_gcdex(f, g) == (s, h) + assert R.dup_gcdex(f, g) == (s, t, h) + + f = x**4 + 4*x**3 - x + 1 + g = x**3 - x + 1 + + s, t, h = R.dup_gcdex(f, g) + S, T, H = R.dup_gcdex(g, f) + + 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 + + f = 2*x + g = x**2 - 16 + + s = QQ(1,32)*x + t = -QQ(1,16) + h = 1 + + assert R.dup_half_gcdex(f, g) == (s, h) + assert R.dup_gcdex(f, g) == (s, t, h) + + +def test_dup_invert(): + R, x = ring("x", QQ) + assert R.dup_invert(2*x, x**2 - 16) == QQ(1,32)*x + + +def test_dup_euclidean_prs(): + 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)] + + +def test_dup_primitive_prs(): + 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] + + +def test_dup_subresultants(): + R, x = ring("x", ZZ) + + assert R.dup_resultant(0, 0) == 0 + + assert R.dup_resultant(1, 0) == 0 + assert R.dup_resultant(0, 1) == 0 + + 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 = 15*x**4 - 3*x**2 + 9 + b = 65*x**2 + 125*x - 245 + c = 9326*x - 12300 + d = 260708 + + assert R.dup_subresultants(f, g) == [f, g, a, b, c, d] + assert R.dup_resultant(f, g) == R.dup_LC(d) + + f = x**2 - 2*x + 1 + g = x**2 - 1 + + a = 2*x - 2 + + assert R.dup_subresultants(f, g) == [f, g, a] + assert R.dup_resultant(f, g) == 0 + + f = x**2 + 1 + g = x**2 - 1 + + a = -2 + + assert R.dup_subresultants(f, g) == [f, g, a] + assert R.dup_resultant(f, g) == 4 + + f = x**2 - 1 + g = x**3 - x**2 + 2 + + assert R.dup_resultant(f, g) == 0 + + f = 3*x**3 - x + g = 5*x**2 + 1 + + assert R.dup_resultant(f, g) == 64 + + f = x**2 - 2*x + 7 + g = x**3 - x + 5 + + assert R.dup_resultant(f, g) == 265 + + f = x**3 - 6*x**2 + 11*x - 6 + g = x**3 - 15*x**2 + 74*x - 120 + + assert R.dup_resultant(f, g) == -8640 + + f = x**3 - 6*x**2 + 11*x - 6 + g = x**3 - 10*x**2 + 29*x - 20 + + assert R.dup_resultant(f, g) == 0 + + f = x**3 - 1 + g = x**3 + 2*x**2 + 2*x - 1 + + assert R.dup_resultant(f, g) == 16 + + f = x**8 - 2 + g = x - 1 + + assert R.dup_resultant(f, g) == -1 + + +def test_dmp_subresultants(): + 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 R.dmp_resultant(1, 0) == 0 + assert R.dmp_resultant(1, 0) == 0 + assert R.dmp_resultant(1, 0) == 0 + + 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 = 3*x**2*y - y**3 - 4 + g = x**2 + x*y**3 - 9 + + 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 = R.dmp_LC(b) + + assert R.dmp_subresultants(f, g) == [f, g, a, b] + + 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 = -x**3 + 5 + g = 3*x**2*y + x**2 + + a = 45*y**2 + 30*y + 5 + b = 675*y**3 + 675*y**2 + 225*y + 25 + + r = R.dmp_LC(b) + + 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 + + R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) + + f = 6*x**2 - 3*x*y - 2*x*z + y*z + g = x**2 - x*u - x*v + u*v + + 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 + + assert R.dmp_zz_collins_resultant(f, g) == r.drop(x) + + 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) + + Rt, t = ring("t", ZZ) + Rx, x = ring("x", Rt) + + f = x**6 - 5*x**4 + 5*x**2 + 4 + g = -6*t*x**5 + x**4 + 20*t*x**3 - 3*x**2 - 10*t*x + 6 + + assert Rx.dup_resultant(f, g) == 2930944*t**6 + 2198208*t**4 + 549552*t**2 + 45796 + + +def test_dup_discriminant(): + 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 + + +def test_dmp_discriminant(): + 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 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 R.dmp_discriminant(x**2*y + 2*y) == (-8*y**2).drop(x) + assert R.dmp_discriminant(x*y**2 + 2*x) == 1 + + R, x, y, z = ring("x,y,z", ZZ) + assert R.dmp_discriminant(x*y + z) == 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) + + +def test_dup_gcd(): + 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) + + f, g = 0, -2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, 0, -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) + + 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) + + f, g = 2, 2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (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) + + f, g = 2, -2 + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (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) + + 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) + + 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) + + 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) + + 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) + + 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) + + 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) + + f, g = x - 31, x + assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (1, f, g) + + 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 R.dup_zz_heu_gcd(f, g) == (h, cff, cfg) + assert R.dup_rr_prs_gcd(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 R.dup_zz_heu_gcd(f, g) == (h, cff, cfg) + assert R.dup_rr_prs_gcd(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 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 = 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 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 + + R, x = ring("x", QQ) + + f = QQ(1,2)*x**2 + x + QQ(1,2) + g = QQ(1,2)*x + QQ(1,2) + + 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) + + +def test_dmp_gcd(): + 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) + + 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) + + 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) + + f, g = 2, 2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (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) + + f, g = 2, -2 + assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (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) + + 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) + + 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) + + 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) + + 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) + + 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) + + 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) + + R, x, y, z, u = ring("x,y,z,u", ZZ) + + 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) + + 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 R.dmp_zz_heu_gcd(f, g) == (h, cff, cfg) + assert R.dmp_rr_prs_gcd(f, g) == (h, cff, cfg) + + assert R.dmp_zz_heu_gcd(g, f) == (h, cfg, cff) + assert R.dmp_rr_prs_gcd(g, f) == (h, cfg, cff) + + R, x, y, z = ring("x,y,z", ZZ) + + f, g, h = map(R.from_dense, dmp_fateman_poly_F_1(2, ZZ)) + H, cff, cfg = R.dmp_zz_heu_gcd(f, g) + + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g + + H, cff, cfg = R.dmp_rr_prs_gcd(f, g) + + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g + + R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) + + f, g, h = 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 R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g + + R, x, y, z, u, v, a, b = ring("x,y,z,u,v,a,b", ZZ) + + f, g, h = map(R.from_dense, dmp_fateman_poly_F_1(6, ZZ)) + H, cff, cfg = R.dmp_zz_heu_gcd(f, g) + + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(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 = map(R.from_dense, dmp_fateman_poly_F_1(8, ZZ)) + H, cff, cfg = R.dmp_zz_heu_gcd(f, g) + + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g + + R, x, y, z = ring("x,y,z", ZZ) + + f, g, h = 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 R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g + + H, cff, cfg = R.dmp_rr_prs_gcd(f, g) + + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g + + f, g, h = 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 R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g + + H, cff, cfg = R.dmp_rr_prs_gcd(f, g) + + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g + + R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) + + f, g, h = map(R.from_dense, dmp_fateman_poly_F_3(4, ZZ)) + H, cff, cfg = R.dmp_inner_gcd(f, g) + + assert H == h and R.dmp_mul(H, cff) == f \ + and R.dmp_mul(H, cfg) == g + + 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) + + +def test_dup_lcm(): + 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 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 + + +def test_dmp_lcm(): + R, x, y = ring("x,y", ZZ) + + assert R.dmp_lcm(2, 6) == 6 + assert R.dmp_lcm(x, y) == x*y + + 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 + + assert R.dmp_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 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 + + +def test_dmp_content(): + R, x,y = ring("x,y", ZZ) + + assert R.dmp_content(-2) == 2 + + f, g, F = 3*y**2 + 2*y + 1, 1, 0 + + for i in range(0, 5): + g *= f + F += x**i*g + + assert R.dmp_content(F) == f.drop(x) + + 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 + + +def test_dmp_primitive(): + R, x,y = ring("x,y", ZZ) + + 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 *= f + F += x**i*g + + assert R.dmp_primitive(F) == (f.drop(x), F / 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 + + +def test_dup_cancel(): + R, x = ring("x", ZZ) + + f = 2*x**2 - 2 + g = x**2 - 2*x + 1 + + p = 2*x + 2 + q = x - 1 + + assert R.dup_cancel(f, g) == (p, q) + assert R.dup_cancel(f, g, include=False) == (1, 1, p, q) + + f = -x - 2 + g = 3*x - 4 + + F = x + 2 + G = -3*x + 4 + + assert R.dup_cancel(f, g) == (f, g) + assert R.dup_cancel(F, G) == (f, g) + + assert R.dup_cancel(0, 0) == (0, 0) + assert R.dup_cancel(0, 0, include=False) == (1, 1, 0, 0) + + 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) + + +def test_dmp_cancel(): + R, x, y = ring("x,y", ZZ) + + f = 2*x**2 - 2 + g = x**2 - 2*x + 1 + + p = 2*x + 2 + q = x - 1 + + assert R.dmp_cancel(f, g) == (p, q) + assert R.dmp_cancel(f, g, include=False) == (1, 1, p, q) + + assert R.dmp_cancel(0, 0) == (0, 0) + assert R.dmp_cancel(0, 0, include=False) == (1, 1, 0, 0) + + assert R.dmp_cancel(y, 0) == (1, 0) + assert R.dmp_cancel(y, 0, include=False) == (1, 1, 1, 0) + + assert R.dmp_cancel(0, y) == (0, 1) + assert R.dmp_cancel(0, y, include=False) == (1, 1, 0, 1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_factortools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_factortools.py new file mode 100644 index 0000000000000000000000000000000000000000..7f99097c71e9cde761a800b01b149ec5c9896266 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_factortools.py @@ -0,0 +1,784 @@ +"""Tools for polynomial factorization routines in characteristic zero. """ + +from sympy.polys.rings import ring, xring +from sympy.polys.domains import FF, ZZ, QQ, ZZ_I, QQ_I, RR, EX + +from sympy.polys import polyconfig as config +from sympy.polys.polyerrors import DomainError +from sympy.polys.polyclasses import ANP +from sympy.polys.specialpolys import f_polys, w_polys + +from sympy.core.numbers import I +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin +from sympy.ntheory.generate import nextprime +from sympy.testing.pytest import raises, XFAIL + + +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(): + 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(): + 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(): + R, x = ring("x", ZZ) + assert R.dup_zz_mignotte_bound(2*x**2 + 3*x + 4) == 6 + assert R.dup_zz_mignotte_bound(x**3 + 14*x**2 + 56*x + 64) == 152 + + +def test_dmp_zz_mignotte_bound(): + 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(): + 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 + + +def test_dup_zz_hensel_lift(): + 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] + + +def test_dup_zz_irreducible_p(): + 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 + + +def test_dup_cyclotomic_p(): + R, x = ring("x", ZZ) + + 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 + + R, x = ring("x", ZZ["y"]) + assert R.dup_cyclotomic_p(x**2 + x + 1) is False + + +def test_dup_zz_cyclotomic_poly(): + 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(): + 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] + + +def test_dup_zz_factor(): + 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 = x**4 + x + 1 + + for i in range(0, 20): + assert R.dup_zz_factor(f) == (1, [(f, 1)]) + + assert R.dup_zz_factor(x**2 + 2*x + 2) == \ + (1, [(x**2 + 2*x + 2, 1)]) + + assert R.dup_zz_factor(18*x**2 + 12*x + 2) == \ + (2, [(3*x + 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]) + + # The order of the factors will be different when the ground types are + # flint. At the higher level dup_factor_list will sort the factors. + c, factors = R.dup_zz_factor(x**3 - 6*x**2 + 11*x - 6) + assert c == 1 + assert set(factors) == {(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]) + + c, factors = R.dup_zz_factor(-x**6 + x**2) + assert c == -1 + assert set(factors) == {(x, 2), (x - 1, 1), (x + 1, 1), (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 + + c, factors = R.dup_zz_factor(f) + assert c == -95367431640625 + assert set(factors) == { + (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 = x**10 - 1 + + config.setup('USE_CYCLOTOMIC_FACTOR', True) + c0, F_0 = R.dup_zz_factor(f) + + config.setup('USE_CYCLOTOMIC_FACTOR', False) + c1, F_1 = R.dup_zz_factor(f) + + assert c0 == c1 == 1 + assert set(F_0) == set(F_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 = x**10 + 1 + + config.setup('USE_CYCLOTOMIC_FACTOR', True) + F_0 = R.dup_zz_factor(f) + + config.setup('USE_CYCLOTOMIC_FACTOR', False) + F_1 = R.dup_zz_factor(f) + + assert F_0 == F_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(): + R, x,y,z = ring("x,y,z", ZZ) + UV, _x = ring("x", ZZ) + + p = ZZ(nextprime(R.dmp_zz_mignotte_bound(w_1))) + assert p == 6291469 + + 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 = zip([ t.drop(x) for t in T ], K) + + A = [ZZ(-14), ZZ(3)] + + S = R.dmp_eval_tail(w_1, A) + cs, s = UV.dup_primitive(S) + + assert cs == 1 and s == S == \ + 1036728*_x**6 + 915552*_x**5 + 55748*_x**4 + 105621*_x**3 - 17304*_x**2 - 26841*_x - 644 + + 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 = UV.dup_zz_factor_sqf(s) + + 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 = [ lc.drop(x) for lc in [-4*y - 4*z, -y*z**2, y**2 - z**2] ] + + assert R.dmp_zz_wang_lead_coeffs(w_1, T, cs, E, H, A) == (w_1, H, LC) + + factors = R.dmp_zz_wang_hensel_lifting(w_1, H, LC, A, p) + assert R.dmp_expand(factors) == w_1 + + +@XFAIL +def test_dmp_zz_wang_fail(): + R, x,y,z = ring("x,y,z", ZZ) + UV, _x = ring("x", ZZ) + + p = ZZ(nextprime(R.dmp_zz_mignotte_bound(w_1))) + assert p == 6291469 + + 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] + + 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 + + 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] + + +def test_issue_6355(): + # This tests a bug in the Wang algorithm that occurred 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] + + R, x, y, z = ring("x,y,z", ZZ) + f = 2*x**2 + y*z - y - z**2 + z + + assert R.dmp_zz_wang(f, seed=random_sequence) == [f] + + +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)]) + + +def test_dup_qq_i_factor(): + R, x = ring("x", QQ_I) + i = QQ_I(0, 1) + + assert R.dup_qq_i_factor(x**2 - 2) == (QQ_I(1, 0), [(x**2 - 2, 1)]) + + assert R.dup_qq_i_factor(x**2 - 1) == (QQ_I(1, 0), [(x - 1, 1), (x + 1, 1)]) + + assert R.dup_qq_i_factor(x**2 + 1) == (QQ_I(1, 0), [(x - i, 1), (x + i, 1)]) + + assert R.dup_qq_i_factor(x**2/4 + 1) == \ + (QQ_I(QQ(1, 4), 0), [(x - 2*i, 1), (x + 2*i, 1)]) + + assert R.dup_qq_i_factor(x**2 + 4) == \ + (QQ_I(1, 0), [(x - 2*i, 1), (x + 2*i, 1)]) + + assert R.dup_qq_i_factor(x**2 + 2*x + 1) == \ + (QQ_I(1, 0), [(x + 1, 2)]) + + assert R.dup_qq_i_factor(x**2 + 2*i*x - 1) == \ + (QQ_I(1, 0), [(x + i, 2)]) + + f = 8192*x**2 + x*(22656 + 175232*i) - 921416 + 242313*i + + assert R.dup_qq_i_factor(f) == \ + (QQ_I(8192, 0), [(x + QQ_I(QQ(177, 128), QQ(1369, 128)), 2)]) + + +def test_dmp_qq_i_factor(): + R, x, y = ring("x, y", QQ_I) + i = QQ_I(0, 1) + + assert R.dmp_qq_i_factor(x**2 + 2*y**2) == \ + (QQ_I(1, 0), [(x**2 + 2*y**2, 1)]) + + assert R.dmp_qq_i_factor(x**2 + y**2) == \ + (QQ_I(1, 0), [(x - i*y, 1), (x + i*y, 1)]) + + assert R.dmp_qq_i_factor(x**2 + y**2/4) == \ + (QQ_I(1, 0), [(x - i*y/2, 1), (x + i*y/2, 1)]) + + assert R.dmp_qq_i_factor(4*x**2 + y**2) == \ + (QQ_I(4, 0), [(x - i*y/2, 1), (x + i*y/2, 1)]) + + +def test_dup_zz_i_factor(): + R, x = ring("x", ZZ_I) + i = ZZ_I(0, 1) + + assert R.dup_zz_i_factor(x**2 - 2) == (ZZ_I(1, 0), [(x**2 - 2, 1)]) + + assert R.dup_zz_i_factor(x**2 - 1) == (ZZ_I(1, 0), [(x - 1, 1), (x + 1, 1)]) + + assert R.dup_zz_i_factor(x**2 + 1) == (ZZ_I(1, 0), [(x - i, 1), (x + i, 1)]) + + assert R.dup_zz_i_factor(x**2 + 4) == \ + (ZZ_I(1, 0), [(x - 2*i, 1), (x + 2*i, 1)]) + + assert R.dup_zz_i_factor(x**2 + 2*x + 1) == \ + (ZZ_I(1, 0), [(x + 1, 2)]) + + assert R.dup_zz_i_factor(x**2 + 2*i*x - 1) == \ + (ZZ_I(1, 0), [(x + i, 2)]) + + f = 8192*x**2 + x*(22656 + 175232*i) - 921416 + 242313*i + + assert R.dup_zz_i_factor(f) == \ + (ZZ_I(0, 1), [((64 - 64*i)*x + (773 + 596*i), 2)]) + + +def test_dmp_zz_i_factor(): + R, x, y = ring("x, y", ZZ_I) + i = ZZ_I(0, 1) + + assert R.dmp_zz_i_factor(x**2 + 2*y**2) == \ + (ZZ_I(1, 0), [(x**2 + 2*y**2, 1)]) + + assert R.dmp_zz_i_factor(x**2 + y**2) == \ + (ZZ_I(1, 0), [(x - i*y, 1), (x + i*y, 1)]) + + assert R.dmp_zz_i_factor(4*x**2 + y**2) == \ + (ZZ_I(1, 0), [(2*x - i*y, 1), (2*x + i*y, 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) + + assert R.dup_ext_factor(0) == (anp([]), []) + + f = anp([QQ(1)])*x + anp([QQ(1)]) + + assert R.dup_ext_factor(f) == (anp([QQ(1)]), [(f, 1)]) + + g = anp([QQ(2)])*x + anp([QQ(2)]) + + assert R.dup_ext_factor(g) == (anp([QQ(2)]), [(f, 1)]) + + f = anp([QQ(7)])*x**4 + anp([QQ(1, 1)]) + g = anp([QQ(1)])*x**4 + anp([QQ(1, 7)]) + + assert R.dup_ext_factor(f) == (anp([QQ(7)]), [(g, 1)]) + + f = anp([QQ(1)])*x**4 + anp([QQ(1)]) + + 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(4, 1)])*x**2 + anp([QQ(9, 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(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 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)]) + + R, x = ring("x", QQ.algebraic_field(sqrt(2))) + def anp(element): + return ANP(element, [QQ(1), QQ(0), QQ(-2)], QQ) + + f = anp([QQ(1)])*x**4 + anp([QQ(1, 1)]) + + 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)]) + + f = anp([QQ(1, 1)])*x**2 + anp([QQ(2), QQ(0)])*x + anp([QQ(2, 1)]) + + assert R.dup_ext_factor(f) == \ + (anp([QQ(1, 1)]), [(anp([1])*x + anp([1, 0]), 2)]) + + assert R.dup_ext_factor(f**3) == \ + (anp([QQ(1, 1)]), [(anp([1])*x + anp([1, 0]), 6)]) + + f *= anp([QQ(2, 1)]) + + 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)]) + + +def test_dmp_ext_factor(): + K = QQ.algebraic_field(sqrt(2)) + R, x,y = ring("x,y", K) + sqrt2 = K.unit + + def anp(x): + return ANP(x, [QQ(1), QQ(0), QQ(-2)], QQ) + + assert R.dmp_ext_factor(0) == (anp([]), []) + + f = anp([QQ(1)])*x + anp([QQ(1)]) + + assert R.dmp_ext_factor(f) == (anp([QQ(1)]), [(f, 1)]) + + g = anp([QQ(2)])*x + anp([QQ(2)]) + + assert R.dmp_ext_factor(g) == (anp([QQ(2)]), [(f, 1)]) + + f = anp([QQ(1)])*x**2 + anp([QQ(-2)])*y**2 + + 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)])*x**2 + anp([QQ(-4)])*y**2 + + 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)]) + + f1 = y + 1 + f2 = y + sqrt2 + f3 = x**2 + x + 2 + 3*sqrt2 + f = f1**2 * f2**2 * f3**2 + assert R.dmp_ext_factor(f) == (K.one, [(f1, 2), (f2, 2), (f3, 2)]) + + +def test_dup_factor_list(): + R, x = ring("x", ZZ) + assert R.dup_factor_list(0) == (0, []) + assert R.dup_factor_list(7) == (7, []) + + R, x = ring("x", QQ) + assert R.dup_factor_list(0) == (0, []) + assert R.dup_factor_list(QQ(1, 7)) == (QQ(1, 7), []) + + R, x = ring("x", ZZ['t']) + assert R.dup_factor_list(0) == (0, []) + assert R.dup_factor_list(7) == (7, []) + + R, x = ring("x", QQ['t']) + assert R.dup_factor_list(0) == (0, []) + assert R.dup_factor_list(QQ(1, 7)) == (QQ(1, 7), []) + + R, x = ring("x", ZZ) + assert R.dup_factor_list_include(0) == [(0, 1)] + assert R.dup_factor_list_include(7) == [(7, 1)] + + 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)] + # issue 8037 + assert R.dup_factor_list(6*x**2 - 5*x - 6) == (1, [(2*x - 3, 1), (3*x + 2, 1)]) + + 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)]) + + 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 = 6.7225336055071*x**2 - 10.6463972754741*x - 0.33469524022264 + coeff, factors = R.dup_factor_list(f) + assert coeff == RR(10.6463972754741) + assert len(factors) == 1 + assert factors[0][0].max_norm() == RR(1.0) + assert factors[0][1] == 1 + + Rt, t = ring("t", ZZ) + R, x = ring("x", Rt) + + f = 4*t*x**2 + 4*t**2*x + + assert R.dup_factor_list(f) == \ + (4*t, [(x, 1), + (x + t, 1)]) + + Rt, t = ring("t", QQ) + R, x = ring("x", Rt) + + f = QQ(1, 2)*t*x**2 + QQ(1, 2)*t**2*x + + assert R.dup_factor_list(f) == \ + (QQ(1, 2)*t, [(x, 1), + (x + t, 1)]) + + R, x = ring("x", QQ.algebraic_field(I)) + def anp(element): + return ANP(element, [QQ(1), QQ(0), QQ(1)], QQ) + + f = anp([QQ(1, 1)])*x**4 + anp([QQ(2, 1)])*x**2 + + 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)]) + + R, x = ring("x", EX) + raises(DomainError, lambda: R.dup_factor_list(EX(sin(1)))) + + +def test_dmp_factor_list(): + 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), []) + + Rt, t = ring("t", ZZ) + R, x, y = ring("x,y", Rt) + assert R.dmp_factor_list(0) == (0, []) + assert R.dmp_factor_list(7) == (ZZ(7), []) + + Rt, t = ring("t", QQ) + R, x, y = ring("x,y", Rt) + assert R.dmp_factor_list(0) == (0, []) + assert R.dmp_factor_list(QQ(1, 7)) == (QQ(1, 7), []) + + 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)] + + R, X = xring("x:200", ZZ) + + f, g = X[0]**2 + 2*X[0] + 1, X[0] + 1 + assert R.dmp_factor_list(f) == (1, [(g, 2)]) + + f, g = X[-1]**2 + 2*X[-1] + 1, X[-1] + 1 + assert R.dmp_factor_list(f) == (1, [(g, 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)]) + + 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)]) + + R, x, y = ring("x,y", ZZ) + f = 4*x**2*y + 4*x*y**2 + + assert R.dmp_factor_list(f) == \ + (4, [(y, 1), + (x, 1), + (x + y, 1)]) + + assert R.dmp_factor_list_include(f) == \ + [(4*y, 1), + (x, 1), + (x + y, 1)] + + R, x, y = ring("x,y", QQ) + f = QQ(1,2)*x**2*y + QQ(1,2)*x*y**2 + + assert R.dmp_factor_list(f) == \ + (QQ(1,2), [(y, 1), + (x, 1), + (x + y, 1)]) + + R, x, y = ring("x,y", RR) + f = 2.0*x**2 - 8.0*y**2 + + assert R.dmp_factor_list(f) == \ + (RR(8.0), [(0.5*x - y, 1), + (0.5*x + y, 1)]) + + f = 6.7225336055071*x**2*y**2 - 10.6463972754741*x*y - 0.33469524022264 + coeff, factors = R.dmp_factor_list(f) + assert coeff == RR(10.6463972754741) + assert len(factors) == 1 + assert factors[0][0].max_norm() == RR(1.0) + assert factors[0][1] == 1 + + Rt, t = ring("t", ZZ) + R, x, y = ring("x,y", Rt) + f = 4*t*x**2 + 4*t**2*x + + assert R.dmp_factor_list(f) == \ + (4*t, [(x, 1), + (x + t, 1)]) + + Rt, t = ring("t", QQ) + R, x, y = ring("x,y", Rt) + f = QQ(1, 2)*t*x**2 + QQ(1, 2)*t**2*x + + assert R.dmp_factor_list(f) == \ + (QQ(1, 2)*t, [(x, 1), + (x + t, 1)]) + + 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)))) + + +def test_dup_irreducible_p(): + 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(): + 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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_fields.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_fields.py new file mode 100644 index 0000000000000000000000000000000000000000..4f85a00d75dc02ab794ff94c83ba18ddc2023313 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_fields.py @@ -0,0 +1,353 @@ +"""Test sparse rational functions. """ + +from sympy.polys.fields import field, sfield, FracField, FracElement +from sympy.polys.rings import ring +from sympy.polys.domains import ZZ, QQ +from sympy.polys.orderings import lex + +from sympy.testing.pytest import raises, XFAIL +from sympy.core import symbols, E +from sympy.core.numbers import Rational +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt + +def test_FracField___init__(): + F1 = FracField("x,y", ZZ, lex) + F2 = FracField("x,y", ZZ, lex) + F3 = FracField("x,y,z", ZZ, lex) + + assert F1.x == F1.gens[0] + assert F1.y == F1.gens[1] + assert F1.x == F2.x + assert F1.y == F2.y + assert F1.x != F3.x + assert F1.y != F3.y + +def test_FracField___hash__(): + F, x, y, z = field("x,y,z", QQ) + assert hash(F) + +def test_FracField___eq__(): + assert field("x,y,z", QQ)[0] == field("x,y,z", QQ)[0] + assert field("x,y,z", QQ)[0] != field("x,y,z", ZZ)[0] + assert field("x,y,z", ZZ)[0] != field("x,y,z", QQ)[0] + assert field("x,y,z", QQ)[0] != field("x,y", QQ)[0] + assert field("x,y", QQ)[0] != field("x,y,z", QQ)[0] + +def test_sfield(): + x = symbols("x") + + F = FracField((E, exp(exp(x)), exp(x)), ZZ, lex) + e, exex, ex = F.gens + assert sfield(exp(x)*exp(exp(x) + 1 + log(exp(x) + 3)/2)**2/(exp(x) + 3)) \ + == (F, e**2*exex**2*ex) + + F = FracField((x, exp(1/x), log(x), x**QQ(1, 3)), ZZ, lex) + _, ex, lg, x3 = F.gens + assert sfield(((x-3)*log(x)+4*x**2)*exp(1/x+log(x)/3)/x**2) == \ + (F, (4*F.x**2*ex + F.x*ex*lg - 3*ex*lg)/x3**5) + + F = FracField((x, log(x), sqrt(x + log(x))), ZZ, lex) + _, lg, srt = F.gens + assert sfield((x + 1) / (x * (x + log(x))**QQ(3, 2)) - 1/(x * log(x)**2)) \ + == (F, (F.x*lg**2 - F.x*srt + lg**2 - lg*srt)/ + (F.x**2*lg**2*srt + F.x*lg**3*srt)) + +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 F.is_element(f) + + f = F.from_expr(Rational(3, 7)) + assert f == F(3)/7 and F.is_element(f) + + f = F.from_expr(x) + assert f == X and F.is_element(f) + + f = F.from_expr(Rational(3,7)*x) + assert f == X*Rational(3, 7) and F.is_element(f) + + f = F.from_expr(1/x) + assert f == 1/X and F.is_element(f) + + f = F.from_expr(x*y*z) + assert f == X*Y*Z and F.is_element(f) + + f = F.from_expr(x*y/z) + assert f == X*Y/Z and F.is_element(f) + + f = F.from_expr(x*y*z + x*y + x) + assert f == X*Y*Z + X*Y + X and F.is_element(f) + + 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 F.is_element(f) + + 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 F.is_element(f) + + raises(ValueError, lambda: F.from_expr(2**x)) + raises(ValueError, lambda: F.from_expr(7*x + sqrt(2))) + + assert isinstance(ZZ[2**x].get_field().convert(2**(-x)), + FracElement) + assert isinstance(ZZ[x**2].get_field().convert(x**(-6)), + FracElement) + assert isinstance(ZZ[exp(Rational(1, 3))].get_field().convert(E), + FracElement) + + +def test_FracField_nested(): + a, b, x = symbols('a b x') + F1 = ZZ.frac_field(a, b) + F2 = F1.frac_field(x) + frac = F2(a + b) + assert frac.numer == F1.poly_ring(x)(a + b) + assert frac.numer.coeffs() == [F1(a + b)] + assert frac.denom == F1.poly_ring(x)(1) + + F3 = ZZ.poly_ring(a, b) + F4 = F3.frac_field(x) + frac = F4(a + b) + assert frac.numer == F3.poly_ring(x)(a + b) + assert frac.numer.coeffs() == [F3(a + b)] + assert frac.denom == F3.poly_ring(x)(1) + + frac = F2(F3(a + b)) + assert frac.numer == F1.poly_ring(x)(a + b) + assert frac.numer.coeffs() == [F1(a + b)] + assert frac.denom == F1.poly_ring(x)(1) + + frac = F4(F1(a + b)) + assert frac.numer == F3.poly_ring(x)(a + b) + assert frac.numer.coeffs() == [F3(a + b)] + assert frac.denom == F3.poly_ring(x)(1) + + +def test_FracElement__lt_le_gt_ge__(): + F, x, y = field("x,y", ZZ) + + assert F(1) < 1/x < 1/x**2 < 1/x**3 + assert F(1) <= 1/x <= 1/x**2 <= 1/x**3 + + assert -7/x < 1/x < 3/x < y/x < 1/x**2 + assert -7/x <= 1/x <= 3/x <= y/x <= 1/x**2 + + assert 1/x**3 > 1/x**2 > 1/x > F(1) + assert 1/x**3 >= 1/x**2 >= 1/x >= F(1) + + assert 1/x**2 > y/x > 3/x > 1/x > -7/x + assert 1/x**2 >= y/x >= 3/x >= 1/x >= -7/x + +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 + + Fuv, u,v = field("u,v", ZZ) + Fxyzt, x,y,z,t = field("x,y,z,t", Fuv) + + f = (u*v + x)/(y + u*v) + assert dict(f.numer) == {(1, 0, 0, 0): 1, (0, 0, 0, 0): u*v} + assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0): u*v} + + Ruv, u,v = ring("u,v", ZZ) + Fxyzt, x,y,z,t = field("x,y,z,t", Ruv) + + f = (u*v + x)/(y + u*v) + assert dict(f.numer) == {(1, 0, 0, 0): 1, (0, 0, 0, 0): u*v} + assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0): u*v} + +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 + + Fuv, u,v = field("u,v", ZZ) + Fxyzt, x,y,z,t = field("x,y,z,t", Fuv) + + f = (u*v - x)/(y - u*v) + assert dict(f.numer) == {(1, 0, 0, 0):-1, (0, 0, 0, 0): u*v} + assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0):-u*v} + + Ruv, u,v = ring("u,v", ZZ) + Fxyzt, x,y,z,t = field("x,y,z,t", Ruv) + + f = (u*v - x)/(y - u*v) + assert dict(f.numer) == {(1, 0, 0, 0):-1, (0, 0, 0, 0): u*v} + assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0):-u*v} + +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 == x*Rational(3, 7) + + Fuv, u,v = field("u,v", ZZ) + Fxyzt, x,y,z,t = field("x,y,z,t", Fuv) + + 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} + + Ruv, u,v = ring("u,v", ZZ) + Fxyzt, x,y,z,t = field("x,y,z,t", Ruv) + + 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___truediv__(): + 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 == x*Rational(7, 3) + + raises(ZeroDivisionError, lambda: x/0) + raises(ZeroDivisionError, lambda: 1/(x - x)) + raises(ZeroDivisionError, lambda: x/(x - x)) + + Fuv, u,v = field("u,v", ZZ) + Fxyzt, x,y,z,t = field("x,y,z,t", Fuv) + + f = (u*v)/(x*y) + assert dict(f.numer) == {(0, 0, 0, 0): u*v} + assert dict(f.denom) == {(1, 1, 0, 0): 1} + + g = (x*y)/(u*v) + assert dict(g.numer) == {(1, 1, 0, 0): 1} + assert dict(g.denom) == {(0, 0, 0, 0): u*v} + + Ruv, u,v = ring("u,v", ZZ) + Fxyzt, x,y,z,t = field("x,y,z,t", Ruv) + + f = (u*v)/(x*y) + assert dict(f.numer) == {(0, 0, 0, 0): u*v} + assert dict(f.denom) == {(1, 1, 0, 0): 1} + + g = (x*y)/(u*v) + assert dict(g.numer) == {(1, 1, 0, 0): 1} + assert dict(g.denom) == {(0, 0, 0, 0): u*v} + +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 + + raises(ZeroDivisionError, lambda: (x - x)**-3) + +def test_FracElement_diff(): + F, x,y,z = field("x,y,z", ZZ) + + assert ((x**2 + y)/(z + 1)).diff(x) == 2*x/(z + 1) + +@XFAIL +def test_FracElement___call__(): + F, x,y,z = field("x,y,z", ZZ) + f = (x**2 + 3*y)/z + + r = f(1, 1, 1) + assert r == 4 and not isinstance(r, FracElement) + raises(ZeroDivisionError, lambda: f(1, 1, 0)) + +def test_FracElement_evaluate(): + F, x,y,z = field("x,y,z", ZZ) + Fyz = field("y,z", ZZ)[0] + f = (x**2 + 3*y)/z + + assert f.evaluate(x, 0) == 3*Fyz.y/Fyz.z + raises(ZeroDivisionError, lambda: f.evaluate(z, 0)) + +def test_FracElement_subs(): + F, x,y,z = field("x,y,z", ZZ) + f = (x**2 + 3*y)/z + + assert f.subs(x, 0) == 3*y/z + raises(ZeroDivisionError, lambda: f.subs(z, 0)) + +def test_FracElement_compose(): + pass + +def test_FracField_index(): + a = symbols("a") + F, x, y, z = field('x y z', QQ) + assert F.index(x) == 0 + assert F.index(y) == 1 + + raises(ValueError, lambda: F.index(1)) + raises(ValueError, lambda: F.index(a)) + pass diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_galoistools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_galoistools.py new file mode 100644 index 0000000000000000000000000000000000000000..e512bdd865c300bb138cb40b4ff78f393b323c22 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_galoistools.py @@ -0,0 +1,875 @@ +from sympy.polys.galoistools import ( + gf_crt, gf_crt1, gf_crt2, gf_int, + gf_degree, 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_add, gf_sub, gf_add_mul, gf_sub_mul, gf_mul, gf_sqr, + gf_div, gf_rem, gf_quo, gf_exquo, + gf_lshift, gf_rshift, gf_expand, + gf_pow, gf_pow_mod, + gf_gcdex, gf_gcd, gf_lcm, gf_cofactors, + gf_LC, gf_TC, gf_monic, + gf_eval, gf_multi_eval, + gf_compose, gf_compose_mod, + gf_trace_map, + gf_diff, + gf_irreducible, gf_irreducible_p, + gf_irred_p_ben_or, gf_irred_p_rabin, + gf_sqf_list, gf_sqf_part, gf_sqf_p, + gf_Qmatrix, gf_Qbasis, + gf_ddf_zassenhaus, gf_ddf_shoup, + gf_edf_zassenhaus, gf_edf_shoup, + gf_berlekamp, + gf_factor_sqf, gf_factor, + gf_value, linear_congruence, _csolve_prime_las_vegas, + csolve_prime, gf_csolve, gf_frobenius_map, gf_frobenius_monomial_base +) + +from sympy.polys.polyerrors import ( + ExactQuotientFailed, +) + +from sympy.polys import polyconfig as config + +from sympy.polys.domains import ZZ +from sympy.core.numbers import pi +from sympy.ntheory.generate import nextprime +from sympy.testing.pytest import raises + + +def test_gf_crt(): + U = [49, 76, 65] + M = [99, 97, 95] + + p = 912285 + u = 639985 + + assert gf_crt(U, M, ZZ) == u + + E = [9215, 9405, 9603] + S = [62, 24, 12] + + 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(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 + + +def test_gf_strip(): + assert gf_strip([]) == [] + assert gf_strip([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([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) == [] + assert gf_trunc([1], 11) == [1] + 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] + + +def test_gf_normal(): + 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] + + 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] + + assert gf_from_dict(f, 11, ZZ) == g + assert gf_to_dict(g, 11) == F + + 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_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 + + +def test_gf_TC(): + assert gf_TC([], ZZ) == 0 + assert gf_TC([1], ZZ) == 1 + assert gf_TC([1, 2], ZZ) == 2 + + +def test_gf_monic(): + 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(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]) + + +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_add_ground([], 0, 11, ZZ) == [] + assert gf_sub_ground([], 0, 11, ZZ) == [] + + assert gf_add_ground([], 3, 11, ZZ) == [3] + assert gf_sub_ground([], 3, 11, ZZ) == [8] + + assert gf_add_ground([1], 3, 11, ZZ) == [4] + assert gf_sub_ground([1], 3, 11, ZZ) == [9] + + 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_mul_ground([], 0, 11, ZZ) == [] + assert gf_mul_ground([], 1, 11, ZZ) == [] + + 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_add([], [], 11, ZZ) == [] + assert gf_add([1], [], 11, ZZ) == [1] + assert gf_add([], [1], 11, ZZ) == [1] + 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, 3], [8, 9, 10], 11, ZZ) == [9, 0, 2] + + assert gf_sub([], [], 11, ZZ) == [] + assert gf_sub([1], [], 11, ZZ) == [1] + assert gf_sub([], [1], 11, ZZ) == [10] + 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([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_mul([], [], 11, ZZ) == [] + assert gf_mul([], [1], 11, ZZ) == [] + assert gf_mul([1], [], 11, ZZ) == [] + 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([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([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 = 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 + assert gf_quo(f, g, 7, ZZ) == q + + raises(ExactQuotientFailed, lambda: gf_exquo(f, g, 7, ZZ)) + + 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 + assert gf_quo(f, g, 7, ZZ) == q + + raises(ExactQuotientFailed, lambda: gf_exquo(f, g, 7, ZZ)) + + 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] + + 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_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, 5, ZZ) == ([], f) + + +def test_gf_expand(): + 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] + + +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], 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) == \ + [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(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(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(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(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]) + + +def test_gf_gcd(): + 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(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] + + +def test_gf_lcm(): + 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(ZZ.map([]), ZZ.map([1, 0]), 11, ZZ) == [] + assert gf_lcm(ZZ.map([1, 0]), ZZ.map([]), 11, ZZ) == [] + + 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(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])) + + +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([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 + assert gf_eval([], 27, 11, ZZ) == 0 + 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_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], [], 11, ZZ) == [1] + 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]) + + 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 = 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) == \ + ([1, 1, 1], [1, 1, 1]) + assert gf_trace_map(a, b, c, 1, f, 11, ZZ) == \ + ([5, 2, 10, 3], [5, 3, 0, 4]) + assert gf_trace_map(a, b, c, 2, f, 11, ZZ) == \ + ([5, 9, 5, 3], [10, 1, 5, 7]) + assert gf_trace_map(a, b, c, 3, f, 11, ZZ) == \ + ([1, 10, 6, 0], [7]) + assert gf_trace_map(a, b, c, 4, f, 11, ZZ) == \ + ([1, 1, 1], [1, 1, 8]) + assert gf_trace_map(a, b, c, 5, f, 11, ZZ) == \ + ([5, 2, 10, 3], [5, 3, 0, 0]) + 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) 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(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(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(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 = 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) is True + assert gf_irred_p_ben_or(g, 17, ZZ) is True + + assert gf_irred_p_ben_or(h, 17, ZZ) is False + + 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 + + +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_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) is False + + assert gf_sqf_list(f, 11, ZZ) == \ + (1, [([1, 1], 11)]) + + f = [1, 5, 8, 4] + + assert gf_sqf_p(f, 11, ZZ) is False + + assert gf_sqf_list(f, 11, ZZ) == \ + (1, [([1, 1], 1), + ([1, 2], 2)]) + + assert gf_sqf_part(f, 11, ZZ) == [1, 3, 2] + + 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_frobenius_map(): + f = ZZ.map([2, 0, 1, 0, 2, 2, 0, 2, 2, 2]) + g = ZZ.map([1,1,0,2,0,1,0,2,0,1]) + p = 3 + b = gf_frobenius_monomial_base(g, p, ZZ) + h = gf_frobenius_map(f, g, b, p, ZZ) + h1 = gf_pow_mod(f, p, g, p, ZZ) + assert h == h1 + + +def test_gf_berlekamp(): + 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]] + + V = [[1, 0, 0, 0, 0, 0], + [0, 1, 1, 1, 1, 0], + [0, 0, 7, 9, 0, 1]] + + assert gf_Qmatrix(f, 11, ZZ) == Q + assert gf_Qbasis(Q, 11, ZZ) == V + + assert gf_berlekamp(f, 11, ZZ) == \ + [[1, 1], [1, 5, 3], [1, 2, 3, 4]] + + f = ZZ.map([1, 0, 1, 0, 10, 10, 8, 2, 8]) + + 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]]) + + 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]] + + assert gf_Qmatrix(f, 13, ZZ) == Q + assert gf_Qbasis(Q, 13, ZZ) == V + + 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: 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: ZZ(1), 0: ZZ(1)}, 2, ZZ) + g = [([1, 1], 1), + ([1, 1, 1], 2), + ([1, 1, 1, 1, 1, 1, 1], 3), + ([1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1], 6)] + + assert gf_ddf_zassenhaus(f, 2, ZZ) == g + assert gf_ddf_shoup(f, 2, ZZ) == g + + 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 = 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)] + + assert gf_ddf_zassenhaus(f, 809, ZZ) == g + assert gf_ddf_shoup(f, 809, ZZ) == g + + p = ZZ(nextprime(int((2**15 * pi).evalf()))) + f = gf_from_dict({15: 1, 1: 1, 0: 1}, p, ZZ) + g = [([1, 22730, 68144], 2), + ([1, 64876, 83977, 10787, 12561, 68608, 52650, 88001, 84356], 4), + ([1, 15347, 95022, 84569, 94508, 92335], 5)] + + assert gf_ddf_zassenhaus(f, p, ZZ) == g + assert gf_ddf_shoup(f, p, ZZ) == g + + +def test_gf_edf(): + 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_issue_23174(): + f = ZZ.map([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) + g = ZZ.map([[1, 0, 0, 1, 1, 1, 0, 0, 1], [1, 1, 1, 0, 1, 0, 1, 1, 1]]) + + assert gf_edf_zassenhaus(f, 8, 2, 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_sqf([], 11, ZZ) == (0, []) + assert gf_factor_sqf([1], 11, ZZ) == (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]]) + + 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]]) + + config.setup('GF_FACTOR_METHOD', 'shoup') + + 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 = ZZ.map([1, 0, 0, 1, 0]), 2 + + g = (1, [([1, 0], 1), + ([1, 1], 1), + ([1, 1, 1], 1)]) + + config.setup('GF_FACTOR_METHOD', 'berlekamp') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'shoup') + assert gf_factor(f, p, ZZ) == g + + g = (1, [[1, 0], + [1, 1], + [1, 1, 1]]) + + config.setup('GF_FACTOR_METHOD', 'berlekamp') + assert gf_factor_sqf(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor_sqf(f, p, ZZ) == g + + 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 + + g = (1, [([1, 1], 1), + ([1, 5, 3], 1), + ([1, 2, 3, 4], 1)]) + + config.setup('GF_FACTOR_METHOD', 'berlekamp') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'shoup') + assert gf_factor(f, p, ZZ) == g + + f, p = [1, 5, 8, 4], 11 + + g = (1, [([1, 1], 1), ([1, 2], 2)]) + + config.setup('GF_FACTOR_METHOD', 'berlekamp') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'shoup') + assert gf_factor(f, p, ZZ) == g + + f, p = [1, 1, 10, 1, 0, 10, 10, 10, 0, 0], 11 + + g = (1, [([1, 0], 2), ([1, 9, 5], 1), ([1, 3, 0, 8, 5, 2], 1)]) + + config.setup('GF_FACTOR_METHOD', 'berlekamp') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'shoup') + assert gf_factor(f, p, ZZ) == g + + f, p = gf_from_dict({32: 1, 0: 1}, 11, ZZ), 11 + + g = (1, [([1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 10], 1), + ([1, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 10], 1)]) + + config.setup('GF_FACTOR_METHOD', 'berlekamp') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'shoup') + assert gf_factor(f, p, ZZ) == g + + f, p = gf_from_dict({32: ZZ(8), 0: ZZ(5)}, 11, ZZ), 11 + + g = (8, [([1, 3], 1), + ([1, 8], 1), + ([1, 0, 9], 1), + ([1, 2, 2], 1), + ([1, 9, 2], 1), + ([1, 0, 5, 0, 7], 1), + ([1, 0, 6, 0, 7], 1), + ([1, 0, 0, 0, 1, 0, 0, 0, 6], 1), + ([1, 0, 0, 0, 10, 0, 0, 0, 6], 1)]) + + config.setup('GF_FACTOR_METHOD', 'berlekamp') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'shoup') + assert gf_factor(f, p, ZZ) == g + + f, p = gf_from_dict({63: ZZ(8), 0: ZZ(5)}, 11, ZZ), 11 + + g = (8, [([1, 7], 1), + ([1, 4, 5], 1), + ([1, 6, 8, 2], 1), + ([1, 9, 9, 2], 1), + ([1, 0, 0, 9, 0, 0, 4], 1), + ([1, 2, 0, 8, 4, 6, 4], 1), + ([1, 2, 3, 8, 0, 6, 4], 1), + ([1, 2, 6, 0, 8, 4, 4], 1), + ([1, 3, 3, 1, 6, 8, 4], 1), + ([1, 5, 6, 0, 8, 6, 4], 1), + ([1, 6, 2, 7, 9, 8, 4], 1), + ([1, 10, 4, 7, 10, 7, 4], 1), + ([1, 10, 10, 1, 4, 9, 4], 1)]) + + config.setup('GF_FACTOR_METHOD', 'berlekamp') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'shoup') + assert gf_factor(f, p, ZZ) == g + + # Gathen polynomials: x**n + x + 1 (mod p > 2**n * pi) + + 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) is True + + g = (1, [([1, 22730, 68144], 1), + ([1, 81553, 77449, 86810, 4724], 1), + ([1, 86276, 56779, 14859, 31575], 1), + ([1, 15347, 95022, 84569, 94508, 92335], 1)]) + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'shoup') + assert gf_factor(f, p, ZZ) == g + + g = (1, [[1, 22730, 68144], + [1, 81553, 77449, 86810, 4724], + [1, 86276, 56779, 14859, 31575], + [1, 15347, 95022, 84569, 94508, 92335]]) + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor_sqf(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'shoup') + assert gf_factor_sqf(f, p, ZZ) == g + + # Shoup polynomials: f = a_0 x**n + a_1 x**(n-1) + ... + a_n + # (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 = ZZ.map([1, 2, 5, 26, 41, 39, 38]) + + assert gf_sqf_p(f, p, ZZ) is True + + g = (1, [([1, 44, 26], 1), + ([1, 11, 25, 18, 30], 1)]) + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'shoup') + assert gf_factor(f, p, ZZ) == g + + g = (1, [[1, 44, 26], + [1, 11, 25, 18, 30]]) + + config.setup('GF_FACTOR_METHOD', 'zassenhaus') + assert gf_factor_sqf(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'shoup') + assert gf_factor_sqf(f, p, ZZ) == g + + config.setup('GF_FACTOR_METHOD', 'other') + 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 + + assert linear_congruence(4, 3, 5) == [2] + assert linear_congruence(0, 3, 5) == [] + assert linear_congruence(6, 1, 4) == [] + assert linear_congruence(0, 5, 5) == [0, 1, 2, 3, 4] + assert linear_congruence(3, 12, 15) == [4, 9, 14] + assert linear_congruence(6, 0, 18) == [0, 3, 6, 9, 12, 15] + # _csolve_prime_las_vegas + assert _csolve_prime_las_vegas([2, 3, 1], 5) == [2, 4] + assert _csolve_prime_las_vegas([2, 0, 1], 5) == [] + from sympy.ntheory import primerange + for p in primerange(2, 100): + # f = x**(p-1) - 1 + f = gf_sub_ground(gf_pow([1, 0], p - 1, p, ZZ), 1, p, ZZ) + assert _csolve_prime_las_vegas(f, p) == list(range(1, p)) + # with power = 1 + assert csolve_prime([1, 3, 2, 17], 7) == [3] + 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([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, 1, 7], 15) == [] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_groebnertools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_groebnertools.py new file mode 100644 index 0000000000000000000000000000000000000000..b7d0fc112047ac26f67d096db02eb8a1c91cab89 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_groebnertools.py @@ -0,0 +1,533 @@ +"""Tests for Groebner bases. """ + +from sympy.polys.groebnertools import ( + groebner, sig, sig_key, + lbp, lbp_key, critical_pair, + cp_key, is_rewritable_or_comparable, + Sign, Polyn, Num, s_poly, f5_reduce, + groebner_lcm, groebner_gcd, is_groebner, + is_reduced +) + +from sympy.polys.fglmtools import _representing_matrices +from sympy.polys.orderings import lex, grlex + +from sympy.polys.rings import ring, xring +from sympy.polys.domains import ZZ, QQ + +from sympy.testing.pytest import slow +from sympy.polys import polyconfig as config + +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 + + assert groebner([f, g], R) == [x, y**3 - QQ(1,2)] + + R, y,x = ring("y,x", QQ, lex) + f = 2*x**2*y + y**2 + g = 2*x**3 + x*y - 1 + + assert groebner([f, g], R) == [y, x**3 - QQ(1,2)] + + R, x,y,z = ring("x,y,z", QQ, lex) + f = x - z**2 + g = y - z**3 + + assert groebner([f, g], R) == [f, g] + + R, x,y = ring("x,y", QQ, grlex) + f = x**3 - 2*x*y + g = x**2*y + x - 2*y**2 + + assert groebner([f, g], R) == [x**2, x*y, -QQ(1,2)*x + y**2] + + R, x,y,z = ring("x,y,z", QQ, lex) + f = -x**2 + y + g = -x**3 + z + + assert groebner([f, g], R) == [x**2 - y, x*y - z, x*z - y**2, y**3 - z**2] + + R, x,y,z = ring("x,y,z", QQ, grlex) + f = -x**2 + y + g = -x**3 + z + + assert groebner([f, g], R) == [y**3 - z**2, x**2 - y, x*y - z, x*z - y**2] + + R, x,y,z = ring("x,y,z", QQ, lex) + f = -x**2 + z + g = -x**3 + y + + assert groebner([f, g], R) == [x**2 - z, x*y - z**2, x*z - y, y**2 - z**3] + + R, x,y,z = ring("x,y,z", QQ, grlex) + f = -x**2 + z + g = -x**3 + y + + assert groebner([f, g], R) == [-y**2 + z**3, x**2 - z, x*y - z**2, x*z - y] + + R, x,y,z = ring("x,y,z", QQ, lex) + f = x - y**2 + g = -y**3 + z + + assert groebner([f, g], R) == [x - y**2, y**3 - z] + + R, x,y,z = ring("x,y,z", QQ, grlex) + f = x - y**2 + g = -y**3 + z + + assert groebner([f, g], R) == [x**2 - y*z, x*y - z, -x + y**2] + + R, x,y,z = ring("x,y,z", QQ, lex) + f = x - z**2 + g = y - z**3 + + assert groebner([f, g], R) == [x - z**2, y - z**3] + + R, x,y,z = ring("x,y,z", QQ, grlex) + f = x - z**2 + g = y - z**3 + + assert groebner([f, g], R) == [x**2 - y*z, x*z - y, -x + z**2] + + R, x,y,z = ring("x,y,z", QQ, lex) + f = -y**2 + z + g = x - y**3 + + assert groebner([f, g], R) == [x - y*z, y**2 - z] + + R, x,y,z = ring("x,y,z", QQ, grlex) + f = -y**2 + z + g = x - y**3 + + assert groebner([f, g], R) == [-x**2 + z**3, x*y - z**2, y**2 - z, -x + y*z] + + R, x,y,z = ring("x,y,z", QQ, lex) + f = y - z**2 + g = x - z**3 + + assert groebner([f, g], R) == [x - z**3, y - z**2] + + R, x,y,z = ring("x,y,z", QQ, grlex) + f = y - z**2 + g = x - z**3 + + assert groebner([f, g], R) == [-x**2 + y**3, x*z - y**2, -x + y*z, -y + z**2] + + 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 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), + ] + +def test_groebner_buchberger(): + with config.using(groebner='buchberger'): + _do_test_groebner() + +def test_groebner_f5b(): + with config.using(groebner='f5b'): + _do_test_groebner() + +def _do_test_benchmark_minpoly(): + R, x,y,z = ring("x,y,z", QQ, lex) + + 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(F, R) == G + +def test_benchmark_minpoly_buchberger(): + with config.using(groebner='buchberger'): + _do_test_benchmark_minpoly() + +def test_benchmark_minpoly_f5b(): + with config.using(groebner='f5b'): + _do_test_benchmark_minpoly() + + +def test_benchmark_coloring(): + V = 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)] + + 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 + + I3 = [x**3 - 1 for x in V] + Ig = [x**2 + x*y + y**2 for x, y in E] + + I = I3 + Ig + + assert groebner(I[:-1], R) == [ + x1 + x11 + x12, + x2 - x11, + x3 - x12, + x4 - x12, + x5 + x11 + x12, + x6 - x11, + x7 - x12, + x8 + x11 + x12, + x9 - x11, + x10 + x11 + x12, + x11**2 + x11*x12 + x12**2, + x12**3 - 1, + ] + + assert groebner(I, R) == [1] + + +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, 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, + ] + + 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_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, 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, + ] + + 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, + 33*x1 + 63*x2**2 + 2268*x2*x3**2 - 188*x2*x3 + 34*x2 + 2520*x3**3 - 849*x3**2 + 3*x3, + 7*x1**2 - x1 - 7*x2**2 - 24*x2*x3 + 3*x2 - 15*x3**2 + 5*x3, + 14*x1*x2 - x1 + 14*x2**2 + 18*x2*x3 - 4*x2 + 6*x3**2 - 2*x3, + 14*x1*x3 - x1 + 7*x2**2 + 32*x2*x3 - 4*x2 + 27*x3**2 - 9*x3, + x0 + 2*x1 + 2*x2 + 2*x3 - 1, + ] + +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, + ] + +# NOTE: This is very slow (> 2 minutes on 3.4 GHz) without GMPY +@slow +def test_benchmark_czichowski_buchberger(): + with config.using(groebner='buchberger'): + _do_test_benchmark_czichowski() + +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] + + 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 + ] + + 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, + c**4 + 2*c**2*d**2 - d**4 - 2, + c**3*d + c*d**3 + d**4 + 1, + b*c**2 - c**3 - c**2*d - 2*c*d**2 - d**3, + b**2 - c**2, b*d + c**2 + c*d + d**2, + a + b + c + d + ] + +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) + s2 = sig((1,) * 3, 4) + s3 = sig((2,) * 3, 2) + + assert sig_key(s1, lex) > sig_key(s2, lex) + assert sig_key(s2, lex) < sig_key(s3, lex) + + +def test_lbp_key(): + 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) + + +def test_critical_pair(): + # from cyclic4 with grlex + 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), 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, 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 + 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), 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) + + cp1 = critical_pair(p1, q1, R) + cp2 = critical_pair(p2, q2, R) + + 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) + + +def test_is_rewritable_or_comparable(): + # from katsura4 with grlex + 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) 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)] + + # comparable: + assert is_rewritable_or_comparable(Sign(p), Num(p), B) is True + + +def test_f5_reduce(): + # katsura3 with lex + 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], R) + s = s_poly(cp) + + 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) == s + + +def test_representing_matrices(): + R, x,y = ring("x,y", QQ, grlex) + + basis = [(0, 0), (0, 1), (1, 0), (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 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 + +def test_is_groebner(): + R, x,y = ring("x,y", QQ, grlex) + valid_groebner = [x**2, x*y, -QQ(1,2)*x + y**2] + invalid_groebner = [x**3, x*y, -QQ(1,2)*x + y**2] + assert is_groebner(valid_groebner, R) is True + assert is_groebner(invalid_groebner, R) is False + +def test_is_reduced(): + R, x, y = ring("x,y", QQ, lex) + f = x**2 + 2*x*y**2 + g = x*y + 2*y**3 - 1 + assert is_reduced([f, g], R) == False + G = groebner([f, g], R) + assert is_reduced(G, R) == True diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_heuristicgcd.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_heuristicgcd.py new file mode 100644 index 0000000000000000000000000000000000000000..7ff6bd6ea4effbd49c5e942ea8925cfcca4ba162 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_heuristicgcd.py @@ -0,0 +1,152 @@ +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 + + +def test_issue_10996(): + R, x, y, z = ring("x,y,z", ZZ) + + f = 12*x**6*y**7*z**3 - 3*x**4*y**9*z**3 + 12*x**3*y**5*z**4 + g = -48*x**7*y**8*z**3 + 12*x**5*y**10*z**3 - 48*x**5*y**7*z**2 + \ + 36*x**4*y**7*z - 48*x**4*y**6*z**4 + 12*x**3*y**9*z**2 - 48*x**3*y**4 \ + - 9*x**2*y**9*z - 48*x**2*y**5*z**3 + 12*x*y**6 + 36*x*y**5*z**2 - 48*y**2*z + + H, cff, cfg = heugcd(f, g) + + assert H == 12*x**3*y**4 - 3*x*y**6 + 12*y**2*z + assert H*cff == f and H*cfg == g + + +def test_issue_25793(): + R, x = ring("x", ZZ) + f = x - 4851 # failure starts for values more than 4850 + g = f*(2*x + 1) + H, cff, cfg = R.dup_zz_heu_gcd(f, g) + assert H == f + # needs a test for dmp, too, that fails in master before this change diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_hypothesis.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_hypothesis.py new file mode 100644 index 0000000000000000000000000000000000000000..78c2369179c3f0ea4d34b8a7868417506177e3c5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_hypothesis.py @@ -0,0 +1,36 @@ +from hypothesis import given +from hypothesis import strategies as st +from sympy.abc import x +from sympy.polys.polytools import Poly + + +def polys(*, nonzero=False, domain="ZZ"): + # This is a simple strategy, but sufficient the tests below + elems = {"ZZ": st.integers(), "QQ": st.fractions()} + coeff_st = st.lists(elems[domain]) + if nonzero: + coeff_st = coeff_st.filter(any) + return st.builds(Poly, coeff_st, st.just(x), domain=st.just(domain)) + + +@given(f=polys(), g=polys(), r=polys()) +def test_gcd_hypothesis(f, g, r): + gcd_1 = f.gcd(g) + gcd_2 = g.gcd(f) + assert gcd_1 == gcd_2 + + # multiply by r + gcd_3 = g.gcd(f + r * g) + assert gcd_1 == gcd_3 + + +@given(f_z=polys(), g_z=polys(nonzero=True)) +def test_poly_hypothesis_integers(f_z, g_z): + remainder_z = f_z.rem(g_z) + assert g_z.degree() >= remainder_z.degree() or remainder_z.degree() == 0 + + +@given(f_q=polys(domain="QQ"), g_q=polys(nonzero=True, domain="QQ")) +def test_poly_hypothesis_rationals(f_q, g_q): + remainder_q = f_q.rem(g_q) + assert g_q.degree() >= remainder_q.degree() or remainder_q.degree() == 0 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_injections.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_injections.py new file mode 100644 index 0000000000000000000000000000000000000000..63a5537c94f00e52a3899c97f0d78bfadab78a67 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_injections.py @@ -0,0 +1,39 @@ +"""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 + +def test_vring(): + ns = {'vring':vring, 'QQ':QQ} + exec('R = vring("r", QQ)', ns) + exec('assert r == R.gens[0]', ns) + + exec('R = vring("rb rbb rcc rzz _rx", QQ)', ns) + exec('assert rb == R.gens[0]', ns) + exec('assert rbb == R.gens[1]', ns) + exec('assert rcc == R.gens[2]', ns) + exec('assert rzz == R.gens[3]', ns) + exec('assert _rx == R.gens[4]', ns) + + exec('R = vring(["rd", "re", "rfg"], QQ)', ns) + exec('assert rd == R.gens[0]', ns) + exec('assert re == R.gens[1]', ns) + exec('assert rfg == R.gens[2]', ns) + +def test_vfield(): + ns = {'vfield':vfield, 'QQ':QQ} + exec('F = vfield("f", QQ)', ns) + exec('assert f == F.gens[0]', ns) + + exec('F = vfield("fb fbb fcc fzz _fx", QQ)', ns) + exec('assert fb == F.gens[0]', ns) + exec('assert fbb == F.gens[1]', ns) + exec('assert fcc == F.gens[2]', ns) + exec('assert fzz == F.gens[3]', ns) + exec('assert _fx == F.gens[4]', ns) + + exec('F = vfield(["fd", "fe", "ffg"], QQ)', ns) + exec('assert fd == F.gens[0]', ns) + exec('assert fe == F.gens[1]', ns) + exec('assert ffg == F.gens[2]', ns) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_modulargcd.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_modulargcd.py new file mode 100644 index 0000000000000000000000000000000000000000..20510f59186524ed4008ade943fab526a9ae7194 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_modulargcd.py @@ -0,0 +1,325 @@ +from sympy.polys.rings import ring +from sympy.polys.domains import ZZ, QQ, AlgebraicField +from sympy.polys.modulargcd import ( + modgcd_univariate, + modgcd_bivariate, + _chinese_remainder_reconstruction_multivariate, + modgcd_multivariate, + _to_ZZ_poly, + _to_ANP_poly, + func_field_modgcd, + _func_field_modgcd_m) +from sympy.functions.elementary.miscellaneous import sqrt + + +def test_modgcd_univariate_integers(): + R, x = ring("x", ZZ) + + f, g = R.zero, R.zero + assert modgcd_univariate(f, g) == (0, 0, 0) + + f, g = R.zero, x + assert modgcd_univariate(f, g) == (x, 0, 1) + assert modgcd_univariate(g, f) == (x, 1, 0) + + f, g = R.zero, -x + assert modgcd_univariate(f, g) == (x, 0, -1) + assert modgcd_univariate(g, f) == (x, -1, 0) + + f, g = 2*x, R(2) + assert modgcd_univariate(f, g) == (2, x, 1) + + f, g = 2*x + 2, 6*x**2 - 6 + assert modgcd_univariate(f, g) == (2*x + 2, 1, 3*x - 3) + + 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 modgcd_univariate(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 modgcd_univariate(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 modgcd_univariate(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 + + assert modgcd_univariate(f, f.diff(x))[0] == g + + f = 1317378933230047068160*x + 2945748836994210856960 + g = 120352542776360960*x + 269116466014453760 + + h = 120352542776360960*x + 269116466014453760 + cff = 10946 + cfg = 1 + + assert modgcd_univariate(f, g) == (h, cff, cfg) + + +def test_modgcd_bivariate_integers(): + R, x, y = ring("x,y", ZZ) + + f, g = R.zero, R.zero + assert modgcd_bivariate(f, g) == (0, 0, 0) + + f, g = 2*x, R(2) + assert modgcd_bivariate(f, g) == (2, x, 1) + + f, g = x + 2*y, x + y + assert modgcd_bivariate(f, g) == (1, f, g) + + f, g = x**2 + 2*x*y + y**2, x**3 + y**3 + assert modgcd_bivariate(f, g) == (x + y, x + y, x**2 - x*y + y**2) + + f, g = x*y**2 + 2*x*y + x, x*y**3 + x + assert modgcd_bivariate(f, g) == (x*y + x, y + 1, y**2 - y + 1) + + f, g = x**2*y**2 + x**2*y + 1, x*y**2 + x*y + 1 + assert modgcd_bivariate(f, g) == (1, f, g) + + f = 2*x*y**2 + 4*x*y + 2*x + y**2 + 2*y + 1 + g = 2*x*y**3 + 2*x + y**3 + 1 + assert modgcd_bivariate(f, g) == (2*x*y + 2*x + y + 1, y + 1, y**2 - y + 1) + + f, g = 2*x**2 + 4*x + 2, x + 1 + assert modgcd_bivariate(f, g) == (x + 1, 2*x + 2, 1) + + f, g = x + 1, 2*x**2 + 4*x + 2 + assert modgcd_bivariate(f, g) == (x + 1, 1, 2*x + 2) + + f = 2*x**2 + 4*x*y - 2*x - 4*y + g = x**2 + x - 2 + assert modgcd_bivariate(f, g) == (x - 1, 2*x + 4*y, x + 2) + + f = 2*x**2 + 2*x*y - 3*x - 3*y + g = 4*x*y - 2*x + 4*y**2 - 2*y + assert modgcd_bivariate(f, g) == (x + y, 2*x - 3, 4*y - 2) + + +def test_chinese_remainder(): + R, x, y = ring("x, y", ZZ) + p, q = 3, 5 + + hp = x**3*y - x**2 - 1 + hq = -x**3*y - 2*x*y**2 + 2 + + hpq = _chinese_remainder_reconstruction_multivariate(hp, hq, p, q) + + assert hpq.trunc_ground(p) == hp + assert hpq.trunc_ground(q) == hq + + T, z = ring("z", R) + p, q = 3, 7 + + hp = (x*y + 1)*z**2 + x + hq = (x**2 - 3*y)*z + 2 + + hpq = _chinese_remainder_reconstruction_multivariate(hp, hq, p, q) + + assert hpq.trunc_ground(p) == hp + assert hpq.trunc_ground(q) == hq + + +def test_modgcd_multivariate_integers(): + R, x, y = ring("x,y", ZZ) + + f, g = R.zero, R.zero + assert modgcd_multivariate(f, g) == (0, 0, 0) + + f, g = 2*x**2 + 4*x + 2, x + 1 + assert modgcd_multivariate(f, g) == (x + 1, 2*x + 2, 1) + + f, g = x + 1, 2*x**2 + 4*x + 2 + assert modgcd_multivariate(f, g) == (x + 1, 1, 2*x + 2) + + f = 2*x**2 + 2*x*y - 3*x - 3*y + g = 4*x*y - 2*x + 4*y**2 - 2*y + assert modgcd_multivariate(f, g) == (x + y, 2*x - 3, 4*y - 2) + + f, g = x*y**2 + 2*x*y + x, x*y**3 + x + assert modgcd_multivariate(f, g) == (x*y + x, y + 1, y**2 - y + 1) + + f, g = x**2*y**2 + x**2*y + 1, x*y**2 + x*y + 1 + assert modgcd_multivariate(f, g) == (1, f, g) + + 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 modgcd_multivariate(f, g) == (h, cff, cfg) + + R, x, y, z, u = ring("x,y,z,u", ZZ) + + f, g = x + y + z, -x - y - z - u + assert modgcd_multivariate(f, g) == (1, f, g) + + f, g = u**2 + 2*u + 1, 2*u + 2 + assert modgcd_multivariate(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 modgcd_multivariate(f, g) == (h, cff, cfg) + assert modgcd_multivariate(g, f) == (h, cfg, cff) + + R, x, y, z = ring("x,y,z", ZZ) + + f, g = x - y*z, x - y*z + assert modgcd_multivariate(f, g) == (x - y*z, 1, 1) + + f, g, h = R.fateman_poly_F_1() + H, cff, cfg = modgcd_multivariate(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 = modgcd_multivariate(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 = modgcd_multivariate(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 = modgcd_multivariate(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 = modgcd_multivariate(f, g) + + assert H == h and H*cff == f and H*cfg == g + + f, g, h = R.fateman_poly_F_3() + H, cff, cfg = modgcd_multivariate(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 = modgcd_multivariate(f, g) + + assert H == h and H*cff == f and H*cfg == g + + +def test_to_ZZ_ANP_poly(): + A = AlgebraicField(QQ, sqrt(2)) + R, x = ring("x", A) + f = x*(sqrt(2) + 1) + + T, x_, z_ = ring("x_, z_", ZZ) + f_ = x_*z_ + x_ + + assert _to_ZZ_poly(f, T) == f_ + assert _to_ANP_poly(f_, R) == f + + R, x, t, s = ring("x, t, s", A) + f = x*t**2 + x*s + sqrt(2) + + D, t_, s_ = ring("t_, s_", ZZ) + T, x_, z_ = ring("x_, z_", D) + f_ = (t_**2 + s_)*x_ + z_ + + assert _to_ZZ_poly(f, T) == f_ + assert _to_ANP_poly(f_, R) == f + + +def test_modgcd_algebraic_field(): + A = AlgebraicField(QQ, sqrt(2)) + R, x = ring("x", A) + one = A.one + + f, g = 2*x, R(2) + assert func_field_modgcd(f, g) == (one, f, g) + + f, g = 2*x, R(sqrt(2)) + assert func_field_modgcd(f, g) == (one, f, g) + + f, g = 2*x + 2, 6*x**2 - 6 + assert func_field_modgcd(f, g) == (x + 1, R(2), 6*x - 6) + + R, x, y = ring("x, y", A) + + f, g = x + sqrt(2)*y, x + y + assert func_field_modgcd(f, g) == (one, f, g) + + f, g = x*y + sqrt(2)*y**2, R(sqrt(2))*y + assert func_field_modgcd(f, g) == (y, x + sqrt(2)*y, R(sqrt(2))) + + f, g = x**2 + 2*sqrt(2)*x*y + 2*y**2, x + sqrt(2)*y + assert func_field_modgcd(f, g) == (g, g, one) + + A = AlgebraicField(QQ, sqrt(2), sqrt(3)) + R, x, y, z = ring("x, y, z", A) + + h = x**2*y**7 + sqrt(6)/21*z + f, g = h*(27*y**3 + 1), h*(y + x) + assert func_field_modgcd(f, g) == (h, 27*y**3+1, y+x) + + h = x**13*y**3 + 1/2*x**10 + 1/sqrt(2) + f, g = h*(x + 1), h*sqrt(2)/sqrt(3) + assert func_field_modgcd(f, g) == (h, x + 1, R(sqrt(2)/sqrt(3))) + + A = AlgebraicField(QQ, sqrt(2)**(-1)*sqrt(3)) + R, x = ring("x", A) + + f, g = x + 1, x - 1 + assert func_field_modgcd(f, g) == (A.one, f, g) + + +# when func_field_modgcd supports function fields, this test can be changed +def test_modgcd_func_field(): + D, t = ring("t", ZZ) + R, x, z = ring("x, z", D) + + minpoly = (z**2*t**2 + z**2*t - 1).drop(0) + f, g = x + 1, x - 1 + + assert _func_field_modgcd_m(f, g, minpoly) == R.one diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_monomials.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_monomials.py new file mode 100644 index 0000000000000000000000000000000000000000..c5ed28ba0e8e3f8e9f85c543a4fffcaef855fff8 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_monomials.py @@ -0,0 +1,269 @@ +"""Tests for tools and arithmetics for monomials of distributed polynomials. """ + +from sympy.polys.monomials import ( + itermonomials, monomial_count, + monomial_mul, monomial_div, + monomial_gcd, monomial_lcm, + monomial_max, monomial_min, + monomial_divides, monomial_pow, + Monomial, +) + +from sympy.polys.polyerrors import ExactQuotientFailed + +from sympy.abc import a, b, c, x, y, z +from sympy.core import S, symbols +from sympy.testing.pytest import raises + +def test_monomials(): + + # total_degree tests + assert set(itermonomials([], 0)) == {S.One} + assert set(itermonomials([], 1)) == {S.One} + assert set(itermonomials([], 2)) == {S.One} + + assert set(itermonomials([], 0, 0)) == {S.One} + assert set(itermonomials([], 1, 0)) == {S.One} + assert set(itermonomials([], 2, 0)) == {S.One} + + raises(StopIteration, lambda: next(itermonomials([], 0, 1))) + raises(StopIteration, lambda: next(itermonomials([], 0, 2))) + raises(StopIteration, lambda: next(itermonomials([], 0, 3))) + + assert set(itermonomials([], 0, 1)) == set() + assert set(itermonomials([], 0, 2)) == set() + assert set(itermonomials([], 0, 3)) == set() + + raises(ValueError, lambda: set(itermonomials([], -1))) + raises(ValueError, lambda: set(itermonomials([x], -1))) + raises(ValueError, lambda: set(itermonomials([x, y], -1))) + + assert set(itermonomials([x], 0)) == {S.One} + assert set(itermonomials([x], 1)) == {S.One, x} + assert set(itermonomials([x], 2)) == {S.One, x, x**2} + assert set(itermonomials([x], 3)) == {S.One, x, x**2, x**3} + + assert set(itermonomials([x, y], 0)) == {S.One} + assert set(itermonomials([x, y], 1)) == {S.One, x, y} + assert set(itermonomials([x, y], 2)) == {S.One, x, y, x**2, y**2, x*y} + assert set(itermonomials([x, y], 3)) == \ + {S.One, x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2} + + i, j, k = symbols('i j k', commutative=False) + assert set(itermonomials([i, j, k], 0)) == {S.One} + assert set(itermonomials([i, j, k], 1)) == {S.One, i, j, k} + assert set(itermonomials([i, j, k], 2)) == \ + {S.One, i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j} + + assert set(itermonomials([i, j, k], 3)) == \ + {S.One, i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j, + i**3, j**3, k**3, + i**2 * j, i**2 * k, j * i**2, k * i**2, + j**2 * i, j**2 * k, i * j**2, k * j**2, + k**2 * i, k**2 * j, i * k**2, j * k**2, + i*j*i, i*k*i, j*i*j, j*k*j, k*i*k, k*j*k, + i*j*k, i*k*j, j*i*k, j*k*i, k*i*j, k*j*i, + } + + assert set(itermonomials([x, i, j], 0)) == {S.One} + assert set(itermonomials([x, i, j], 1)) == {S.One, x, i, j} + assert set(itermonomials([x, i, j], 2)) == {S.One, x, i, j, x*i, x*j, i*j, j*i, x**2, i**2, j**2} + assert set(itermonomials([x, i, j], 3)) == \ + {S.One, x, i, j, x*i, x*j, i*j, j*i, x**2, i**2, j**2, + x**3, i**3, j**3, + x**2 * i, x**2 * j, + x * i**2, j * i**2, i**2 * j, i*j*i, + x * j**2, i * j**2, j**2 * i, j*i*j, + x * i * j, x * j * i + } + + # degree_list tests + assert set(itermonomials([], [])) == {S.One} + + raises(ValueError, lambda: set(itermonomials([], [0]))) + raises(ValueError, lambda: set(itermonomials([], [1]))) + raises(ValueError, lambda: set(itermonomials([], [2]))) + + raises(ValueError, lambda: set(itermonomials([x], [1], []))) + raises(ValueError, lambda: set(itermonomials([x], [1, 2], []))) + raises(ValueError, lambda: set(itermonomials([x], [1, 2, 3], []))) + + raises(ValueError, lambda: set(itermonomials([x], [], [1]))) + raises(ValueError, lambda: set(itermonomials([x], [], [1, 2]))) + raises(ValueError, lambda: set(itermonomials([x], [], [1, 2, 3]))) + + raises(ValueError, lambda: set(itermonomials([x, y], [1, 2], [1, 2, 3]))) + raises(ValueError, lambda: set(itermonomials([x, y, z], [1, 2, 3], [0, 1]))) + + raises(ValueError, lambda: set(itermonomials([x], [1], [-1]))) + raises(ValueError, lambda: set(itermonomials([x, y], [1, 2], [1, -1]))) + + raises(ValueError, lambda: set(itermonomials([], [], 1))) + raises(ValueError, lambda: set(itermonomials([], [], 2))) + raises(ValueError, lambda: set(itermonomials([], [], 3))) + + raises(ValueError, lambda: set(itermonomials([x, y], [0, 1], [1, 2]))) + raises(ValueError, lambda: set(itermonomials([x, y, z], [0, 0, 3], [0, 1, 2]))) + + assert set(itermonomials([x], [0])) == {S.One} + assert set(itermonomials([x], [1])) == {S.One, x} + assert set(itermonomials([x], [2])) == {S.One, x, x**2} + assert set(itermonomials([x], [3])) == {S.One, x, x**2, x**3} + + assert set(itermonomials([x], [3], [1])) == {x, x**3, x**2} + assert set(itermonomials([x], [3], [2])) == {x**3, x**2} + + assert set(itermonomials([x, y], 3, 3)) == {x**3, x**2*y, x*y**2, y**3} + assert set(itermonomials([x, y], 3, 2)) == {x**2, x*y, y**2, x**3, x**2*y, x*y**2, y**3} + + assert set(itermonomials([x, y], [0, 0])) == {S.One} + assert set(itermonomials([x, y], [0, 1])) == {S.One, y} + assert set(itermonomials([x, y], [0, 2])) == {S.One, y, y**2} + assert set(itermonomials([x, y], [0, 2], [0, 1])) == {y, y**2} + assert set(itermonomials([x, y], [0, 2], [0, 2])) == {y**2} + + assert set(itermonomials([x, y], [1, 0])) == {S.One, x} + assert set(itermonomials([x, y], [1, 1])) == {S.One, x, y, x*y} + assert set(itermonomials([x, y], [1, 2])) == {S.One, x, y, x*y, y**2, x*y**2} + assert set(itermonomials([x, y], [1, 2], [1, 1])) == {x*y, x*y**2} + assert set(itermonomials([x, y], [1, 2], [1, 2])) == {x*y**2} + + assert set(itermonomials([x, y], [2, 0])) == {S.One, x, x**2} + assert set(itermonomials([x, y], [2, 1])) == {S.One, x, y, x*y, x**2, x**2*y} + assert set(itermonomials([x, y], [2, 2])) == \ + {S.One, y**2, x*y**2, x, x*y, x**2, x**2*y**2, y, x**2*y} + + i, j, k = symbols('i j k', commutative=False) + assert set(itermonomials([i, j, k], 2, 2)) == \ + {k*i, i**2, i*j, j*k, j*i, k**2, j**2, k*j, i*k} + assert set(itermonomials([i, j, k], 3, 2)) == \ + {j*k**2, i*k**2, k*i*j, k*i**2, k**2, j*k*j, k*j**2, i*k*i, i*j, + j**2*k, i**2*j, j*i*k, j**3, i**3, k*j*i, j*k*i, j*i, + k**2*j, j*i**2, k*j, k*j*k, i*j*i, j*i*j, i*j**2, j**2, + k*i*k, i**2, j*k, i*k, i*k*j, k**3, i**2*k, j**2*i, k**2*i, + i*j*k, k*i + } + assert set(itermonomials([i, j, k], [0, 0, 0])) == {S.One} + assert set(itermonomials([i, j, k], [0, 0, 1])) == {1, k} + assert set(itermonomials([i, j, k], [0, 1, 0])) == {1, j} + assert set(itermonomials([i, j, k], [1, 0, 0])) == {i, 1} + assert set(itermonomials([i, j, k], [0, 0, 2])) == {k**2, 1, k} + assert set(itermonomials([i, j, k], [0, 2, 0])) == {1, j, j**2} + assert set(itermonomials([i, j, k], [2, 0, 0])) == {i, 1, i**2} + assert set(itermonomials([i, j, k], [1, 1, 1])) == {1, k, j, j*k, i*k, i, i*j, i*j*k} + assert set(itermonomials([i, j, k], [2, 2, 2])) == \ + {1, k, i**2*k**2, j*k, j**2, i, i*k, j*k**2, i*j**2*k**2, + i**2*j, i**2*j**2, k**2, j**2*k, i*j**2*k, + j**2*k**2, i*j, i**2*k, i**2*j**2*k, j, i**2*j*k, + i*j**2, i*k**2, i*j*k, i**2*j**2*k**2, i*j*k**2, i**2, i**2*j*k**2 + } + + assert set(itermonomials([x, j, k], [0, 0, 0])) == {S.One} + assert set(itermonomials([x, j, k], [0, 0, 1])) == {1, k} + assert set(itermonomials([x, j, k], [0, 1, 0])) == {1, j} + assert set(itermonomials([x, j, k], [1, 0, 0])) == {x, 1} + assert set(itermonomials([x, j, k], [0, 0, 2])) == {k**2, 1, k} + assert set(itermonomials([x, j, k], [0, 2, 0])) == {1, j, j**2} + assert set(itermonomials([x, j, k], [2, 0, 0])) == {x, 1, x**2} + assert set(itermonomials([x, j, k], [1, 1, 1])) == {1, k, j, j*k, x*k, x, x*j, x*j*k} + assert set(itermonomials([x, j, k], [2, 2, 2])) == \ + {1, k, x**2*k**2, j*k, j**2, x, x*k, j*k**2, x*j**2*k**2, + x**2*j, x**2*j**2, k**2, j**2*k, x*j**2*k, + j**2*k**2, x*j, x**2*k, x**2*j**2*k, j, x**2*j*k, + x*j**2, x*k**2, x*j*k, x**2*j**2*k**2, x*j*k**2, x**2, x**2*j*k**2 + } + +def test_monomial_count(): + assert monomial_count(2, 2) == 6 + assert monomial_count(2, 3) == 10 + +def test_monomial_mul(): + 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) + +def test_monomial_gcd(): + 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) + +def test_monomial_max(): + assert monomial_max((3, 4, 5), (0, 5, 1), (6, 3, 9)) == (6, 5, 9) + +def test_monomial_pow(): + assert monomial_pow((1, 2, 3), 3) == (3, 6, 9) + +def test_monomial_min(): + 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 + +def test_Monomial(): + m = Monomial((3, 4, 1), (x, y, z)) + n = Monomial((1, 2, 0), (x, y, z)) + + assert m.as_expr() == x**3*y**4*z + assert n.as_expr() == x**1*y**2 + + assert m.as_expr(a, b, c) == a**3*b**4*c + assert n.as_expr(a, b, c) == a**1*b**2 + + assert m.exponents == (3, 4, 1) + assert m.gens == (x, y, z) + + assert n.exponents == (1, 2, 0) + assert n.gens == (x, y, z) + + assert m == (3, 4, 1) + assert n != (3, 4, 1) + assert m != (1, 2, 0) + assert n == (1, 2, 0) + assert (m == 1) is False + + assert m[0] == m[-3] == 3 + assert m[1] == m[-2] == 4 + assert m[2] == m[-1] == 1 + + assert n[0] == n[-3] == 1 + assert n[1] == n[-2] == 2 + assert n[2] == n[-1] == 0 + + assert m[:2] == (3, 4) + assert n[:2] == (1, 2) + + assert m*n == Monomial((4, 6, 1)) + assert m/n == Monomial((2, 2, 1)) + + assert m*(1, 2, 0) == Monomial((4, 6, 1)) + assert m/(1, 2, 0) == Monomial((2, 2, 1)) + + assert m.gcd(n) == Monomial((1, 2, 0)) + assert m.lcm(n) == Monomial((3, 4, 1)) + + assert m.gcd((1, 2, 0)) == Monomial((1, 2, 0)) + assert m.lcm((1, 2, 0)) == Monomial((3, 4, 1)) + + 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)) + _a = Monomial((0, 0, 0)) + for n in range(10): + assert _a == m**n + _a *= m + + raises(ExactQuotientFailed, lambda: m/Monomial((5, 2, 0))) + + mm = Monomial((1, 2, 3)) + raises(ValueError, lambda: mm.as_expr()) + assert str(mm) == 'Monomial((1, 2, 3))' + assert str(m) == 'x**3*y**4*z**1' + raises(NotImplementedError, lambda: m*1) + raises(NotImplementedError, lambda: m/1) + raises(ValueError, lambda: m**-1) + raises(TypeError, lambda: m.gcd(3)) + raises(TypeError, lambda: m.lcm(3)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_multivariate_resultants.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_multivariate_resultants.py new file mode 100644 index 0000000000000000000000000000000000000000..0799feb41fc875cf038723916a3efd62ff31b1b4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_multivariate_resultants.py @@ -0,0 +1,294 @@ +"""Tests for Dixon's and Macaulay's classes. """ + +from sympy.matrices.dense import Matrix +from sympy.polys.polytools import factor +from sympy.core import symbols +from sympy.tensor.indexed import IndexedBase + +from sympy.polys.multivariate_resultants import (DixonResultant, + MacaulayResultant) + +c, d = symbols("a, b") +x, y = symbols("x, y") + +p = c * x + y +q = x + d * y + +dixon = DixonResultant(polynomials=[p, q], variables=[x, y]) +macaulay = MacaulayResultant(polynomials=[p, q], variables=[x, y]) + +def test_dixon_resultant_init(): + """Test init method of DixonResultant.""" + a = IndexedBase("alpha") + + assert dixon.polynomials == [p, q] + assert dixon.variables == [x, y] + assert dixon.n == 2 + assert dixon.m == 2 + assert dixon.dummy_variables == [a[0], a[1]] + +def test_get_dixon_polynomial_numerical(): + """Test Dixon's polynomial for a numerical example.""" + a = IndexedBase("alpha") + + p = x + y + q = x ** 2 + y **3 + h = x ** 2 + y + + dixon = DixonResultant([p, q, h], [x, y]) + polynomial = -x * y ** 2 * a[0] - x * y ** 2 * a[1] - x * y * a[0] \ + * a[1] - x * y * a[1] ** 2 - x * a[0] * a[1] ** 2 + x * a[0] - \ + y ** 2 * a[0] * a[1] + y ** 2 * a[1] - y * a[0] * a[1] ** 2 + y * \ + a[1] ** 2 + + assert dixon.get_dixon_polynomial().as_expr().expand() == polynomial + +def test_get_max_degrees(): + """Tests max degrees function.""" + + p = x + y + q = x ** 2 + y **3 + h = x ** 2 + y + + dixon = DixonResultant(polynomials=[p, q, h], variables=[x, y]) + dixon_polynomial = dixon.get_dixon_polynomial() + + assert dixon.get_max_degrees(dixon_polynomial) == [1, 2] + +def test_get_dixon_matrix(): + """Test Dixon's resultant for a numerical example.""" + + x, y = symbols('x, y') + + p = x + y + q = x ** 2 + y ** 3 + h = x ** 2 + y + + dixon = DixonResultant([p, q, h], [x, y]) + polynomial = dixon.get_dixon_polynomial() + + assert dixon.get_dixon_matrix(polynomial).det() == 0 + +def test_get_dixon_matrix_example_two(): + """Test Dixon's matrix for example from [Palancz08]_.""" + x, y, z = symbols('x, y, z') + + f = x ** 2 + y ** 2 - 1 + z * 0 + g = x ** 2 + z ** 2 - 1 + y * 0 + h = y ** 2 + z ** 2 - 1 + + example_two = DixonResultant([f, g, h], [y, z]) + poly = example_two.get_dixon_polynomial() + matrix = example_two.get_dixon_matrix(poly) + + expr = 1 - 8 * x ** 2 + 24 * x ** 4 - 32 * x ** 6 + 16 * x ** 8 + assert (matrix.det() - expr).expand() == 0 + +def test_KSY_precondition(): + """Tests precondition for KSY Resultant.""" + A, B, C = symbols('A, B, C') + + m1 = Matrix([[1, 2, 3], + [4, 5, 12], + [6, 7, 18]]) + + m2 = Matrix([[0, C**2], + [-2 * C, -C ** 2]]) + + m3 = Matrix([[1, 0], + [0, 1]]) + + m4 = Matrix([[A**2, 0, 1], + [A, 1, 1 / A]]) + + m5 = Matrix([[5, 1], + [2, B], + [0, 1], + [0, 0]]) + + assert dixon.KSY_precondition(m1) == False + assert dixon.KSY_precondition(m2) == True + assert dixon.KSY_precondition(m3) == True + assert dixon.KSY_precondition(m4) == False + assert dixon.KSY_precondition(m5) == True + +def test_delete_zero_rows_and_columns(): + """Tests method for deleting rows and columns containing only zeros.""" + A, B, C = symbols('A, B, C') + + m1 = Matrix([[0, 0], + [0, 0], + [1, 2]]) + + m2 = Matrix([[0, 1, 2], + [0, 3, 4], + [0, 5, 6]]) + + m3 = Matrix([[0, 0, 0, 0], + [0, 1, 2, 0], + [0, 3, 4, 0], + [0, 0, 0, 0]]) + + m4 = Matrix([[1, 0, 2], + [0, 0, 0], + [3, 0, 4]]) + + m5 = Matrix([[0, 0, 0, 1], + [0, 0, 0, 2], + [0, 0, 0, 3], + [0, 0, 0, 4]]) + + m6 = Matrix([[0, 0, A], + [B, 0, 0], + [0, 0, C]]) + + assert dixon.delete_zero_rows_and_columns(m1) == Matrix([[1, 2]]) + + assert dixon.delete_zero_rows_and_columns(m2) == Matrix([[1, 2], + [3, 4], + [5, 6]]) + + assert dixon.delete_zero_rows_and_columns(m3) == Matrix([[1, 2], + [3, 4]]) + + assert dixon.delete_zero_rows_and_columns(m4) == Matrix([[1, 2], + [3, 4]]) + + assert dixon.delete_zero_rows_and_columns(m5) == Matrix([[1], + [2], + [3], + [4]]) + + assert dixon.delete_zero_rows_and_columns(m6) == Matrix([[0, A], + [B, 0], + [0, C]]) + +def test_product_leading_entries(): + """Tests product of leading entries method.""" + A, B = symbols('A, B') + + m1 = Matrix([[1, 2, 3], + [0, 4, 5], + [0, 0, 6]]) + + m2 = Matrix([[0, 0, 1], + [2, 0, 3]]) + + m3 = Matrix([[0, 0, 0], + [1, 2, 3], + [0, 0, 0]]) + + m4 = Matrix([[0, 0, A], + [1, 2, 3], + [B, 0, 0]]) + + assert dixon.product_leading_entries(m1) == 24 + assert dixon.product_leading_entries(m2) == 2 + assert dixon.product_leading_entries(m3) == 1 + assert dixon.product_leading_entries(m4) == A * B + +def test_get_KSY_Dixon_resultant_example_one(): + """Tests the KSY Dixon resultant for example one""" + x, y, z = symbols('x, y, z') + + p = x * y * z + q = x**2 - z**2 + h = x + y + z + dixon = DixonResultant([p, q, h], [x, y]) + dixon_poly = dixon.get_dixon_polynomial() + dixon_matrix = dixon.get_dixon_matrix(dixon_poly) + D = dixon.get_KSY_Dixon_resultant(dixon_matrix) + + assert D == -z**3 + +def test_get_KSY_Dixon_resultant_example_two(): + """Tests the KSY Dixon resultant for example two""" + x, y, A = symbols('x, y, A') + + p = x * y + x * A + x - A**2 - A + y**2 + y + q = x**2 + x * A - x + x * y + y * A - y + h = x**2 + x * y + 2 * x - x * A - y * A - 2 * A + + dixon = DixonResultant([p, q, h], [x, y]) + dixon_poly = dixon.get_dixon_polynomial() + dixon_matrix = dixon.get_dixon_matrix(dixon_poly) + D = factor(dixon.get_KSY_Dixon_resultant(dixon_matrix)) + + assert D == -8*A*(A - 1)*(A + 2)*(2*A - 1)**2 + +def test_macaulay_resultant_init(): + """Test init method of MacaulayResultant.""" + + assert macaulay.polynomials == [p, q] + assert macaulay.variables == [x, y] + assert macaulay.n == 2 + assert macaulay.degrees == [1, 1] + assert macaulay.degree_m == 1 + assert macaulay.monomials_size == 2 + +def test_get_degree_m(): + assert macaulay._get_degree_m() == 1 + +def test_get_size(): + assert macaulay.get_size() == 2 + +def test_macaulay_example_one(): + """Tests the Macaulay for example from [Bruce97]_""" + + x, y, z = symbols('x, y, z') + a_1_1, a_1_2, a_1_3 = symbols('a_1_1, a_1_2, a_1_3') + a_2_2, a_2_3, a_3_3 = symbols('a_2_2, a_2_3, a_3_3') + b_1_1, b_1_2, b_1_3 = symbols('b_1_1, b_1_2, b_1_3') + b_2_2, b_2_3, b_3_3 = symbols('b_2_2, b_2_3, b_3_3') + c_1, c_2, c_3 = symbols('c_1, c_2, c_3') + + f_1 = a_1_1 * x ** 2 + a_1_2 * x * y + a_1_3 * x * z + \ + a_2_2 * y ** 2 + a_2_3 * y * z + a_3_3 * z ** 2 + f_2 = b_1_1 * x ** 2 + b_1_2 * x * y + b_1_3 * x * z + \ + b_2_2 * y ** 2 + b_2_3 * y * z + b_3_3 * z ** 2 + f_3 = c_1 * x + c_2 * y + c_3 * z + + mac = MacaulayResultant([f_1, f_2, f_3], [x, y, z]) + + assert mac.degrees == [2, 2, 1] + assert mac.degree_m == 3 + + assert mac.monomial_set == [x ** 3, x ** 2 * y, x ** 2 * z, + x * y ** 2, + x * y * z, x * z ** 2, y ** 3, + y ** 2 *z, y * z ** 2, z ** 3] + assert mac.monomials_size == 10 + assert mac.get_row_coefficients() == [[x, y, z], [x, y, z], + [x * y, x * z, y * z, z ** 2]] + + matrix = mac.get_matrix() + assert matrix.shape == (mac.monomials_size, mac.monomials_size) + assert mac.get_submatrix(matrix) == Matrix([[a_1_1, a_2_2], + [b_1_1, b_2_2]]) + +def test_macaulay_example_two(): + """Tests the Macaulay formulation for example from [Stiller96]_.""" + + x, y, z = symbols('x, y, z') + a_0, a_1, a_2 = symbols('a_0, a_1, a_2') + b_0, b_1, b_2 = symbols('b_0, b_1, b_2') + c_0, c_1, c_2, c_3, c_4 = symbols('c_0, c_1, c_2, c_3, c_4') + + f = a_0 * y - a_1 * x + a_2 * z + g = b_1 * x ** 2 + b_0 * y ** 2 - b_2 * z ** 2 + h = c_0 * y - c_1 * x ** 3 + c_2 * x ** 2 * z - c_3 * x * z ** 2 + \ + c_4 * z ** 3 + + mac = MacaulayResultant([f, g, h], [x, y, z]) + + assert mac.degrees == [1, 2, 3] + assert mac.degree_m == 4 + assert mac.monomials_size == 15 + assert len(mac.get_row_coefficients()) == mac.n + + matrix = mac.get_matrix() + assert matrix.shape == (mac.monomials_size, mac.monomials_size) + assert mac.get_submatrix(matrix) == Matrix([[-a_1, a_0, a_2, 0], + [0, -a_1, 0, 0], + [0, 0, -a_1, 0], + [0, 0, 0, -a_1]]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_orderings.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_orderings.py new file mode 100644 index 0000000000000000000000000000000000000000..d61d4887754c9d9f49905c2e131d253a45cf2ffd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_orderings.py @@ -0,0 +1,124 @@ +"""Tests of monomial orderings. """ + +from sympy.polys.orderings import ( + monomial_key, lex, grlex, grevlex, ilex, igrlex, + LexOrder, InverseOrder, ProductOrder, build_product_order, +) + +from sympy.abc import x, y, z, t +from sympy.core import S +from sympy.testing.pytest import raises + +def test_lex_order(): + assert lex((1, 2, 3)) == (1, 2, 3) + assert str(lex) == 'lex' + + 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.is_global is True + assert lex == LexOrder() + assert lex != grlex + +def test_grlex_order(): + assert grlex((1, 2, 3)) == (6, (1, 2, 3)) + assert str(grlex) == 'grlex' + + 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((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((0, 2, 3)) < grlex((1, 2, 2)) + assert grlex((1, 1, 3)) < grlex((1, 2, 2)) + + assert grlex((0, 1, 1)) > grlex((0, 0, 2)) + assert grlex((0, 3, 1)) < grlex((2, 2, 1)) + + assert grlex.is_global is True + +def test_grevlex_order(): + assert grevlex((1, 2, 3)) == (6, (-3, -2, -1)) + assert str(grevlex) == 'grevlex' + + 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((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((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.is_global is True + +def test_InverseOrder(): + ilex = InverseOrder(lex) + igrlex = InverseOrder(grlex) + + 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" + assert ilex.is_global is False + assert igrlex.is_global is False + 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)) + assert str(P) == "ProductOrder(grlex, grlex)" + assert P.is_global is True + 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 + + assert monomial_key('lex') == lex + assert monomial_key('grlex') == grlex + assert monomial_key('grevlex') == grevlex + + raises(ValueError, lambda: monomial_key('foo')) + raises(ValueError, lambda: monomial_key(1)) + + M = [x, x**2*z**2, x*y, x**2, S.One, y**2, x**3, y, z, x*y**2*z, x**2*y**2] + assert sorted(M, key=monomial_key('lex', [z, y, x])) == \ + [S.One, x, x**2, x**3, y, x*y, y**2, x**2*y**2, z, x*y**2*z, x**2*z**2] + assert sorted(M, key=monomial_key('grlex', [z, y, x])) == \ + [S.One, x, y, z, x**2, x*y, y**2, x**3, x**2*y**2, x*y**2*z, x**2*z**2] + assert sorted(M, key=monomial_key('grevlex', [z, y, x])) == \ + [S.One, x, y, z, x**2, x*y, y**2, x**3, x**2*y**2, x**2*z**2, x*y**2*z] + +def test_build_product_order(): + 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]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_orthopolys.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_orthopolys.py new file mode 100644 index 0000000000000000000000000000000000000000..e81fbe75aa6285d229ba817026f44b23b76abd6a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_orthopolys.py @@ -0,0 +1,175 @@ +"""Tests for efficient functions for generating orthogonal polynomials. """ + +from sympy.core.numbers import Rational as Q +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.polys.polytools import Poly +from sympy.testing.pytest import raises + +from sympy.polys.orthopolys import ( + jacobi_poly, + gegenbauer_poly, + chebyshevt_poly, + chebyshevu_poly, + hermite_poly, + hermite_prob_poly, + legendre_poly, + laguerre_poly, + spherical_bessel_fn, +) + +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(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 + a*Q(7, 8) + b**2/8 + + b*Q(7, 8) + Q(3, 2)) + x*(a**2/4 + + a*Q(3, 4) - b**2/4 - b*Q(3, 4)) - S.Half) + + 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(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 + a*Q(8, 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)) + + assert chebyshevt_poly(1, x, polys=True) == Poly(x) + + assert chebyshevt_poly(0, x) == 1 + assert chebyshevt_poly(1, x) == x + assert chebyshevt_poly(2, x) == 2*x**2 - 1 + assert chebyshevt_poly(3, x) == 4*x**3 - 3*x + assert chebyshevt_poly(4, x) == 8*x**4 - 8*x**2 + 1 + assert chebyshevt_poly(5, x) == 16*x**5 - 20*x**3 + 5*x + assert chebyshevt_poly(6, x) == 32*x**6 - 48*x**4 + 18*x**2 - 1 + assert chebyshevt_poly(75, x) == (2*chebyshevt_poly(37, x)*chebyshevt_poly(38, x) - x).expand() + assert chebyshevt_poly(100, x) == (2*chebyshevt_poly(50, x)**2 - 1).expand() + + 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)) + + assert chebyshevu_poly(1, x, polys=True) == Poly(2*x) + + assert chebyshevu_poly(0, x) == 1 + assert chebyshevu_poly(1, x) == 2*x + assert chebyshevu_poly(2, x) == 4*x**2 - 1 + assert chebyshevu_poly(3, x) == 8*x**3 - 4*x + assert chebyshevu_poly(4, x) == 16*x**4 - 12*x**2 + 1 + assert chebyshevu_poly(5, x) == 32*x**5 - 32*x**3 + 6*x + assert chebyshevu_poly(6, x) == 64*x**6 - 80*x**4 + 24*x**2 - 1 + + 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)) + + assert hermite_poly(1, x, polys=True) == Poly(2*x) + + assert hermite_poly(0, x) == 1 + assert hermite_poly(1, x) == 2*x + assert hermite_poly(2, x) == 4*x**2 - 2 + assert hermite_poly(3, x) == 8*x**3 - 12*x + assert hermite_poly(4, x) == 16*x**4 - 48*x**2 + 12 + assert hermite_poly(5, x) == 32*x**5 - 160*x**3 + 120*x + assert hermite_poly(6, x) == 64*x**6 - 480*x**4 + 720*x**2 - 120 + + assert hermite_poly(1).dummy_eq(2*x) + assert hermite_poly(1, polys=True) == Poly(2*x) + + +def test_hermite_prob_poly(): + raises(ValueError, lambda: hermite_prob_poly(-1, x)) + + assert hermite_prob_poly(1, x, polys=True) == Poly(x) + + assert hermite_prob_poly(0, x) == 1 + assert hermite_prob_poly(1, x) == x + assert hermite_prob_poly(2, x) == x**2 - 1 + assert hermite_prob_poly(3, x) == x**3 - 3*x + assert hermite_prob_poly(4, x) == x**4 - 6*x**2 + 3 + assert hermite_prob_poly(5, x) == x**5 - 10*x**3 + 15*x + assert hermite_prob_poly(6, x) == x**6 - 15*x**4 + 45*x**2 - 15 + + assert hermite_prob_poly(1).dummy_eq(x) + assert hermite_prob_poly(1, polys=True) == Poly(x) + + +def test_legendre_poly(): + raises(ValueError, lambda: legendre_poly(-1, x)) + + assert legendre_poly(1, x, polys=True) == Poly(x, domain='QQ') + + 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(1).dummy_eq(x) + assert legendre_poly(1, polys=True) == Poly(x) + + +def test_laguerre_poly(): + raises(ValueError, lambda: laguerre_poly(-1, x)) + + assert laguerre_poly(1, x, polys=True) == Poly(-x + 1, domain='QQ') + + 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(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 + a*Q(3, 2) + 1 + assert laguerre_poly(3, x, a) == -x**3/6 + (a/2 + Q( + 3)/2)*x**2 + (-a**2/2 - a*Q(5, 2) - 3)*x + a**3/6 + a**2 + a*Q(11, 6) + 1 + + assert laguerre_poly(1).dummy_eq(-x + 1) + assert laguerre_poly(1, polys=True) == Poly(-x + 1) + + +def test_spherical_bessel_fn(): + x, z = symbols("x z") + assert spherical_bessel_fn(1, z) == 1/z**2 + assert spherical_bessel_fn(2, z) == -1/z + 3/z**3 + assert spherical_bessel_fn(3, z) == -6/z**2 + 15/z**4 + assert spherical_bessel_fn(4, z) == 1/z - 45/z**3 + 105/z**5 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_partfrac.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_partfrac.py new file mode 100644 index 0000000000000000000000000000000000000000..83c5d48383d20e67dbb53c081093ad35e654c9a0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_partfrac.py @@ -0,0 +1,249 @@ +"""Tests for algorithms for partial fraction decomposition of rational +functions. """ + +from sympy.polys.partfrac import ( + apart_undetermined_coeffs, + apart, + apart_list, assemble_partfrac_list +) + +from sympy.core.expr import Expr +from sympy.core.function import Lambda +from sympy.core.numbers import (E, I, Rational, pi, all_close) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices.dense import Matrix +from sympy.polys.polytools import (Poly, factor) +from sympy.polys.rationaltools import together +from sympy.polys.rootoftools import RootSum +from sympy.testing.pytest import raises, XFAIL +from sympy.abc import x, y, a, b, c + + +def test_apart(): + assert apart(1) == 1 + assert apart(1, x) == 1 + + f, g = (x**2 + 1)/(x + 1), 2/(x + 1) + x - 1 + + 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) + + 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 + + assert apart(f, full=False) == g + assert apart(f, full=True) == g + + 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) + + assert apart(x/2, y) == x/2 + + f, g = (x+y)/(2*x - y), Rational(3, 2)*y/(2*x - y) + S.Half + + assert apart(f, x, full=False) == g + assert apart(f, x, full=True) == g + + f, g = (x+y)/(2*x - y), 3*x/(2*x - y) - 1 + + assert apart(f, y, full=False) == g + assert apart(f, y, full=True) == g + + 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/(2*x) - (S.Half)/(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 + + 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)) + + +def _make_extension_example(): + # https://github.com/sympy/sympy/issues/18531 + from sympy.core import Mul + def mul2(expr): + # 2-arg mul hack... + return Mul(2, expr, evaluate=False) + + f = ((x**2 + 1)**3/((x - 1)**2*(x + 1)**2*(-x**2 + 2*x + 1)*(x**2 + 2*x - 1))) + g = (1/mul2(x - sqrt(2) + 1) + - 1/mul2(x - sqrt(2) - 1) + + 1/mul2(x + 1 + sqrt(2)) + - 1/mul2(x - 1 + sqrt(2)) + + 1/mul2((x + 1)**2) + + 1/mul2((x - 1)**2)) + return f, g + + +def test_apart_extension(): + f = 2/(x**2 + 1) + g = I/(x + I) - I/(x - I) + + assert apart(f, extension=I) == g + assert apart(f, gaussian=True) == g + + f = x/((x - 2)*(x + I)) + + assert factor(together(apart(f)).expand()) == f + + f, g = _make_extension_example() + + # XXX: Only works with dotprodsimp. See test_apart_extension_xfail below + from sympy.matrices import dotprodsimp + with dotprodsimp(True): + assert apart(f, x, extension={sqrt(2)}) == g + + +def test_apart_extension_xfail(): + f, g = _make_extension_example() + assert apart(f, x, extension={sqrt(2)}) == g + + +def test_apart_full(): + f = 1/(x**2 + 1) + + assert apart(f, full=False) == f + assert apart(f, full=True).dummy_eq( + -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).dummy_eq( + RootSum(x**3 + x + 1, + Lambda(a, (a**2*Rational(6, 31) - a*Rational(9, 31) + Rational(4, 31))/(x - a)), auto=False)) + + f = 1/(x**5 + 1) + + assert apart(f, full=False) == \ + (Rational(-1, 5))*((x**3 - 2*x**2 + 3*x - 4)/(x**4 - x**3 + x**2 - + x + 1)) + (Rational(1, 5))/(x + 1) + assert apart(f, full=True).dummy_eq( + -RootSum(x**4 - x**3 + x**2 - x + 1, + Lambda(a, a/(x - a)), auto=False)/5 + (Rational(1, 5))/(x + 1)) + + +def test_apart_full_floats(): + # https://github.com/sympy/sympy/issues/26648 + f = ( + 6.43369157032015e-9*x**3 + 1.35203404799555e-5*x**2 + + 0.00357538393743079*x + 0.085 + )/( + 4.74334912634438e-11*x**4 + 4.09576274286244e-6*x**3 + + 0.00334241812250921*x**2 + 0.15406018058983*x + 1.0 + ) + + expected = ( + 133.599202650992/(x + 85524.0054884464) + + 1.07757928431867/(x + 774.88576677949) + + 0.395006955518971/(x + 40.7977016133126) + + 0.564264854137341/(x + 7.79746609204661) + ) + + f_apart = apart(f, full=True).evalf() + + # There is a significant floating point error in this operation. + assert all_close(f_apart, expected, rtol=1e-3, atol=1e-5) + + +def test_apart_undetermined_coeffs(): + p = Poly(2*x - 3) + q = Poly(x**9 - x**8 - x**6 + x**5 - 2*x**2 + 3*x - 1) + r = (-x**7 - x**6 - x**5 + 4)/(x**8 - x**5 - 2*x + 1) + 1/(x - 1) + + assert apart_undetermined_coeffs(p, q) == r + + p = Poly(1, x, domain='ZZ[a,b]') + q = Poly((x + a)*(x + b), x, domain='ZZ[a,b]') + 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 + def dummy_eq(i, j): + if type(i) in (list, tuple): + return all(dummy_eq(i, j) for i, j in zip(i, j)) + return i == j or i.dummy_eq(j) + + w0, w1, w2 = Symbol("w0"), Symbol("w1"), Symbol("w2") + _a = Dummy("a") + + f = (-2*x - 2*x**2) / (3*x**2 - 6*x) + got = apart_list(f, x, dummies=numbered_symbols("w")) + ans = (-1, Poly(Rational(2, 3), x, domain='QQ'), + [(Poly(w0 - 2, w0, domain='ZZ'), Lambda(_a, 2), Lambda(_a, -_a + x), 1)]) + assert dummy_eq(got, ans) + + got = apart_list(2/(x**2-2), x, dummies=numbered_symbols("w")) + ans = (1, Poly(0, x, domain='ZZ'), [(Poly(w0**2 - 2, w0, domain='ZZ'), + Lambda(_a, _a/2), + Lambda(_a, -_a + x), 1)]) + assert dummy_eq(got, ans) + + f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2) + got = apart_list(f, x, dummies=numbered_symbols("w")) + ans = (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)]) + assert dummy_eq(got, ans) + + +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))) + + +@XFAIL +def test_noncommutative_pseudomultivariate(): + # apart doesn't go inside noncommutative expressions + 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_noncommutative(): + class foo(Expr): + is_commutative=False + e = x/(x + x*y) + c = 1/(1 + y) + assert apart(e + foo()) == c + foo() + +def test_issue_5798(): + 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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyclasses.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyclasses.py new file mode 100644 index 0000000000000000000000000000000000000000..5e2c8f2c3ca94c42fc524c3ec1c0300d881cf3a5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyclasses.py @@ -0,0 +1,601 @@ +"""Tests for OO layer of several polynomial representations. """ + +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.polys.domains import ZZ, QQ +from sympy.polys.polyclasses import DMP, DMF, ANP +from sympy.polys.polyerrors import (CoercionFailed, ExactQuotientFailed, + NotInvertible) +from sympy.polys.specialpolys import f_polys +from sympy.testing.pytest import raises, warns_deprecated_sympy + +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([[ZZ(0)], [], [ZZ(0), ZZ(1), ZZ(2)], [ZZ(3)]], ZZ) + + assert f._rep == [[1, 2], [3]] + assert f.dom == ZZ + assert f.lev == 1 + + f = DMP([[ZZ(1), ZZ(2)], [ZZ(3)]], ZZ, 1) + + assert f._rep == [[1, 2], [3]] + assert f.dom == ZZ + assert f.lev == 1 + + f = DMP.from_dict({(1, 1): ZZ(1), (0, 0): ZZ(2)}, 1, ZZ) + + assert f._rep == [[1, 0], [2]] + assert f.dom == ZZ + assert f.lev == 1 + + +def test_DMP_rep_deprecation(): + f = DMP([1, 2, 3], ZZ) + + with warns_deprecated_sympy(): + assert f.rep == [1, 2, 3] + + +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([[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)) is False + assert bool(DMP([[ZZ(1)]], ZZ)) is True + + +def test_DMP_to_dict(): + f = DMP([[ZZ(3)], [], [ZZ(2)], [], [ZZ(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)} + + +def test_DMP_properties(): + assert DMP([[]], ZZ).is_zero is True + assert DMP([[ZZ(1)]], ZZ).is_zero is False + + assert DMP([[ZZ(1)]], ZZ).is_one is True + assert DMP([[ZZ(2)]], ZZ).is_one is False + + assert DMP([[ZZ(1)]], ZZ).is_ground is True + assert DMP([[ZZ(1)], [ZZ(2)], [ZZ(1)]], ZZ).is_ground is False + + assert DMP([[ZZ(1)], [ZZ(2), ZZ(0)], [ZZ(1), ZZ(0)]], ZZ).is_sqf is True + assert DMP([[ZZ(1)], [ZZ(2), ZZ(0)], [ZZ(1), ZZ(0), ZZ(0)]], ZZ).is_sqf is False + + assert DMP([[ZZ(1), ZZ(2)], [ZZ(3)]], ZZ).is_monic is True + assert DMP([[ZZ(2), ZZ(2)], [ZZ(3)]], ZZ).is_monic is False + + assert DMP([[ZZ(1), ZZ(2)], [ZZ(3)]], ZZ).is_primitive is True + assert DMP([[ZZ(2), ZZ(4)], [ZZ(6)]], ZZ).is_primitive is False + + +def test_DMP_arithmetics(): + f = DMP([[ZZ(2)], [ZZ(2), ZZ(0)]], ZZ) + + assert f.mul_ground(2) == DMP([[ZZ(4)], [ZZ(4), ZZ(0)]], ZZ) + assert f.quo_ground(2) == DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ) + + raises(ExactQuotientFailed, lambda: f.exquo_ground(3)) + + f = DMP([[ZZ(-5)]], ZZ) + g = DMP([[ZZ(5)]], ZZ) + + assert f.abs() == g + assert abs(f) == g + + assert g.neg() == f + assert -g == f + + h = DMP([[]], ZZ) + + assert f.add(g) == h + assert f + g == h + assert g + f == h + assert f + 5 == h + assert 5 + f == h + + h = DMP([[ZZ(-10)]], ZZ) + + assert f.sub(g) == h + assert f - g == h + assert g - f == -h + assert f - 5 == h + assert 5 - f == -h + + h = DMP([[ZZ(-25)]], ZZ) + + assert f.mul(g) == h + assert f * g == h + assert g * f == h + assert f * 5 == h + assert 5 * f == h + + h = DMP([[ZZ(25)]], ZZ) + + assert f.sqr() == h + assert f.pow(2) == h + assert f**2 == h + + raises(TypeError, lambda: f.pow('x')) + + f = DMP([[ZZ(1)], [], [ZZ(1), ZZ(0), ZZ(0)]], ZZ) + g = DMP([[ZZ(2)], [ZZ(-2), ZZ(0)]], ZZ) + + q = DMP([[ZZ(2)], [ZZ(2), ZZ(0)]], ZZ) + r = DMP([[ZZ(8), ZZ(0), ZZ(0)]], ZZ) + + assert f.pdiv(g) == (q, r) + assert f.pquo(g) == q + assert f.prem(g) == r + + raises(ExactQuotientFailed, lambda: f.pexquo(g)) + + f = DMP([[ZZ(1)], [], [ZZ(1), ZZ(0), ZZ(0)]], ZZ) + g = DMP([[ZZ(1)], [ZZ(-1), ZZ(0)]], ZZ) + + q = DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ) + r = DMP([[ZZ(2), ZZ(0), ZZ(0)]], ZZ) + + assert f.div(g) == (q, r) + assert f.quo(g) == q + assert f.rem(g) == r + + assert divmod(f, g) == (q, r) + assert f // g == q + assert f % g == r + + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + f = DMP([ZZ(1), ZZ(0), ZZ(-1)], ZZ) + g = DMP([ZZ(2), ZZ(-2)], ZZ) + + q = DMP([], ZZ) + r = f + + pq = DMP([ZZ(2), ZZ(2)], ZZ) + pr = DMP([], ZZ) + + assert f.div(g) == (q, r) + assert f.quo(g) == q + assert f.rem(g) == r + + assert divmod(f, g) == (q, r) + assert f // g == q + assert f % g == r + + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + assert f.pdiv(g) == (pq, pr) + assert f.pquo(g) == pq + assert f.prem(g) == pr + assert f.pexquo(g) == pq + + +def test_DMP_functionality(): + f = DMP([[ZZ(1)], [ZZ(2), ZZ(0)], [ZZ(1), ZZ(0), ZZ(0)]], ZZ) + g = DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ) + h = DMP([[ZZ(1)]], ZZ) + + assert f.degree() == 2 + assert f.degree_list() == (2, 2) + assert f.total_degree() == 2 + + assert f.LC() == ZZ(1) + assert f.TC() == ZZ(0) + assert f.nth(1, 1) == ZZ(2) + + raises(TypeError, lambda: f.nth(0, 'x')) + + assert f.max_norm() == 2 + assert f.l1_norm() == 4 + + u = DMP([[ZZ(2)], [ZZ(2), ZZ(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([ZZ(1), ZZ(2), ZZ(1)], ZZ) + v = DMP([ZZ(1), ZZ(2), ZZ(1)], ZZ) + + assert f.eval(a=1, j=0) == u + assert f.eval(a=1, j=1) == v + + assert f.eval(1).eval(1) == ZZ(4) + + assert f.cofactors(g) == (g, g, h) + 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) + + assert u.monic() == v + + assert (4*f).content() == ZZ(4) + assert (4*f).primitive() == (ZZ(4), f) + + f = DMP([QQ(1,3), QQ(1)], QQ) + g = DMP([QQ(1,7), QQ(1)], QQ) + + assert f.cancel(g) == f.cancel(g, include=True) == ( + DMP([QQ(7), QQ(21)], QQ), + DMP([QQ(3), QQ(21)], QQ) + ) + assert f.cancel(g, include=False) == ( + QQ(7), + QQ(3), + DMP([QQ(1), QQ(3)], QQ), + DMP([QQ(1), QQ(7)], QQ) + ) + + f = DMP([[ZZ(1)], [ZZ(2)], [ZZ(3)], [ZZ(4)], [ZZ(5)], [ZZ(6)]], ZZ) + + assert f.trunc(3) == DMP([[ZZ(1)], [ZZ(-1)], [], [ZZ(1)], [ZZ(-1)], []], ZZ) + + f = DMP(f_4, ZZ) + + assert f.sqf_part() == -f + assert f.sqf_list() == (ZZ(-1), [(-f, 1)]) + + f = DMP([[ZZ(-1)], [], [], [ZZ(5)]], ZZ) + g = DMP([[ZZ(3), ZZ(1)], [], []], ZZ) + h = DMP([[ZZ(45), ZZ(30), ZZ(5)]], ZZ) + + r = DMP([ZZ(675), ZZ(675), ZZ(225), ZZ(25)], ZZ) + + assert f.subresultants(g) == [f, g, h] + assert f.resultant(g) == r + + f = DMP([ZZ(1), ZZ(3), ZZ(9), ZZ(-13)], ZZ) + + assert f.discriminant() == -11664 + + 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) + h = DMP([QQ(1)], QQ) + + assert f.half_gcdex(g) == (s, h) + assert f.gcdex(g) == (s, t, h) + + assert f.invert(g) == s + + f = DMP([[QQ(1)], [QQ(2)], [QQ(3)]], QQ) + + raises(ValueError, lambda: f.half_gcdex(f)) + raises(ValueError, lambda: f.gcdex(f)) + + raises(ValueError, lambda: f.invert(f)) + + f = DMP(ZZ.map([1, 0, 20, 0, 150, 0, 500, 0, 625, -2, 0, -10, 9]), ZZ) + g = DMP([ZZ(1), ZZ(0), ZZ(0), ZZ(-2), ZZ(9)], ZZ) + h = DMP([ZZ(1), ZZ(0), ZZ(5), ZZ(0)], ZZ) + + assert g.compose(h) == f + assert f.decompose() == [g, h] + + f = DMP([[QQ(1)], [QQ(2)], [QQ(3)]], QQ) + + raises(ValueError, lambda: f.decompose()) + raises(ValueError, lambda: f.sturm()) + + +def test_DMP_exclude(): + f = [[[[[[[[[[[[[[[[[[[[[[[[[[ZZ(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] + + assert DMP(f, ZZ).exclude() == (J, DMP([ZZ(1), ZZ(0)], ZZ)) + assert DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ).exclude() ==\ + ([], DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ)) + + +def test_DMF__init__(): + 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.lev == 1 + assert f.dom == ZZ + + f = DMF(([[1, 2], [3]], [[1, 2, 3]]), ZZ, 1) + + 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) + + 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) + + 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) + + assert f.num == [[-1], [-2]] + assert f.den == [[3], [-4]] + assert f.lev == 1 + assert f.dom == ZZ + + f = DMF(([[]], [[-3], [4]]), ZZ) + + assert f.num == [[]] + assert f.den == [[1]] + assert f.lev == 1 + assert f.dom == ZZ + + f = DMF(17, ZZ, 1) + + assert f.num == [[17]] + assert f.den == [[1]] + assert f.lev == 1 + assert f.dom == ZZ + + f = DMF(([[1], [2]]), ZZ) + + 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) + + 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) + + 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) + + 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) + + 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__bool__(): + assert bool(DMF([[]], ZZ)) is False + assert bool(DMF([[1]], ZZ)) is True + + +def test_DMF_properties(): + 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]], [[2]]), ZZ).is_one is False + + +def test_DMF_arithmetics(): + 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) + + 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) + + assert f.sub(g) == f - g == h + + 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) + + assert f.quo(g) == f/g == h + + h = DMF(([[1]], [[1], [], [], []]), ZZ) + + assert f.pow(3) == f**3 == h + + h = DMF(([[1]], [[1, 0, 0, 0]]), ZZ) + + assert g.pow(3) == g**3 == h + + h = DMF(([[1, 0]], [[1]]), ZZ) + + assert g.pow(-1) == g**-1 == h + + +def test_ANP___init__(): + rep = [QQ(1), QQ(1)] + mod = [QQ(1), QQ(0), QQ(1)] + + f = ANP(rep, mod, QQ) + + assert f.to_list() == [QQ(1), QQ(1)] + assert f.mod_to_list() == [QQ(1), QQ(0), QQ(1)] + assert f.dom == QQ + + rep = {1: QQ(1), 0: QQ(1)} + mod = {2: QQ(1), 0: QQ(1)} + + f = ANP(rep, mod, QQ) + + assert f.to_list() == [QQ(1), QQ(1)] + assert f.mod_to_list() == [QQ(1), QQ(0), QQ(1)] + assert f.dom == QQ + + f = ANP(1, mod, QQ) + + assert f.to_list() == [QQ(1)] + assert f.mod_to_list() == [QQ(1), QQ(0), QQ(1)] + assert f.dom == QQ + + f = ANP([1, 0.5], mod, QQ) + + assert all(QQ.of_type(a) for a in f.to_list()) + + raises(CoercionFailed, lambda: ANP([sqrt(2)], mod, 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) + + assert (a == a) is True + assert (a != a) is False + + assert (a == b) is False + assert (a != b) is True + + b = ANP([QQ(1), QQ(2)], [QQ(1), QQ(0), QQ(1)], QQ) + + assert (a == b) is False + assert (a != b) is True + + +def test_ANP___bool__(): + 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)] + + assert ANP([QQ(0)], mod, QQ).is_zero is True + assert ANP([QQ(1)], mod, QQ).is_zero is False + + assert ANP([QQ(1)], mod, QQ).is_one is True + assert ANP([QQ(2)], mod, QQ).is_one is False + + +def test_ANP_arithmetics(): + 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) + + c = ANP([QQ(-2), QQ(1), QQ(-1)], mod, QQ) + + assert a.neg() == -a == c + + c = ANP([QQ(2), QQ(0), QQ(3)], mod, QQ) + + 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 + + c = ANP([QQ(-2), QQ(2), QQ(1)], mod, QQ) + + 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) + + assert a.pow(0) == a**(0) == ANP(1, mod, QQ) + assert a.pow(1) == a**(1) == a + + assert a.pow(-1) == a**(-1) == c + + assert a.quo(a) == a.mul(a.pow(-1)) == a*a**(-1) == ANP(1, mod, QQ) + + c = ANP([], [1, 0, 0, -2], QQ) + r1 = a.rem(b) + + (q, r2) = a.div(b) + + assert r1 == r2 == c == a % b + + raises(NotInvertible, lambda: a.div(c)) + raises(NotInvertible, lambda: a.rem(c)) + + # Comparison with "hard-coded" value fails despite looking identical + # from sympy import Rational + # c = ANP([Rational(11, 10), Rational(-1, 5), Rational(-3, 5)], [1, 0, 0, -2], QQ) + + assert q == a/b # == c + +def test_ANP_unify(): + mod_z = [ZZ(1), ZZ(0), ZZ(-2)] + mod_q = [QQ(1), QQ(0), QQ(-2)] + + a = ANP([QQ(1)], mod_q, QQ) + b = ANP([ZZ(1)], mod_z, ZZ) + + assert a.unify(b)[0] == QQ + assert b.unify(a)[0] == QQ + assert a.unify(a)[0] == QQ + assert b.unify(b)[0] == ZZ + + assert a.unify_ANP(b)[-1] == QQ + assert b.unify_ANP(a)[-1] == QQ + assert a.unify_ANP(a)[-1] == QQ + assert b.unify_ANP(b)[-1] == ZZ + + +def test_zero_poly(): + from sympy import Symbol + x = Symbol('x') + + R_old = ZZ.old_poly_ring(x) + zero_poly_old = R_old(0) + cont_old, prim_old = zero_poly_old.primitive() + + assert cont_old == 0 + assert prim_old == zero_poly_old + assert prim_old.is_primitive is False diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyfuncs.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyfuncs.py new file mode 100644 index 0000000000000000000000000000000000000000..496f63bf14e4dd9f68cf653004eb35a3ed7615ca --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyfuncs.py @@ -0,0 +1,126 @@ +"""Tests for high-level polynomials manipulation functions. """ + +from sympy.polys.polyfuncs import ( + symmetrize, horner, interpolate, rational_interpolate, viete, +) + +from sympy.polys.polyerrors import ( + MultivariatePolynomialError, +) + +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.testing.pytest import raises + +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) + + s1 = x + y + z + s2 = x*y + x*z + y*z + + assert symmetrize(1) == (1, 0) + assert symmetrize(1, formal=True) == (1, 0, []) + + assert symmetrize(x) == (x, 0) + assert symmetrize(x + 1) == (x + 1, 0) + + assert symmetrize(x, x, y) == (x + y, -y) + assert symmetrize(x + 1, x, y) == (x + y + 1, -y) + + assert symmetrize(x, x, y, z) == (s1, -y - z) + assert symmetrize(x + 1, x, y, z) == (s1 + 1, -y - z) + + assert symmetrize(x**2, x, y, z) == (s1**2 - 2*s2, -y**2 - z**2) + + assert symmetrize(x**2 + y**2) == (-2*x*y + (x + y)**2, 0) + 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)) + + U = [u0, u1, u2] = symbols('u:3') + + assert symmetrize(x + 1, x, y, z, formal=True, symbols=U) == \ + (u0 + 1, -y - z, [(u0, x + y + z), (u1, x*y + x*z + y*z), (u2, x*y*z)]) + + assert symmetrize([1, 2, 3]) == [(1, 0), (2, 0), (3, 0)] + assert symmetrize([1, 2, 3], formal=True) == ([(1, 0), (2, 0), (3, 0)], []) + + assert symmetrize([x + y, x - y]) == [(x + y, 0), (x + y, -2*y)] + + +def test_horner(): + assert horner(0) == 0 + assert horner(1) == 1 + assert horner(x) == x + + assert horner(x + 1) == x + 1 + assert horner(x**2 + 1) == x**2 + 1 + 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(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, 25], x) == S(3)*x**3/2 - S(8)*x**2 + S(33)*x/2 - 9 + 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 + assert interpolate({5: 2, 7: 5, 8: 10, 9: 13}, x) == \ + -S(13)*x**3/24 + S(12)*x**2 - S(2003)*x/24 + 187 + assert interpolate([(1, 3), (0, 6), (2, 5), (5, 7), (-2, 4)], x) == \ + S(-61)*x**4/280 + S(247)*x**3/210 + S(139)*x**2/280 - S(1871)*x/420 + 6 + assert interpolate((9, 4, 9), 3) == 9 + assert interpolate((1, 9, 16), 1) is S.One + assert interpolate(((x, 1), (2, 3)), x) is S.One + assert interpolate({x: 1, 2: 3}, x) is S.One + assert interpolate(((2, x), (1, 3)), x) == x**2 - 4*x + 6 + + +def test_rational_interpolate(): + x, y = symbols('x,y') + xdata = [1, 2, 3, 4, 5, 6] + ydata1 = [120, 150, 200, 255, 312, 370] + ydata2 = [-210, -35, 105, 231, 350, 465] + assert rational_interpolate(list(zip(xdata, ydata1)), 2) == ( + (60*x**2 + 60)/x ) + assert rational_interpolate(list(zip(xdata, ydata1)), 3) == ( + (60*x**2 + 60)/x ) + assert rational_interpolate(list(zip(xdata, ydata2)), 2, X=y) == ( + (105*y**2 - 525)/(y + 1) ) + xdata = list(range(1,11)) + ydata = [-1923885361858460, -5212158811973685, -9838050145867125, + -15662936261217245, -22469424125057910, -30073793365223685, + -38332297297028735, -47132954289530109, -56387719094026320, + -66026548943876885] + assert rational_interpolate(list(zip(xdata, ydata)), 5) == ( + (-12986226192544605*x**4 + + 8657484128363070*x**3 - 30301194449270745*x**2 + 4328742064181535*x + - 4328742064181535)/(x**3 + 9*x**2 - 3*x + 11)) + + +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)] + + raises(ValueError, lambda: viete(1, [], x)) + raises(ValueError, lambda: viete(x**2 + 1, [r1])) + + raises(MultivariatePolynomialError, lambda: viete(x + y, [r1])) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polymatrix.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polymatrix.py new file mode 100644 index 0000000000000000000000000000000000000000..287f23d537392510acda094e764a8c3dbbd1ef73 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polymatrix.py @@ -0,0 +1,185 @@ +from sympy.testing.pytest import raises + +from sympy.polys.polymatrix import PolyMatrix +from sympy.polys import Poly + +from sympy.core.singleton import S +from sympy.matrices.dense import Matrix +from sympy.polys.domains.integerring import ZZ +from sympy.polys.domains.rationalfield import QQ + +from sympy.abc import x, y + + +def _test_polymatrix(): + pm1 = PolyMatrix([[Poly(x**2, x), Poly(-x, x)], [Poly(x**3, x), Poly(-1 + x, x)]]) + v1 = PolyMatrix([[1, 0], [-1, 0]], ring='ZZ[x]') + m1 = PolyMatrix([[1, 0], [-1, 0]], ring='ZZ[x]') + A = PolyMatrix([[Poly(x**2 + x, x), Poly(0, x)], \ + [Poly(x**3 - x + 1, x), Poly(0, x)]]) + B = PolyMatrix([[Poly(x**2, x), Poly(-x, x)], [Poly(-x**2, x), Poly(x, x)]]) + assert A.ring == ZZ[x] + assert isinstance(pm1*v1, PolyMatrix) + assert pm1*v1 == A + assert pm1*m1 == A + assert v1*pm1 == B + + pm2 = PolyMatrix([[Poly(x**2, x, domain='QQ'), Poly(0, x, domain='QQ'), Poly(-x**2, x, domain='QQ'), \ + Poly(x**3, x, domain='QQ'), Poly(0, x, domain='QQ'), Poly(-x**3, x, domain='QQ')]]) + assert pm2.ring == QQ[x] + v2 = PolyMatrix([1, 0, 0, 0, 0, 0], ring='ZZ[x]') + m2 = PolyMatrix([1, 0, 0, 0, 0, 0], ring='ZZ[x]') + C = PolyMatrix([[Poly(x**2, x, domain='QQ')]]) + assert pm2*v2 == C + assert pm2*m2 == C + + pm3 = PolyMatrix([[Poly(x**2, x), S.One]], ring='ZZ[x]') + v3 = S.Half*pm3 + assert v3 == PolyMatrix([[Poly(S.Half*x**2, x, domain='QQ'), S.Half]], ring='QQ[x]') + assert pm3*S.Half == v3 + assert v3.ring == QQ[x] + + pm4 = PolyMatrix([[Poly(x**2, x, domain='ZZ'), Poly(-x**2, x, domain='ZZ')]]) + v4 = PolyMatrix([1, -1], ring='ZZ[x]') + assert pm4*v4 == PolyMatrix([[Poly(2*x**2, x, domain='ZZ')]]) + + assert len(PolyMatrix(ring=ZZ[x])) == 0 + assert PolyMatrix([1, 0, 0, 1], x)/(-1) == PolyMatrix([-1, 0, 0, -1], x) + + +def test_polymatrix_constructor(): + M1 = PolyMatrix([[x, y]], ring=QQ[x,y]) + assert M1.ring == QQ[x,y] + assert M1.domain == QQ + assert M1.gens == (x, y) + assert M1.shape == (1, 2) + assert M1.rows == 1 + assert M1.cols == 2 + assert len(M1) == 2 + assert list(M1) == [Poly(x, (x, y), domain=QQ), Poly(y, (x, y), domain=QQ)] + + M2 = PolyMatrix([[x, y]], ring=QQ[x][y]) + assert M2.ring == QQ[x][y] + assert M2.domain == QQ[x] + assert M2.gens == (y,) + assert M2.shape == (1, 2) + assert M2.rows == 1 + assert M2.cols == 2 + assert len(M2) == 2 + assert list(M2) == [Poly(x, (y,), domain=QQ[x]), Poly(y, (y,), domain=QQ[x])] + + assert PolyMatrix([[x, y]], y) == PolyMatrix([[x, y]], ring=ZZ.frac_field(x)[y]) + assert PolyMatrix([[x, y]], ring='ZZ[x,y]') == PolyMatrix([[x, y]], ring=ZZ[x,y]) + + assert PolyMatrix([[x, y]], (x, y)) == PolyMatrix([[x, y]], ring=QQ[x,y]) + assert PolyMatrix([[x, y]], x, y) == PolyMatrix([[x, y]], ring=QQ[x,y]) + assert PolyMatrix([x, y]) == PolyMatrix([[x], [y]], ring=QQ[x,y]) + assert PolyMatrix(1, 2, [x, y]) == PolyMatrix([[x, y]], ring=QQ[x,y]) + assert PolyMatrix(1, 2, lambda i,j: [x,y][j]) == PolyMatrix([[x, y]], ring=QQ[x,y]) + assert PolyMatrix(0, 2, [], x, y).shape == (0, 2) + assert PolyMatrix(2, 0, [], x, y).shape == (2, 0) + assert PolyMatrix([[], []], x, y).shape == (2, 0) + assert PolyMatrix(ring=QQ[x,y]) == PolyMatrix(0, 0, [], ring=QQ[x,y]) == PolyMatrix([], ring=QQ[x,y]) + raises(TypeError, lambda: PolyMatrix()) + raises(TypeError, lambda: PolyMatrix(1)) + + assert PolyMatrix([Poly(x), Poly(y)]) == PolyMatrix([[x], [y]], ring=ZZ[x,y]) + + # XXX: Maybe a bug in parallel_poly_from_expr (x lost from gens and domain): + assert PolyMatrix([Poly(y, x), 1]) == PolyMatrix([[y], [1]], ring=QQ[y]) + + +def test_polymatrix_eq(): + assert (PolyMatrix([x]) == PolyMatrix([x])) is True + assert (PolyMatrix([y]) == PolyMatrix([x])) is False + assert (PolyMatrix([x]) != PolyMatrix([x])) is False + assert (PolyMatrix([y]) != PolyMatrix([x])) is True + + assert PolyMatrix([[x, y]]) != PolyMatrix([x, y]) == PolyMatrix([[x], [y]]) + + assert PolyMatrix([x], ring=QQ[x]) != PolyMatrix([x], ring=ZZ[x]) + + assert PolyMatrix([x]) != Matrix([x]) + assert PolyMatrix([x]).to_Matrix() == Matrix([x]) + + assert PolyMatrix([1], x) == PolyMatrix([1], x) + assert PolyMatrix([1], x) != PolyMatrix([1], y) + + +def test_polymatrix_from_Matrix(): + assert PolyMatrix.from_Matrix(Matrix([1, 2]), x) == PolyMatrix([1, 2], x, ring=QQ[x]) + assert PolyMatrix.from_Matrix(Matrix([1]), ring=QQ[x]) == PolyMatrix([1], x) + pmx = PolyMatrix([1, 2], x) + pmy = PolyMatrix([1, 2], y) + assert pmx != pmy + assert pmx.set_gens(y) == pmy + + +def test_polymatrix_repr(): + assert repr(PolyMatrix([[1, 2]], x)) == 'PolyMatrix([[1, 2]], ring=QQ[x])' + assert repr(PolyMatrix(0, 2, [], x)) == 'PolyMatrix(0, 2, [], ring=QQ[x])' + + +def test_polymatrix_getitem(): + M = PolyMatrix([[1, 2], [3, 4]], x) + assert M[:, :] == M + assert M[0, :] == PolyMatrix([[1, 2]], x) + assert M[:, 0] == PolyMatrix([1, 3], x) + assert M[0, 0] == Poly(1, x, domain=QQ) + assert M[0] == Poly(1, x, domain=QQ) + assert M[:2] == [Poly(1, x, domain=QQ), Poly(2, x, domain=QQ)] + + +def test_polymatrix_arithmetic(): + M = PolyMatrix([[1, 2], [3, 4]], x) + assert M + M == PolyMatrix([[2, 4], [6, 8]], x) + assert M - M == PolyMatrix([[0, 0], [0, 0]], x) + assert -M == PolyMatrix([[-1, -2], [-3, -4]], x) + raises(TypeError, lambda: M + 1) + raises(TypeError, lambda: M - 1) + raises(TypeError, lambda: 1 + M) + raises(TypeError, lambda: 1 - M) + + assert M * M == PolyMatrix([[7, 10], [15, 22]], x) + assert 2 * M == PolyMatrix([[2, 4], [6, 8]], x) + assert M * 2 == PolyMatrix([[2, 4], [6, 8]], x) + assert S(2) * M == PolyMatrix([[2, 4], [6, 8]], x) + assert M * S(2) == PolyMatrix([[2, 4], [6, 8]], x) + raises(TypeError, lambda: [] * M) + raises(TypeError, lambda: M * []) + M2 = PolyMatrix([[1, 2]], ring=ZZ[x]) + assert S.Half * M2 == PolyMatrix([[S.Half, 1]], ring=QQ[x]) + assert M2 * S.Half == PolyMatrix([[S.Half, 1]], ring=QQ[x]) + + assert M / 2 == PolyMatrix([[S(1)/2, 1], [S(3)/2, 2]], x) + assert M / Poly(2, x) == PolyMatrix([[S(1)/2, 1], [S(3)/2, 2]], x) + raises(TypeError, lambda: M / []) + + +def test_polymatrix_manipulations(): + M1 = PolyMatrix([[1, 2], [3, 4]], x) + assert M1.transpose() == PolyMatrix([[1, 3], [2, 4]], x) + M2 = PolyMatrix([[5, 6], [7, 8]], x) + assert M1.row_join(M2) == PolyMatrix([[1, 2, 5, 6], [3, 4, 7, 8]], x) + assert M1.col_join(M2) == PolyMatrix([[1, 2], [3, 4], [5, 6], [7, 8]], x) + assert M1.applyfunc(lambda e: 2*e) == PolyMatrix([[2, 4], [6, 8]], x) + + +def test_polymatrix_ones_zeros(): + assert PolyMatrix.zeros(1, 2, x) == PolyMatrix([[0, 0]], x) + assert PolyMatrix.eye(2, x) == PolyMatrix([[1, 0], [0, 1]], x) + + +def test_polymatrix_rref(): + M = PolyMatrix([[1, 2], [3, 4]], x) + assert M.rref() == (PolyMatrix.eye(2, x), (0, 1)) + raises(ValueError, lambda: PolyMatrix([1, 2], ring=ZZ[x]).rref()) + raises(ValueError, lambda: PolyMatrix([1, x], ring=QQ[x]).rref()) + + +def test_polymatrix_nullspace(): + M = PolyMatrix([[1, 2], [3, 6]], x) + assert M.nullspace() == [PolyMatrix([-2, 1], x)] + raises(ValueError, lambda: PolyMatrix([1, 2], ring=ZZ[x]).nullspace()) + raises(ValueError, lambda: PolyMatrix([1, x], ring=QQ[x]).nullspace()) + assert M.rank() == 1 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyoptions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyoptions.py new file mode 100644 index 0000000000000000000000000000000000000000..fa2e6054bad43aef5470949180ea5c2ffdc11f30 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyoptions.py @@ -0,0 +1,485 @@ +"""Tests for options manager for :class:`Poly` and public API functions. """ + +from sympy.polys.polyoptions import ( + Options, Expand, Gens, Wrt, Sort, Order, Field, Greedy, Domain, + Split, Gaussian, Extension, Modulus, Symmetric, Strict, Auto, + Frac, Formal, Polys, Include, All, Gen, Symbols, Method) + +from sympy.polys.orderings import lex +from sympy.polys.domains import FF, GF, ZZ, QQ, QQ_I, RR, CC, EX + +from sympy.polys.polyerrors import OptionError, GeneratorsError + +from sympy.core.numbers import (I, Integer) +from sympy.core.symbol import Symbol +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.testing.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) is False + + new_opt = opt.clone({'gens': (x, y), 'order': 'lex'}) + + assert opt.gens == (x, y, z) + assert opt.domain == ZZ + assert ('order' in opt) is False + + assert new_opt.gens == (x, y) + assert new_opt.domain == ZZ + assert ('order' in new_opt) is True + + +def test_Expand_preprocess(): + assert Expand.preprocess(False) is False + assert Expand.preprocess(True) is True + + assert Expand.preprocess(0) is False + assert Expand.preprocess(1) is True + + 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) + assert Gens.preprocess(((x, y, z),)) == (x, y, z) + + a = Symbol('a', commutative=False) + + 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('') == [] + assert Wrt.preprocess(' ') == [] + assert Wrt.preprocess('x,y') == ['x', 'y'] + assert Wrt.preprocess('x y') == ['x', 'y'] + assert Wrt.preprocess('x, y') == ['x', 'y'] + assert Wrt.preprocess('x , y') == ['x', 'y'] + assert Wrt.preprocess(' x, y') == ['x', 'y'] + assert Wrt.preprocess(' x, y') == ['x', 'y'] + assert Wrt.preprocess([x, y]) == ['x', 'y'] + + 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'] + + assert Sort.preprocess('x > y > z') == ['x', 'y', 'z'] + assert Sort.preprocess('x>y>z') == ['x', 'y', 'z'] + + raises(OptionError, lambda: Sort.preprocess(0)) + raises(OptionError, lambda: Sort.preprocess({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 + + assert Field.preprocess(0) is False + assert Field.preprocess(1) is True + + 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 + + assert Greedy.preprocess(0) is False + assert Greedy.preprocess(1) is True + + 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('Z') == ZZ + assert Domain.preprocess('Q') == QQ + + assert Domain.preprocess('ZZ') == ZZ + assert Domain.preprocess('QQ') == QQ + + assert Domain.preprocess('EX') == EX + + assert Domain.preprocess('FF(23)') == FF(23) + assert Domain.preprocess('GF(23)') == GF(23) + + raises(OptionError, lambda: Domain.preprocess('Z[]')) + + assert Domain.preprocess('Z[x]') == ZZ[x] + assert Domain.preprocess('Q[x]') == QQ[x] + assert Domain.preprocess('R[x]') == RR[x] + assert Domain.preprocess('C[x]') == CC[x] + + assert Domain.preprocess('ZZ[x]') == ZZ[x] + assert Domain.preprocess('QQ[x]') == QQ[x] + assert Domain.preprocess('RR[x]') == RR[x] + assert Domain.preprocess('CC[x]') == CC[x] + + assert Domain.preprocess('Z[x,y]') == ZZ[x, y] + assert Domain.preprocess('Q[x,y]') == QQ[x, y] + assert Domain.preprocess('R[x,y]') == RR[x, y] + assert Domain.preprocess('C[x,y]') == CC[x, y] + + assert Domain.preprocess('ZZ[x,y]') == ZZ[x, y] + assert Domain.preprocess('QQ[x,y]') == QQ[x, y] + assert Domain.preprocess('RR[x,y]') == RR[x, y] + assert Domain.preprocess('CC[x,y]') == CC[x, y] + + raises(OptionError, lambda: Domain.preprocess('Z()')) + + assert Domain.preprocess('Z(x)') == ZZ.frac_field(x) + assert Domain.preprocess('Q(x)') == QQ.frac_field(x) + + 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('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) + + 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': (), + 'domain': EX})) + raises(GeneratorsError, lambda: Domain.postprocess({'domain': EX})) + + +def test_Split_preprocess(): + assert Split.preprocess(False) is False + assert Split.preprocess(True) is True + + assert Split.preprocess(0) is False + assert Split.preprocess(1) is True + + 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 + + assert Gaussian.preprocess(0) is False + assert Gaussian.preprocess(1) is True + + raises(OptionError, lambda: Gaussian.preprocess(x)) + + +def test_Gaussian_postprocess(): + opt = {'gaussian': True} + Gaussian.postprocess(opt) + + assert opt == { + 'gaussian': True, + 'domain': QQ_I, + } + + +def test_Extension_preprocess(): + assert Extension.preprocess(True) is True + assert Extension.preprocess(1) is True + + assert Extension.preprocess([]) is None + + assert Extension.preprocess(sqrt(2)) == {sqrt(2)} + assert Extension.preprocess([sqrt(2)]) == {sqrt(2)} + + assert Extension.preprocess([sqrt(2), I]) == {sqrt(2), I} + + raises(OptionError, lambda: Extension.preprocess(False)) + raises(OptionError, lambda: Extension.preprocess(0)) + + +def test_Extension_postprocess(): + opt = {'extension': {sqrt(2)}} + Extension.postprocess(opt) + + assert opt == { + 'extension': {sqrt(2)}, + 'domain': QQ.algebraic_field(sqrt(2)), + } + + opt = {'extension': True} + Extension.postprocess(opt) + + assert opt == {'extension': True} + + +def test_Modulus_preprocess(): + assert Modulus.preprocess(23) == 23 + assert Modulus.preprocess(Integer(23)) == 23 + + raises(OptionError, lambda: Modulus.preprocess(0)) + raises(OptionError, lambda: Modulus.preprocess(x)) + + +def test_Modulus_postprocess(): + opt = {'modulus': 5} + Modulus.postprocess(opt) + + assert opt == { + 'modulus': 5, + 'domain': FF(5), + } + + opt = {'modulus': 5, 'symmetric': False} + Modulus.postprocess(opt) + + assert opt == { + 'modulus': 5, + 'domain': FF(5, False), + 'symmetric': False, + } + + +def test_Symmetric_preprocess(): + assert Symmetric.preprocess(False) is False + assert Symmetric.preprocess(True) is True + + assert Symmetric.preprocess(0) is False + assert Symmetric.preprocess(1) is True + + 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 + + assert Strict.preprocess(0) is False + assert Strict.preprocess(1) is True + + 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 + + assert Auto.preprocess(0) is False + assert Auto.preprocess(1) is True + + 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 + + assert Frac.preprocess(0) is False + assert Frac.preprocess(1) is True + + 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 + + assert Formal.preprocess(0) is False + assert Formal.preprocess(1) is True + + 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 + + assert Polys.preprocess(0) is False + assert Polys.preprocess(1) is True + + 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 + + assert Include.preprocess(0) is False + assert Include.preprocess(1) is True + + 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 + + assert All.preprocess(0) is False + assert All.preprocess(1) is True + + raises(OptionError, lambda: All.preprocess(x)) + + +def test_All_postprocess(): + opt = {'all': True} + All.postprocess(opt) + + assert opt == {'all': True} + + +def test_Gen_postprocess(): + opt = {'gen': x} + Gen.postprocess(opt) + + 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) + + assert opt == {'method': 'f5b'} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyroots.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyroots.py new file mode 100644 index 0000000000000000000000000000000000000000..7f96b1930f6789ce3150ae2c920ba7d9faa68791 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyroots.py @@ -0,0 +1,758 @@ +"""Tests for algorithms for computing symbolic roots of polynomials. """ + +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, Wild, symbols) +from sympy.functions.elementary.complexes import (conjugate, im, re) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import (root, sqrt) +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (acos, cos, sin) +from sympy.polys.domains.integerring import ZZ +from sympy.sets.sets import Interval +from sympy.simplify.powsimp import powsimp + +from sympy.polys import Poly, cyclotomic_poly, intervals, nroots, rootof + +from sympy.polys.polyroots import (root_factors, roots_linear, + roots_quadratic, roots_cubic, roots_quartic, roots_quintic, + roots_cyclotomic, roots_binomial, preprocess_roots, roots) + +from sympy.polys.orthopolys import legendre_poly +from sympy.polys.polyerrors import PolynomialError, \ + UnsolvableFactorError +from sympy.polys.polyutils import _nsort + +from sympy.testing.pytest import raises, slow +from sympy.core.random import verify_numerically +import mpmath +from itertools import product + + + +a, b, c, d, e, q, t, x, y, z = symbols('a,b,c,d,e,q,t,x,y,z') + + +def _check(roots): + # this is the desired invariant for roots returned + # by all_roots. It is trivially true for linear + # polynomials. + nreal = sum(1 if i.is_real else 0 for i in roots) + assert sorted(roots[:nreal]) == list(roots[:nreal]) + for ix in range(nreal, len(roots), 2): + if not ( + roots[ix + 1] == roots[ix] or + roots[ix + 1] == conjugate(roots[ix])): + return False + return True + + +def test_roots_linear(): + 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] + _check(Poly(2*x**2 + 4*x + 3, x).all_roots()) + + 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), + -e*(a + c)/(a - c) + sqrt(a*b + c*d - a*d - b*c + 4*a*c*e**2)/(a - c)] + + # check for simplification + f = Poly(y*x**2 - 2*x - 2*y, x) + assert roots_quadratic(f) == \ + [-sqrt(2*y**2 + 1)/y + 1/y, sqrt(2*y**2 + 1)/y + 1/y] + f = Poly(x**2 + (-y**2 - 2)*x + y**2 + 1, x) + assert roots_quadratic(f) == \ + [1,y**2 + 1] + + f = Poly(sqrt(2)*x**2 - 1, x) + r = roots_quadratic(f) + assert r == _nsort(r) + + # issue 8255 + f = Poly(-24*x**2 - 180*x + 264) + assert [w.n(2) for w in f.all_roots(radicals=True)] == \ + [w.n(2) for w in f.all_roots(radicals=False)] + for _a, _b, _c in product((-2, 2), (-2, 2), (0, -1)): + f = Poly(_a*x**2 + _b*x + _c) + roots = roots_quadratic(f) + assert roots == _nsort(roots) + + +def test_issue_7724(): + eq = Poly(x**4*I + x**2 + I, x) + assert roots(eq) == { + sqrt(I/2 + sqrt(5)*I/2): 1, + sqrt(-sqrt(5)*I/2 + I/2): 1, + -sqrt(I/2 + sqrt(5)*I/2): 1, + -sqrt(-sqrt(5)*I/2 + I/2): 1} + + +def test_issue_8438(): + p = Poly([1, y, -2, -3], x).as_expr() + roots = roots_cubic(Poly(p, x), x) + z = Rational(-3, 2) - I*7/2 # this will fail in code given in commit msg + post = [r.subs(y, z) for r in roots] + assert set(post) == \ + set(roots_cubic(Poly(p.subs(y, z), x))) + # /!\ if p is not made an expression, this is *very* slow + assert all(p.subs({y: z, x: i}).n(2, chop=True) == 0 for i in post) + + +def test_issue_8285(): + roots = (Poly(4*x**8 - 1, x)*Poly(x**2 + 1)).all_roots() + assert _check(roots) + f = Poly(x**4 + 5*x**2 + 6, x) + ro = [rootof(f, i) for i in range(4)] + roots = Poly(x**4 + 5*x**2 + 6, x).all_roots() + assert roots == ro + assert _check(roots) + # more than 2 complex roots from which to identify the + # imaginary ones + roots = Poly(2*x**8 - 1).all_roots() + assert _check(roots) + assert len(Poly(2*x**10 - 1).all_roots()) == 10 # doesn't fail + + +def test_issue_8289(): + roots = (Poly(x**2 + 2)*Poly(x**4 + 2)).all_roots() + assert _check(roots) + roots = Poly(x**6 + 3*x**3 + 2, x).all_roots() + assert _check(roots) + roots = Poly(x**6 - x + 1).all_roots() + assert _check(roots) + # all imaginary roots with multiplicity of 2 + roots = Poly(x**4 + 4*x**2 + 4, x).all_roots() + assert _check(roots) + + +def test_issue_14291(): + assert Poly(((x - 1)**2 + 1)*((x - 1)**2 + 2)*(x - 1) + ).all_roots() == [1, 1 - I, 1 + I, 1 - sqrt(2)*I, 1 + sqrt(2)*I] + p = x**4 + 10*x**2 + 1 + ans = [rootof(p, i) for i in range(4)] + assert Poly(p).all_roots() == ans + _check(ans) + + +def test_issue_13340(): + eq = Poly(y**3 + exp(x)*y + x, y, domain='EX') + roots_d = roots(eq) + assert len(roots_d) == 3 + + +def test_issue_14522(): + eq = Poly(x**4 + x**3*(16 + 32*I) + x**2*(-285 + 386*I) + x*(-2824 - 448*I) - 2058 - 6053*I, x) + roots_eq = roots(eq) + assert all(eq(r) == 0 for r in roots_eq) + + +def test_issue_15076(): + sol = roots_quartic(Poly(t**4 - 6*t**2 + t/x - 3, t)) + assert sol[0].has(x) + + +def test_issue_16589(): + eq = Poly(x**4 - 8*sqrt(2)*x**3 + 4*x**3 - 64*sqrt(2)*x**2 + 1024*x, x) + roots_eq = roots(eq) + assert 0 in roots_eq + + +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] + + # valid for arbitrary y (issue 21263) + r = root(y, 3) + assert roots_cubic(Poly(x**3 - y, x)) == [r, + r*(-S.Half + sqrt(3)*I/2), + r*(-S.Half - sqrt(3)*I/2)] + # simpler form when y is negative + assert roots_cubic(Poly(x**3 - -1, x)) == \ + [-1, S.Half - I*sqrt(3)/2, S.Half + I*sqrt(3)/2] + assert roots_cubic(Poly(2*x**3 - 3*x**2 - 3*x - 1, x))[0] == \ + S.Half + 3**Rational(1, 3)/2 + 3**Rational(2, 3)/2 + eq = -x**3 + 2*x**2 + 3*x - 2 + assert roots(eq, trig=True, multiple=True) == \ + roots_cubic(Poly(eq, x), trig=True) == [ + Rational(2, 3) + 2*sqrt(13)*cos(acos(8*sqrt(13)/169)/3)/3, + -2*sqrt(13)*sin(-acos(8*sqrt(13)/169)/3 + pi/6)/3 + Rational(2, 3), + -2*sqrt(13)*cos(-acos(8*sqrt(13)/169)/3 + pi/3)/3 + Rational(2, 3), + ] + + +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] + ] + 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] + ] + + lhs = roots_quartic(Poly(x**4 + x, x)) + rhs = [S.Half + I*sqrt(3)/2, S.Half - I*sqrt(3)/2, S.Zero, -S.One] + + assert sorted(lhs, key=hash) == sorted(rhs, key=hash) + + # test of all branches of roots quartic + for i, (a, b, c, d) in enumerate([(1, 2, 3, 0), + (3, -7, -9, 9), + (1, 2, 3, 4), + (1, 2, 3, 4), + (-7, -3, 3, -6), + (-3, 5, -6, -4), + (6, -5, -10, -3)]): + if i == 2: + c = -a*(a**2/S(8) - b/S(2)) + elif i == 3: + d = a*(a*(a**2*Rational(3, 256) - b/S(16)) + c/S(4)) + eq = x**4 + a*x**3 + b*x**2 + c*x + d + 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(verify_numerically(eq.subs(x, i), 0) for i in sol) + z = symbols('z', negative=True) + eq = x**4 + 2*x**3 + 3*x**2 + x*(z + 11) + 5 + zans = roots_quartic(Poly(eq, x)) + assert all(verify_numerically(eq.subs(((x, i), (z, -1))), 0) for i in zans) + # but some are (see also issue 4989) + # it's ok if the solution is not Piecewise, but the tests below should pass + eq = Poly(y*x**4 + x**3 - x + z, x) + ans = roots_quartic(eq) + assert all(type(i) == Piecewise for i in ans) + reps = ( + {"y": Rational(-1, 3), "z": Rational(-1, 4)}, # 4 real + {"y": Rational(-1, 3), "z": Rational(-1, 2)}, # 2 real + {"y": Rational(-1, 3), "z": -2}) # 0 real + for rep in reps: + sol = roots_quartic(Poly(eq.subs(rep), x)) + assert all(verify_numerically(w.subs(rep) - s, 0) for w, s in zip(ans, sol)) + + +def test_issue_21287(): + assert not any(isinstance(i, Piecewise) for i in roots_quartic( + Poly(x**4 - x**2*(3 + 5*I) + 2*x*(-1 + I) - 1 + 3*I, x))) + + +def test_roots_quintic(): + eqs = (x**5 - 2, + (x/2 + 1)**5 - 5*(x/2 + 1) + 12, + x**5 - 110*x**3 - 55*x**2 + 2310*x + 979) + for eq in eqs: + roots = roots_quintic(Poly(eq)) + assert len(roots) == 5 + assert all(eq.subs(x, r.n(10)).n(chop = 1e-5) == 0 for r in roots) + + +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)) == [Rational(-1, 2) - I*sqrt(3)/2, Rational(-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.Half - I*sqrt(3)/2, S.Half + 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(pi*Rational(3, 7)) - I*sin(pi*Rational(3, 7)), + -cos(pi*Rational(3, 7)) + I*sin(pi*Rational(3, 7)), + cos(pi*Rational(2, 7)) - I*sin(pi*Rational(2, 7)), + cos(pi*Rational(2, 7)) + I*sin(pi*Rational(2, 7)), + ] + + 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, + ] + + 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, + ] + + 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) == \ + [-root(-1, 3), -1 + root(-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) == \ + [-root(-1, 5), -root(-1, 5)**3, root(-1, 5)**2, -1 - root(-1, 5)**2 + root(-1, 5) + root(-1, 5)**3] + + assert roots_cyclotomic(cyclotomic_poly(6, x, polys=True), factor=True) == \ + [1 - root(-1, 3), root(-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)] + + A = 10**Rational(3, 4)/10 + + assert roots_binomial(Poly(5*x**4 + 2, x)) == \ + [-A - A*I, -A + A*I, A - A*I, A + A*I] + _check(roots_binomial(Poly(x**8 - 2))) + + a1 = Symbol('a1', nonnegative=True) + b1 = Symbol('b1', nonnegative=True) + + r0 = roots_quadratic(Poly(a1*x**2 + b1, x)) + r1 = roots_binomial(Poly(a1*x**2 + b1, x)) + + assert powsimp(r0[0]) == powsimp(r1[0]) + assert powsimp(r0[1]) == powsimp(r1[1]) + for a, b, s, n in product((1, 2), (1, 2), (-1, 1), (2, 3, 4, 5)): + if a == b and a != 1: # a == b == 1 is sufficient + continue + p = Poly(a*x**n + s*b) + ans = roots_binomial(p) + assert ans == _nsort(ans) + + # issue 8813 + assert roots(Poly(2*x**3 - 16*y**3, x)) == { + 2*y*(Rational(-1, 2) - sqrt(3)*I/2): 1, + 2*y: 1, + 2*y*(Rational(-1, 2) + sqrt(3)*I/2): 1} + + +def test_roots_preprocessing(): + f = a*y*x**2 + y - b + + coeff, poly = preprocess_roots(Poly(f, x)) + + assert coeff == 1 + assert poly == Poly(a*y*x**2 + y - b, x) + + f = c**3*x**3 + c**2*x**2 + c*x + a + + coeff, poly = preprocess_roots(Poly(f, x)) + + assert coeff == 1/c + assert poly == Poly(x**3 + x**2 + x + a, x) + + f = c**3*x**3 + c**2*x**2 + a + + coeff, poly = preprocess_roots(Poly(f, x)) + + assert coeff == 1/c + assert poly == Poly(x**3 + x**2 + a, x) + + f = c**3*x**3 + c*x + a + + coeff, poly = preprocess_roots(Poly(f, x)) + + assert coeff == 1/c + assert poly == Poly(x**3 + x + a, x) + + f = c**3*x**3 + a + + coeff, poly = preprocess_roots(Poly(f, x)) + + assert coeff == 1/c + assert poly == Poly(x**3 + a, x) + + 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 + + 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 + + f = Poly(-y**2 + x**2*exp(x), y, domain=ZZ[x, exp(x)]) + g = Poly(-y**2 + exp(x), y, domain=ZZ[exp(x)]) + + assert preprocess_roots(f) == (x, g) + + +def test_roots0(): + 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(2*x + 1, x) == {Rational(-1, 2): 1} + assert roots((2*x + 1)**2, x) == {Rational(-1, 2): 2} + assert roots((2*x + 1)**5, x) == {Rational(-1, 2): 5} + assert roots((2*x + 1)**10, x) == {Rational(-1, 2): 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)**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(((a*x - b)**5).expand(), x) == { b/a: 5} + assert roots(((a*x + b)**5).expand(), x) == {-b/a: 5} + + assert roots(x**2 + (-a - 1)*x + a, x) == {a: 1, S.One: 1} + + assert roots(x**4 - 2*x**2 + 1, x) == {S.One: 2, S.NegativeOne: 2} + + 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, + -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 + + assert roots(f) == {S.Zero: 2, -S(2): 2, S(2): 1, Rational(-7, 2): 1, + Rational(-3, 2): 1, Rational(-1, 2): 1, Rational(3, 2): 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 + 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} + assert roots((x**2 - x)*(x**3 + 2*x**2 + 4*x + 8), x ) == \ + {S.One: 1, S.Zero: 1, -S(2): 1, -2*I: 1, 2*I: 1} + + r1_2, r1_3 = S.Half, Rational(1, 3) + + x0 = (3*sqrt(33) + 19)**r1_3 + x1 = 4/x0/3 + x2 = x0/3 + x3 = sqrt(3)*I/2 + x4 = x3 - r1_2 + x5 = -x3 - r1_2 + assert roots(x**3 + x**2 - x + 1, x, cubics=True) == { + -x1 - x2 - r1_3: 1, + -x1/x4 - x2*x4 - r1_3: 1, + -x1/x5 - x2*x5 - r1_3: 1, + } + + 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)) ] + + s2 = sqrt(2) + assert roots(f, x) == { + r13_20 + r1_20*sqrt(1 - 8*I*s2): 1, + r13_20 - r1_20*sqrt(1 - 8*I*s2): 1, + r13_20 + r1_20*sqrt(1 + 8*I*s2): 1, + r13_20 - r1_20*sqrt(1 + 8*I*s2): 1, + } + + 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)) ] + + assert roots(f, x) == { + -r1_4 + r1_4*5**r1_2 + I*(r5_8 + r1_8*5**r1_2)**r1_2: 1, + -r1_4 + r1_4*5**r1_2 - I*(r5_8 + r1_8*5**r1_2)**r1_2: 1, + -r1_4 - r1_4*5**r1_2 + I*(r5_8 - r1_8*5**r1_2)**r1_2: 1, + -r1_4 - r1_4*5**r1_2 - I*(r5_8 - r1_8*5**r1_2)**r1_2: 1, + } + + f = z**3 + (-2 - y)*z**2 + (1 + 2*y - 2*x**2)*z - y + 2*x**2 + + assert roots(f, z) == { + S.One: 1, + S.Half + S.Half*y + S.Half*sqrt(1 - 2*y + y**2 + 8*x**2): 1, + S.Half + S.Half*y - S.Half*sqrt(1 - 2*y + y**2 + 8*x**2): 1, + } + + 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 - 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] + + ar, br = symbols('a, b', real=True) + p = x**2*(ar-br)**2 + 2*x*(br-ar) + 1 + assert roots(p, x, filter='R') == {1/(ar - br): 2} + + assert roots(x**3, x, multiple=True) == [S.Zero, S.Zero, S.Zero] + assert roots(1234, x, multiple=True) == [] + + 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*Rational(2, 7)) - cos(pi*Rational(2, 7)): 1, + -I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 7)): 1, + I*sin(pi/7) + cos(pi/7): 1, + I*sin(pi*Rational(2, 7)) - cos(pi*Rational(2, 7)): 1, + I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 7)): 1, + } + + g = ((x**2 + 1)*f**2).expand() + + assert roots(g) == { + -I*sin(pi/7) + cos(pi/7): 2, + -I*sin(pi*Rational(2, 7)) - cos(pi*Rational(2, 7)): 2, + -I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 7)): 2, + I*sin(pi/7) + cos(pi/7): 2, + I*sin(pi*Rational(2, 7)) - cos(pi*Rational(2, 7)): 2, + I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 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 = 108 + 6*sqrt(1074) + assert real_root == -2*root(cr, 3)/3 + 20/root(cr, 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) + root(7, 3)*(-S.Half - sqrt(3)*I/2): 1, + -sqrt(2) + root(7, 3)*(-S.Half + sqrt(3)*I/2): 1, + -sqrt(2) + root(7, 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) + + 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) + + assert list(roots(e1 - e2, k).values()) == [1, 1, 1] + + f = x**3 + 2*x**2 + 8 + R = list(roots(f).keys()) + + assert not any(i for i in [f.subs(x, ri).n(chop=True) for ri in R]) + + +def test_roots_inexact(): + R1 = roots(x**2 + x + 1, x, multiple=True) + R2 = roots(x**2 + x + 1.0, x, multiple=True) + + 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) + + R1 = roots(f, multiple=True) + R2 = (-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 + + 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] + + w = Wild('w') + p = w*E*J/(F*L**2) + + assert len(R1) == len(R2) + + for r1, r2 in zip(R1, R2): + match = r1.match(p) + assert match is not None and abs(match[w] - r2) < 1e-10 + + +def test_roots_strict(): + assert roots(x**2 - 2*x + 1, strict=False) == {1: 2} + assert roots(x**2 - 2*x + 1, strict=True) == {1: 2} + + assert roots(x**6 - 2*x**5 - x**2 + 3*x - 2, strict=False) == {2: 1} + raises(UnsolvableFactorError, lambda: roots(x**6 - 2*x**5 - x**2 + 3*x - 2, strict=True)) + + +def test_roots_mixed(): + f = -1936 - 5056*x - 7592*x**2 + 2704*x**3 - 49*x**4 + + _re, _im = intervals(f, all=True) + _nroots = nroots(f) + _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 ] + + _intervals = _re + _im + _sroots = [ r.evalf() for r in _sroots ] + + _nroots = sorted(_nroots, key=lambda x: x.sort_key()) + _sroots = sorted(_sroots, key=lambda x: x.sort_key()) + + for _roots in (_nroots, _sroots): + for i, r in zip(_intervals, _roots): + if r.is_real: + assert r in i + 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)] + + assert root_factors(x**2 - 1, x) == [x + 1, x - 1] + assert root_factors(x**2 - y, x) == [x - sqrt(y), x + sqrt(y)] + + assert root_factors((x**4 - 1)**2) == \ + [x + 1, x + 1, x - 1, x - 1, x - I, x - I, x + I, x + I] + + assert root_factors(Poly(x**4 - 1, x), filter='Z') == \ + [Poly(x + 1, x), Poly(x - 1, x), Poly(x**2 + 1, x)] + assert root_factors(8*x**2 + 12*x**4 + 6*x**6 + x**8, x, filter='Q') == \ + [x, x, x**6 + 6*x**4 + 12*x**2 + 8] + + +@slow +def test_nroots1(): + n = 64 + p = legendre_poly(n, x, polys=True) + + raises(mpmath.mp.NoConvergence, lambda: p.nroots(n=3, maxsteps=5)) + + roots = p.nroots(n=3) + # The order of roots matters. They are ordered from smallest to the + # largest. + assert [str(r) for r in roots] == \ + ['-0.999', '-0.996', '-0.991', '-0.983', '-0.973', '-0.961', + '-0.946', '-0.930', '-0.911', '-0.889', '-0.866', '-0.841', + '-0.813', '-0.784', '-0.753', '-0.720', '-0.685', '-0.649', + '-0.611', '-0.572', '-0.531', '-0.489', '-0.446', '-0.402', + '-0.357', '-0.311', '-0.265', '-0.217', '-0.170', '-0.121', + '-0.0730', '-0.0243', '0.0243', '0.0730', '0.121', '0.170', + '0.217', '0.265', '0.311', '0.357', '0.402', '0.446', '0.489', + '0.531', '0.572', '0.611', '0.649', '0.685', '0.720', '0.753', + '0.784', '0.813', '0.841', '0.866', '0.889', '0.911', '0.930', + '0.946', '0.961', '0.973', '0.983', '0.991', '0.996', '0.999'] + +def test_nroots2(): + p = Poly(x**5 + 3*x + 1, x) + + roots = p.nroots(n=3) + # The order of roots matters. The roots are ordered by their real + # components (if they agree, then by their imaginary components), + # with real roots appearing first. + assert [str(r) for r in roots] == \ + ['-0.332', '-0.839 - 0.944*I', '-0.839 + 0.944*I', + '1.01 - 0.937*I', '1.01 + 0.937*I'] + + roots = p.nroots(n=5) + assert [str(r) for r in roots] == \ + ['-0.33199', '-0.83907 - 0.94385*I', '-0.83907 + 0.94385*I', + '1.0051 - 0.93726*I', '1.0051 + 0.93726*I'] + + +def test_roots_composite(): + assert len(roots(Poly(y**3 + y**2*sqrt(x) + y + x, y, composite=True))) == 3 + + +def test_issue_19113(): + eq = cos(x)**3 - cos(x) + 1 + raises(PolynomialError, lambda: roots(eq)) + + +def test_issue_17454(): + assert roots([1, -3*(-4 - 4*I)**2/8 + 12*I, 0], multiple=True) == [0, 0] + + +def test_issue_20913(): + assert Poly(x + 9671406556917067856609794, x).real_roots() == [-9671406556917067856609794] + assert Poly(x**3 + 4, x).real_roots() == [-2**(S(2)/3)] + + +def test_issue_22768(): + e = Rational(1, 3) + r = (-1/a)**e*(a + 1)**(5*e) + assert roots(Poly(a*x**3 + (a + 1)**5, x)) == { + r: 1, + -r*(1 + sqrt(3)*I)/2: 1, + r*(-1 + sqrt(3)*I)/2: 1} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polytools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polytools.py new file mode 100644 index 0000000000000000000000000000000000000000..a4096447cecea9db6e7559c305af6312b2a72725 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polytools.py @@ -0,0 +1,3976 @@ +"""Tests for user-friendly public interface to polynomial functions. """ + +import pickle + +from sympy.polys.polytools import ( + Poly, PurePoly, poly, + parallel_poly_from_expr, + degree, degree_list, + total_degree, + LC, LM, LT, + pdiv, prem, pquo, pexquo, + div, rem, quo, exquo, + half_gcdex, gcdex, invert, + subresultants, + resultant, discriminant, + terms_gcd, cofactors, + gcd, gcd_list, + lcm, lcm_list, + trunc, + monic, content, primitive, + compose, decompose, + sturm, + gff_list, gff, + sqf_norm, sqf_part, sqf_list, sqf, + factor_list, factor, + intervals, refine_root, count_roots, + all_roots, real_roots, nroots, ground_roots, + nth_power_roots_poly, + cancel, reduced, groebner, + GroebnerBasis, is_zero_dimensional, + _torational_factor_list, + to_rational_coeffs) + +from sympy.polys.polyerrors import ( + MultivariatePolynomialError, + ExactQuotientFailed, + PolificationFailed, + ComputationFailed, + UnificationFailed, + RefinementFailed, + GeneratorsNeeded, + GeneratorsError, + PolynomialError, + CoercionFailed, + DomainError, + OptionError, + FlagError) + +from sympy.polys.polyclasses import DMP + +from sympy.polys.fields import field +from sympy.polys.domains import FF, ZZ, QQ, ZZ_I, QQ_I, RR, EX +from sympy.polys.domains.realfield import RealField +from sympy.polys.domains.complexfield import ComplexField +from sympy.polys.orderings import lex, grlex, grevlex + +from sympy.combinatorics.galois import S4TransitiveSubgroups +from sympy.core.add import Add +from sympy.core.basic import _aresame +from sympy.core.containers import Tuple +from sympy.core.expr import Expr +from sympy.core.function import (Derivative, diff, expand) +from sympy.core.mul import _keep_coeff, Mul +from sympy.core.numbers import (Float, I, Integer, Rational, oo, pi) +from sympy.core.power import Pow +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.complexes import (im, re) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.hyperbolic import tanh +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import sin +from sympy.matrices.dense import Matrix +from sympy.matrices.expressions.matexpr import MatrixSymbol +from sympy.polys.rootoftools import rootof +from sympy.simplify.simplify import signsimp +from sympy.utilities.iterables import iterable +from sympy.utilities.exceptions import SymPyDeprecationWarning + +from sympy.testing.pytest import ( + raises, warns_deprecated_sympy, warns, tooslow, XFAIL +) + +from sympy.abc import a, b, c, d, p, q, t, w, x, y, z + + +def _epsilon_eq(a, b): + for u, v in zip(a, b): + if abs(u - v) > 1e-10: + return False + return True + + +def _strict_eq(a, b): + if type(a) == type(b): + if iterable(a): + if len(a) == len(b): + return all(_strict_eq(c, d) for c, d in zip(a, b)) + else: + return False + else: + return isinstance(a, Poly) and a.eq(b, strict=True) + else: + return False + + +def test_Poly_mixed_operations(): + p = Poly(x, x) + with warns_deprecated_sympy(): + p * exp(x) + with warns_deprecated_sympy(): + p + exp(x) + with warns_deprecated_sympy(): + p - exp(x) + + +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=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') + + +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=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))) + + +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) + + 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([ZZ(1), ZZ(7)], ZZ) + assert Poly.from_poly(f, domain=QQ).rep == DMP([QQ(1), QQ(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([ZZ(1), ZZ(7)], ZZ) + assert Poly.from_poly(f, gens=x, domain=QQ).rep == DMP([QQ(1), QQ(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)') + + K = FF(2) + + assert Poly.from_poly(g) == g + assert Poly.from_poly(g, domain=ZZ).rep == DMP([ZZ(1), ZZ(-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, gens=x) == g + assert Poly.from_poly(g, gens=x, domain=ZZ).rep == DMP([ZZ(1), ZZ(-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) + + 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, 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]) + 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]) + 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]) + 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]) + 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]) + 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), 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.Zero)) + raises(GeneratorsNeeded, lambda: Poly.from_expr(S(7))) + + F3 = FF(3) + + assert Poly.from_expr(x + 5, domain=F3).rep == DMP([F3(1), F3(2)], F3) + assert Poly.from_expr(y + 5, domain=F3).rep == DMP([F3(1), F3(2)], F3) + + assert Poly.from_expr(x + 5, x, domain=F3).rep == DMP([F3(1), F3(2)], F3) + assert Poly.from_expr(y + 5, y, domain=F3).rep == DMP([F3(1), F3(2)], F3) + + assert Poly.from_expr(x + y, domain=F3).rep == DMP([[F3(1)], [F3(1), F3(0)]], F3) + assert Poly.from_expr(x + y, x, y, domain=F3).rep == DMP([[F3(1)], [F3(1), F3(0)]], F3) + + assert Poly.from_expr(x + 5).rep == DMP([ZZ(1), ZZ(5)], ZZ) + assert Poly.from_expr(y + 5).rep == DMP([ZZ(1), ZZ(5)], ZZ) + + assert Poly.from_expr(x + 5, x).rep == DMP([ZZ(1), ZZ(5)], ZZ) + assert Poly.from_expr(y + 5, y).rep == DMP([ZZ(1), ZZ(5)], ZZ) + + assert Poly.from_expr(x + 5, domain=ZZ).rep == DMP([ZZ(1), ZZ(5)], ZZ) + assert Poly.from_expr(y + 5, domain=ZZ).rep == DMP([ZZ(1), ZZ(5)], ZZ) + + assert Poly.from_expr(x + 5, x, domain=ZZ).rep == DMP([ZZ(1), ZZ(5)], ZZ) + assert Poly.from_expr(y + 5, y, domain=ZZ).rep == DMP([ZZ(1), ZZ(5)], ZZ) + + assert Poly.from_expr(x + 5, x, y, domain=ZZ).rep == DMP([[ZZ(1)], [ZZ(5)]], ZZ) + assert Poly.from_expr(y + 5, x, y, domain=ZZ).rep == DMP([[ZZ(1), ZZ(5)]], ZZ) + + +def test_Poly_rootof_extension(): + r1 = rootof(x**3 + x + 3, 0) + r2 = rootof(x**3 + x + 3, 1) + K1 = QQ.algebraic_field(r1) + K2 = QQ.algebraic_field(r2) + assert Poly(r1, y) == Poly(r1, y, domain=EX) + assert Poly(r2, y) == Poly(r2, y, domain=EX) + assert Poly(r1, y, extension=True) == Poly(r1, y, domain=K1) + assert Poly(r2, y, extension=True) == Poly(r2, y, domain=K2) + + +@tooslow +def test_Poly_rootof_extension_primitive_element(): + r1 = rootof(x**3 + x + 3, 0) + r2 = rootof(x**3 + x + 3, 1) + K12 = QQ.algebraic_field(r1 + r2) + assert Poly(r1*y + r2, y, extension=True) == Poly(r1*y + r2, y, domain=K12) + + +@XFAIL +def test_Poly_rootof_same_symbol_issue_26808(): + # XXX: This fails because r1 contains x. + r1 = rootof(x**3 + x + 3, 0) + K1 = QQ.algebraic_field(r1) + assert Poly(r1, x) == Poly(r1, x, domain=EX) + assert Poly(r1, x, extension=True) == Poly(r1, x, domain=K1) + + +def test_Poly_rootof_extension_to_sympy(): + # Verify that when primitive elements and RootOf are used, the expression + # is not exploded on the way back to sympy. + r1 = rootof(y**3 + y**2 - 1, 0) + r2 = rootof(z**5 + z**2 - 1, 0) + p = -x**5 + x**2 + x*r1 - r2 + 3*r1**2 + assert p.as_poly(x, extension=True).as_expr() == p + + +def test_poly_from_domain_element(): + dom = ZZ[x] + assert Poly(dom(x+1), y, domain=dom).rep == DMP([dom(x+1)], dom) + dom = dom.get_field() + assert Poly(dom(x+1), y, domain=dom).rep == DMP([dom(x+1)], dom) + + dom = QQ[x] + assert Poly(dom(x+1), y, domain=dom).rep == DMP([dom(x+1)], dom) + dom = dom.get_field() + assert Poly(dom(x+1), y, domain=dom).rep == DMP([dom(x+1)], dom) + + dom = ZZ.old_poly_ring(x) + assert Poly(dom([ZZ(1), ZZ(1)]), y, domain=dom).rep == DMP([dom([ZZ(1), ZZ(1)])], dom) + dom = dom.get_field() + assert Poly(dom([ZZ(1), ZZ(1)]), y, domain=dom).rep == DMP([dom([ZZ(1), ZZ(1)])], dom) + + dom = QQ.old_poly_ring(x) + assert Poly(dom([QQ(1), QQ(1)]), y, domain=dom).rep == DMP([dom([QQ(1), QQ(1)])], dom) + dom = dom.get_field() + assert Poly(dom([QQ(1), QQ(1)]), y, domain=dom).rep == DMP([dom([QQ(1), QQ(1)])], dom) + + dom = QQ.algebraic_field(I) + assert Poly(dom([1, 1]), x, domain=dom).rep == DMP([dom([1, 1])], dom) + + +def test_Poly__new__(): + 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(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, 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=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=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(GeneratorsNeeded, lambda: Poly({1: 2, 0: 1})) + raises(GeneratorsNeeded, lambda: Poly([2, 1])) + raises(GeneratorsNeeded, lambda: Poly((2, 1))) + + raises(GeneratorsNeeded, lambda: Poly(1)) + + assert Poly('x-x') == Poly(0, x) + + f = a*x**2 + b*x + c + + assert Poly({2: a, 1: b, 0: c}, x) == f + assert Poly(iter([a, b, c]), x) == f + 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] + assert Poly(3*x**2 + 2*x + 1, domain='QQ').all_coeffs() == [3, 2, 1] + 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 + x*Rational(2, 5) + 1, domain='ZZ')) + assert Poly( + 3*x**2/5 + x*Rational(2, 5) + 1, domain='QQ').all_coeffs() == [Rational(3, 5), Rational(2, 5), 1] + assert _epsilon_eq( + Poly(3*x**2/5 + x*Rational(2, 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] + + 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() == [Rational(31, 10), Rational(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) == \ + 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) + + 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) + 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) + + N = 10**100 + assert Poly(-1, x, modulus=N, symmetric=False).as_expr() == N - 1 + + assert isinstance(Poly(x**2 + x + 1.0).get_domain(), RealField) + assert isinstance(Poly(x**2 + x + I + 1.0).get_domain(), ComplexField) + + +def test_Poly__args(): + assert Poly(x**2 + 1).args == (x**2 + 1, x) + + +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, 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)).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), 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), 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) + + +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)) + + F3 = FF(3) + + assert Poly(x, x, modulus=3)._unify(Poly(y, y, modulus=3))[2:] == ( + DMP([[F3(1)], []], F3), DMP([[F3(1), F3(0)]], F3)) + raises(UnificationFailed, lambda: Poly(x, x, modulus=3)._unify(Poly(y, y, modulus=5))) + + raises(UnificationFailed, lambda: Poly(y, x, y)._unify(Poly(x, x, modulus=3))) + raises(UnificationFailed, lambda: Poly(x, x, modulus=3)._unify(Poly(y, x, y))) + + assert Poly(x + 1, x)._unify(Poly(x + 2, x))[2:] ==\ + (DMP([ZZ(1), ZZ(1)], ZZ), DMP([ZZ(1), ZZ(2)], ZZ)) + assert Poly(x + 1, x, domain='QQ')._unify(Poly(x + 2, x))[2:] ==\ + (DMP([QQ(1), QQ(1)], QQ), DMP([QQ(1), QQ(2)], QQ)) + assert Poly(x + 1, x)._unify(Poly(x + 2, x, domain='QQ'))[2:] ==\ + (DMP([QQ(1), QQ(1)], QQ), DMP([QQ(1), QQ(2)], QQ)) + + assert Poly(x + 1, x)._unify(Poly(x + 2, x, y))[2:] ==\ + (DMP([[ZZ(1)], [ZZ(1)]], ZZ), DMP([[ZZ(1)], [ZZ(2)]], ZZ)) + assert Poly(x + 1, x, domain='QQ')._unify(Poly(x + 2, x, y))[2:] ==\ + (DMP([[QQ(1)], [QQ(1)]], QQ), DMP([[QQ(1)], [QQ(2)]], QQ)) + assert Poly(x + 1, x)._unify(Poly(x + 2, x, y, domain='QQ'))[2:] ==\ + (DMP([[QQ(1)], [QQ(1)]], QQ), DMP([[QQ(1)], [QQ(2)]], QQ)) + + assert Poly(x + 1, x, y)._unify(Poly(x + 2, x))[2:] ==\ + (DMP([[ZZ(1)], [ZZ(1)]], ZZ), DMP([[ZZ(1)], [ZZ(2)]], ZZ)) + assert Poly(x + 1, x, y, domain='QQ')._unify(Poly(x + 2, x))[2:] ==\ + (DMP([[QQ(1)], [QQ(1)]], QQ), DMP([[QQ(1)], [QQ(2)]], QQ)) + assert Poly(x + 1, x, y)._unify(Poly(x + 2, x, domain='QQ'))[2:] ==\ + (DMP([[QQ(1)], [QQ(1)]], QQ), DMP([[QQ(1)], [QQ(2)]], QQ)) + + assert Poly(x + 1, x, y)._unify(Poly(x + 2, x, y))[2:] ==\ + (DMP([[ZZ(1)], [ZZ(1)]], ZZ), DMP([[ZZ(1)], [ZZ(2)]], ZZ)) + assert Poly(x + 1, x, y, domain='QQ')._unify(Poly(x + 2, x, y))[2:] ==\ + (DMP([[QQ(1)], [QQ(1)]], QQ), DMP([[QQ(1)], [QQ(2)]], QQ)) + assert Poly(x + 1, x, y)._unify(Poly(x + 2, x, y, domain='QQ'))[2:] ==\ + (DMP([[QQ(1)], [QQ(1)]], QQ), DMP([[QQ(1)], [QQ(2)]], QQ)) + + assert Poly(x + 1, x)._unify(Poly(x + 2, y, x))[2:] ==\ + (DMP([[ZZ(1), ZZ(1)]], ZZ), DMP([[ZZ(1), ZZ(2)]], ZZ)) + assert Poly(x + 1, x, domain='QQ')._unify(Poly(x + 2, y, x))[2:] ==\ + (DMP([[QQ(1), QQ(1)]], QQ), DMP([[QQ(1), QQ(2)]], QQ)) + assert Poly(x + 1, x)._unify(Poly(x + 2, y, x, domain='QQ'))[2:] ==\ + (DMP([[QQ(1), QQ(1)]], QQ), DMP([[QQ(1), QQ(2)]], QQ)) + + assert Poly(x + 1, y, x)._unify(Poly(x + 2, x))[2:] ==\ + (DMP([[ZZ(1), ZZ(1)]], ZZ), DMP([[ZZ(1), ZZ(2)]], ZZ)) + assert Poly(x + 1, y, x, domain='QQ')._unify(Poly(x + 2, x))[2:] ==\ + (DMP([[QQ(1), QQ(1)]], QQ), DMP([[QQ(1), QQ(2)]], QQ)) + assert Poly(x + 1, y, x)._unify(Poly(x + 2, x, domain='QQ'))[2:] ==\ + (DMP([[QQ(1), QQ(1)]], QQ), DMP([[QQ(1), QQ(2)]], QQ)) + + assert Poly(x + 1, x, y)._unify(Poly(x + 2, y, x))[2:] ==\ + (DMP([[ZZ(1)], [ZZ(1)]], ZZ), DMP([[ZZ(1)], [ZZ(2)]], ZZ)) + assert Poly(x + 1, x, y, domain='QQ')._unify(Poly(x + 2, y, x))[2:] ==\ + (DMP([[QQ(1)], [QQ(1)]], QQ), DMP([[QQ(1)], [QQ(2)]], QQ)) + assert Poly(x + 1, x, y)._unify(Poly(x + 2, y, x, domain='QQ'))[2:] ==\ + (DMP([[QQ(1)], [QQ(1)]], QQ), DMP([[QQ(1)], [QQ(2)]], QQ)) + + assert Poly(x + 1, y, x)._unify(Poly(x + 2, x, y))[2:] ==\ + (DMP([[ZZ(1), ZZ(1)]], ZZ), DMP([[ZZ(1), ZZ(2)]], ZZ)) + assert Poly(x + 1, y, x, domain='QQ')._unify(Poly(x + 2, x, y))[2:] ==\ + (DMP([[QQ(1), QQ(1)]], QQ), DMP([[QQ(1), QQ(2)]], QQ)) + assert Poly(x + 1, y, x)._unify(Poly(x + 2, x, y, domain='QQ'))[2:] ==\ + (DMP([[QQ(1), QQ(1)]], QQ), DMP([[QQ(1), QQ(2)]], QQ)) + + assert Poly(x**2 + I, x, domain=ZZ_I).unify(Poly(x**2 + sqrt(2), x, extension=True)) == \ + (Poly(x**2 + I, x, domain='QQ'), Poly(x**2 + sqrt(2), x, domain='QQ')) + + F, A, B = field("a,b", ZZ) + + assert Poly(a*x, x, domain='ZZ[a]')._unify(Poly(a*b*x, x, domain='ZZ(a,b)'))[2:] == \ + (DMP([A, F(0)], F.to_domain()), DMP([A*B, F(0)], F.to_domain())) + + assert Poly(a*x, x, domain='ZZ(a)')._unify(Poly(a*b*x, x, domain='ZZ(a,b)'))[2:] == \ + (DMP([A, F(0)], F.to_domain()), DMP([A*B, F(0)], F.to_domain())) + + raises(CoercionFailed, lambda: Poly(Poly(x**2 + x**2*z, y, field=True), domain='ZZ(x)')) + + f = Poly(t**2 + t/3 + x, t, domain='QQ(x)') + g = Poly(t**2 + t/3 + x, t, domain='QQ[x]') + + assert f._unify(g)[2:] == (f.rep, f.rep) + + +def test_Poly_free_symbols(): + assert Poly(x**2 + 1).free_symbols == {x} + assert Poly(x**2 + y*z).free_symbols == {x, y, z} + assert Poly(x**2 + y*z, x).free_symbols == {x, y, z} + assert Poly(x**2 + sin(y*z)).free_symbols == {x, y, z} + assert Poly(x**2 + sin(y*z), x).free_symbols == {x, y, z} + assert Poly(x**2 + sin(y*z), x, domain=EX).free_symbols == {x, y, z} + assert Poly(1 + x + x**2, x, y, z).free_symbols == {x} + assert Poly(x + sin(y), z).free_symbols == {x, y} + + +def test_PurePoly_free_symbols(): + assert PurePoly(x**2 + 1).free_symbols == set() + assert PurePoly(x**2 + y*z).free_symbols == set() + assert PurePoly(x**2 + y*z, x).free_symbols == {y, z} + assert PurePoly(x**2 + sin(y*z)).free_symbols == set() + assert PurePoly(x**2 + sin(y*z), x).free_symbols == {y, z} + assert PurePoly(x**2 + sin(y*z), x, domain=EX).free_symbols == {y, z} + + +def test_Poly__eq__(): + assert (Poly(x, x) == Poly(x, x)) is True + assert (Poly(x, x, domain=QQ) == Poly(x, x)) is False + assert (Poly(x, x) == Poly(x, x, domain=QQ)) is False + + assert (Poly(x, x, domain=ZZ[a]) == Poly(x, x)) is False + assert (Poly(x, x) == Poly(x, x, domain=ZZ[a])) is False + + assert (Poly(x*y, x, y) == Poly(x, x)) is 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)) 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) is False + assert f.ne(g) is True + + assert f.eq(g, strict=True) is False + assert f.ne(g, strict=True) is True + + t0 = Symbol('t0') + + f = Poly((t0/2 + x**2)*t**2 - x**2*t, t, domain='QQ[x,t0]') + g = Poly((t0/2 + x**2)*t**2 - x**2*t, t, domain='ZZ(x,t0)') + + assert (f == g) is False + + +def test_PurePoly__eq__(): + 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)) is True + assert (PurePoly(x, x) == PurePoly(x, x, domain=ZZ[a])) is True + + assert (PurePoly(x*y, x, y) == PurePoly(x, x)) is 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)) 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) is True + assert f.ne(g) is False + + 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) is True + assert f.ne(g) is False + + assert f.eq(g, strict=True) is False + assert f.ne(g, strict=True) is True + + +def test_PurePoly_Poly(): + 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 + + assert Poly(2*x, domain='ZZ').get_domain() == ZZ + assert Poly(2*x, domain='QQ').get_domain() == QQ + + assert Poly(x/2).get_domain() == QQ + + raises(CoercionFailed, lambda: Poly(x/2, domain='ZZ')) + assert Poly(x/2, domain='QQ').get_domain() == QQ + + assert isinstance(Poly(0.2*x).get_domain(), RealField) + + +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) + + assert Poly(2*x + 1).set_domain(QQ) == Poly(2*x + 1, domain='QQ') + assert Poly(2*x + 1).set_domain('QQ') == Poly(2*x + 1, domain='QQ') + + assert Poly(Rational(2, 10)*x + Rational(1, 10)).set_domain('RR') == Poly(0.2*x + 0.1) + assert Poly(0.2*x + 0.1).set_domain('QQ') == Poly(Rational(2, 10)*x + Rational(1, 10)) + + raises(CoercionFailed, lambda: Poly(x/2 + 1).set_domain(ZZ)) + raises(CoercionFailed, lambda: Poly(x + 1, modulus=2).set_domain(QQ)) + + 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).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) + + +def test_Poly_neg(): + 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) + assert Poly(0, x) + Poly(0, x) == Poly(0, x) + + assert Poly(1, x).add(Poly(0, x)) == Poly(1, x) + assert Poly(1, x, y) + Poly(0, x) == Poly(1, x, y) + 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) + with warns_deprecated_sympy(): + Poly(1, x) + sin(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) + assert Poly(0, x) - Poly(0, x) == Poly(0, x) + + assert Poly(1, x).sub(Poly(0, x)) == Poly(1, x) + assert Poly(1, x, y) - Poly(0, x) == Poly(1, x, y) + 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) + with warns_deprecated_sympy(): + Poly(1, x) - sin(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) + assert Poly(0, x) * Poly(0, x) == Poly(0, x) + + assert Poly(2, x).mul(Poly(4, x)) == Poly(8, x) + assert Poly(2, x, y) * Poly(4, x) == Poly(8, x, y) + assert Poly(4, x).mul(Poly(2, x, y)) == Poly(8, x, y) + assert Poly(4, x, y) * Poly(2, x, y) == Poly(8, x, y) + + assert Poly(1, x) * x == Poly(x, x) + with warns_deprecated_sympy(): + Poly(1, x) * sin(x) + + assert Poly(x, x) * 2 == Poly(2*x, x) + assert 2 * Poly(x, x) == Poly(2*x, x) + +def test_issue_13079(): + assert Poly(x)*x == Poly(x**2, x, domain='ZZ') + assert x*Poly(x) == Poly(x**2, x, domain='ZZ') + assert -2*Poly(x) == Poly(-2*x, x, domain='ZZ') + assert S(-2)*Poly(x) == Poly(-2*x, x, domain='ZZ') + assert Poly(x)*S(-2) == Poly(-2*x, x, domain='ZZ') + +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) + + assert Poly(2*y, x, y).pow(4) == Poly(16*y**4, x, y) + assert Poly(2*y, x, y).pow(Integer(4)) == Poly(16*y**4, x, y) + + assert Poly(7*x*y, x, y)**3 == Poly(343*x**3*y**3, x, y) + + raises(TypeError, lambda: Poly(x*y + 1, x, y)**(-1)) + raises(TypeError, lambda: Poly(x*y + 1, x, y)**x) + + +def test_Poly_divmod(): + f, g = Poly(x**2), Poly(x) + q, r = g, Poly(0, x) + + assert divmod(f, g) == (q, r) + assert f // g == q + assert f % g == r + + assert divmod(f, x) == (q, r) + assert f // x == q + assert f % x == r + + q, r = Poly(0, x), Poly(2, x) + + assert divmod(2, g) == (q, r) + assert 2 // g == q + assert 2 % g == r + + assert Poly(x)/Poly(x) == 1 + 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)) 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 + + +def test_Poly_nonzero(): + 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 is True + assert Poly(1, x).is_zero is False + + assert Poly(1, x).is_one is True + assert Poly(2, x).is_one is 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 is True + assert Poly(2*x - 1, x).is_monic is 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 is True + assert Poly(x, x).is_ground is 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 is True + assert Poly(x*y*z + 1).is_quadratic is 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 is True + assert Poly(x**3 + x*y).is_homogeneous is False + + assert Poly(x).is_univariate is True + assert Poly(x*y).is_univariate is 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 + + +def test_Poly_is_irreducible(): + 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 + + +def test_Poly_subs(): + assert Poly(x + 1).subs(x, 0) == 1 + + assert Poly(x + 1).subs(x, x) == Poly(x + 1) + assert Poly(x + 1).subs(x, y) == Poly(y + 1) + + 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) + + raises(PolynomialError, lambda: Poly(x + y).replace(z)) + + assert Poly(x + 1).replace(x, x) == Poly(x + 1) + assert Poly(x + 1).replace(x, y) == Poly(y + 1) + + assert Poly(x + y).replace(x, x) == Poly(x + y) + assert Poly(x + y).replace(x, z) == Poly(z + y, z, y) + + assert Poly(x + y).replace(y, y) == Poly(x + y) + assert Poly(x + y).replace(y, z) == Poly(x + z, x, z) + assert Poly(x + y).replace(z, t) == Poly(x + y) + + raises(PolynomialError, lambda: Poly(x + y).replace(x, y)) + + assert Poly(x + y, x).replace(x, z) == Poly(z + y, z) + assert Poly(x + y, y).replace(y, z) == Poly(x + z, z) + + 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)) + + 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) + + assert Poly(x + y, y, x).reorder(x, y) == Poly(x + y, x, y) + assert Poly(x + y, y, x).reorder(y, x) == Poly(x + y, y, x) + + 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) + assert Poly(x*y - x, z, x, y).ltrim(1) == Poly(x*y - x, x, y) + + raises(PolynomialError, lambda: Poly(x*y**2 + y**2, x, y).ltrim(y)) + raises(PolynomialError, lambda: Poly(x*y - x, x, y).ltrim(-1)) + +def test_Poly_has_only_gens(): + 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') + + 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(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(2.0*x + 1.0).to_field() == Poly(2.0*x + 1.0) + + +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]) + + assert f.retract() == Poly(x**2 + 1, x, domain='ZZ') + assert f.retract(field=True) == Poly(x**2 + 1, x, domain='QQ') + + assert Poly(0, x, y).retract() == Poly(0, x, y) + + +def test_Poly_slice(): + f = Poly(x**3 + 2*x**2 + 3*x + 4) + + assert f.slice(0, 0) == Poly(0, x) + assert f.slice(0, 1) == Poly(4, x) + assert f.slice(0, 2) == Poly(3*x + 4, x) + assert f.slice(0, 3) == Poly(2*x**2 + 3*x + 4, x) + assert f.slice(0, 4) == Poly(x**3 + 2*x**2 + 3*x + 4, x) + + assert f.slice(x, 0, 0) == Poly(0, x) + assert f.slice(x, 0, 1) == Poly(4, x) + assert f.slice(x, 0, 2) == Poly(3*x + 4, x) + 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) + + g = Poly(x**3 + 1) + + assert g.slice(0, 3) == Poly(1, 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(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(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(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)] + + +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(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(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(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) + g = Poly(x**2 + 2*x + 4) + + def func(monom, coeff): + (k,) = monom + return coeff//10**(2 - k) + + assert f.termwise(func) == g + + def func(monom, coeff): + (k,) = monom + 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 + + +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(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} + + +def test_Poly_as_expr(): + assert Poly(0, x).as_expr() == 0 + assert Poly(0, x, y, z).as_expr() == 0 + + 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( + 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) + + assert f.as_expr() == -y + x**2 + 2*x*y**2 + + assert f.as_expr({x: 5}) == 25 - y + 10*y**2 + assert f.as_expr({y: 6}) == -6 + 72*x + x**2 + + assert f.as_expr({x: 5, y: 6}) == 379 + assert f.as_expr(5, 6) == 379 + + raises(GeneratorsError, lambda: f.as_expr({z: 7})) + + +def test_Poly_lift(): + p = Poly(x**4 - I*x + 17*I, x, gaussian=True) + assert p.lift() == Poly(x**8 + x**2 - 34*x + 289, x, domain='QQ') + + +def test_Poly_lift_multiple(): + + r1 = rootof(y**3 + y**2 - 1, 0) + r2 = rootof(z**5 + z**2 - 1, 0) + p = Poly(r1*x + 3*r1**2 - r2 + x**2 - x**5, x, extension=True) + + assert p.lift() == Poly( + -x**75 + 15*x**72 - 5*x**71 + 15*x**70 - 105*x**69 + 70*x**68 - + 220*x**67 + 560*x**66 - 635*x**65 + 1495*x**64 - 2735*x**63 + + 4415*x**62 - 7410*x**61 + 12741*x**60 - 22090*x**59 + 32125*x**58 - + 56281*x**57 + 88157*x**56 - 126842*x**55 + 214223*x**54 - 311802*x**53 + + 462667*x**52 - 700883*x**51 + 1006278*x**50 - 1480950*x**49 + + 2078055*x**48 - 3004675*x**47 + 4140410*x**46 - 5664222*x**45 + + 8029445*x**44 - 10528785*x**43 + 14309614*x**42 - 19032988*x**41 + + 24570573*x**40 - 32530459*x**39 + 41239581*x**38 - 52968051*x**37 + + 65891606*x**36 - 81997276*x**35 + 102530732*x**34 - 122009994*x**33 + + 150227996*x**32 - 176452478*x**31 + 206393768*x**30 - 245291426*x**29 + + 276598718*x**28 - 320005297*x**27 + 353649032*x**26 + - 393246309*x**25 + 434566186*x**24 - 460608964*x**23 + 508052079*x**22 + - 513976618*x**21 + 539374498*x**20 - 557851717*x**19 + 540788016*x**18 + - 564949060*x**17 + 520866566*x**16 + - 507861375*x**15 + 474999819*x**14 - 423619160*x**13 + 414540540*x**12 + - 322522367*x**11 + 311586511*x**10 - 238812299*x**9 + 184482053*x**8 + - 189265274*x**7 + 93619528*x**6 - 106852385*x**5 + 57294385*x**4 - + 26486666*x**3 + 42614683*x**2 - 1511583*x + 15975845, x, domain='QQ' + ) + + +def test_Poly_deflate(): + assert Poly(0, x).deflate() == ((1,), Poly(0, x)) + assert Poly(1, x).deflate() == ((1,), Poly(1, x)) + assert Poly(x, x).deflate() == ((1,), Poly(x, x)) + + 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)) + + +def test_Poly_inject(): + f = Poly(x**2*y + x*y**3 + x*y + 1, x) + + 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[t, w]') + assert g.eject(z, t, w) == Poly(ex, x, y, domain='ZZ[z, t, w]') + + 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 + assert Poly(1, x, y)._gen_to_level( 0) == 0 + assert Poly(1, x, y)._gen_to_level( 1) == 1 + + raises(PolynomialError, lambda: Poly(1, x, y)._gen_to_level(-3)) + raises(PolynomialError, lambda: Poly(1, x, y)._gen_to_level( 2)) + + assert Poly(1, x, y)._gen_to_level(x) == 0 + assert Poly(1, x, y)._gen_to_level(y) == 1 + + assert Poly(1, x, y)._gen_to_level('x') == 0 + assert Poly(1, x, y)._gen_to_level('y') == 1 + + 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() is -oo + assert Poly(1, x).degree() == 0 + assert Poly(x, x).degree() == 1 + + assert Poly(0, x).degree(gen=0) is -oo + assert Poly(1, x).degree(gen=0) == 0 + assert Poly(x, x).degree(gen=0) == 1 + + assert Poly(0, x).degree(gen=x) is -oo + assert Poly(1, x).degree(gen=x) == 0 + assert Poly(x, x).degree(gen=x) == 1 + + assert Poly(0, x).degree(gen='x') is -oo + assert Poly(1, x).degree(gen='x') == 0 + assert Poly(x, x).degree(gen='x') == 1 + + raises(PolynomialError, lambda: Poly(1, x).degree(gen=1)) + raises(PolynomialError, lambda: Poly(1, x).degree(gen=y)) + raises(PolynomialError, lambda: Poly(1, x).degree(gen='y')) + + assert Poly(1, x, y).degree() == 0 + assert Poly(2*y, x, y).degree() == 0 + assert Poly(x*y, x, y).degree() == 1 + + assert Poly(1, x, y).degree(gen=x) == 0 + assert Poly(2*y, x, y).degree(gen=x) == 0 + assert Poly(x*y, x, y).degree(gen=x) == 1 + + assert Poly(1, x, y).degree(gen=y) == 0 + assert Poly(2*y, x, y).degree(gen=y) == 1 + assert Poly(x*y, x, y).degree(gen=y) == 1 + + assert degree(0, x) is -oo + assert degree(1, x) == 0 + assert degree(x, x) == 1 + + assert degree(x*y**2, x) == 1 + assert degree(x*y**2, y) == 2 + assert degree(x*y**2, z) == 0 + + assert degree(pi) == 1 + + raises(TypeError, lambda: degree(y**2 + x**3)) + raises(TypeError, lambda: degree(y**2 + x**3, 1)) + raises(PolynomialError, lambda: degree(x, 1.1)) + raises(PolynomialError, lambda: degree(x**2/(x**3 + 1), x)) + + assert degree(Poly(0,x),z) is -oo + assert degree(Poly(1,x),z) == 0 + assert degree(Poly(x**2+y**3,y)) == 3 + assert degree(Poly(y**2 + x**3, y, x), 1) == 3 + assert degree(Poly(y**2 + x**3, x), z) == 0 + assert degree(Poly(y**2 + x**3 + z**4, x), z) == 4 + +def test_Poly_degree_list(): + assert Poly(0, x).degree_list() == (-oo,) + assert Poly(0, x, y).degree_list() == (-oo, -oo) + assert Poly(0, x, y, z).degree_list() == (-oo, -oo, -oo) + + 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(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) + + 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 + z**3).total_degree() == 3 + assert Poly(x*y*z + z**4).total_degree() == 4 + assert Poly(x**3 + x + 1).total_degree() == 3 + + assert total_degree(x*y + z**3) == 3 + assert total_degree(x*y + z**3, x, y) == 2 + assert total_degree(1) == 0 + assert total_degree(Poly(y**2 + x**3 + z**4)) == 4 + assert total_degree(Poly(y**2 + x**3 + z**4, x)) == 3 + assert total_degree(Poly(y**2 + x**3 + z**4, x), z) == 4 + assert total_degree(Poly(x**9 + x*z*y + x**3*z**2 + z**7,x), z) == 7 + +def test_Poly_homogenize(): + assert Poly(x**2+y).homogenize(z) == Poly(x**2+y*z) + assert Poly(x+y).homogenize(z) == Poly(x+y, x, y, z) + assert Poly(x+y**2).homogenize(y) == Poly(x*y+y**2) + + +def test_Poly_homogeneous_order(): + assert Poly(0, x, y).homogeneous_order() is -oo + assert Poly(1, x, y).homogeneous_order() == 0 + assert Poly(x, x, y).homogeneous_order() == 1 + assert Poly(x*y, x, y).homogeneous_order() == 2 + + assert Poly(x + 1, x, y).homogeneous_order() is None + assert Poly(x*y + x, x, y).homogeneous_order() is None + + 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(x*y**7 + 2*x**2*y**3).LC('lex') == 2 + assert Poly(x*y**7 + 2*x**2*y**3).LC('grlex') == 1 + + 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 + + +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(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 + + assert Poly(1, x).nth(0) == 1 + assert Poly(1, x).nth(1) == 0 + + assert Poly(x**8, x).nth(0) == 0 + assert Poly(x**8, x).nth(7) == 0 + assert Poly(x**8, x).nth(8) == 1 + assert Poly(x**8, x).nth(9) == 0 + + 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 + + raises(ValueError, lambda: Poly(x*y + 1, x, y).nth(1)) + + +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(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) + + 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)) + + 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(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(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) + + 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(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 + + 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 + + coeff, poly = Poly(2*x**2 + 3, modulus=5).clear_denoms() + assert coeff == 1 and poly == Poly( + 2*x**2 + 3, x, modulus=5) and poly.get_domain() == FF(5) + + 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 + + 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 + + +def test_Poly_rat_clear_denoms(): + f = Poly(x**2/y + 1, x) + g = Poly(x**3 + y, x) + + assert f.rat_clear_denoms(g) == \ + (Poly(x**2 + y, x), Poly(y*x**3 + y**2, x)) + + f = f.set_domain(EX) + g = g.set_domain(EX) + + assert f.rat_clear_denoms(g) == (f, g) + + +def test_issue_20427(): + f = Poly(-117968192370600*18**(S(1)/3)/(217603955769048*(24201 + + 253*sqrt(9165))**(S(1)/3) + 2273005839412*sqrt(9165)*(24201 + + 253*sqrt(9165))**(S(1)/3)) - 15720318185*2**(S(2)/3)*3**(S(1)/3)*(24201 + + 253*sqrt(9165))**(S(2)/3)/(217603955769048*(24201 + 253*sqrt(9165))** + (S(1)/3) + 2273005839412*sqrt(9165)*(24201 + 253*sqrt(9165))**(S(1)/3)) + + 15720318185*12**(S(1)/3)*(24201 + 253*sqrt(9165))**(S(2)/3)/( + 217603955769048*(24201 + 253*sqrt(9165))**(S(1)/3) + 2273005839412* + sqrt(9165)*(24201 + 253*sqrt(9165))**(S(1)/3)) + 117968192370600*2**( + S(1)/3)*3**(S(2)/3)/(217603955769048*(24201 + 253*sqrt(9165))**(S(1)/3) + + 2273005839412*sqrt(9165)*(24201 + 253*sqrt(9165))**(S(1)/3)), x) + assert f == Poly(0, x, domain='EX') + + +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) + assert Poly(x + 1).integrate((x, 1)) == Poly(x**2/2 + x) + + assert Poly(x*y + 1).integrate(x) == Poly(x**2*y/2 + x) + assert Poly(x*y + 1).integrate(y) == Poly(x*y**2/2 + y) + + assert Poly(x*y + 1).integrate(x, x) == Poly(x**3*y/6 + x**2/2) + assert Poly(x*y + 1).integrate(y, y) == Poly(x*y**3/6 + y**2/2) + + assert Poly(x*y + 1).integrate((x, 2)) == Poly(x**3*y/6 + x**2/2) + assert Poly(x*y + 1).integrate((y, 2)) == Poly(x*y**3/6 + y**2/2) + + 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) + assert Poly(x**2 + x).diff((x, 1)) == Poly(2*x + 1) + + assert Poly(x**2*y**2 + x*y).diff(x) == Poly(2*x*y**2 + y) + assert Poly(x**2*y**2 + x*y).diff(y) == Poly(2*x**2*y + x) + + assert Poly(x**2*y**2 + x*y).diff(x, x) == Poly(2*y**2, x, y) + assert Poly(x**2*y**2 + x*y).diff(y, y) == Poly(2*x**2, x, y) + + assert Poly(x**2*y**2 + x*y).diff((x, 2)) == Poly(2*y**2, x, y) + assert Poly(x**2*y**2 + x*y).diff((y, 2)) == Poly(2*x**2, x, y) + + 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_issue_9585(): + assert diff(Poly(x**2 + x)) == Poly(2*x + 1) + assert diff(Poly(x**2 + x), x, evaluate=False) == \ + Derivative(Poly(x**2 + x), x) + assert Derivative(Poly(x**2 + x), x).doit() == Poly(2*x + 1) + + +def test_Poly_eval(): + assert Poly(0, x).eval(7) == 0 + assert Poly(1, x).eval(7) == 1 + assert Poly(x, x).eval(7) == 7 + + assert Poly(0, x).eval(0, 7) == 0 + assert Poly(1, x).eval(0, 7) == 1 + assert Poly(x, x).eval(0, 7) == 7 + + assert Poly(0, x).eval(x, 7) == 0 + assert Poly(1, x).eval(x, 7) == 1 + assert Poly(x, x).eval(x, 7) == 7 + + assert Poly(0, x).eval('x', 7) == 0 + assert Poly(1, x).eval('x', 7) == 1 + assert Poly(x, x).eval('x', 7) == 7 + + raises(PolynomialError, lambda: Poly(1, x).eval(1, 7)) + raises(PolynomialError, lambda: Poly(1, x).eval(y, 7)) + raises(PolynomialError, lambda: Poly(1, x).eval('y', 7)) + + assert Poly(123, x, y).eval(7) == Poly(123, y) + assert Poly(2*y, x, y).eval(7) == Poly(2*y, y) + assert Poly(x*y, x, y).eval(7) == Poly(7*y, y) + + assert Poly(123, x, y).eval(x, 7) == Poly(123, y) + assert Poly(2*y, x, y).eval(x, 7) == Poly(2*y, y) + assert Poly(x*y, x, y).eval(x, 7) == Poly(7*y, y) + + assert Poly(123, x, y).eval(y, 7) == Poly(123, x) + assert Poly(2*y, x, y).eval(y, 7) == Poly(14, x) + assert Poly(x*y, x, y).eval(y, 7) == Poly(7*x, x) + + assert Poly(x*y + y, x, y).eval({x: 7}) == Poly(8*y, y) + assert Poly(x*y + y, x, y).eval({y: 7}) == Poly(7*x + 7, x) + + assert Poly(x*y + y, x, y).eval({x: 6, y: 7}) == 49 + assert Poly(x*y + y, x, y).eval({x: 7, y: 6}) == 48 + + assert Poly(x*y + y, x, y).eval((6, 7)) == 49 + assert Poly(x*y + y, x, y).eval([6, 7]) == 49 + + assert Poly(x + 1, domain='ZZ').eval(S.Half) == Rational(3, 2) + assert 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.Half, auto=False)) + + # issue 6344 + 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) + + assert f(2) == Poly(5*y + 2*z + 6) + 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([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 + + F, G, Q, R = [ Poly(h, x, y) for h in (f, g, q, r) ] + + assert F.pdiv(G) == (Q, R) + assert F.prem(G) == R + assert F.pquo(G) == Q + assert F.pexquo(G) == Q + + assert pdiv(f, g) == (q, r) + assert prem(f, g) == r + assert pquo(f, g) == q + assert pexquo(f, g) == 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 + assert pquo(F, G) == Q + assert pexquo(F, G) == Q + + assert pdiv(f, g, polys=True) == (Q, R) + assert prem(f, g, polys=True) == R + assert pquo(f, g, polys=True) == Q + assert pexquo(f, g, polys=True) == Q + + assert pdiv(F, G, polys=False) == (q, r) + assert prem(F, G, polys=False) == r + assert pquo(F, G, polys=False) == q + assert pexquo(F, G, polys=False) == q + + raises(ComputationFailed, lambda: pdiv(4, 2)) + raises(ComputationFailed, lambda: prem(4, 2)) + 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 + + F, G, Q, R = [ Poly(h, x, y) for h in (f, g, q, r) ] + + assert F.div(G) == (Q, R) + assert F.rem(G) == R + assert F.quo(G) == Q + assert F.exquo(G) == Q + + assert div(f, g) == (q, r) + assert rem(f, g) == r + assert quo(f, g) == q + assert exquo(f, g) == 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 + assert quo(F, G) == Q + assert exquo(F, G) == Q + + assert div(f, g, polys=True) == (Q, R) + assert rem(f, g, polys=True) == R + assert quo(f, g, polys=True) == Q + assert exquo(f, g, polys=True) == Q + + assert div(F, G, polys=False) == (q, r) + assert rem(F, G, polys=False) == r + assert quo(F, G, polys=False) == q + assert exquo(F, G, polys=False) == q + + raises(ComputationFailed, lambda: div(4, 2)) + raises(ComputationFailed, lambda: rem(4, 2)) + raises(ComputationFailed, lambda: quo(4, 2)) + raises(ComputationFailed, lambda: exquo(4, 2)) + + f, g = x**2 + 1, 2*x - 4 + + qz, rz = 0, x**2 + 1 + qq, rq = x/2 + 1, 5 + + assert div(f, g) == (qq, rq) + assert div(f, g, auto=True) == (qq, rq) + assert div(f, g, auto=False) == (qz, rz) + assert div(f, g, domain=ZZ) == (qz, rz) + assert div(f, g, domain=QQ) == (qq, rq) + assert div(f, g, domain=ZZ, auto=True) == (qq, rq) + assert div(f, g, domain=ZZ, auto=False) == (qz, rz) + assert div(f, g, domain=QQ, auto=True) == (qq, rq) + assert div(f, g, domain=QQ, auto=False) == (qq, rq) + + assert rem(f, g) == rq + assert rem(f, g, auto=True) == rq + assert rem(f, g, auto=False) == rz + assert rem(f, g, domain=ZZ) == rz + assert rem(f, g, domain=QQ) == rq + assert rem(f, g, domain=ZZ, auto=True) == rq + assert rem(f, g, domain=ZZ, auto=False) == rz + assert rem(f, g, domain=QQ, auto=True) == rq + assert rem(f, g, domain=QQ, auto=False) == rq + + assert quo(f, g) == qq + assert quo(f, g, auto=True) == qq + assert quo(f, g, auto=False) == qz + assert quo(f, g, domain=ZZ) == qz + assert quo(f, g, domain=QQ) == qq + assert quo(f, g, domain=ZZ, auto=True) == qq + assert quo(f, g, domain=ZZ, auto=False) == qz + assert quo(f, g, domain=QQ, auto=True) == qq + assert quo(f, g, domain=QQ, auto=False) == qq + + f, g, q = x**2, 2*x, x/2 + + assert exquo(f, g) == q + assert exquo(f, g, auto=True) == q + raises(ExactQuotientFailed, lambda: exquo(f, g, auto=False)) + raises(ExactQuotientFailed, lambda: exquo(f, g, domain=ZZ)) + assert exquo(f, g, domain=QQ) == q + assert exquo(f, g, domain=ZZ, auto=True) == q + raises(ExactQuotientFailed, lambda: exquo(f, g, domain=ZZ, auto=False)) + assert exquo(f, g, domain=QQ, auto=True) == q + assert exquo(f, g, domain=QQ, auto=False) == q + + f, g = Poly(x**2), Poly(x) + + q, r = f.div(g) + assert q.get_domain().is_ZZ and r.get_domain().is_ZZ + r = f.rem(g) + assert r.get_domain().is_ZZ + q = f.quo(g) + assert q.get_domain().is_ZZ + q = f.exquo(g) + assert q.get_domain().is_ZZ + + f, g = Poly(x+y, x), Poly(2*x+y, x) + q, r = f.div(g) + assert q.get_domain().is_Frac and r.get_domain().is_Frac + + # https://github.com/sympy/sympy/issues/19579 + p = Poly(2+3*I, x, domain=ZZ_I) + q = Poly(1-I, x, domain=ZZ_I) + assert p.div(q, auto=False) == \ + (Poly(0, x, domain='ZZ_I'), Poly(2 + 3*I, x, domain='ZZ_I')) + assert p.div(q, auto=True) == \ + (Poly(-S(1)/2 + 5*I/2, x, domain='QQ_I'), Poly(0, x, domain='QQ_I')) + + f = 5*x**2 + 10*x + 3 + g = 2*x + 2 + assert div(f, g, domain=ZZ) == (0, f) + + +def test_issue_7864(): + q, r = div(a, .408248290463863*a) + assert abs(q - 2.44948974278318) < 1e-14 + assert r == 0 + + +def test_gcdex(): + f, g = 2*x, x**2 - 16 + 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) ] + + assert F.half_gcdex(G) == (S, H) + assert F.gcdex(G) == (S, T, H) + assert F.invert(G) == S + + assert half_gcdex(f, g) == (s, h) + assert gcdex(f, g) == (s, t, h) + assert invert(f, g) == s + + assert half_gcdex(f, g, x) == (s, h) + assert gcdex(f, g, x) == (s, t, h) + assert invert(f, g, x) == s + + assert half_gcdex(f, g, (x,)) == (s, h) + assert gcdex(f, g, (x,)) == (s, t, h) + assert invert(f, g, (x,)) == s + + assert half_gcdex(F, G) == (S, H) + assert gcdex(F, G) == (S, T, H) + assert invert(F, G) == S + + assert half_gcdex(f, g, polys=True) == (S, H) + assert gcdex(f, g, polys=True) == (S, T, H) + assert invert(f, g, polys=True) == S + + assert half_gcdex(F, G, polys=False) == (s, h) + assert gcdex(F, G, polys=False) == (s, t, h) + assert invert(F, G, polys=False) == s + + assert half_gcdex(100, 2004) == (-20, 4) + assert gcdex(100, 2004) == (-20, 1, 4) + assert invert(3, 7) == 5 + + raises(DomainError, lambda: half_gcdex(x + 1, 2*x + 1, auto=False)) + 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) + + assert F.subresultants(G) == [F, G, H] + assert subresultants(f, g) == [f, g, h] + assert subresultants(f, g, x) == [f, g, h] + assert subresultants(f, g, (x,)) == [f, g, h] + assert subresultants(F, G) == [F, G, H] + assert subresultants(f, g, polys=True) == [F, G, H] + assert subresultants(F, G, polys=False) == [f, g, h] + + 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) + + assert F.resultant(G) == h + assert resultant(f, g) == h + assert resultant(f, g, x) == h + assert resultant(f, g, (x,)) == h + 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) + + assert F.resultant(G) == H + assert resultant(f, g) == h + assert resultant(f, g, x) == h + assert resultant(f, g, (x,)) == h + assert resultant(F, G) == H + assert resultant(f, g, polys=True) == H + assert resultant(F, G, polys=False) == h + + raises(ComputationFailed, lambda: resultant(4, 2)) + + +def test_discriminant(): + f, g = x**3 + 3*x**2 + 9*x - 13, -11664 + F = Poly(f) + + assert F.discriminant() == g + assert discriminant(f) == g + assert discriminant(f, x) == g + assert discriminant(f, (x,)) == g + assert discriminant(F) == g + assert discriminant(f, polys=True) == g + assert discriminant(F, polys=False) == g + + f, g = a*x**2 + b*x + c, b**2 - 4*a*c + F, G = Poly(f), Poly(g) + + assert F.discriminant() == G + assert discriminant(f) == g + assert discriminant(f, x, a, b, c) == g + assert discriminant(f, (x, a, b, c)) == g + assert discriminant(F) == G + assert discriminant(f, polys=True) == G + assert discriminant(F, polys=False) == g + + raises(ComputationFailed, lambda: discriminant(4)) + + +def test_dispersion(): + # We test only the API here. For more mathematical + # tests see the dedicated test file. + fp = poly((x + 1)*(x + 2), x) + assert sorted(fp.dispersionset()) == [0, 1] + assert fp.dispersion() == 1 + + fp = poly(x**4 - 3*x**2 + 1, x) + gp = fp.shift(-3) + assert sorted(fp.dispersionset(gp)) == [2, 3, 4] + assert fp.dispersion(gp) == 4 + + +def test_gcd_list(): + F = [x**3 - 1, x**2 - 1, x**2 - 3*x + 2] + + assert gcd_list(F) == x - 1 + assert gcd_list(F, polys=True) == Poly(x - 1) + + assert gcd_list([]) == 0 + assert gcd_list([1, 2]) == 1 + assert gcd_list([4, 6, 8]) == 2 + + assert gcd_list([x*(y + 42) - x*y - x*42]) == 0 + + gcd = gcd_list([], x) + assert gcd.is_Number and gcd is S.Zero + + gcd = gcd_list([], x, polys=True) + assert gcd.is_Poly and gcd.is_zero + + a = sqrt(2) + assert gcd_list([a, -a]) == gcd_list([-a, a]) == a + + raises(ComputationFailed, lambda: gcd_list([], polys=True)) + + +def test_lcm_list(): + F = [x**3 - 1, x**2 - 1, x**2 - 3*x + 2] + + assert lcm_list(F) == x**5 - x**4 - 2*x**3 - x**2 + x + 2 + assert lcm_list(F, polys=True) == Poly(x**5 - x**4 - 2*x**3 - x**2 + x + 2) + + assert lcm_list([]) == 1 + assert lcm_list([1, 2]) == 2 + assert lcm_list([4, 6, 8]) == 24 + + assert lcm_list([x*(y + 42) - x*y - x*42]) == 0 + + lcm = lcm_list([], x) + assert lcm.is_Number and lcm is S.One + + lcm = lcm_list([], x, polys=True) + assert lcm.is_Poly and lcm.is_one + + 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 + h, r = x - 1, x**4 + x**3 - x - 1 + + F, G, S, T, H, R = [ Poly(u) for u in (f, g, s, t, h, r) ] + + assert F.cofactors(G) == (H, S, T) + assert F.gcd(G) == H + assert F.lcm(G) == R + + assert cofactors(f, g) == (h, s, t) + assert gcd(f, g) == h + assert lcm(f, g) == r + + assert cofactors(f, g, x) == (h, s, t) + assert gcd(f, g, x) == h + assert lcm(f, g, x) == r + + assert cofactors(f, g, (x,)) == (h, s, t) + assert gcd(f, g, (x,)) == h + assert lcm(f, g, (x,)) == r + + assert cofactors(F, G) == (H, S, T) + assert gcd(F, G) == H + assert lcm(F, G) == R + + assert cofactors(f, g, polys=True) == (H, S, T) + assert gcd(f, g, polys=True) == H + assert lcm(f, g, polys=True) == R + + assert cofactors(F, G, polys=False) == (h, s, t) + assert gcd(F, G, polys=False) == h + assert lcm(F, G, polys=False) == r + + f, g = 1.0*x**2 - 1.0, 1.0*x - 1.0 + h, s, t = g, 1.0*x + 1.0, 1.0 + + assert cofactors(f, g) == (h, s, t) + assert gcd(f, g) == h + assert lcm(f, g) == f + + f, g = 1.0*x**2 - 1.0, 1.0*x - 1.0 + h, s, t = g, 1.0*x + 1.0, 1.0 + + assert cofactors(f, g) == (h, s, t) + assert gcd(f, g) == h + assert lcm(f, g) == f + + assert cofactors(8, 6) == (2, 4, 3) + assert gcd(8, 6) == 2 + assert lcm(8, 6) == 24 + + f, g = x**2 - 3*x - 4, x**3 - 4*x**2 + x - 4 + l = x**4 - 3*x**3 - 3*x**2 - 3*x - 4 + h, s, t = x - 4, x + 1, x**2 + 1 + + assert cofactors(f, g, modulus=11) == (h, s, t) + assert gcd(f, g, modulus=11) == h + assert lcm(f, g, modulus=11) == l + + f, g = x**2 + 8*x + 7, x**3 + 7*x**2 + x + 7 + l = x**4 + 8*x**3 + 8*x**2 + 8*x + 7 + h, s, t = x + 7, x + 1, x**2 + 1 + + assert cofactors(f, g, modulus=11, symmetric=False) == (h, s, t) + assert gcd(f, g, modulus=11, symmetric=False) == h + assert lcm(f, g, modulus=11, symmetric=False) == l + + a, b = sqrt(2), -sqrt(2) + assert gcd(a, b) == gcd(b, a) == sqrt(2) + + a, b = sqrt(-2), -sqrt(-2) + assert gcd(a, b) == gcd(b, a) == sqrt(2) + + assert gcd(Poly(x - 2, x), Poly(I*x, x)) == Poly(1, x, domain=ZZ_I) + + raises(TypeError, lambda: gcd(x)) + raises(TypeError, lambda: lcm(x)) + + f = Poly(-1, x) + g = Poly(1, x) + assert lcm(f, g) == Poly(1, x) + + f = Poly(0, x) + g = Poly([1, 1], x) + for i in (f, g): + assert lcm(i, 0) == 0 + assert lcm(0, i) == 0 + assert lcm(i, f) == 0 + assert lcm(f, i) == 0 + + f = 4*x**2 + x + 2 + pfz = Poly(f, domain=ZZ) + pfq = Poly(f, domain=QQ) + + assert pfz.gcd(pfz) == pfz + assert pfz.lcm(pfz) == pfz + assert pfq.gcd(pfq) == pfq.monic() + assert pfq.lcm(pfq) == pfq.monic() + assert gcd(f, f) == f + assert lcm(f, f) == f + assert gcd(f, f, domain=QQ) == monic(f) + assert lcm(f, f, domain=QQ) == monic(f) + + +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(Rational(3, 2), Rational(9, 4)), Rational) + assert isinstance(gcd(Rational(3, 2)*x, Rational(9, 4)), Rational) + + assert gcd(Rational(3, 2), Rational(9, 4)) == Rational(3, 4) + assert gcd(Rational(3, 2)*x, Rational(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 + + # partial fix of 20597 + assert gcd(Mul(2, 3, evaluate=False), 2) == 2 + + +def test_terms_gcd(): + assert terms_gcd(1) == 1 + assert terms_gcd(1, x) == 1 + + assert terms_gcd(x - 1) == x - 1 + assert terms_gcd(-x - 1) == -x - 1 + + assert terms_gcd(2*x + 3) == 2*x + 3 + assert terms_gcd(6*x + 4) == Mul(2, 3*x + 2, evaluate=False) + + assert terms_gcd(x**3*y + x*y**3) == x*y*(x**2 + y**2) + assert terms_gcd(2*x**3*y + 2*x*y**3) == 2*x*y*(x**2 + y**2) + assert terms_gcd(x**3*y/2 + x*y**3/2) == x*y/2*(x**2 + y**2) + + assert terms_gcd(x**3*y + 2*x*y**3) == x*y*(x**2 + 2*y**2) + assert terms_gcd(2*x**3*y + 4*x*y**3) == 2*x*y*(x**2 + 2*y**2) + assert terms_gcd(2*x**3*y/3 + 4*x*y**3/5) == x*y*Rational(2, 15)*(5*x**2 + 6*y**2) + + assert terms_gcd(2.0*x**3*y + 4.1*x*y**3) == x*y*(2.0*x**2 + 4.1*y**2) + assert _aresame(terms_gcd(2.0*x + 3), 2.0*x + 3) + + 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)) + + eq = Eq(2*x, 2*y + 2*z*y) + assert terms_gcd(eq) == Eq(2*x, 2*y*(z + 1)) + assert terms_gcd(eq, deep=True) == Eq(2*x, 2*y*(z + 1)) + + raises(TypeError, lambda: terms_gcd(x < 2)) + + +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) + + assert F.trunc(3) == G + assert trunc(f, 3) == g + assert trunc(f, 3, x) == g + assert trunc(f, 3, (x,)) == g + assert trunc(F, 3) == G + assert trunc(f, 3, polys=True) == G + assert trunc(F, 3, polys=False) == g + + f, g = 6*x**5 + 5*x**4 + 4*x**3 + 3*x**2 + 2*x + 1, -x**4 + x**3 - x + 1 + F, G = Poly(f), Poly(g) + + assert F.trunc(3) == G + assert trunc(f, 3) == g + assert trunc(f, 3, x) == g + assert trunc(f, 3, (x,)) == g + assert trunc(F, 3) == G + assert trunc(f, 3, polys=True) == G + assert trunc(F, 3, polys=False) == g + + f = Poly(x**2 + 2*x + 3, modulus=5) + + assert f.trunc(2) == Poly(x**2 + 1, modulus=5) + + +def test_monic(): + f, g = 2*x - 1, x - S.Half + F, G = Poly(f, domain='QQ'), Poly(g) + + assert F.monic() == G + assert monic(f) == g + assert monic(f, x) == g + assert monic(f, (x,)) == g + assert monic(F) == G + assert monic(f, polys=True) == G + assert monic(F, polys=False) == g + + raises(ComputationFailed, lambda: monic(4)) + + assert monic(2*x**2 + 6*x + 4, auto=False) == x**2 + 3*x + 2 + raises(ExactQuotientFailed, lambda: monic(2*x + 6*x + 1, auto=False)) + + 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) + + assert F.content() == 2 + assert content(f) == 2 + + raises(ComputationFailed, lambda: content(4)) + + f = Poly(2*x, modulus=3) + + assert f.content() == 1 + + +def test_primitive(): + f, g = 4*x + 2, 2*x + 1 + F, G = Poly(f), Poly(g) + + assert F.primitive() == (2, G) + assert primitive(f) == (2, g) + assert primitive(f, x) == (2, g) + assert primitive(f, (x,)) == (2, g) + assert primitive(F) == (2, G) + assert primitive(f, polys=True) == (2, G) + assert primitive(F, polys=False) == (2, g) + + raises(ComputationFailed, lambda: primitive(4)) + + f = Poly(2*x, modulus=3) + g = Poly(2.0*x, domain=RR) + + assert f.primitive() == (1, f) + assert g.primitive() == (1.0, g) + + 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 + g = x**4 - 2*x + 9 + h = x**3 + 5*x + + F, G, H = map(Poly, (f, g, h)) + + assert G.compose(H) == F + assert compose(g, h) == f + assert compose(g, h, x) == f + assert compose(g, h, (x,)) == f + assert compose(G, H) == F + assert compose(g, h, polys=True) == F + assert compose(G, H, polys=False) == f + + assert F.decompose() == [G, H] + assert decompose(f) == [g, h] + assert decompose(f, x) == [g, h] + assert decompose(f, (x,)) == [g, h] + assert decompose(F) == [G, H] + assert decompose(f, polys=True) == [G, H] + assert decompose(F, polys=False) == [g, h] + + 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, 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_shift_list(): + assert Poly(x*y, [x,y]).shift_list([1,2]) == Poly((x+1)*(y+2), [x,y]) + + +def test_transform(): + # Also test that 3-way unification is done correctly + assert Poly(x**2 - 2*x + 1, x).transform(Poly(x + 1), Poly(x - 1)) == \ + Poly(4, x) == \ + cancel((x - 1)**2*(x**2 - 2*x + 1).subs(x, (x + 1)/(x - 1))) + + assert Poly(x**2 - x/2 + 1, x).transform(Poly(x + 1), Poly(x - 1)) == \ + Poly(3*x**2/2 + Rational(5, 2), x) == \ + cancel((x - 1)**2*(x**2 - x/2 + 1).subs(x, (x + 1)/(x - 1))) + + assert Poly(x**2 - 2*x + 1, x).transform(Poly(x + S.Half), Poly(x - 1)) == \ + Poly(Rational(9, 4), x) == \ + cancel((x - 1)**2*(x**2 - 2*x + 1).subs(x, (x + S.Half)/(x - 1))) + + assert Poly(x**2 - 2*x + 1, x).transform(Poly(x + 1), Poly(x - S.Half)) == \ + Poly(Rational(9, 4), x) == \ + cancel((x - S.Half)**2*(x**2 - 2*x + 1).subs(x, (x + 1)/(x - S.Half))) + + # Unify ZZ, QQ, and RR + assert Poly(x**2 - 2*x + 1, x).transform(Poly(x + 1.0), Poly(x - S.Half)) == \ + Poly(Rational(9, 4), x, domain='RR') == \ + cancel((x - S.Half)**2*(x**2 - 2*x + 1).subs(x, (x + 1.0)/(x - S.Half))) + + raises(ValueError, lambda: Poly(x*y).transform(Poly(x + 1), Poly(x - 1))) + raises(ValueError, lambda: Poly(x).transform(Poly(y + 1), Poly(x - 1))) + raises(ValueError, lambda: Poly(x).transform(Poly(x + 1), Poly(y - 1))) + raises(ValueError, lambda: Poly(x).transform(Poly(x*y + 1), Poly(x - 1))) + raises(ValueError, lambda: Poly(x).transform(Poly(x + 1), Poly(x*y - 1))) + + +def test_sturm(): + f, F = x, Poly(x, domain='QQ') + g, G = 1, Poly(1, x, domain='QQ') + + assert F.sturm() == [F, G] + assert sturm(f) == [f, g] + assert sturm(f, x) == [f, g] + assert sturm(f, (x,)) == [f, g] + assert sturm(F) == [F, G] + assert sturm(f, polys=True) == [F, G] + assert sturm(F, polys=False) == [f, g] + + 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 + + Rational(1, 62500)*x + - Rational(1, 625), x, domain='ZZ(pi)') + + assert sturm(f) == \ + [Poly(x**3 - 100*x**2 + pi**4/64*x - 25*pi**4/16, x, domain='ZZ(pi)'), + Poly(3*x**2 - 200*x + pi**4/64, x, domain='ZZ(pi)'), + Poly((Rational(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 + + assert Poly(f).gff_list() == [(Poly(x), 1), (Poly(x + 2), 4)] + assert gff_list(f) == [(x, 1), (x + 2, 4)] + + raises(NotImplementedError, lambda: gff(f)) + + 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 gff_list(f) == [(x**2 - 5*x + 4, 1), (x**2 - 5*x + 4, 2), (x, 3)] + + raises(NotImplementedError, lambda: gff(f)) + + +def test_norm(): + a, b = sqrt(2), sqrt(3) + f = Poly(a*x + b*y, x, y, extension=(a, b)) + assert f.norm() == Poly(4*x**4 - 12*x**2*y**2 + 9*y**4, x, y, domain='QQ') + + +def test_sqf_norm(): + 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)) == \ + ([1], x**2 - 2*sqrt(2)*x - 1, x**4 - 10*x**2 + 1) + + 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() == \ + ([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 + h = x - 1 + + p = x**4 + x**3 - x - 1 + + F, G, H, P = map(Poly, (f, g, h, p)) + + assert F.sqf_part() == P + assert sqf_part(f) == p + assert sqf_part(f, x) == p + assert sqf_part(f, (x,)) == p + assert sqf_part(F) == P + assert sqf_part(f, polys=True) == P + assert sqf_part(F, polys=False) == p + + assert F.sqf_list() == (1, [(G, 1), (H, 2)]) + assert sqf_list(f) == (1, [(g, 1), (h, 2)]) + assert sqf_list(f, x) == (1, [(g, 1), (h, 2)]) + assert sqf_list(f, (x,)) == (1, [(g, 1), (h, 2)]) + assert sqf_list(F) == (1, [(G, 1), (H, 2)]) + assert sqf_list(f, polys=True) == (1, [(G, 1), (H, 2)]) + assert sqf_list(F, polys=False) == (1, [(g, 1), (h, 2)]) + + assert F.sqf_list_include() == [(G, 1), (H, 2)] + + raises(ComputationFailed, lambda: sqf_part(4)) + + assert sqf(1) == 1 + assert sqf_list(1) == (1, []) + + assert sqf((2*x**2 + 2)**7) == 128*(x**2 + 1)**7 + + assert sqf(f) == g*h**2 + assert sqf(f, x) == g*h**2 + assert sqf(f, (x,)) == g*h**2 + + d = x**2 + y**2 + + assert sqf(f/d) == (g*h**2)/d + assert sqf(f/d, x) == (g*h**2)/d + assert sqf(f/d, (x,)) == (g*h**2)/d + + assert sqf(x - 1) == x - 1 + assert sqf(-x - 1) == -x - 1 + + assert sqf(x - 1) == x - 1 + assert sqf(6*x - 10) == Mul(2, 3*x - 5, evaluate=False) + + assert sqf((6*x - 10)/(3*x - 6)) == Rational(2, 3)*((3*x - 5)/(x - 2)) + assert sqf(Poly(x**2 - 2*x + 1)) == (x - 1)**2 + + f = 3 + x - x*(1 + x) + x**2 + + assert sqf(f) == 3 + + f = (x**2 + 2*x + 1)**20000000000 + + assert sqf(f) == (x + 1)**40000000000 + assert sqf_list(f) == (1, [(x + 1, 40000000000)]) + + # https://github.com/sympy/sympy/issues/26497 + assert sqf(expand(((y - 2)**2 * (y + 2) * (x + 1)))) == \ + (y - 2)**2 * expand((y + 2) * (x + 1)) + assert sqf(expand(((y - 2)**2 * (y + 2) * (z + 1)))) == \ + (y - 2)**2 * expand((y + 2) * (z + 1)) + assert sqf(expand(((y - I)**2 * (y + I) * (x + 1)))) == \ + (y - I)**2 * expand((y + I) * (x + 1)) + assert sqf(expand(((y - I)**2 * (y + I) * (z + 1)))) == \ + (y - I)**2 * expand((y + I) * (z + 1)) + + # Check that factors are combined and sorted. + p = (x - 2)**2*(x - 1)*(x + y)**2*(y - 2)**2*(y - 1) + assert Poly(p).sqf_list() == (1, [ + (Poly(x*y - x - y + 1), 1), + (Poly(x**2*y - 2*x**2 + x*y**2 - 4*x*y + 4*x - 2*y**2 + 4*y), 2) + ]) + + +def test_factor(): + f = x**5 - x**3 - x**2 + 1 + + u = x + 1 + v = x - 1 + w = x**2 + x + 1 + + F, U, V, W = map(Poly, (f, u, v, w)) + + assert F.factor_list() == (1, [(U, 1), (V, 2), (W, 1)]) + assert factor_list(f) == (1, [(u, 1), (v, 2), (w, 1)]) + assert factor_list(f, x) == (1, [(u, 1), (v, 2), (w, 1)]) + assert factor_list(f, (x,)) == (1, [(u, 1), (v, 2), (w, 1)]) + assert factor_list(F) == (1, [(U, 1), (V, 2), (W, 1)]) + assert factor_list(f, polys=True) == (1, [(U, 1), (V, 2), (W, 1)]) + assert factor_list(F, polys=False) == (1, [(u, 1), (v, 2), (w, 1)]) + + assert F.factor_list_include() == [(U, 1), (V, 2), (W, 1)] + + assert factor_list(1) == (1, []) + assert factor_list(6) == (6, []) + assert factor_list(sqrt(3), x) == (sqrt(3), []) + 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(6) == 6 and factor(6).is_Integer + + assert factor_list(3*x) == (3, [(x, 1)]) + assert factor_list(3*x**2) == (3, [(x, 2)]) + + assert factor(3*x) == 3*x + assert factor(3*x**2) == 3*x**2 + + assert factor((2*x**2 + 2)**7) == 128*(x**2 + 1)**7 + + assert factor(f) == u*v**2*w + assert factor(f, x) == u*v**2*w + assert factor(f, (x,)) == u*v**2*w + + g, p, q, r = x**2 - y**2, x - y, x + y, x**2 + 1 + + assert factor(f/g) == (u*v**2*w)/(p*q) + assert factor(f/g, x) == (u*v**2*w)/(p*q) + assert factor(f/g, (x,)) == (u*v**2*w)/(p*q) + + p = Symbol('p', positive=True) + i = Symbol('i', integer=True) + r = Symbol('r', real=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) + + assert factor((y*x**2 - y)**i) == y**i*(x - 1)**i*(x + 1)**i + assert factor((y*x**2 + y)**i) == y**i*(x**2 + 1)**i + + assert factor((y*x**2 - y)**t) == (y*(x - 1)*(x + 1))**t + assert factor((y*x**2 + y)**t) == (y*(x**2 + 1))**t + + f = sqrt(expand((r**2 + 1)*(p + 1)*(p - 1)*(p - 2)**3)) + g = sqrt((p - 2)**3*(p - 1))*sqrt(p + 1)*sqrt(r**2 + 1) + + assert factor(f) == g + assert factor(g) == g + + g = (x - 1)**5*(r**2 + 1) + f = sqrt(expand(g)) + + assert factor(f) == sqrt(g) + + f = Poly(sin(1)*x + 1, x, domain=EX) + + assert f.factor_list() == (1, [(f, 1)]) + + f = x**4 + 1 + + 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(x**2 + 4*I*x - 4) == (x + 2*I)**2 + + f = x**2 + 2*I*x - 4 + + assert factor(f) == f + + f = 8192*x**2 + x*(22656 + 175232*I) - 921416 + 242313*I + f_zzi = I*(x*(64 - 64*I) + 773 + 596*I)**2 + f_qqi = 8192*(x + S(177)/128 + 1369*I/128)**2 + + assert factor(f) == f_zzi + assert factor(f, domain=ZZ_I) == f_zzi + assert factor(f, domain=QQ_I) == f_qqi + + f = x**2 + 2*sqrt(2)*x + 2 + + assert factor(f, extension=sqrt(2)) == (x + sqrt(2))**2 + assert factor(f**3, extension=sqrt(2)) == (x + sqrt(2))**6 + + assert factor(x**2 - 2*y**2, extension=sqrt(2)) == \ + (x + sqrt(2)*y)*(x - sqrt(2)*y) + assert factor(2*x**2 - 4*y**2, extension=sqrt(2)) == \ + 2*((x + sqrt(2)*y)*(x - sqrt(2)*y)) + + 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) + + f = x/pi + x*sin(x)/pi + g = y/(pi**2 + 2*pi + 1) + y*sin(x)/(pi**2 + 2*pi + 1) + + 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)) + + f = (x**2 - 1)/(x**2 + 4*x + 4) + + assert factor(f) == (x + 1)*(x - 1)/(x + 2)**2 + assert factor(f, x) == (x + 1)*(x - 1)/(x + 2)**2 + + f = 3 + x - x*(1 + x) + x**2 + + 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(f, expand=False) == f + raises(PolynomialError, lambda: factor(f, x, expand=False)) + + raises(FlagError, lambda: factor(x**2 - 1, polys=True)) + + 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) is True + assert isinstance( + PurePoly(x**3 + x + 1).factor_list()[1][0][0], PurePoly) is True + + assert factor(sqrt(-x)) == sqrt(-x) + + # issue 5917 + e = (-2*x*(-x + 1)*(x - 1)*(-x*(-x + 1)*(x - 1) - x*(x - 1)**2)*(x**2*(x - + 1) - x*(x - 1) - x) - (-2*x**2*(x - 1)**2 - x*(-x + 1)*(-x*(-x + 1) + + 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 + assert factor(sin(x**2 + x)*x, deep=True) == sin(x*(x + 1))*x + + assert factor(sqrt(x**2)) == sqrt(x**2) + + # issue 13149 + assert factor(expand((0.5*x+1)*(0.5*y+1))) == Mul(1.0, 0.5*x + 1.0, + 0.5*y + 1.0, evaluate = False) + assert factor(expand((0.5*x+0.5)**2)) == 0.25*(1.0*x + 1.0)**2 + + eq = x**2*y**2 + 11*x**2*y + 30*x**2 + 7*x*y**2 + 77*x*y + 210*x + 12*y**2 + 132*y + 360 + assert factor(eq, x) == (x + 3)*(x + 4)*(y**2 + 11*y + 30) + assert factor(eq, x, deep=True) == (x + 3)*(x + 4)*(y**2 + 11*y + 30) + assert factor(eq, y, deep=True) == (y + 5)*(y + 6)*(x**2 + 7*x + 12) + + # fraction option + f = 5*x + 3*exp(2 - 7*x) + assert factor(f, deep=True) == factor(f, deep=True, fraction=True) + assert factor(f, deep=True, fraction=False) == 5*x + 3*exp(2)*exp(-7*x) + + assert factor_list(x**3 - x*y**2, t, w, x) == ( + 1, [(x, 1), (x - y, 1), (x + y, 1)]) + assert factor_list((x+1)*(x**6-1)) == ( + 1, [(x - 1, 1), (x + 1, 2), (x**2 - x + 1, 1), (x**2 + x + 1, 1)]) + + # https://github.com/sympy/sympy/issues/24952 + s2, s2p, s2n = sqrt(2), 1 + sqrt(2), 1 - sqrt(2) + pip, pin = 1 + pi, 1 - pi + assert factor_list(s2p*s2n) == (-1, [(-s2n, 1), (s2p, 1)]) + assert factor_list(pip*pin) == (-1, [(-pin, 1), (pip, 1)]) + # Not sure about this one. Maybe coeff should be 1 or -1? + assert factor_list(s2*s2n) == (-s2, [(-s2n, 1)]) + assert factor_list(pi*pin) == (-1, [(-pin, 1), (pi, 1)]) + assert factor_list(s2p*s2n, x) == (s2p*s2n, []) + assert factor_list(pip*pin, x) == (pip*pin, []) + assert factor_list(s2*s2n, x) == (s2*s2n, []) + assert factor_list(pi*pin, x) == (pi*pin, []) + assert factor_list((x - sqrt(2)*pi)*(x + sqrt(2)*pi), x) == ( + 1, [(x - sqrt(2)*pi, 1), (x + sqrt(2)*pi, 1)]) + + # https://github.com/sympy/sympy/issues/26497 + p = ((y - I)**2 * (y + I) * (x + 1)) + assert factor(expand(p)) == p + + p = ((x - I)**2 * (x + I) * (y + 1)) + assert factor(expand(p)) == p + + p = (y + 1)**2*(y + sqrt(2))**2*(x**2 + x + 2 + 3*sqrt(2))**2 + assert factor(expand(p), extension=True) == p + + e = ( + -x**2*y**4/(y**2 + 1) + 2*I*x**2*y**3/(y**2 + 1) + 2*I*x**2*y/(y**2 + 1) + + x**2/(y**2 + 1) - 2*x*y**4/(y**2 + 1) + 4*I*x*y**3/(y**2 + 1) + + 4*I*x*y/(y**2 + 1) + 2*x/(y**2 + 1) - y**4 - y**4/(y**2 + 1) + 2*I*y**3 + + 2*I*y**3/(y**2 + 1) + 2*I*y + 2*I*y/(y**2 + 1) + 1 + 1/(y**2 + 1) + ) + assert factor(e) == -(y - I)**3*(y + I)*(x**2 + 2*x + y**2 + 2)/(y**2 + 1) + + # issue 27506 + e = (I*t*x*y - 3*I*t - I*x*y*z - 6*x*y + 3*I*z + 18) + assert factor(e) == -I*(x*y - 3)*(-t + z - 6*I) + + e = (8*x**2*z**2 - 32*x**2*z*t + 24*x**2*t**2 - 4*I*x*y*z**2 + 16*I*x*y*z*t - + 12*I*x*y*t**2 + z**4 - 8*z**3*t + 22*z**2*t**2 - 24*z*t**3 + 9*t**4) + assert factor(e) == (-3*t + z)*(-t + z)*(3*t**2 - 4*t*z + 8*x**2 - 4*I*x*y + z**2) + + +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) + + 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(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) + 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) + + 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)]) + 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)]) + + +def test_factor_noeval(): + assert factor(6*x - 10) == Mul(2, 3*x - 5, evaluate=False) + assert factor((6*x - 10)/(3*x - 6)) == Mul(Rational(2, 3), 3*x - 5, 1/(x - 2)) + + +def test_intervals(): + assert intervals(0) == [] + assert intervals(1) == [] + + assert intervals(x, sqf=True) == [(0, 0)] + assert intervals(x) == [((0, 0), 1)] + + assert intervals(x**128) == [((0, 0), 128)] + assert intervals([x**2, x**4]) == [((0, 0), {0: 2, 1: 4})] + + f = Poly((x*Rational(2, 5) - Rational(17, 3))*(4*x + Rational(1, 257))) + + assert f.intervals(sqf=True) == [(-1, 0), (14, 15)] + assert f.intervals() == [((-1, 0), 1), ((14, 15), 1)] + + assert f.intervals(fast=True, sqf=True) == [(-1, 0), (14, 15)] + assert f.intervals(fast=True) == [((-1, 0), 1), ((14, 15), 1)] + + assert f.intervals(eps=Rational(1, 10)) == f.intervals(eps=0.1) == \ + [((Rational(-1, 258), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] + assert f.intervals(eps=Rational(1, 100)) == f.intervals(eps=0.01) == \ + [((Rational(-1, 258), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] + assert f.intervals(eps=Rational(1, 1000)) == f.intervals(eps=0.001) == \ + [((Rational(-1, 1002), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] + assert f.intervals(eps=Rational(1, 10000)) == f.intervals(eps=0.0001) == \ + [((Rational(-1, 1028), Rational(-1, 1028)), 1), ((Rational(85, 6), Rational(85, 6)), 1)] + + f = (x*Rational(2, 5) - Rational(17, 3))*(4*x + Rational(1, 257)) + + assert intervals(f, sqf=True) == [(-1, 0), (14, 15)] + assert intervals(f) == [((-1, 0), 1), ((14, 15), 1)] + + assert intervals(f, eps=Rational(1, 10)) == intervals(f, eps=0.1) == \ + [((Rational(-1, 258), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] + assert intervals(f, eps=Rational(1, 100)) == intervals(f, eps=0.01) == \ + [((Rational(-1, 258), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] + assert intervals(f, eps=Rational(1, 1000)) == intervals(f, eps=0.001) == \ + [((Rational(-1, 1002), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] + assert intervals(f, eps=Rational(1, 10000)) == intervals(f, eps=0.0001) == \ + [((Rational(-1, 1028), Rational(-1, 1028)), 1), ((Rational(85, 6), Rational(85, 6)), 1)] + + f = Poly((x**2 - 2)*(x**2 - 3)**7*(x + 1)*(7*x + 3)**3) + + assert f.intervals() == \ + [((-2, Rational(-3, 2)), 7), ((Rational(-3, 2), -1), 1), + ((-1, -1), 1), ((-1, 0), 3), + ((1, Rational(3, 2)), 1), ((Rational(3, 2), 2), 7)] + + assert intervals([x**5 - 200, x**5 - 201]) == \ + [((Rational(75, 26), Rational(101, 35)), {0: 1}), ((Rational(309, 107), Rational(26, 9)), {1: 1})] + + assert intervals([x**5 - 200, x**5 - 201], fast=True) == \ + [((Rational(75, 26), Rational(101, 35)), {0: 1}), ((Rational(309, 107), Rational(26, 9)), {1: 1})] + + assert intervals([x**2 - 200, x**2 - 201]) == \ + [((Rational(-71, 5), Rational(-85, 6)), {1: 1}), ((Rational(-85, 6), -14), {0: 1}), + ((14, Rational(85, 6)), {0: 1}), ((Rational(85, 6), Rational(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})] + + f, g, h = x**2 - 2, x**4 - 4*x**2 + 4, x - 1 + + assert intervals(f, inf=Rational(7, 4), sqf=True) == [] + assert intervals(f, inf=Rational(7, 5), sqf=True) == [(Rational(7, 5), Rational(3, 2))] + assert intervals(f, sup=Rational(7, 4), sqf=True) == [(-2, -1), (1, Rational(3, 2))] + assert intervals(f, sup=Rational(7, 5), sqf=True) == [(-2, -1)] + + assert intervals(g, inf=Rational(7, 4)) == [] + assert intervals(g, inf=Rational(7, 5)) == [((Rational(7, 5), Rational(3, 2)), 2)] + assert intervals(g, sup=Rational(7, 4)) == [((-2, -1), 2), ((1, Rational(3, 2)), 2)] + assert intervals(g, sup=Rational(7, 5)) == [((-2, -1), 2)] + + assert intervals([g, h], inf=Rational(7, 4)) == [] + assert intervals([g, h], inf=Rational(7, 5)) == [((Rational(7, 5), Rational(3, 2)), {0: 2})] + assert intervals([g, h], sup=S( + 7)/4) == [((-2, -1), {0: 2}), ((1, 1), {1: 1}), ((1, Rational(3, 2)), {0: 2})] + assert intervals( + [g, h], sup=Rational(7, 5)) == [((-2, -1), {0: 2}), ((1, 1), {1: 1})] + + 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) == \ + [((-2, -2), {0: 1}), ((Rational(-3, 2), -1), {1: 1}), ((1, 2), {1: 1})] + + f = 7*z**4 - 19*z**3 + 20*z**2 + 17*z + 20 + + assert intervals(f) == [] + + 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 complex_part == [(Rational(-40, 7) - I*40/7, 0), + (Rational(-40, 7), I*40/7), + (I*Rational(-40, 7), Rational(40, 7)), + (0, Rational(40, 7) + I*40/7)] + + real_part, complex_part = intervals(f, all=True, sqf=True, eps=Rational(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))) + + 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)) + + +def test_refine_root(): + f = Poly(x**2 - 2) + + assert f.refine_root(1, 2, steps=0) == (1, 2) + assert f.refine_root(-2, -1, steps=0) == (-2, -1) + + assert f.refine_root(1, 2, steps=None) == (1, Rational(3, 2)) + assert f.refine_root(-2, -1, steps=None) == (Rational(-3, 2), -1) + + assert f.refine_root(1, 2, steps=1) == (1, Rational(3, 2)) + assert f.refine_root(-2, -1, steps=1) == (Rational(-3, 2), -1) + + assert f.refine_root(1, 2, steps=1, fast=True) == (1, Rational(3, 2)) + assert f.refine_root(-2, -1, steps=1, fast=True) == (Rational(-3, 2), -1) + + assert f.refine_root(1, 2, eps=Rational(1, 100)) == (Rational(24, 17), Rational(17, 12)) + assert f.refine_root(1, 2, eps=1e-2) == (Rational(24, 17), Rational(17, 12)) + + raises(PolynomialError, lambda: (f**2).refine_root(1, 2, check_sqf=True)) + + raises(RefinementFailed, lambda: (f**2).refine_root(1, 2)) + raises(RefinementFailed, lambda: (f**2).refine_root(2, 3)) + + f = x**2 - 2 + + assert refine_root(f, 1, 2, steps=1) == (1, Rational(3, 2)) + assert refine_root(f, -2, -1, steps=1) == (Rational(-3, 2), -1) + + assert refine_root(f, 1, 2, steps=1, fast=True) == (1, Rational(3, 2)) + assert refine_root(f, -2, -1, steps=1, fast=True) == (Rational(-3, 2), -1) + + assert refine_root(f, 1, 2, eps=Rational(1, 100)) == (Rational(24, 17), Rational(17, 12)) + assert refine_root(f, 1, 2, eps=1e-2) == (Rational(24, 17), Rational(17, 12)) + + raises(PolynomialError, lambda: refine_root(1, 7, 8, eps=Rational(1, 100))) + + 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 + + assert count_roots(x**2 - 2, inf=-oo) == 2 + assert count_roots(x**2 - 2, sup=+oo) == 2 + assert count_roots(x**2 - 2, inf=-oo, sup=+oo) == 2 + + assert count_roots(x**2 - 2, inf=-2) == 2 + assert count_roots(x**2 - 2, inf=-1) == 1 + + assert count_roots(x**2 - 2, sup=1) == 1 + assert count_roots(x**2 - 2, sup=2) == 2 + + assert count_roots(x**2 - 2, inf=-1, sup=1) == 0 + assert count_roots(x**2 - 2, inf=-2, sup=2) == 2 + + assert count_roots(x**2 - 2, inf=-1, sup=1) == 0 + assert count_roots(x**2 - 2, inf=-2, sup=2) == 2 + + assert count_roots(x**2 + 2) == 0 + assert count_roots(x**2 + 2, inf=-2*I) == 2 + assert count_roots(x**2 + 2, sup=+2*I) == 2 + assert count_roots(x**2 + 2, inf=-2*I, sup=+2*I) == 2 + + assert count_roots(x**2 + 2, inf=0) == 0 + assert count_roots(x**2 + 2, sup=0) == 0 + + assert count_roots(x**2 + 2, inf=-I) == 1 + assert count_roots(x**2 + 2, sup=+I) == 1 + + assert count_roots(x**2 + 2, inf=+I/2, sup=+I) == 0 + assert count_roots(x**2 + 2, inf=-I, sup=-I/2) == 0 + + raises(PolynomialError, lambda: count_roots(1)) + + +def test_count_roots_extension(): + + p1 = Poly(sqrt(2)*x**2 - 2, x, extension=True) + assert p1.count_roots() == 2 + assert p1.count_roots(inf=0) == 1 + assert p1.count_roots(sup=0) == 1 + + p2 = Poly(x**2 + sqrt(2), x, extension=True) + assert p2.count_roots() == 0 + + p3 = Poly(x**2 + 2*sqrt(2)*x + 1, x, extension=True) + assert p3.count_roots() == 2 + assert p3.count_roots(inf=-10, sup=10) == 2 + assert p3.count_roots(inf=-10, sup=0) == 2 + assert p3.count_roots(inf=-10, sup=-3) == 0 + assert p3.count_roots(inf=-3, sup=-2) == 1 + assert p3.count_roots(inf=-1, sup=0) == 1 + + +def test_Poly_root(): + f = Poly(2*x**3 - 7*x**2 + 4*x + 4) + + assert f.root(0) == Rational(-1, 2) + assert f.root(1) == 2 + assert f.root(2) == 2 + raises(IndexError, lambda: f.root(3)) + + 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)] + + assert real_roots(x**3) == [0, 0, 0] + 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**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**2 - 2, radicals=False) == [ + rootof(x**2 - 2, 0, radicals=False), + rootof(x**2 - 2, 1, radicals=False), + ] + + f = 2*x**3 - 7*x**2 + 4*x + 4 + g = x**3 + x + 1 + + assert Poly(f).real_roots() == [Rational(-1, 2), 2, 2] + assert Poly(g).real_roots() == [rootof(g, 0)] + + # testing extension + f = x**2 - sqrt(2) + roots = [-2**(S(1)/4), 2**(S(1)/4)] + raises(NotImplementedError, lambda: real_roots(f)) + raises(NotImplementedError, lambda: real_roots(Poly(f, x))) + assert real_roots(f, extension=True) == roots + assert real_roots(Poly(f, extension=True)) == roots + assert real_roots(Poly(f), extension=True) == roots + + +def test_all_roots(): + + f = 2*x**3 - 7*x**2 + 4*x + 4 + froots = [Rational(-1, 2), 2, 2] + assert all_roots(f) == Poly(f).all_roots() == froots + + g = x**3 + x + 1 + groots = [rootof(g, 0), rootof(g, 1), rootof(g, 2)] + assert all_roots(g) == Poly(g).all_roots() == groots + + assert all_roots(x**2 - 2) == [-sqrt(2), sqrt(2)] + assert all_roots(x**2 - 2, multiple=False) == [(-sqrt(2), 1), (sqrt(2), 1)] + assert all_roots(x**2 - 2, radicals=False) == [ + rootof(x**2 - 2, 0, radicals=False), + rootof(x**2 - 2, 1, radicals=False), + ] + + p = x**5 - x - 1 + assert all_roots(p) == [ + rootof(p, 0), rootof(p, 1), rootof(p, 2), rootof(p, 3), rootof(p, 4) + ] + + # testing extension + f = x**2 + sqrt(2) + roots = [-2**(S(1)/4)*I, 2**(S(1)/4)*I] + raises(NotImplementedError, lambda: all_roots(f)) + raises(NotImplementedError, lambda : all_roots(Poly(f, x))) + assert all_roots(f, extension=True) == roots + assert all_roots(Poly(f, extension=True)) == roots + assert all_roots(Poly(f), extension=True) == roots + + +def test_nroots(): + assert Poly(0, x).nroots() == [] + assert Poly(1, x).nroots() == [] + + assert Poly(x**2 - 1, x).nroots() == [-1.0, 1.0] + assert Poly(x**2 + 1, x).nroots() == [-1.0*I, 1.0*I] + + roots = Poly(x**2 - 1, x).nroots() + assert roots == [-1.0, 1.0] + + roots = Poly(x**2 + 1, x).nroots() + assert roots == [-1.0*I, 1.0*I] + + roots = Poly(x**2/3 - Rational(1, 3), x).nroots() + assert roots == [-1.0, 1.0] + + roots = Poly(x**2/3 + Rational(1, 3), x).nroots() + assert roots == [-1.0*I, 1.0*I] + + 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(0.2*x + 0.1).nroots() == [-0.5] + + roots = nroots(x**5 + x + 1, n=5) + eps = Float("1e-5") + + assert re(roots[0]).epsilon_eq(-0.75487, eps) is S.true + assert im(roots[0]) == 0 + assert re(roots[1]) == Float(-0.5, 5) + assert im(roots[1]).epsilon_eq(-0.86602, eps) is S.true + assert re(roots[2]) == Float(-0.5, 5) + assert im(roots[2]).epsilon_eq(+0.86602, eps) is S.true + assert re(roots[3]).epsilon_eq(+0.87743, eps) is S.true + assert im(roots[3]).epsilon_eq(-0.74486, eps) is S.true + assert re(roots[4]).epsilon_eq(+0.87743, eps) is S.true + assert im(roots[4]).epsilon_eq(+0.74486, eps) is S.true + + eps = Float("1e-6") + + assert re(roots[0]).epsilon_eq(-0.75487, eps) is S.false + assert im(roots[0]) == 0 + assert re(roots[1]) == Float(-0.5, 5) + assert im(roots[1]).epsilon_eq(-0.86602, eps) is S.false + assert re(roots[2]) == Float(-0.5, 5) + assert im(roots[2]).epsilon_eq(+0.86602, eps) is S.false + assert re(roots[3]).epsilon_eq(+0.87743, eps) is S.false + assert im(roots[3]).epsilon_eq(-0.74486, eps) is S.false + assert re(roots[4]).epsilon_eq(+0.87743, eps) is S.false + assert im(roots[4]).epsilon_eq(+0.74486, eps) is S.false + + raises(DomainError, lambda: Poly(x + y, x).nroots()) + raises(MultivariatePolynomialError, lambda: Poly(x + y).nroots()) + + assert nroots(x**2 - 1) == [-1.0, 1.0] + + roots = nroots(x**2 - 1) + assert roots == [-1.0, 1.0] + + assert nroots(x + I) == [-1.0*I] + assert nroots(x + 2*I) == [-2.0*I] + + raises(PolynomialError, lambda: nroots(0)) + + # issue 8296 + f = Poly(x**4 - 1) + assert f.nroots(2) == [w.n(2) for w in f.all_roots()] + + assert str(Poly(x**16 + 32*x**14 + 508*x**12 + 5440*x**10 + + 39510*x**8 + 204320*x**6 + 755548*x**4 + 1434496*x**2 + + 877969).nroots(2)) == ('[-1.7 - 1.9*I, -1.7 + 1.9*I, -1.7 ' + '- 2.5*I, -1.7 + 2.5*I, -1.0*I, 1.0*I, -1.7*I, 1.7*I, -2.8*I, ' + '2.8*I, -3.4*I, 3.4*I, 1.7 - 1.9*I, 1.7 + 1.9*I, 1.7 - 2.5*I, ' + '1.7 + 2.5*I]') + assert str(Poly(1e-15*x**2 -1).nroots()) == ('[-31622776.6016838, 31622776.6016838]') + + # https://github.com/sympy/sympy/issues/23861 + + i = Float('3.000000000000000000000000000000000000000000000000001') + [r] = nroots(x + I*i, n=300) + assert abs(r + I*i) < 1e-300 + + +def test_ground_roots(): + f = x**6 - 4*x**4 + 4*x**3 - x**2 + + assert Poly(f).ground_roots() == {S.One: 2, S.Zero: 2} + assert ground_roots(f) == {S.One: 2, S.Zero: 2} + + +def test_nth_power_roots_poly(): + f = x**4 - x**2 + 1 + + f_2 = (x**2 - x + 1)**2 + f_3 = (x**2 + 1)**2 + f_4 = (x**2 + x + 1)**2 + f_12 = (x - 1)**4 + + assert nth_power_roots_poly(f, 1) == f + + raises(ValueError, lambda: nth_power_roots_poly(f, 0)) + raises(ValueError, lambda: nth_power_roots_poly(f, x)) + + assert factor(nth_power_roots_poly(f, 2)) == f_2 + assert factor(nth_power_roots_poly(f, 3)) == f_3 + 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)) + +def test_which_real_roots(): + f = Poly(x**4 - 1) + + assert f.which_real_roots([1, -1]) == [1, -1] + assert f.which_real_roots([1, -1, 2, 4]) == [1, -1] + assert f.which_real_roots([1, -1, -1, 1, 2, 5]) == [1, -1] + assert f.which_real_roots([10, 8, 7, -1, 1]) == [-1, 1] + + # no real roots + # (technically its still a superset) + f = Poly(x**2 + 1) + assert f.which_real_roots([5, 10]) == [] + + # not square free + f = Poly((x-1)**2) + assert f.which_real_roots([1, 1, -1, 2]) == [1] + + # candidates not superset + f = Poly(x**2 - 1) + assert f.which_real_roots([0, 2]) == [0, 2] + +def test_which_all_roots(): + f = Poly(x**4 - 1) + + assert f.which_all_roots([1, -1, I, -I]) == [1, -1, I, -I] + assert f.which_all_roots([I, I, -I, 1, -1]) == [I, -I, 1, -1] + + f = Poly(x**2 + 1) + assert f.which_all_roots([I, -I, I/2]) == [I, -I] + + # not square free + f = Poly((x-I)**2) + assert f.which_all_roots([I, I, 1, -1, 0]) == [I] + + # candidates not superset + f = Poly(x**2 + 1) + assert f.which_all_roots([I/2, -I/2]) == [I/2, -I/2] + +def test_same_root(): + f = Poly(x**4 + x**3 + x**2 + x + 1) + eq = f.same_root + r0 = exp(2 * I * pi / 5) + assert [i for i, r in enumerate(f.all_roots()) if eq(r, r0)] == [3] + + raises(PolynomialError, + lambda: Poly(x + 1, domain=QQ).same_root(0, 0)) + raises(DomainError, + lambda: Poly(x**2 + 1, domain=FF(7)).same_root(0, 0)) + raises(DomainError, + lambda: Poly(x ** 2 + 1, domain=ZZ_I).same_root(0, 0)) + raises(DomainError, + lambda: Poly(y * x**2 + 1, domain=ZZ[y]).same_root(0, 0)) + raises(MultivariatePolynomialError, + lambda: Poly(x * y + 1, domain=ZZ).same_root(0, 0)) + + +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 + assert cancel(7) == 7 + assert cancel(x) == x + + assert cancel(oo) is oo + + raises(ValueError, lambda: cancel((1, 2, 3))) + + # test first tuple returnr + assert (t:=cancel((2, 3))) == (1, 2, 3) + assert isinstance(t, tuple) + + # tests 2nd tuple return + assert (t:=cancel((1, 0), x)) == (1, 1, 0) + assert isinstance(t, tuple) + 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 = [ Poly(u, x) for u in (f, g, p, q) ] + + assert F.cancel(G) == (1, P, Q) + assert cancel((f, g)) == (1, p, q) + assert cancel((f, g), x) == (1, p, q) + assert cancel((f, g), (x,)) == (1, p, q) + # tests 3rd tuple return + assert (t:=cancel((F, G))) == (1, P, Q) + assert isinstance(t, tuple) + assert cancel((f, g), polys=True) == (1, P, Q) + assert cancel((F, G), polys=False) == (1, p, q) + + f = (x**2 - 2)/(x + sqrt(2)) + + assert cancel(f) == f + assert cancel(f, greedy=False) == x - sqrt(2) + + f = (x**2 - 2)/(x - sqrt(2)) + + assert cancel(f) == f + assert cancel(f, greedy=False) == x + sqrt(2) + + assert cancel((x**2/4 - 1, x/2 - 1)) == (1, x + 2, 2) + # assert cancel((x**2/4 - 1, x/2 - 1)) == (S.Half, x + 2, 1) + + 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**3 - 1)/(x**2 - 1)) == (x**2 + x + 1)/(x + 1) + assert cancel((x**3/2 - S.Half)/(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 + + f = Poly(x**2 - a**2, x) + g = Poly(x - a, x) + + F = Poly(x + a, x, domain='ZZ[a]') + G = Poly(1, x, domain='ZZ[a]') + + assert cancel((f, g)) == (1, F, G) + + f = x**3 + (sqrt(2) - 2)*x**2 - (2*sqrt(2) + 3)*x - 3*sqrt(2) + g = x**2 - 2 + + assert cancel((f, g), extension=True) == (1, x**2 - 2*x - 3, x - sqrt(2)) + + f = Poly(-2*x + 3, x) + g = Poly(-x**9 + x**8 + x**6 - x**5 + 2*x**2 - 3*x + 1, x) + + assert cancel((f, g)) == (1, -f, -g) + + f = Poly(x/3 + 1, x) + g = Poly(x/7 + 1, x) + + assert f.cancel(g) == (S(7)/3, + Poly(x + 3, x, domain=QQ), + Poly(x + 7, x, domain=QQ)) + assert f.cancel(g, include=True) == ( + Poly(7*x + 21, x, domain=QQ), + Poly(3*x + 21, x, domain=QQ)) + + pairs = [ + (1 + x, 1 + x, 1, 1, 1), + (1 + x, 1 - x, -1, -1-x, -1+x), + (1 - x, 1 + x, -1, 1-x, 1+x), + (1 - x, 1 - x, 1, 1, 1), + ] + for f, g, coeff, p, q in pairs: + assert cancel((f, g)) == (1, p, q) + pf = Poly(f, x) + pg = Poly(g, x) + pp = Poly(p, x) + pq = Poly(q, x) + assert pf.cancel(pg) == (coeff, coeff*pp, pq) + assert pf.rep.cancel(pg.rep) == (pp.rep, pq.rep) + assert pf.rep.cancel(pg.rep, include=True) == (pp.rep, pq.rep) + + 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)')) + + 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)')) + + f = -(-2*x - 4*y + 0.005*(z - y)**2)/((z - y)*(-z + y + 2)) + assert cancel(f).is_Mul == True + + P = tanh(x - 3.0) + Q = tanh(x + 3.0) + f = ((-2*P**2 + 2)*(-P**2 + 1)*Q**2/2 + (-2*P**2 + 2)*(-2*Q**2 + 2)*P*Q - (-2*P**2 + 2)*P**2*Q**2 + (-2*Q**2 + 2)*(-Q**2 + 1)*P**2/2 - (-2*Q**2 + 2)*P**2*Q**2)/(2*sqrt(P**2*Q**2 + 0.0001)) \ + + (-(-2*P**2 + 2)*P*Q**2/2 - (-2*Q**2 + 2)*P**2*Q/2)*((-2*P**2 + 2)*P*Q**2/2 + (-2*Q**2 + 2)*P**2*Q/2)/(2*(P**2*Q**2 + 0.0001)**Rational(3, 2)) + assert cancel(f).is_Mul == True + + # issue 7022 + A = Symbol('A', commutative=False) + p1 = Piecewise((A*(x**2 - 1)/(x + 1), x > 1), ((x + 2)/(x**2 + 2*x), True)) + p2 = Piecewise((A*(x - 1), x > 1), (1/x, True)) + assert cancel(p1) == p2 + assert cancel(2*p1) == 2*p2 + assert cancel(1 + p1) == 1 + p2 + assert cancel((x**2 - 1)/(x + 1)*p1) == (x - 1)*p2 + assert cancel((x**2 - 1)/(x + 1) + p1) == (x - 1) + p2 + p3 = Piecewise(((x**2 - 1)/(x + 1), x > 1), ((x + 2)/(x**2 + 2*x), True)) + p4 = Piecewise(((x - 1), x > 1), (1/x, True)) + assert cancel(p3) == p4 + assert cancel(2*p3) == 2*p4 + assert cancel(1 + p3) == 1 + p4 + assert cancel((x**2 - 1)/(x + 1)*p3) == (x - 1)*p4 + assert cancel((x**2 - 1)/(x + 1) + p3) == (x - 1) + p4 + + # issue 4077 + q = S('''(2*1*(x - 1/x)/(x*(2*x - (-x + 1/x)/(x**2*(x - 1/x)**2) - 1/(x**2*(x - + 1/x)) - 2/x)) - 2*1*((x - 1/x)/((x*(x - 1/x)**2)) - 1/(x*(x - + 1/x)))*((-x + 1/x)*((x - 1/x)/((x*(x - 1/x)**2)) - 1/(x*(x - + 1/x)))/(2*x - (-x + 1/x)/(x**2*(x - 1/x)**2) - 1/(x**2*(x - 1/x)) - + 2/x) + 1)*((x - 1/x)/((x - 1/x)**2) - ((x - 1/x)/((x*(x - 1/x)**2)) - + 1/(x*(x - 1/x)))**2/(2*x - (-x + 1/x)/(x**2*(x - 1/x)**2) - 1/(x**2*(x + - 1/x)) - 2/x) - 1/(x - 1/x))*(2*x - (-x + 1/x)/(x**2*(x - 1/x)**2) - + 1/(x**2*(x - 1/x)) - 2/x)/x - 1/x)*(((-x + 1/x)/((x*(x - 1/x)**2)) + + 1/(x*(x - 1/x)))*((-(x - 1/x)/(x*(x - 1/x)) - 1/x)*((x - 1/x)/((x*(x - + 1/x)**2)) - 1/(x*(x - 1/x)))/(2*x - (-x + 1/x)/(x**2*(x - 1/x)**2) - + 1/(x**2*(x - 1/x)) - 2/x) - 1 + (x - 1/x)/(x - 1/x))/((x*((x - + 1/x)/((x - 1/x)**2) - ((x - 1/x)/((x*(x - 1/x)**2)) - 1/(x*(x - + 1/x)))**2/(2*x - (-x + 1/x)/(x**2*(x - 1/x)**2) - 1/(x**2*(x - 1/x)) - + 2/x) - 1/(x - 1/x))*(2*x - (-x + 1/x)/(x**2*(x - 1/x)**2) - 1/(x**2*(x + - 1/x)) - 2/x))) + ((x - 1/x)/((x*(x - 1/x))) + 1/x)/((x*(2*x - (-x + + 1/x)/(x**2*(x - 1/x)**2) - 1/(x**2*(x - 1/x)) - 2/x))) + 1/x)/(2*x + + 2*((x - 1/x)/((x*(x - 1/x)**2)) - 1/(x*(x - 1/x)))*((-(x - 1/x)/(x*(x + - 1/x)) - 1/x)*((x - 1/x)/((x*(x - 1/x)**2)) - 1/(x*(x - 1/x)))/(2*x - + (-x + 1/x)/(x**2*(x - 1/x)**2) - 1/(x**2*(x - 1/x)) - 2/x) - 1 + (x - + 1/x)/(x - 1/x))/((x*((x - 1/x)/((x - 1/x)**2) - ((x - 1/x)/((x*(x - + 1/x)**2)) - 1/(x*(x - 1/x)))**2/(2*x - (-x + 1/x)/(x**2*(x - 1/x)**2) + - 1/(x**2*(x - 1/x)) - 2/x) - 1/(x - 1/x))*(2*x - (-x + 1/x)/(x**2*(x + - 1/x)**2) - 1/(x**2*(x - 1/x)) - 2/x))) - 2*((x - 1/x)/((x*(x - + 1/x))) + 1/x)/(x*(2*x - (-x + 1/x)/(x**2*(x - 1/x)**2) - 1/(x**2*(x - + 1/x)) - 2/x)) - 2/x) - ((x - 1/x)/((x*(x - 1/x)**2)) - 1/(x*(x - + 1/x)))*((-x + 1/x)*((x - 1/x)/((x*(x - 1/x)**2)) - 1/(x*(x - + 1/x)))/(2*x - (-x + 1/x)/(x**2*(x - 1/x)**2) - 1/(x**2*(x - 1/x)) - + 2/x) + 1)/(x*((x - 1/x)/((x - 1/x)**2) - ((x - 1/x)/((x*(x - 1/x)**2)) + - 1/(x*(x - 1/x)))**2/(2*x - (-x + 1/x)/(x**2*(x - 1/x)**2) - + 1/(x**2*(x - 1/x)) - 2/x) - 1/(x - 1/x))*(2*x - (-x + 1/x)/(x**2*(x - + 1/x)**2) - 1/(x**2*(x - 1/x)) - 2/x)) + (x - 1/x)/((x*(2*x - (-x + + 1/x)/(x**2*(x - 1/x)**2) - 1/(x**2*(x - 1/x)) - 2/x))) - 1/x''', + evaluate=False) + assert cancel(q, _signsimp=False) is S.NaN + assert q.subs(x, 2) is S.NaN + assert signsimp(q) is S.NaN + + # issue 9363 + M = MatrixSymbol('M', 5, 5) + assert cancel(M[0,0] + 7) == M[0,0] + 7 + expr = sin(M[1, 4] + M[2, 1] * 5 * M[4, 0]) - 5 * M[1, 2] / z + assert cancel(expr) == (z*sin(M[1, 4] + M[2, 1] * 5 * M[4, 0]) - 5 * M[1, 2]) / z + + assert cancel((x**2 + 1)/(x - I)) == x + I + + +def test_cancel_modulus(): + assert cancel((x**2 - 1)/(x + 1), modulus=2) == x + 1 + assert Poly(x**2 - 1, modulus=2).cancel(Poly(x + 1, modulus=2)) ==\ + (1, Poly(x + 1, modulus=2), Poly(1, x, modulus=2)) + + +def test_make_monic_over_integers_by_scaling_roots(): + f = Poly(x**2 + 3*x + 4, x, domain='ZZ') + g, c = f.make_monic_over_integers_by_scaling_roots() + assert g == f + assert c == ZZ.one + + f = Poly(x**2 + 3*x + 4, x, domain='QQ') + g, c = f.make_monic_over_integers_by_scaling_roots() + assert g == f.to_ring() + assert c == ZZ.one + + f = Poly(x**2/2 + S(1)/4 * x + S(1)/8, x, domain='QQ') + g, c = f.make_monic_over_integers_by_scaling_roots() + assert g == Poly(x**2 + 2*x + 4, x, domain='ZZ') + assert c == 4 + + f = Poly(x**3/2 + S(1)/4 * x + S(1)/8, x, domain='QQ') + g, c = f.make_monic_over_integers_by_scaling_roots() + assert g == Poly(x**3 + 8*x + 16, x, domain='ZZ') + assert c == 4 + + f = Poly(x*y, x, y) + raises(ValueError, lambda: f.make_monic_over_integers_by_scaling_roots()) + + f = Poly(x, domain='RR') + raises(ValueError, lambda: f.make_monic_over_integers_by_scaling_roots()) + + +def test_galois_group(): + f = Poly(x ** 4 - 2) + G, alt = f.galois_group(by_name=True) + assert G == S4TransitiveSubgroups.D4 + assert alt is False + + +def test_reduced(): + f = 2*x**4 + y**2 - x**2 + y**3 + G = [x**3 - x, y**3 - y] + + Q = [2*x, 1] + r = x**2 + y**2 + y + + assert reduced(f, G) == (Q, r) + assert reduced(f, G, x, y) == (Q, r) + + H = groebner(G) + + assert H.reduce(f) == (Q, r) + + Q = [Poly(2*x, x, y), Poly(1, x, y)] + r = Poly(x**2 + y**2 + y, x, y) + + assert _strict_eq(reduced(f, G, polys=True), (Q, r)) + assert _strict_eq(reduced(f, G, x, y, polys=True), (Q, r)) + + H = groebner(G, polys=True) + + assert _strict_eq(H.reduce(f), (Q, r)) + + f = 2*x**3 + y**3 + 3*y + G = groebner([x**2 + y**2 - 1, x*y - 2]) + + Q = [x**2 - x*y**3/2 + x*y/2 + y**6/4 - y**4/2 + y**2/4, -y**5/4 + y**3/2 + y*Rational(3, 4)] + r = 0 + + assert reduced(f, G) == (Q, r) + assert G.reduce(f) == (Q, r) + + assert reduced(f, G, auto=False)[1] != 0 + assert G.reduce(f, auto=False)[1] != 0 + + 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])) + + f_poly = Poly(2*x**3 + y**3 + 3*y) + G_poly = groebner([Poly(x**2 + y**2 - 1), Poly(x*y - 2)]) + + Q_poly = [Poly(x**2 - 1/2*x*y**3 + 1/2*x*y + 1/4*y**6 - 1/2*y**4 + 1/4*y**2, x, y, domain='QQ'), + Poly(-1/4*y**5 + 1/2*y**3 + 3/4*y, x, y, domain='QQ')] + r_poly = Poly(0, x, y, domain='QQ') + + assert G_poly.reduce(f_poly) == (Q_poly, r_poly) + + Q, r = G_poly.reduce(f) + assert all(isinstance(q, Poly) for q in Q) + assert isinstance(r, Poly) + + f_wrong_gens = Poly(2*x**3 + y**3 + 3*y, x, y, z) + raises(ValueError, lambda: G_poly.reduce(f_wrong_gens)) + + zero_poly = Poly(0, x, y) + Q, r = G_poly.reduce(zero_poly) + assert all(q.is_zero for q in Q) + assert r.is_zero + + const_poly = Poly(1, x, y) + Q, r = G_poly.reduce(const_poly) + assert isinstance(r, Poly) + assert r.as_expr() == 1 + assert all(q.is_zero for q in Q) + + +def test_groebner(): + assert groebner([], x, y, z) == [] + + assert groebner([x**2 + 1, y**4*x + x**3], x, y, order='lex') == [1 + x**2, -1 + y**4] + assert groebner([x**2 + 1, y**4*x + x**3, x*y*z**3], x, y, z, order='grevlex') == [-1 + y**4, z**3, 1 + x**2] + + 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)] + + assert groebner([x**3 - 1, x**2 - 1]) == [x - 1] + assert groebner([Eq(x**3, 1), Eq(x**2, 1)]) == [x - 1] + + F = [3*x**2 + y*z - 5*x - 1, 2*x + 3*x*y + y**2, x - 3*y + x*z - 2*z**2] + f = z**9 - x**2*y**3 - 3*x*y**2*z + 11*y*z**2 + x**2*z**2 - 5 + + G = groebner(F, x, y, z, modulus=7, symmetric=False) + + assert G == [1 + x + y + 3*z + 2*z**2 + 2*z**3 + 6*z**4 + z**5, + 1 + 3*y + y**2 + 6*z**2 + 3*z**3 + 3*z**4 + 3*z**5 + 4*z**6, + 1 + 4*y + 4*z + y*z + 4*z**3 + z**4 + z**6, + 6 + 6*z + z**2 + 4*z**3 + 3*z**4 + 6*z**5 + 3*z**6 + z**7] + + Q, r = reduced(f, G, x, y, z, modulus=7, symmetric=False, polys=True) + + assert sum([ q*g for q, g in zip(Q, G.polys)], r) == Poly(f, modulus=7) + + F = [x*y - 2*y, 2*y**2 - x**2] + + assert groebner(F, x, y, order='grevlex') == \ + [y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y] + assert groebner(F, y, x, order='grevlex') == \ + [x**3 - 2*x**2, -x**2 + 2*y**2, x*y - 2*y] + assert groebner(F, order='grevlex', field=True) == \ + [y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y] + + assert groebner([1], x) == [1] + + assert groebner([x**2 + 2.0*y], x, y) == [1.0*x**2 + 2.0*y] + raises(ComputationFailed, lambda: groebner([1])) + + assert groebner([x**2 - 1, x**3 + 1], method='buchberger') == [x + 1] + assert groebner([x**2 - 1, x**3 + 1], method='f5b') == [x + 1] + + 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) + + 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, + 4*c*d**4 + 4*c - d**9 + 4*d**5 + 5*d, + 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) + + 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) + + 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) is True + assert is_zero_dimensional([x**3 + y**2], x, y) is 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) 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) is True + + +def test_GroebnerBasis(): + F = [x*y - 2*y, 2*y**2 - x**2] + + G = groebner(F, x, y, order='grevlex') + H = [y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y] + P = [ Poly(h, x, y) for h in H ] + + assert groebner(F + [0], x, y, order='grevlex') == G + assert isinstance(G, GroebnerBasis) is True + + assert len(G) == 3 + + assert G[0] == H[0] and not G[0].is_Poly + assert G[1] == H[1] and not G[1].is_Poly + assert G[2] == H[2] and not G[2].is_Poly + + assert G[1:] == H[1:] and not any(g.is_Poly for g in G[1:]) + assert G[:2] == H[:2] and not any(g.is_Poly for g in G[1:]) + + assert G.exprs == H + assert G.polys == P + assert G.gens == (x, y) + assert G.domain == ZZ + assert G.order == grevlex + + assert G == H + assert G == tuple(H) + assert G == P + assert G == tuple(P) + + assert G != [] + + G = groebner(F, x, y, order='grevlex', polys=True) + + assert G[0] == P[0] and G[0].is_Poly + assert G[1] == P[1] and G[1].is_Poly + assert G[2] == P[2] and G[2].is_Poly + + 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) + + assert poly(x + y) == Poly(x + y, x, y) + assert poly(x + sin(x)) == Poly(x + sin(x), x, sin(x)) + + assert poly(x + y, wrt=y) == Poly(x + y, y, x) + assert poly(x + sin(x), wrt=sin(x)) == Poly(x + sin(x), sin(x), x) + + 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 + (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) + + assert poly(Poly(x + y + z, y, x, z)) == Poly(x + y + z, y, x, z) + + assert poly((x + y)**2, x) == Poly(x**2 + 2*x*y + y**2, x, domain=ZZ[y]) + assert poly((x + y)**2, y) == Poly(x**2 + 2*x*y + y**2, y, domain=ZZ[x]) + + assert poly(1, x) == Poly(1, x) + raises(GeneratorsNeeded, lambda: poly(1)) + + # issue 6184 + assert poly(x + y, x, y) == Poly(x + y, x, y) + assert poly(x + y, y, x) == Poly(x + y, y, x) + + # https://github.com/sympy/sympy/issues/19755 + expr1 = x + (2*x + 3)**2/5 + S(6)/5 + assert poly(expr1).as_expr() == expr1.expand() + expr2 = y*(y+1) + S(1)/3 + assert poly(expr2).as_expr() == expr2.expand() + + +def test_keep_coeff(): + u = Mul(2, x + 1, evaluate=False) + assert _keep_coeff(S.One, x) == x + assert _keep_coeff(S.NegativeOne, x) == -x + assert _keep_coeff(S(1.0), x) == 1.0*x + assert _keep_coeff(S(-1.0), x) == -1.0*x + assert _keep_coeff(S.One, 2*x) == 2*x + assert _keep_coeff(S(2), x/2) == x + assert _keep_coeff(S(2), sin(x)) == 2*sin(x) + assert _keep_coeff(S(2), x + 1) == u + assert _keep_coeff(x, 1/x) == 1 + assert _keep_coeff(x + 1, S(2)) == u + assert _keep_coeff(S.Half, S.One) == S.Half + p = Pow(2, 3, evaluate=False) + assert _keep_coeff(S(-1), p) == Mul(-1, p, evaluate=False) + a = Add(2, p, evaluate=False) + assert _keep_coeff(S.Half, a, clear=True + ) == Mul(S.Half, a, evaluate=False) + assert _keep_coeff(S.Half, a, clear=False + ) == Add(1, Mul(S.Half, p, evaluate=False), evaluate=False) + + +def test_poly_matching_consistency(): + # Test for this issue: + # https://github.com/sympy/sympy/issues/5514 + assert I * Poly(x, x) == Poly(I*x, x) + assert Poly(x, x) * I == Poly(I*x, x) + + +def test_issue_5786(): + 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) + + +def test_to_rational_coeffs(): + assert to_rational_coeffs( + Poly(x**3 + y*x**2 + sqrt(y), x, domain='EX')) is None + # issue 21268 + assert to_rational_coeffs( + Poly(y**3 + sqrt(2)*y**2*sin(x) + 1, y)) is None + + assert to_rational_coeffs(Poly(x, y)) is None + assert to_rational_coeffs(Poly(sqrt(2)*y)) is None + + +def test_factor_terms(): + # issue 7067 + assert factor_list(x*(x + y)) == (1, [(x, 1), (x + y, 1)]) + assert sqf_list(x*(x + y)) == (1, [(x**2 + x*y, 1)]) + + +def test_as_list(): + # issue 14496 + assert Poly(x**3 + 2, x, domain='ZZ').as_list() == [1, 0, 0, 2] + assert Poly(x**2 + y + 1, x, y, domain='ZZ').as_list() == [[1], [], [1, 1]] + assert Poly(x**2 + y + 1, x, y, z, domain='ZZ').as_list() == \ + [[[1]], [[]], [[1], [1]]] + + +def test_issue_11198(): + assert factor_list(sqrt(2)*x) == (sqrt(2), [(x, 1)]) + assert factor_list(sqrt(2)*sin(x), sin(x)) == (sqrt(2), [(sin(x), 1)]) + + +def test_Poly_precision(): + # Make sure Poly doesn't lose precision + p = Poly(pi.evalf(100)*x) + assert p.as_expr() == pi.evalf(100)*x + + +def test_issue_12400(): + # Correction of check for negative exponents + assert poly(1/(1+sqrt(2)), x) == \ + Poly(1/(1+sqrt(2)), x, domain='EX') + +def test_issue_14364(): + assert gcd(S(6)*(1 + sqrt(3))/5, S(3)*(1 + sqrt(3))/10) == Rational(3, 10) * (1 + sqrt(3)) + assert gcd(sqrt(5)*Rational(4, 7), sqrt(5)*Rational(2, 3)) == sqrt(5)*Rational(2, 21) + + assert lcm(Rational(2, 3)*sqrt(3), Rational(5, 6)*sqrt(3)) == S(10)*sqrt(3)/3 + assert lcm(3*sqrt(3), 4/sqrt(3)) == 12*sqrt(3) + assert lcm(S(5)*(1 + 2**Rational(1, 3))/6, S(3)*(1 + 2**Rational(1, 3))/8) == Rational(15, 2) * (1 + 2**Rational(1, 3)) + + assert gcd(Rational(2, 3)*sqrt(3), Rational(5, 6)/sqrt(3)) == sqrt(3)/18 + assert gcd(S(4)*sqrt(13)/7, S(3)*sqrt(13)/14) == sqrt(13)/14 + + # gcd_list and lcm_list + assert gcd([S(2)*sqrt(47)/7, S(6)*sqrt(47)/5, S(8)*sqrt(47)/5]) == sqrt(47)*Rational(2, 35) + assert gcd([S(6)*(1 + sqrt(7))/5, S(2)*(1 + sqrt(7))/7, S(4)*(1 + sqrt(7))/13]) == (1 + sqrt(7))*Rational(2, 455) + assert lcm((Rational(7, 2)/sqrt(15), Rational(5, 6)/sqrt(15), Rational(5, 8)/sqrt(15))) == Rational(35, 2)/sqrt(15) + assert lcm([S(5)*(2 + 2**Rational(5, 7))/6, S(7)*(2 + 2**Rational(5, 7))/2, S(13)*(2 + 2**Rational(5, 7))/4]) == Rational(455, 2) * (2 + 2**Rational(5, 7)) + + +def test_issue_15669(): + x = Symbol("x", positive=True) + expr = (16*x**3/(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**2 - + 2*2**Rational(4, 5)*x*(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**Rational(3, 5) + 10*x) + assert factor(expr, deep=True) == x*(x**2 + 2) + + +def test_issue_17988(): + x = Symbol('x') + p = poly(x - 1) + with warns_deprecated_sympy(): + M = Matrix([[poly(x + 1), poly(x + 1)]]) + with warns(SymPyDeprecationWarning, test_stacklevel=False): + assert p * M == M * p == Matrix([[poly(x**2 - 1), poly(x**2 - 1)]]) + + +def test_issue_18205(): + assert cancel((2 + I)*(3 - I)) == 7 + I + assert cancel((2 + I)*(2 - I)) == 5 + + +def test_issue_8695(): + p = (x**2 + 1) * (x - 1)**2 * (x - 2)**3 * (x - 3)**3 + result = (1, [(x**2 + 1, 1), (x - 1, 2), (x**2 - 5*x + 6, 3)]) + assert sqf_list(p) == result + + +def test_issue_19113(): + eq = sin(x)**3 - sin(x) + 1 + raises(PolynomialError, lambda: refine_root(eq, 1, 2, 1e-2)) + raises(PolynomialError, lambda: count_roots(eq, -1, 1)) + raises(PolynomialError, lambda: real_roots(eq)) + raises(PolynomialError, lambda: nroots(eq)) + raises(PolynomialError, lambda: ground_roots(eq)) + raises(PolynomialError, lambda: nth_power_roots_poly(eq, 2)) + + +def test_issue_19360(): + f = 2*x**2 - 2*sqrt(2)*x*y + y**2 + assert factor(f, extension=sqrt(2)) == 2*(x - (sqrt(2)*y/2))**2 + + f = -I*t*x - t*y + x*z - I*y*z + assert factor(f, extension=I) == (x - I*y)*(-I*t + z) + + +def test_poly_copy_equals_original(): + poly = Poly(x + y, x, y, z) + copy = poly.copy() + assert poly == copy, ( + "Copied polynomial not equal to original.") + assert poly.gens == copy.gens, ( + "Copied polynomial has different generators than original.") + + +def test_deserialized_poly_equals_original(): + poly = Poly(x + y, x, y, z) + deserialized = pickle.loads(pickle.dumps(poly)) + assert poly == deserialized, ( + "Deserialized polynomial not equal to original.") + assert poly.gens == deserialized.gens, ( + "Deserialized polynomial has different generators than original.") + + +def test_issue_20389(): + result = degree(x * (x + 1) - x ** 2 - x, x) + assert result == -oo + + +def test_issue_20985(): + from sympy.core.symbol import symbols + w, R = symbols('w R') + poly = Poly(1.0 + I*w/R, w, 1/R) + assert poly.degree() == S(1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyutils.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyutils.py new file mode 100644 index 0000000000000000000000000000000000000000..f39561a1c5035fed52add5e49476d0eea91bdae0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_polyutils.py @@ -0,0 +1,300 @@ +"""Tests for useful utilities for higher level polynomial classes. """ + +from sympy.core.mul import Mul +from sympy.core.numbers import (Integer, pi) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.integrals.integrals import Integral +from sympy.testing.pytest import raises + +from sympy.polys.polyutils import ( + _nsort, + _sort_gens, + _unify_gens, + _analyze_gens, + _sort_factors, + parallel_dict_from_expr, + dict_from_expr, +) + +from sympy.polys.polyerrors import PolynomialError + +from sympy.polys.domains import ZZ + +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__nsort(): + # issue 6137 + r = S('''[3/2 + sqrt(-14/3 - 2*(-415/216 + 13*I/12)**(1/3) - 4/sqrt(-7/3 + + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3)) - + 61/(18*(-415/216 + 13*I/12)**(1/3)))/2 - sqrt(-7/3 + 61/(18*(-415/216 + + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3))/2, 3/2 - sqrt(-7/3 + + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + + 13*I/12)**(1/3))/2 - sqrt(-14/3 - 2*(-415/216 + 13*I/12)**(1/3) - + 4/sqrt(-7/3 + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + + 13*I/12)**(1/3)) - 61/(18*(-415/216 + 13*I/12)**(1/3)))/2, 3/2 + + sqrt(-14/3 - 2*(-415/216 + 13*I/12)**(1/3) + 4/sqrt(-7/3 + + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3)) - + 61/(18*(-415/216 + 13*I/12)**(1/3)))/2 + sqrt(-7/3 + 61/(18*(-415/216 + + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3))/2, 3/2 + sqrt(-7/3 + + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + + 13*I/12)**(1/3))/2 - sqrt(-14/3 - 2*(-415/216 + 13*I/12)**(1/3) + + 4/sqrt(-7/3 + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + + 13*I/12)**(1/3)) - 61/(18*(-415/216 + 13*I/12)**(1/3)))/2]''') + ans = [r[1], r[0], r[-1], r[-2]] + assert _nsort(r) == ans + assert len(_nsort(r, separated=True)[0]) == 0 + b, c, a = exp(-1000), exp(-999), exp(-1001) + assert _nsort((b, c, a)) == [a, b, c] + # issue 12560 + a = cos(1)**2 + sin(1)**2 - 1 + assert _nsort([a]) == [a] + + +def test__sort_gens(): + assert _sort_gens([]) == () + + assert _sort_gens([x]) == (x,) + 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) + + # https://github.com/sympy/sympy/issues/19353 + n1 = Symbol('\n1') + assert _sort_gens([n1]) == (n1,) + assert _sort_gens([x, n1]) == (x, n1) + + 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, 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, 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], [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) + + +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]] + + 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]] + + 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]] + + 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)] + + 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)] + + 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)] + + 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)] + + 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(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))) + + +def test__dict_from_expr_no_gens(): + assert dict_from_expr(Integer(17)) == ({(): Integer(17)}, ()) + + 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(sqrt(2)) == ({(1,): Integer(1)}, (sqrt(2),)) + assert dict_from_expr(sqrt(2), greedy=False) == ({(): sqrt(2)}, ()) + + 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=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,)) + + +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)) + 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)) + assert parallel_dict_from_expr((Mul(x, x**2, evaluate=False),)) == \ + ([{(3,): 1}], (x,)) + + +def test_parallel_dict_from_expr(): + assert parallel_dict_from_expr([Eq(x, 1), Eq( + x**2, 2)]) == ([{(0,): -Integer(1), (1,): Integer(1)}, + {(0,): -Integer(2), (2,): Integer(1)}], (x,)) + raises(PolynomialError, lambda: parallel_dict_from_expr([A*B - B*A])) + + +def test_dict_from_expr(): + assert dict_from_expr(Eq(x, 1)) == \ + ({(0,): -Integer(1), (1,): Integer(1)}, (x,)) + raises(PolynomialError, lambda: dict_from_expr(A*B - B*A)) + raises(PolynomialError, lambda: dict_from_expr(S.true)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_puiseux.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_puiseux.py new file mode 100644 index 0000000000000000000000000000000000000000..031881e9d12c53053d8ec7136374bd8b3a385df0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_puiseux.py @@ -0,0 +1,204 @@ +# +# Tests for PuiseuxRing and PuiseuxPoly +# + +from sympy.testing.pytest import raises + +from sympy import ZZ, QQ, ring +from sympy.polys.puiseux import PuiseuxRing, PuiseuxPoly, puiseux_ring + +from sympy.abc import x, y + + +def test_puiseux_ring(): + R, px = puiseux_ring('x', QQ) + R2, px2 = puiseux_ring([x], QQ) + assert isinstance(R, PuiseuxRing) + assert isinstance(px, PuiseuxPoly) + assert R == R2 + assert px == px2 + assert R == PuiseuxRing('x', QQ) + assert R == PuiseuxRing([x], QQ) + assert R != PuiseuxRing('y', QQ) + assert R != PuiseuxRing('x', ZZ) + assert R != PuiseuxRing('x, y', QQ) + assert R != QQ + assert str(R) == 'PuiseuxRing((x,), QQ)' + + +def test_puiseux_ring_attributes(): + R1, px1, py1 = ring('x, y', QQ) + R2, px2, py2 = puiseux_ring('x, y', QQ) + assert R2.domain == QQ + assert R2.symbols == (x, y) + assert R2.gens == (px2, py2) + assert R2.ngens == 2 + assert R2.poly_ring == R1 + assert R2.zero == PuiseuxPoly(R1.zero, R2) + assert R2.one == PuiseuxPoly(R1.one, R2) + assert R2.zero_monom == R1.zero_monom == (0, 0) # type: ignore + assert R2.monomial_mul((1, 2), (3, 4)) == (4, 6) + + +def test_puiseux_ring_methods(): + R1, px1, py1 = ring('x, y', QQ) + R2, px2, py2 = puiseux_ring('x, y', QQ) + assert R2({(1, 2): 3}) == 3*px2*py2**2 + assert R2(px1) == px2 + assert R2(1) == R2.one + assert R2(QQ(1,2)) == QQ(1,2)*R2.one + assert R2.from_poly(px1) == px2 + assert R2.from_poly(px1) != py2 + assert R2.from_dict({(1, 2): QQ(3)}) == 3*px2*py2**2 + assert R2.from_dict({(QQ(1,2), 2): QQ(3)}) == 3*px2**QQ(1,2)*py2**2 + assert R2.from_int(3) == 3*R2.one + assert R2.domain_new(3) == QQ(3) + assert QQ.of_type(R2.domain_new(3)) + assert R2.ground_new(3) == 3*R2.one + assert isinstance(R2.ground_new(3), PuiseuxPoly) + assert R2.index(px2) == 0 + assert R2.index(py2) == 1 + + +def test_puiseux_poly(): + R1, px1 = ring('x', QQ) + R2, px2 = puiseux_ring('x', QQ) + assert PuiseuxPoly(px1, R2) == px2 + assert px2.ring == R2 + assert px2.as_expr() == px1.as_expr() == x + assert px1 != px2 + assert R2.one == px2**0 == 1 + assert px2 == px1 + assert px2 != 2.0 + assert px2**QQ(1,2) != px1 + + +def test_puiseux_poly_normalization(): + R, x = puiseux_ring('x', QQ) + assert (x**2 + 1) / x == x + 1/x == R({(1,): 1, (-1,): 1}) + assert (x**QQ(1,6))**2 == x**QQ(1,3) == R({(QQ(1,3),): 1}) + assert (x**QQ(1,6))**(-2) == x**(-QQ(1,3)) == R({(-QQ(1,3),): 1}) + assert (x**QQ(1,6))**QQ(1,2) == x**QQ(1,12) == R({(QQ(1,12),): 1}) + assert (x**QQ(1,6))**6 == x == R({(1,): 1}) + assert x**QQ(1,6) * x**QQ(1,3) == x**QQ(1,2) == R({(QQ(1,2),): 1}) + assert 1/x * x**2 == x == R({(1,): 1}) + assert 1/x**QQ(1,3) * x**QQ(1,3) == 1 == R({(0,): 1}) + + +def test_puiseux_poly_monoms(): + R, x = puiseux_ring('x', QQ) + assert x.monoms() == [(1,)] + assert list(x) == [(1,)] + assert (x**2 + 1).monoms() == [(2,), (0,)] + assert R({(1,): 1, (-1,): 1}).monoms() == [(1,), (-1,)] + assert R({(QQ(1,3),): 1}).monoms() == [(QQ(1,3),)] + assert R({(-QQ(1,3),): 1}).monoms() == [(-QQ(1,3),)] + p = x**QQ(1,6) + assert p[(QQ(1,6),)] == 1 + raises(KeyError, lambda: p[(1,)]) + assert p.to_dict() == {(QQ(1,6),): 1} + assert R(p.to_dict()) == p + assert PuiseuxPoly.from_dict({(QQ(1,6),): 1}, R) == p + + +def test_puiseux_poly_repr(): + R, x = puiseux_ring('x', QQ) + assert repr(x) == 'x' + assert repr(x**QQ(1,2)) == 'x**(1/2)' + assert repr(1/x) == 'x**(-1)' + assert repr(2*x**2 + 1) == '1 + 2*x**2' + assert repr(R.one) == '1' + assert repr(2*R.one) == '2' + + +def test_puiseux_poly_unify(): + R, x = puiseux_ring('x', QQ) + assert 1/x + x == x + 1/x == R({(1,): 1, (-1,): 1}) + assert repr(1/x + x) == 'x**(-1) + x' + assert 1/x + 1/x == 2/x == R({(-1,): 2}) + assert repr(1/x + 1/x) == '2*x**(-1)' + assert x**QQ(1,2) + x**QQ(1,2) == 2*x**QQ(1,2) == R({(QQ(1,2),): 2}) + assert repr(x**QQ(1,2) + x**QQ(1,2)) == '2*x**(1/2)' + assert x**QQ(1,2) + x**QQ(1,3) == R({(QQ(1,2),): 1, (QQ(1,3),): 1}) + assert repr(x**QQ(1,2) + x**QQ(1,3)) == 'x**(1/3) + x**(1/2)' + assert x + x**QQ(1,2) == R({(1,): 1, (QQ(1,2),): 1}) + assert repr(x + x**QQ(1,2)) == 'x**(1/2) + x' + assert 1/x**QQ(1,2) + 1/x**QQ(1,3) == R({(-QQ(1,2),): 1, (-QQ(1,3),): 1}) + assert repr(1/x**QQ(1,2) + 1/x**QQ(1,3)) == 'x**(-1/2) + x**(-1/3)' + assert 1/x + x**QQ(1,2) == x**QQ(1,2) + 1/x == R({(-1,): 1, (QQ(1,2),): 1}) + assert repr(1/x + x**QQ(1,2)) == 'x**(-1) + x**(1/2)' + + +def test_puiseux_poly_arit(): + R, x = puiseux_ring('x', QQ) + R2, y = puiseux_ring('y', QQ) + p = x**2 + 1 + assert +p == p + assert -p == -1 - x**2 + assert p + p == 2*p == 2*x**2 + 2 + assert p + 1 == 1 + p == x**2 + 2 + assert p + QQ(1,2) == QQ(1,2) + p == x**2 + QQ(3,2) + assert p - p == 0 + assert p - 1 == -1 + p == x**2 + assert p - QQ(1,2) == -QQ(1,2) + p == x**2 + QQ(1,2) + assert 1 - p == -p + 1 == -x**2 + assert QQ(1,2) - p == -p + QQ(1,2) == -x**2 - QQ(1,2) + assert p * p == x**4 + 2*x**2 + 1 + assert p * 1 == 1 * p == p + assert 2 * p == p * 2 == 2*x**2 + 2 + assert p * QQ(1,2) == QQ(1,2) * p == QQ(1,2)*x**2 + QQ(1,2) + assert x**QQ(1,2) * x**QQ(1,2) == x + raises(ValueError, lambda: x + y) + raises(ValueError, lambda: x - y) + raises(ValueError, lambda: x * y) + raises(TypeError, lambda: x + None) + raises(TypeError, lambda: x - None) + raises(TypeError, lambda: x * None) + raises(TypeError, lambda: None + x) + raises(TypeError, lambda: None - x) + raises(TypeError, lambda: None * x) + + +def test_puiseux_poly_div(): + R, x = puiseux_ring('x', QQ) + R2, y = puiseux_ring('y', QQ) + p = x**2 - 1 + assert p / 1 == p + assert p / QQ(1,2) == 2*p == 2*x**2 - 2 + assert p / x == x - 1/x == R({(1,): 1, (-1,): -1}) + assert 2 / x == 2*x**-1 == R({(-1,): 2}) + assert QQ(1,2) / x == QQ(1,2)*x**-1 == 1/(2*x) == 1/x/2 == R({(-1,): QQ(1,2)}) + raises(ZeroDivisionError, lambda: p / 0) + raises(ValueError, lambda: (x + 1) / (x + 2)) + raises(ValueError, lambda: (x + 1) / (x + 1)) + raises(ValueError, lambda: x / y) + raises(TypeError, lambda: x / None) + raises(TypeError, lambda: None / x) + + +def test_puiseux_poly_pow(): + R, x = puiseux_ring('x', QQ) + Rz, xz = puiseux_ring('x', ZZ) + assert x**0 == 1 == R({(0,): 1}) + assert x**1 == x == R({(1,): 1}) + assert x**2 == x*x == R({(2,): 1}) + assert x**QQ(1,2) == R({(QQ(1,2),): 1}) + assert x**-1 == 1/x == R({(-1,): 1}) + assert x**-QQ(1,2) == 1/x**QQ(1,2) == R({(-QQ(1,2),): 1}) + assert (2*x)**-1 == 1/(2*x) == QQ(1,2)/x == QQ(1,2)*x**-1 == R({(-1,): QQ(1,2)}) + assert 2/x**2 == 2*x**-2 == R({(-2,): 2}) + assert 2/xz**2 == 2*xz**-2 == Rz({(-2,): 2}) + raises(TypeError, lambda: x**None) + raises(ValueError, lambda: (x + 1)**-1) + raises(ValueError, lambda: (x + 1)**QQ(1,2)) + raises(ValueError, lambda: (2*x)**QQ(1,2)) + raises(ValueError, lambda: (2*xz)**-1) + + +def test_puiseux_poly_diff(): + R, x, y = puiseux_ring('x, y', QQ) + assert (x**2 + 1).diff(x) == 2*x + assert (x**2 + 1).diff(y) == 0 + assert (x**2 + y**2).diff(x) == 2*x + assert (x**QQ(1,2) + y**QQ(1,2)).diff(x) == QQ(1,2)*x**-QQ(1,2) + assert ((x*y)**QQ(1,2)).diff(x) == QQ(1,2)*y**QQ(1,2)*x**-QQ(1,2) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_pythonrational.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_pythonrational.py new file mode 100644 index 0000000000000000000000000000000000000000..547a5679626fd3a6165b151364bb506a574bb1db --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_pythonrational.py @@ -0,0 +1,139 @@ +"""Tests for PythonRational type. """ + +from sympy.polys.domains import PythonRational as QQ +from sympy.testing.pytest import raises + +def test_PythonRational__init__(): + assert QQ(0).numerator == 0 + assert QQ(0).denominator == 1 + assert QQ(0, 1).numerator == 0 + assert QQ(0, 1).denominator == 1 + assert QQ(0, -1).numerator == 0 + assert QQ(0, -1).denominator == 1 + + assert QQ(1).numerator == 1 + assert QQ(1).denominator == 1 + assert QQ(1, 1).numerator == 1 + assert QQ(1, 1).denominator == 1 + assert QQ(-1, -1).numerator == 1 + assert QQ(-1, -1).denominator == 1 + + assert QQ(-1).numerator == -1 + assert QQ(-1).denominator == 1 + assert QQ(-1, 1).numerator == -1 + assert QQ(-1, 1).denominator == 1 + assert QQ( 1, -1).numerator == -1 + assert QQ( 1, -1).denominator == 1 + + assert QQ(1, 2).numerator == 1 + assert QQ(1, 2).denominator == 2 + assert QQ(3, 4).numerator == 3 + assert QQ(3, 4).denominator == 4 + + assert QQ(2, 2).numerator == 1 + assert QQ(2, 2).denominator == 1 + assert QQ(2, 4).numerator == 1 + assert QQ(2, 4).denominator == 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__truediv__(): + 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 --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rationaltools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rationaltools.py new file mode 100644 index 0000000000000000000000000000000000000000..3ee0192a3fbc8997347df081663015afd91dd8ad --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rationaltools.py @@ -0,0 +1,63 @@ +"""Tests for tools for manipulation of rational expressions. """ + +from sympy.polys.rationaltools import together + +from sympy.core.mul import Mul +from sympy.core.numbers import Rational +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.trigonometric import sin +from sympy.integrals.integrals import Integral +from sympy.abc import x, y, z + +A, B = symbols('A,B', commutative=False) + + +def test_together(): + assert together(0) == 0 + assert together(1) == 1 + + assert together(x*y*z) == x*y*z + assert together(x + y) == x + y + + assert together(1/x) == 1/x + + assert together(1/x + 1) == (x + 1)/x + assert together(1/x + 3) == (3*x + 1)/x + assert together(1/x + x) == (x**2 + 1)/x + + assert together(1/x + S.Half) == (x + 2)/(2*x) + assert together(S.Half + x/2) == Mul(S.Half, x + 1, evaluate=False) + + assert together(1/x + 2/y) == (2*x + y)/(y*x) + assert together(1/(1 + 1/x)) == x/(1 + x) + assert together(x/(1 + 1/x)) == x**2/(1 + x) + + assert together(1/x + 1/y + 1/z) == (x*y + x*z + y*z)/(x*y*z) + assert together(1/(1 + x + 1/y + 1/z)) == y*z/(y + z + y*z + x*y*z) + + assert together(1/(x*y) + 1/(x*y)**2) == y**(-2)*x**(-2)*(1 + x*y) + assert together(1/(x*y) + 1/(x*y)**4) == y**(-4)*x**(-4)*(1 + x**3*y**3) + 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))))) == \ + Rational(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 + 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(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) + + assert together((A*B)**-1 + (B*A)**-1) == (A*B)**-1 + (B*A)**-1 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_ring_series.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_ring_series.py new file mode 100644 index 0000000000000000000000000000000000000000..d983fc99f8ffcf9361d8d069f1d381928ac0aada --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_ring_series.py @@ -0,0 +1,831 @@ +from sympy.polys.domains import ZZ, QQ, EX, RR +from sympy.polys.rings import ring +from sympy.polys.puiseux import puiseux_ring +from sympy.polys.ring_series import (_invert_monoms, rs_integrate, + rs_trunc, rs_mul, rs_square, rs_pow, _has_constant_term, rs_hadamard_exp, + rs_series_from_list, rs_exp, rs_log, rs_newton, rs_series_inversion, + rs_compose_add, rs_asin, _atan, rs_atan, _atanh, rs_atanh, rs_asinh, rs_tan, + rs_cot, rs_sin, rs_cos, rs_cos_sin, rs_sinh, rs_cosh, rs_cosh_sinh, rs_tanh, + _tan1, rs_fun, rs_nth_root, rs_LambertW, rs_series_reversion, rs_is_puiseux, + rs_series) +from sympy.testing.pytest import raises, slow +from sympy.core.symbol import symbols +from sympy.functions import (sin, cos, exp, tan, cot, sinh, cosh, atan, atanh, + asinh, tanh, log, sqrt) +from sympy.core.numbers import Rational, pi +from sympy.core import expand, S + +def is_close(a, b): + tol = 10**(-10) + assert abs(a - b) < tol + + +def test_ring_series1(): + R, x = ring('x', QQ) + p = x**4 + 2*x**3 + 3*x + 4 + assert _invert_monoms(p) == 4*x**4 + 3*x**3 + 2*x + 1 + assert rs_hadamard_exp(p) == x**4/24 + x**3/3 + 3*x + 4 + R, x = ring('x', QQ) + p = x**4 + 2*x**3 + 3*x + 4 + assert rs_integrate(p, x) == x**5/5 + x**4/2 + 3*x**2/2 + 4*x + R, x, y = ring('x, y', QQ) + p = x**2*y**2 + x + 1 + assert rs_integrate(p, x) == x**3*y**2/3 + x**2/2 + x + assert rs_integrate(p, y) == x**2*y**3/3 + x*y + y + + +def test_trunc(): + R, x, y, t = ring('x, y, t', QQ) + p = (y + t*x)**4 + p1 = rs_trunc(p, x, 3) + assert p1 == y**4 + 4*y**3*t*x + 6*y**2*t**2*x**2 + + +def test_mul_trunc(): + R, x, y, t = ring('x, y, t', QQ) + p = 1 + t*x + t*y + for i in range(2): + p = rs_mul(p, p, t, 3) + + assert p == 6*x**2*t**2 + 12*x*y*t**2 + 6*y**2*t**2 + 4*x*t + 4*y*t + 1 + p = 1 + t*x + t*y + t**2*x*y + p1 = rs_mul(p, p, t, 2) + assert p1 == 1 + 2*t*x + 2*t*y + R1, z = ring('z', QQ) + raises(ValueError, lambda: rs_mul(p, z, x, 2)) + + p1 = 2 + 2*x + 3*x**2 + p2 = 3 + x**2 + assert rs_mul(p1, p2, x, 4) == 2*x**3 + 11*x**2 + 6*x + 6 + + +def test_square_trunc(): + R, x, y, t = ring('x, y, t', QQ) + p = (1 + t*x + t*y)*2 + p1 = rs_mul(p, p, x, 3) + p2 = rs_square(p, x, 3) + assert p1 == p2 + p = 1 + x + x**2 + x**3 + assert rs_square(p, x, 4) == 4*x**3 + 3*x**2 + 2*x + 1 + + +def test_pow_trunc(): + R, x, y, z = ring('x, y, z', QQ) + p0 = y + x*z + p = p0**16 + for xx in (x, y, z): + p1 = rs_trunc(p, xx, 8) + p2 = rs_pow(p0, 16, xx, 8) + assert p1 == p2 + + p = 1 + x + p1 = rs_pow(p, 3, x, 2) + assert p1 == 1 + 3*x + assert rs_pow(p, 0, x, 2) == 1 + assert rs_pow(p, -2, x, 2) == 1 - 2*x + p = x + y + assert rs_pow(p, 3, y, 3) == x**3 + 3*x**2*y + 3*x*y**2 + assert rs_pow(1 + x, Rational(2, 3), x, 4) == 4*x**3/81 - x**2/9 + x*Rational(2, 3) + 1 + + +def test_has_constant_term(): + R, x, y, z = ring('x, y, z', QQ) + p = y + x*z + assert _has_constant_term(p, x) + p = x + x**4 + assert not _has_constant_term(p, x) + p = 1 + x + x**4 + assert _has_constant_term(p, x) + p = x + y + x*z + + +def test_inversion(): + R, x = ring('x', QQ) + p = 2 + x + 2*x**2 + n = 5 + p1 = rs_series_inversion(p, x, n) + assert rs_trunc(p*p1, x, n) == 1 + R, x, y = ring('x, y', QQ) + p = 2 + x + 2*x**2 + y*x + x**2*y + p1 = rs_series_inversion(p, x, n) + assert rs_trunc(p*p1, x, n) == 1 + + R, x, y = ring('x, y', QQ) + p = 1 + x + y + raises(NotImplementedError, lambda: rs_series_inversion(p, x, 4)) + p = R.zero + raises(ZeroDivisionError, lambda: rs_series_inversion(p, x, 3)) + + R, x = ring('x', ZZ) + p = 2 + x + raises(ValueError, lambda: rs_series_inversion(p, x, 3)) + + +def test_series_reversion(): + R, x, y = ring('x, y', QQ) + + p = rs_tan(x, x, 10) + assert rs_series_reversion(p, x, 8, y) == rs_atan(y, y, 8) + + p = rs_sin(x, x, 10) + assert rs_series_reversion(p, x, 8, y) == 5*y**7/112 + 3*y**5/40 + \ + y**3/6 + y + + +def test_series_from_list(): + R, x = ring('x', QQ) + p = 1 + 2*x + x**2 + 3*x**3 + c = [1, 2, 0, 4, 4] + r = rs_series_from_list(p, c, x, 5) + pc = R.from_list(list(reversed(c))) + r1 = rs_trunc(pc.compose(x, p), x, 5) + assert r == r1 + R, x, y = ring('x, y', QQ) + c = [1, 3, 5, 7] + p1 = rs_series_from_list(x + y, c, x, 3, concur=0) + p2 = rs_trunc((1 + 3*(x+y) + 5*(x+y)**2 + 7*(x+y)**3), x, 3) + assert p1 == p2 + + R, x = ring('x', QQ) + h = 25 + p = rs_exp(x, x, h) - 1 + p1 = rs_series_from_list(p, c, x, h) + p2 = 0 + for i, cx in enumerate(c): + p2 += cx*rs_pow(p, i, x, h) + assert p1 == p2 + + +def test_log(): + R, x = ring('x', QQ) + p = 1 + x + assert rs_log(p, x, 4) == x - x**2/2 + x**3/3 + p = 1 + x +2*x**2/3 + p1 = rs_log(p, x, 9) + assert p1 == -17*x**8/648 + 13*x**7/189 - 11*x**6/162 - x**5/45 + \ + 7*x**4/36 - x**3/3 + x**2/6 + x + p2 = rs_series_inversion(p, x, 9) + p3 = rs_log(p2, x, 9) + assert p3 == -p1 + + R, x, y = ring('x, y', QQ) + p = 1 + x + 2*y*x**2 + p1 = rs_log(p, x, 6) + assert p1 == (4*x**5*y**2 - 2*x**5*y - 2*x**4*y**2 + x**5/5 + 2*x**4*y - + x**4/4 - 2*x**3*y + x**3/3 + 2*x**2*y - x**2/2 + x) + + # Constant term in series + a = symbols('a') + R, x, y = ring('x, y', EX) + assert rs_log(x + a, x, 5) == -EX(1/(4*a**4))*x**4 + EX(1/(3*a**3))*x**3 \ + - EX(1/(2*a**2))*x**2 + EX(1/a)*x + EX(log(a)) + assert rs_log(x + x**2*y + a, x, 4) == -EX(a**(-2))*x**3*y + \ + EX(1/(3*a**3))*x**3 + EX(1/a)*x**2*y - EX(1/(2*a**2))*x**2 + \ + EX(1/a)*x + EX(log(a)) + + p = x + x**2 + 3 + assert rs_log(p, x, 10).compose(x, 5) == EX(log(3) + Rational(19281291595, 9920232)) + + +def test_exp(): + R, x = ring('x', QQ) + p = x + x**4 + for h in [10, 30]: + q = rs_series_inversion(1 + p, x, h) - 1 + p1 = rs_exp(q, x, h) + q1 = rs_log(p1, x, h) + assert q1 == q + p1 = rs_exp(p, x, 30) + assert p1.coeff(x**29) == QQ(74274246775059676726972369, 353670479749588078181744640000) + prec = 21 + p = rs_log(1 + x, x, prec) + p1 = rs_exp(p, x, prec) + assert p1 == x + 1 + + # Constant term in series + a = symbols('a') + R, x, y = ring('x, y', QQ[exp(a), a]) + assert rs_exp(x + a, x, 5) == exp(a)*x**4/24 + exp(a)*x**3/6 + \ + exp(a)*x**2/2 + exp(a)*x + exp(a) + assert rs_exp(x + x**2*y + a, x, 5) == exp(a)*x**4*y**2/2 + \ + exp(a)*x**4*y/2 + exp(a)*x**4/24 + exp(a)*x**3*y + \ + exp(a)*x**3/6 + exp(a)*x**2*y + exp(a)*x**2/2 + exp(a)*x + exp(a) + + R, x, y = ring('x, y', EX) + assert rs_exp(x + a, x, 5) == EX(exp(a)/24)*x**4 + EX(exp(a)/6)*x**3 + \ + EX(exp(a)/2)*x**2 + EX(exp(a))*x + EX(exp(a)) + assert rs_exp(x + x**2*y + a, x, 5) == EX(exp(a)/2)*x**4*y**2 + \ + EX(exp(a)/2)*x**4*y + EX(exp(a)/24)*x**4 + EX(exp(a))*x**3*y + \ + EX(exp(a)/6)*x**3 + EX(exp(a))*x**2*y + EX(exp(a)/2)*x**2 + \ + EX(exp(a))*x + EX(exp(a)) + + +def test_newton(): + R, x = ring('x', QQ) + p = x**2 - 2 + r = rs_newton(p, x, 4) + assert r == 8*x**4 + 4*x**2 + 2 + + +def test_compose_add(): + R, x = ring('x', QQ) + p1 = x**3 - 1 + p2 = x**2 - 2 + assert rs_compose_add(p1, p2) == x**6 - 6*x**4 - 2*x**3 + 12*x**2 - 12*x - 7 + + +def test_fun(): + R, x, y = ring('x, y', QQ) + p = x*y + x**2*y**3 + x**5*y + assert rs_fun(p, rs_tan, x, 10) == rs_tan(p, x, 10) + assert rs_fun(p, _tan1, x, 10) == _tan1(p, x, 10) + + +def test_nth_root(): + R, x, y = puiseux_ring('x, y', QQ) + assert rs_nth_root(1 + x**2*y, 4, x, 10) == -77*x**8*y**4/2048 + \ + 7*x**6*y**3/128 - 3*x**4*y**2/32 + x**2*y/4 + 1 + assert rs_nth_root(1 + x*y + x**2*y**3, 3, x, 5) == -x**4*y**6/9 + \ + 5*x**4*y**5/27 - 10*x**4*y**4/243 - 2*x**3*y**4/9 + 5*x**3*y**3/81 + \ + x**2*y**3/3 - x**2*y**2/9 + x*y/3 + 1 + assert rs_nth_root(8*x, 3, x, 3) == 2*x**QQ(1, 3) + assert rs_nth_root(8*x + x**2 + x**3, 3, x, 3) == x**QQ(4,3)/12 + 2*x**QQ(1,3) + r = rs_nth_root(8*x + x**2*y + x**3, 3, x, 4) + assert r == -x**QQ(7,3)*y**2/288 + x**QQ(7,3)/12 + x**QQ(4,3)*y/12 + 2*x**QQ(1,3) + + # Constant term in series + a = symbols('a') + R, x, y = puiseux_ring('x, y', EX) + assert rs_nth_root(x + EX(a), 3, x, 4) == EX(5/(81*a**QQ(8, 3)))*x**3 - \ + EX(1/(9*a**QQ(5, 3)))*x**2 + EX(1/(3*a**QQ(2, 3)))*x + EX(a**QQ(1, 3)) + assert rs_nth_root(x**QQ(2, 3) + x**2*y + 5, 2, x, 3) == -EX(sqrt(5)/100)*\ + x**QQ(8, 3)*y - EX(sqrt(5)/16000)*x**QQ(8, 3) + EX(sqrt(5)/10)*x**2*y + \ + EX(sqrt(5)/2000)*x**2 - EX(sqrt(5)/200)*x**QQ(4, 3) + \ + EX(sqrt(5)/10)*x**QQ(2, 3) + EX(sqrt(5)) + + +def test_atan(): + R, x, y = ring('x, y', QQ) + assert rs_atan(x, x, 9) == -x**7/7 + x**5/5 - x**3/3 + x + assert rs_atan(x*y + x**2*y**3, x, 9) == 2*x**8*y**11 - x**8*y**9 + \ + 2*x**7*y**9 - x**7*y**7/7 - x**6*y**9/3 + x**6*y**7 - x**5*y**7 + \ + x**5*y**5/5 - x**4*y**5 - x**3*y**3/3 + x**2*y**3 + x*y + + # Constant term in series + a = symbols('a') + R, x, y = ring('x, y', EX) + assert rs_atan(x + a, x, 5) == -EX((a**3 - a)/(a**8 + 4*a**6 + 6*a**4 + \ + 4*a**2 + 1))*x**4 + EX((3*a**2 - 1)/(3*a**6 + 9*a**4 + \ + 9*a**2 + 3))*x**3 - EX(a/(a**4 + 2*a**2 + 1))*x**2 + \ + EX(1/(a**2 + 1))*x + EX(atan(a)) + assert rs_atan(x + x**2*y + a, x, 4) == -EX(2*a/(a**4 + 2*a**2 + 1)) \ + *x**3*y + EX((3*a**2 - 1)/(3*a**6 + 9*a**4 + 9*a**2 + 3))*x**3 + \ + EX(1/(a**2 + 1))*x**2*y - EX(a/(a**4 + 2*a**2 + 1))*x**2 + EX(1/(a**2 \ + + 1))*x + EX(atan(a)) + + # Test for _atan faster for small and univariate series + R, x = ring('x', QQ) + p = x**2 + 2*x + assert _atan(p, x, 5) == rs_atan(p, x, 5) + + R, x = ring('x', EX) + p = x**2 + 2*x + assert _atan(p, x, 9) == rs_atan(p, x, 9) + + +def test_asin(): + R, x, y = ring('x, y', QQ) + assert rs_asin(x + x*y, x, 5) == x**3*y**3/6 + x**3*y**2/2 + x**3*y/2 + \ + x**3/6 + x*y + x + assert rs_asin(x*y + x**2*y**3, x, 6) == x**5*y**7/2 + 3*x**5*y**5/40 + \ + x**4*y**5/2 + x**3*y**3/6 + x**2*y**3 + x*y + + +def test_tan(): + R, x, y = ring('x, y', QQ) + assert rs_tan(x, x, 9) == x + x**3/3 + QQ(2,15)*x**5 + QQ(17,315)*x**7 + assert rs_tan(x*y + x**2*y**3, x, 9) == 4*x**8*y**11/3 + 17*x**8*y**9/45 + \ + 4*x**7*y**9/3 + 17*x**7*y**7/315 + x**6*y**9/3 + 2*x**6*y**7/3 + \ + x**5*y**7 + 2*x**5*y**5/15 + x**4*y**5 + x**3*y**3/3 + x**2*y**3 + x*y + + # Constant term in series + a = symbols('a') + R, x, y = ring('x, y', QQ[tan(a), a]) + assert rs_tan(x + a, x, 5) == (tan(a)**5 + 5*tan(a)**3/3 + + 2*tan(a)/3)*x**4 + (tan(a)**4 + 4*tan(a)**2/3 + Rational(1, 3))*x**3 + \ + (tan(a)**3 + tan(a))*x**2 + (tan(a)**2 + 1)*x + tan(a) + assert rs_tan(x + x**2*y + a, x, 4) == (2*tan(a)**3 + 2*tan(a))*x**3*y + \ + (tan(a)**4 + Rational(4, 3)*tan(a)**2 + Rational(1, 3))*x**3 + (tan(a)**2 + 1)*x**2*y + \ + (tan(a)**3 + tan(a))*x**2 + (tan(a)**2 + 1)*x + tan(a) + + R, x, y = ring('x, y', EX) + assert rs_tan(x + a, x, 5) == EX(tan(a)**5 + 5*tan(a)**3/3 + + 2*tan(a)/3)*x**4 + EX(tan(a)**4 + 4*tan(a)**2/3 + EX(1)/3)*x**3 + \ + EX(tan(a)**3 + tan(a))*x**2 + EX(tan(a)**2 + 1)*x + EX(tan(a)) + assert rs_tan(x + x**2*y + a, x, 4) == EX(2*tan(a)**3 + + 2*tan(a))*x**3*y + EX(tan(a)**4 + 4*tan(a)**2/3 + EX(1)/3)*x**3 + \ + EX(tan(a)**2 + 1)*x**2*y + EX(tan(a)**3 + tan(a))*x**2 + \ + EX(tan(a)**2 + 1)*x + EX(tan(a)) + + p = x + x**2 + 5 + assert rs_atan(p, x, 10).compose(x, 10) == EX(atan(5) + S(67701870330562640) / \ + 668083460499) + + +def test_cot(): + R, x, y = puiseux_ring('x, y', QQ) + assert rs_cot(x**6 + x**7, x, 8) == x**(-6) - x**(-5) + x**(-4) - \ + x**(-3) + x**(-2) - x**(-1) + 1 - x + x**2 - x**3 + x**4 - x**5 + \ + 2*x**6/3 - 4*x**7/3 + assert rs_cot(x + x**2*y, x, 5) == -x**4*y**5 - x**4*y/15 + x**3*y**4 - \ + x**3/45 - x**2*y**3 - x**2*y/3 + x*y**2 - x/3 - y + x**(-1) + + +def test_sin(): + R, x, y = ring('x, y', QQ) + assert rs_sin(x, x, 9) == x - x**3/6 + x**5/120 - x**7/5040 + assert rs_sin(x*y + x**2*y**3, x, 9) == x**8*y**11/12 - \ + x**8*y**9/720 + x**7*y**9/12 - x**7*y**7/5040 - x**6*y**9/6 + \ + x**6*y**7/24 - x**5*y**7/2 + x**5*y**5/120 - x**4*y**5/2 - \ + x**3*y**3/6 + x**2*y**3 + x*y + + # Constant term in series + a = symbols('a') + R, x, y = ring('x, y', QQ[sin(a), cos(a), a]) + assert rs_sin(x + a, x, 5) == sin(a)*x**4/24 - cos(a)*x**3/6 - \ + sin(a)*x**2/2 + cos(a)*x + sin(a) + assert rs_sin(x + x**2*y + a, x, 5) == -sin(a)*x**4*y**2/2 - \ + cos(a)*x**4*y/2 + sin(a)*x**4/24 - sin(a)*x**3*y - cos(a)*x**3/6 + \ + cos(a)*x**2*y - sin(a)*x**2/2 + cos(a)*x + sin(a) + + R, x, y = ring('x, y', EX) + assert rs_sin(x + a, x, 5) == EX(sin(a)/24)*x**4 - EX(cos(a)/6)*x**3 - \ + EX(sin(a)/2)*x**2 + EX(cos(a))*x + EX(sin(a)) + assert rs_sin(x + x**2*y + a, x, 5) == -EX(sin(a)/2)*x**4*y**2 - \ + EX(cos(a)/2)*x**4*y + EX(sin(a)/24)*x**4 - EX(sin(a))*x**3*y - \ + EX(cos(a)/6)*x**3 + EX(cos(a))*x**2*y - EX(sin(a)/2)*x**2 + \ + EX(cos(a))*x + EX(sin(a)) + + +def test_cos(): + R, x, y = ring('x, y', QQ) + assert rs_cos(x, x, 9) == 1 - x**2/2 + x**4/24 - x**6/720 + x**8/40320 + assert rs_cos(x*y + x**2*y**3, x, 9) == x**8*y**12/24 - \ + x**8*y**10/48 + x**8*y**8/40320 + x**7*y**10/6 - \ + x**7*y**8/120 + x**6*y**8/4 - x**6*y**6/720 + x**5*y**6/6 - \ + x**4*y**6/2 + x**4*y**4/24 - x**3*y**4 - x**2*y**2/2 + 1 + + # Constant term in series + a = symbols('a') + R, x, y = ring('x, y', QQ[sin(a), cos(a), a]) + assert rs_cos(x + a, x, 5) == cos(a)*x**4/24 + sin(a)*x**3/6 - \ + cos(a)*x**2/2 - sin(a)*x + cos(a) + assert rs_cos(x + x**2*y + a, x, 5) == -cos(a)*x**4*y**2/2 + \ + sin(a)*x**4*y/2 + cos(a)*x**4/24 - cos(a)*x**3*y + sin(a)*x**3/6 - \ + sin(a)*x**2*y - cos(a)*x**2/2 - sin(a)*x + cos(a) + + R, x, y = ring('x, y', EX) + assert rs_cos(x + a, x, 5) == EX(cos(a)/24)*x**4 + EX(sin(a)/6)*x**3 - \ + EX(cos(a)/2)*x**2 - EX(sin(a))*x + EX(cos(a)) + assert rs_cos(x + x**2*y + a, x, 5) == -EX(cos(a)/2)*x**4*y**2 + \ + EX(sin(a)/2)*x**4*y + EX(cos(a)/24)*x**4 - EX(cos(a))*x**3*y + \ + EX(sin(a)/6)*x**3 - EX(sin(a))*x**2*y - EX(cos(a)/2)*x**2 - \ + EX(sin(a))*x + EX(cos(a)) + + +def test_cos_sin(): + R, x, y = ring('x, y', QQ) + c, s = rs_cos_sin(x, x, 9) + assert c == rs_cos(x, x, 9) + assert s == rs_sin(x, x, 9) + c, s = rs_cos_sin(x + x*y, x, 5) + assert c == rs_cos(x + x*y, x, 5) + assert s == rs_sin(x + x*y, x, 5) + + # constant term in series + c, s = rs_cos_sin(1 + x + x**2, x, 5) + assert c == rs_cos(1 + x + x**2, x, 5) + assert s == rs_sin(1 + x + x**2, x, 5) + + a = symbols('a') + R, x, y = ring('x, y', QQ[sin(a), cos(a), a]) + c, s = rs_cos_sin(x + a, x, 5) + assert c == rs_cos(x + a, x, 5) + assert s == rs_sin(x + a, x, 5) + + R, x, y = ring('x, y', EX) + c, s = rs_cos_sin(x + a, x, 5) + assert c == rs_cos(x + a, x, 5) + assert s == rs_sin(x + a, x, 5) + + +def test_atanh(): + R, x, y = ring('x, y', QQ) + assert rs_atanh(x, x, 9) == x + x**3/3 + x**5/5 + x**7/7 + assert rs_atanh(x*y + x**2*y**3, x, 9) == 2*x**8*y**11 + x**8*y**9 + \ + 2*x**7*y**9 + x**7*y**7/7 + x**6*y**9/3 + x**6*y**7 + x**5*y**7 + \ + x**5*y**5/5 + x**4*y**5 + x**3*y**3/3 + x**2*y**3 + x*y + + # Constant term in series + a = symbols('a') + R, x, y = ring('x, y', EX) + assert rs_atanh(x + a, x, 5) == EX((a**3 + a)/(a**8 - 4*a**6 + 6*a**4 - \ + 4*a**2 + 1))*x**4 - EX((3*a**2 + 1)/(3*a**6 - 9*a**4 + \ + 9*a**2 - 3))*x**3 + EX(a/(a**4 - 2*a**2 + 1))*x**2 - EX(1/(a**2 - \ + 1))*x + EX(atanh(a)) + assert rs_atanh(x + x**2*y + a, x, 4) == EX(2*a/(a**4 - 2*a**2 + \ + 1))*x**3*y - EX((3*a**2 + 1)/(3*a**6 - 9*a**4 + 9*a**2 - 3))*x**3 - \ + EX(1/(a**2 - 1))*x**2*y + EX(a/(a**4 - 2*a**2 + 1))*x**2 - \ + EX(1/(a**2 - 1))*x + EX(atanh(a)) + + p = x + x**2 + 5 + assert rs_atanh(p, x, 10).compose(x, 10) == EX(Rational(-733442653682135, 5079158784) \ + + atanh(5)) + + # Test for _atanh faster for small and univariate series + R,x = ring('x', QQ) + p = x**2 + 2*x + assert _atanh(p, x, 5) == rs_atanh(p, x, 5) + + R,x = ring('x', EX) + p = x**2 + 2*x + assert _atanh(p, x, 9) == rs_atanh(p, x, 9) + + +def test_asinh(): + R, x, y = ring('x, y', QQ) + assert rs_asinh(x, x, 9) == -5/112*x**7 + 3/40*x**5 - 1/6*x**3 + x + assert rs_asinh(x*y + x**2*y**3, x, 9) == 3/4*x**8*y**11 - 5/16*x**8*y**9 + \ + 3/4*x**7*y**9 - 5/112*x**7*y**7 - 1/6*x**6*y**9 + 3/8*x**6*y**7 - 1/2*x \ + **5*y**7 + 3/40*x**5*y**5 - 1/2*x**4*y**5 - 1/6*x**3*y**3 + x**2*y**3 + x*y + + # Constant term in series + a = symbols('a') + R, x, y = ring('x, y', EX) + assert rs_asinh(x + a, x, 3) == -EX(a/(2*a**2*sqrt(a**2 + 1) + 2*sqrt(a**2 + 1))) \ + *x**2 + EX(1/sqrt(a**2 + 1))*x + EX(asinh(a)) + assert rs_asinh(x + x**2*y + a, x, 3) == EX(1/sqrt(a**2 + 1))*x**2*y - EX(a/(2*a**2 \ + *sqrt(a**2 + 1) + 2*sqrt(a**2 + 1)))*x**2 + EX(1/sqrt(a**2 + 1))*x + EX(asinh(a)) + + p = x + x ** 2 + 5 + assert rs_asinh(p, x, 10).compose(x, 10) == EX(asinh(5) + 4643789843094995*sqrt(26)/\ + 205564141692) + + +def test_sinh(): + R, x, y = ring('x, y', QQ) + assert rs_sinh(x, x, 9) == x + x**3/6 + x**5/120 + x**7/5040 + assert rs_sinh(x*y + x**2*y**3, x, 9) == x**8*y**11/12 + \ + x**8*y**9/720 + x**7*y**9/12 + x**7*y**7/5040 + x**6*y**9/6 + \ + x**6*y**7/24 + x**5*y**7/2 + x**5*y**5/120 + x**4*y**5/2 + \ + x**3*y**3/6 + x**2*y**3 + x*y + + # constant term in series + a = symbols('a') + R, x, y = ring('x, y', QQ[sinh(a), cosh(a), a]) + assert rs_sinh(x + a, x, 5) == 1/24*x**4*(sinh(a)) + 1/6*x**3*(cosh(a)) + 1/\ + 2*x**2*(sinh(a)) + x*(cosh(a)) + (sinh(a)) + assert rs_sinh(x + x**2*y + a, x, 5) == 1/2*(sinh(a))*x**4*y**2 + 1/2*(cosh(a))\ + *x**4*y + 1/24*(sinh(a))*x**4 + (sinh(a))*x**3*y + 1/6*(cosh(a))*x**3 + \ + (cosh(a))*x**2*y + 1/2*(sinh(a))*x**2 + (cosh(a))*x + (sinh(a)) + + R, x, y = ring('x, y', EX) + assert rs_sinh(x + a, x, 5) == EX(sinh(a)/24)*x**4 + EX(cosh(a)/6)*x**3 + \ + EX(sinh(a)/2)*x**2 + EX(cosh(a))*x + EX(sinh(a)) + assert rs_sinh(x + x**2*y + a, x, 5) == EX(sinh(a)/2)*x**4*y**2 + EX(cosh(a)/\ + 2)*x**4*y + EX(sinh(a)/24)*x**4 + EX(sinh(a))*x**3*y + EX(cosh(a)/6)*x**3 \ + + EX(cosh(a))*x**2*y + EX(sinh(a)/2)*x**2 + EX(cosh(a))*x + EX(sinh(a)) + + +def test_cosh(): + R, x, y = ring('x, y', QQ) + assert rs_cosh(x, x, 9) == 1 + x**2/2 + x**4/24 + x**6/720 + x**8/40320 + assert rs_cosh(x*y + x**2*y**3, x, 9) == x**8*y**12/24 + \ + x**8*y**10/48 + x**8*y**8/40320 + x**7*y**10/6 + \ + x**7*y**8/120 + x**6*y**8/4 + x**6*y**6/720 + x**5*y**6/6 + \ + x**4*y**6/2 + x**4*y**4/24 + x**3*y**4 + x**2*y**2/2 + 1 + + # constant term in series + a = symbols('a') + R, x, y = ring('x, y', QQ[sinh(a), cosh(a), a]) + assert rs_cosh(x + a, x, 5) == 1/24*(cosh(a))*x**4 + 1/6*(sinh(a))*x**3 + \ + 1/2*(cosh(a))*x**2 + (sinh(a))*x + (cosh(a)) + assert rs_cosh(x + x**2*y + a, x, 5) == 1/2*(cosh(a))*x**4*y**2 + 1/2*(sinh(a))\ + *x**4*y + 1/24*(cosh(a))*x**4 + (cosh(a))*x**3*y + 1/6*(sinh(a))*x**3 + \ + (sinh(a))*x**2*y + 1/2*(cosh(a))*x**2 + (sinh(a))*x + (cosh(a)) + R, x, y = ring('x, y', EX) + assert rs_cosh(x + a, x, 5) == EX(cosh(a)/24)*x**4 + EX(sinh(a)/6)*x**3 + \ + EX(cosh(a)/2)*x**2 + EX(sinh(a))*x + EX(cosh(a)) + assert rs_cosh(x + x**2*y + a, x, 5) == EX(cosh(a)/2)*x**4*y**2 + EX(sinh(a)/\ + 2)*x**4*y + EX(cosh(a)/24)*x**4 + EX(cosh(a))*x**3*y + EX(sinh(a)/6)*x**3 \ + + EX(sinh(a))*x**2*y + EX(cosh(a)/2)*x**2 + EX(sinh(a))*x + EX(cosh(a)) + + +def test_cosh_sinh(): + R, x, y = ring('x, y', QQ) + ch, sh = rs_cosh_sinh(x, x, 9) + assert ch == rs_cosh(x, x, 9) + assert sh == rs_sinh(x, x, 9) + ch, sh = rs_cosh_sinh(x + x*y, x, 5) + assert ch == rs_cosh(x + x*y, x, 5) + assert sh == rs_sinh(x + x*y, x, 5) + + # constant term in series + c, s = rs_cosh_sinh(1 + x + x**2, x, 5) + assert c == rs_cosh(1 + x + x**2, x, 5) + assert s == rs_sinh(1 + x + x**2, x, 5) + + a = symbols('a') + R, x, y = ring('x, y', QQ[sinh(a), cosh(a), a]) + ch, sh = rs_cosh_sinh(x + a, x, 5) + assert ch == rs_cosh(x + a, x, 5) + assert sh == rs_sinh(x + a, x, 5) + R, x, y = ring('x, y', EX) + ch, sh = rs_cosh_sinh(x + a, x, 5) + assert ch == rs_cosh(x + a, x, 5) + assert sh == rs_sinh(x + a, x, 5) + + +def test_tanh(): + R, x, y = ring('x, y', QQ) + assert rs_tanh(x, x, 9) == x - QQ(1,3)*x**3 + QQ(2,15)*x**5 - QQ(17,315)*x**7 + assert rs_tanh(x*y + x**2*y**3, x, 9) == 4*x**8*y**11/3 - \ + 17*x**8*y**9/45 + 4*x**7*y**9/3 - 17*x**7*y**7/315 - x**6*y**9/3 + \ + 2*x**6*y**7/3 - x**5*y**7 + 2*x**5*y**5/15 - x**4*y**5 - \ + x**3*y**3/3 + x**2*y**3 + x*y + + # Constant term in series + a = symbols('a') + R, x, y = ring('x, y', EX) + assert rs_tanh(x + a, x, 5) == EX(tanh(a)**5 - 5*tanh(a)**3/3 + + 2*tanh(a)/3)*x**4 + EX(-tanh(a)**4 + 4*tanh(a)**2/3 - QQ(1, 3))*x**3 + \ + EX(tanh(a)**3 - tanh(a))*x**2 + EX(-tanh(a)**2 + 1)*x + EX(tanh(a)) + + p = rs_tanh(x + x**2*y + a, x, 4) + assert (p.compose(x, 10)).compose(y, 5) == EX(-1000*tanh(a)**4 + \ + 10100*tanh(a)**3 + 2470*tanh(a)**2/3 - 10099*tanh(a) + QQ(530, 3)) + + +def test_RR(): + rs_funcs = [rs_sin, rs_cos, rs_tan, rs_cot, rs_atan, rs_tanh] + sympy_funcs = [sin, cos, tan, cot, atan, tanh] + R, x, y = ring('x, y', RR) + a = symbols('a') + for rs_func, sympy_func in zip(rs_funcs, sympy_funcs): + p = rs_func(2 + x, x, 5).compose(x, 5) + q = sympy_func(2 + a).series(a, 0, 5).removeO() + is_close(p.as_expr(), q.subs(a, 5).n()) + + p = rs_nth_root(2 + x, 5, x, 5).compose(x, 5) + q = ((2 + a)**QQ(1, 5)).series(a, 0, 5).removeO() + is_close(p.as_expr(), q.subs(a, 5).n()) + + +def test_is_regular(): + R, x, y = puiseux_ring('x, y', QQ) + p = 1 + 2*x + x**2 + 3*x**3 + assert not rs_is_puiseux(p, x) + + p = x + x**QQ(1,5)*y + assert rs_is_puiseux(p, x) + assert not rs_is_puiseux(p, y) + + p = x + x**2*y**QQ(1,5)*y + assert not rs_is_puiseux(p, x) + + +def test_puiseux(): + R, x, y = puiseux_ring('x, y', QQ) + p = x**QQ(2,5) + x**QQ(2,3) + x + + r = rs_series_inversion(p, x, 1) + r1 = -x**QQ(14,15) + x**QQ(4,5) - 3*x**QQ(11,15) + x**QQ(2,3) + \ + 2*x**QQ(7,15) - x**QQ(2,5) - x**QQ(1,5) + x**QQ(2,15) - x**QQ(-2,15) \ + + x**QQ(-2,5) + assert r == r1 + + r = rs_nth_root(1 + p, 3, x, 1) + assert r == -x**QQ(4,5)/9 + x**QQ(2,3)/3 + x**QQ(2,5)/3 + 1 + + r = rs_log(1 + p, x, 1) + assert r == -x**QQ(4,5)/2 + x**QQ(2,3) + x**QQ(2,5) + + r = rs_LambertW(p, x, 1) + assert r == -x**QQ(4,5) + x**QQ(2,3) + x**QQ(2,5) + + p1 = x + x**QQ(1,5)*y + r = rs_exp(p1, x, 1) + assert r == x**QQ(4,5)*y**4/24 + x**QQ(3,5)*y**3/6 + x**QQ(2,5)*y**2/2 + \ + x**QQ(1,5)*y + 1 + + r = rs_atan(p, x, 2) + assert r == -x**QQ(9,5) - x**QQ(26,15) - x**QQ(22,15) - x**QQ(6,5)/3 + \ + x + x**QQ(2,3) + x**QQ(2,5) + + r = rs_atan(p1, x, 2) + assert r == x**QQ(9,5)*y**9/9 + x**QQ(9,5)*y**4 - x**QQ(7,5)*y**7/7 - \ + x**QQ(7,5)*y**2 + x*y**5/5 + x - x**QQ(3,5)*y**3/3 + x**QQ(1,5)*y + + r = rs_tan(p, x, 2) + assert r == x**QQ(2,5) + x**QQ(2,3) + x + QQ(1,3)*x**QQ(6,5) + x**QQ(22,15)\ + + x**QQ(26,15) + x**QQ(9,5) + + r = rs_sin(p, x, 2) + assert r == x**QQ(2,5) + x**QQ(2,3) + x - QQ(1,6)*x**QQ(6,5) - QQ(1,2)*x**\ + QQ(22,15) - QQ(1,2)*x**QQ(26,15) - QQ(1,2)*x**QQ(9,5) + + r = rs_cos(p, x, 2) + assert r == 1 - QQ(1,2)*x**QQ(4,5) - x**QQ(16,15) - QQ(1,2)*x**QQ(4,3) - \ + x**QQ(7,5) + QQ(1,24)*x**QQ(8,5) - x**QQ(5,3) + QQ(1,6)*x**QQ(28,15) + + r = rs_asin(p, x, 2) + assert r == x**QQ(9,5)/2 + x**QQ(26,15)/2 + x**QQ(22,15)/2 + \ + x**QQ(6,5)/6 + x + x**QQ(2,3) + x**QQ(2,5) + + r = rs_cot(p, x, 1) + assert r == -x**QQ(14,15) + x**QQ(4,5) - 3*x**QQ(11,15) + \ + 2*x**QQ(2,3)/3 + 2*x**QQ(7,15) - 4*x**QQ(2,5)/3 - x**QQ(1,5) + \ + x**QQ(2,15) - x**QQ(-2,15) + x**QQ(-2,5) + + r = rs_cos_sin(p, x, 2) + assert r[0] == x**QQ(28,15)/6 - x**QQ(5,3) + x**QQ(8,5)/24 - x**QQ(7,5) - \ + x**QQ(4,3)/2 - x**QQ(16,15) - x**QQ(4,5)/2 + 1 + assert r[1] == -x**QQ(9,5)/2 - x**QQ(26,15)/2 - x**QQ(22,15)/2 - \ + x**QQ(6,5)/6 + x + x**QQ(2,3) + x**QQ(2,5) + + r = rs_atanh(p, x, 2) + assert r == x**QQ(9,5) + x**QQ(26,15) + x**QQ(22,15) + x**QQ(6,5)/3 + x + \ + x**QQ(2,3) + x**QQ(2,5) + + r = rs_asinh(p, x, 2) + assert r == x**QQ(2,5) + x**QQ(2,3) + x - QQ(1,6)*x**QQ(6,5) - QQ(1,2)*x**\ + QQ(22,15) - QQ(1,2)*x**QQ(26,15) - QQ(1,2)*x**QQ(9,5) + + r = rs_cosh(p, x, 2) + assert r == x**QQ(28,15)/6 + x**QQ(5,3) + x**QQ(8,5)/24 + x**QQ(7,5) + \ + x**QQ(4,3)/2 + x**QQ(16,15) + x**QQ(4,5)/2 + 1 + + r = rs_sinh(p, x, 2) + assert r == x**QQ(9,5)/2 + x**QQ(26,15)/2 + x**QQ(22,15)/2 + \ + x**QQ(6,5)/6 + x + x**QQ(2,3) + x**QQ(2,5) + + r = rs_cosh_sinh(p, x, 2) + assert r[0] == x**QQ(28,15)/6 + x**QQ(5,3) + x**QQ(8,5)/24 + x**QQ(7,5) + \ + x**QQ(4,3)/2 + x**QQ(16,15) + x**QQ(4,5)/2 + 1 + assert r[1] == x**QQ(9,5)/2 + x**QQ(26,15)/2 + x**QQ(22,15)/2 + \ + x**QQ(6,5)/6 + x + x**QQ(2,3) + x**QQ(2,5) + + r = rs_tanh(p, x, 2) + assert r == -x**QQ(9,5) - x**QQ(26,15) - x**QQ(22,15) - x**QQ(6,5)/3 + \ + x + x**QQ(2,3) + x**QQ(2,5) + + +def test_puiseux_algebraic(): # https://github.com/sympy/sympy/issues/24395 + + K = QQ.algebraic_field(sqrt(2)) + sqrt2 = K.from_sympy(sqrt(2)) + x, y = symbols('x, y') + R, xr, yr = puiseux_ring([x, y], K) + p = (1+sqrt2)*xr**QQ(1,2) + (1-sqrt2)*yr**QQ(2,3) + + assert p.to_dict() == {(QQ(1,2),QQ(0)):1+sqrt2, (QQ(0),QQ(2,3)):1-sqrt2} + assert p.as_expr() == (1 + sqrt(2))*x**(S(1)/2) + (1 - sqrt(2))*y**(S(2)/3) + + +def test1(): + R, x = puiseux_ring('x', QQ) + r = rs_sin(x, x, 15)*x**(-5) + assert r == x**8/6227020800 - x**6/39916800 + x**4/362880 - x**2/5040 + \ + QQ(1,120) - x**-2/6 + x**-4 + + p = rs_sin(x, x, 10) + r = rs_nth_root(p, 2, x, 10) + assert r == -67*x**QQ(17,2)/29030400 - x**QQ(13,2)/24192 + \ + x**QQ(9,2)/1440 - x**QQ(5,2)/12 + x**QQ(1,2) + + p = rs_sin(x, x, 10) + r = rs_nth_root(p, 7, x, 10) + r = rs_pow(r, 5, x, 10) + assert r == -97*x**QQ(61,7)/124467840 - x**QQ(47,7)/16464 + \ + 11*x**QQ(33,7)/3528 - 5*x**QQ(19,7)/42 + x**QQ(5,7) + + r = rs_exp(x**QQ(1,2), x, 10) + assert r == x**QQ(19,2)/121645100408832000 + x**9/6402373705728000 + \ + x**QQ(17,2)/355687428096000 + x**8/20922789888000 + \ + x**QQ(15,2)/1307674368000 + x**7/87178291200 + \ + x**QQ(13,2)/6227020800 + x**6/479001600 + x**QQ(11,2)/39916800 + \ + x**5/3628800 + x**QQ(9,2)/362880 + x**4/40320 + x**QQ(7,2)/5040 + \ + x**3/720 + x**QQ(5,2)/120 + x**2/24 + x**QQ(3,2)/6 + x/2 + \ + x**QQ(1,2) + 1 + + +def test_puiseux2(): + R, y = ring('y', QQ) + S, x = puiseux_ring('x', R.to_domain()) + + p = x + x**QQ(1,5)*y + r = rs_atan(p, x, 3) + assert r == (y**13/13 + y**8 + 2*y**3)*x**QQ(13,5) - (y**11/11 + y**6 + + y)*x**QQ(11,5) + (y**9/9 + y**4)*x**QQ(9,5) - (y**7/7 + + y**2)*x**QQ(7,5) + (y**5/5 + 1)*x - y**3*x**QQ(3,5)/3 + y*x**QQ(1,5) + + +@slow +def test_rs_series(): + x, a, b, c = symbols('x, a, b, c') + + assert rs_series(a, a, 5).as_expr() == a + assert rs_series(sin(a), a, 5).as_expr() == (sin(a).series(a, 0, + 5)).removeO() + assert rs_series(sin(a) + cos(a), a, 5).as_expr() == ((sin(a) + + cos(a)).series(a, 0, 5)).removeO() + assert rs_series(sin(a)*cos(a), a, 5).as_expr() == ((sin(a)* + cos(a)).series(a, 0, 5)).removeO() + + p = (sin(a) - a)*(cos(a**2) + a**4/2) + assert expand(rs_series(p, a, 10).as_expr()) == expand(p.series(a, 0, + 10).removeO()) + + p = sin(a**2/2 + a/3) + cos(a/5)*sin(a/2)**3 + assert expand(rs_series(p, a, 5).as_expr()) == expand(p.series(a, 0, + 5).removeO()) + + p = sin(x**2 + a)*(cos(x**3 - 1) - a - a**2) + assert expand(rs_series(p, a, 5).as_expr()) == expand(p.series(a, 0, + 5).removeO()) + + p = sin(a**2 - a/3 + 2)**5*exp(a**3 - a/2) + assert expand(rs_series(p, a, 10).as_expr()) == expand(p.series(a, 0, + 10).removeO()) + + p = sin(a + b + c) + assert expand(rs_series(p, a, 5).as_expr()) == expand(p.series(a, 0, + 5).removeO()) + + p = tan(sin(a**2 + 4) + b + c) + assert expand(rs_series(p, a, 6).as_expr()) == expand(p.series(a, 0, + 6).removeO()) + + p = a**QQ(2,5) + a**QQ(2,3) + a + + r = rs_series(tan(p), a, 2) + assert r.as_expr() == a**QQ(9,5) + a**QQ(26,15) + a**QQ(22,15) + a**QQ(6,5)/3 + \ + a + a**QQ(2,3) + a**QQ(2,5) + + r = rs_series(exp(p), a, 1) + assert r.as_expr() == a**QQ(4,5)/2 + a**QQ(2,3) + a**QQ(2,5) + 1 + + r = rs_series(sin(p), a, 2) + assert r.as_expr() == -a**QQ(9,5)/2 - a**QQ(26,15)/2 - a**QQ(22,15)/2 - \ + a**QQ(6,5)/6 + a + a**QQ(2,3) + a**QQ(2,5) + + r = rs_series(cos(p), a, 2) + assert r.as_expr() == a**QQ(28,15)/6 - a**QQ(5,3) + a**QQ(8,5)/24 - a**QQ(7,5) - \ + a**QQ(4,3)/2 - a**QQ(16,15) - a**QQ(4,5)/2 + 1 + + assert rs_series(sin(a)/7, a, 5).as_expr() == (sin(a)/7).series(a, 0, + 5).removeO() + + +def test_rs_series_ConstantInExpr(): + x, a = symbols('x a') + assert rs_series(log(1 + x), x, 5).as_expr() == -x**4/4 + x**3/3 - \ + x**2/2 + x + assert rs_series(log(1 + 4*x), x, 5).as_expr() == -64*x**4 + 64*x**3/3 - \ + 8*x**2 + 4*x + assert rs_series(log(1 + x + x**2), x, 10).as_expr() == -2*x**9/9 + \ + x**8/8 + x**7/7 - x**6/3 + x**5/5 + x**4/4 - 2*x**3/3 + x**2/2 + x + assert rs_series(log(1 + x*a**2), x, 7).as_expr() == -x**6*a**12/6 + \ + x**5*a**10/5 - x**4*a**8/4 + x**3*a**6/3 - x**2*a**4/2 + x*a**2 + + assert rs_series(atan(1 + x), x, 9).as_expr() == -x**7/112 + x**6/48 - x**5/40 \ + + x**3/12 - x**2/4 + x/2 + pi/4 + assert rs_series(atan(1 + x + x**2),x, 9).as_expr() == -15*x**7/112 - x**6/48 + \ + 9*x**5/40 - 5*x**3/12 + x**2/4 + x/2 + pi/4 + assert rs_series(atan(1 + x * a), x, 9).as_expr() == -a**7*x**7/112 + a**6*x**6/48 \ + - a**5*x**5/40 + a**3*x**3/12 - a**2*x**2/4 + a*x/2 + pi/4 + + assert rs_series(tanh(1 + x), x, 5).as_expr() == -5*x**4*tanh(1)**3/3 + x**4* \ + tanh(1)**5 + 2*x**4*tanh(1)/3 - x**3*tanh(1)**4 - x**3/3 + 4*x**3*tanh(1) \ + **2/3 - x**2*tanh(1) + x**2*tanh(1)**3 - x*tanh(1)**2 + x + tanh(1) + assert rs_series(tanh(1 + x * a), x, 3).as_expr() == -a**2*x**2*tanh(1) + a**2*x** \ + 2*tanh(1)**3 - a*x*tanh(1)**2 + a*x + tanh(1) + + assert rs_series(sinh(1 + x), x, 5).as_expr() == x**4*sinh(1)/24 + x**3*cosh(1)/6 + \ + x**2*sinh(1)/2 + x*cosh(1) + sinh(1) + assert rs_series(sinh(1 + x * a), x, 5).as_expr() == a**4*x**4*sinh(1)/24 + \ + a**3*x**3*cosh(1)/6 + a**2*x**2*sinh(1)/2 + a*x*cosh(1) + sinh(1) + + assert rs_series(cosh(1 + x), x, 5).as_expr() == x**4*cosh(1)/24 + x**3*sinh(1)/6 + \ + x**2*cosh(1)/2 + x*sinh(1) + cosh(1) + assert rs_series(cosh(1 + x * a), x, 5).as_expr() == a**4*x**4*cosh(1)/24 + \ + a**3*x**3*sinh(1)/6 + a**2*x**2*cosh(1)/2 + a*x*sinh(1) + cosh(1) + + +def test_issue(): + # https://github.com/sympy/sympy/issues/10191 + # https://github.com/sympy/sympy/issues/19543 + + a, b = symbols('a b') + assert rs_series(sin(a**QQ(3,7))*exp(a + b**QQ(6,7)), a,2).as_expr() == \ + a**QQ(10,7)*exp(b**QQ(6,7)) - a**QQ(9,7)*exp(b**QQ(6,7))/6 + a**QQ(3,7)*exp(b**QQ(6,7)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rings.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rings.py new file mode 100644 index 0000000000000000000000000000000000000000..455cc319908d0173737531b339e22def8e4a26fc --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rings.py @@ -0,0 +1,1591 @@ +"""Test sparse polynomials. """ + +from functools import reduce +from operator import add, mul + +from sympy.polys.rings import ring, xring, sring, PolyRing, PolyElement +from sympy.polys.fields import field, FracField +from sympy.polys.densebasic import ninf +from sympy.polys.domains import ZZ, QQ, RR, FF, EX +from sympy.polys.orderings import lex, grlex +from sympy.polys.polyerrors import GeneratorsError, \ + ExactQuotientFailed, MultivariatePolynomialError, CoercionFailed + +from sympy.testing.pytest import raises +from sympy.core import Symbol, symbols +from sympy.core.singleton import S +from sympy.core.numbers import pi +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt + +def test_PolyRing___init__(): + x, y, z, t = map(Symbol, "xyzt") + + 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 + assert len(PolyRing("", ZZ, lex).gens) == 0 + assert len(PolyRing([], ZZ, lex).gens) == 0 + + raises(GeneratorsError, lambda: PolyRing(0, ZZ, lex)) + + assert PolyRing("x", ZZ[t], lex).domain == ZZ[t] + assert PolyRing("x", 'ZZ[t]', lex).domain == ZZ[t] + assert PolyRing("x", PolyRing("t", ZZ, lex), lex).domain == ZZ[t] + + raises(GeneratorsError, lambda: PolyRing("x", PolyRing("x", ZZ, lex), lex)) + + _lex = Symbol("lex") + assert PolyRing("x", ZZ, lex).order == lex + assert PolyRing("x", ZZ, _lex).order == lex + assert PolyRing("x", ZZ, 'lex').order == lex + + R1 = PolyRing("x,y", ZZ, lex) + R2 = PolyRing("x,y", ZZ, lex) + R3 = PolyRing("x,y,z", ZZ, lex) + + assert R1.x == R1.gens[0] + assert R1.y == R1.gens[1] + assert R1.x == R2.x + assert R1.y == R2.y + assert R1.x != R3.x + assert R1.y != R3.y + +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_PolyRing_ring_new(): + R, x, y, z = ring("x,y,z", QQ) + + assert R.ring_new(7) == R(7) + assert R.ring_new(7*x*y*z) == 7*x*y*z + + f = x**2 + 2*x*y + 3*x + 4*z**2 + 5*z + 6 + + assert R.ring_new([[[1]], [[2], [3]], [[4, 5, 6]]]) == f + assert R.ring_new({(2, 0, 0): 1, (1, 1, 0): 2, (1, 0, 0): 3, (0, 0, 2): 4, (0, 0, 1): 5, (0, 0, 0): 6}) == f + assert R.ring_new([((2, 0, 0), 1), ((1, 1, 0), 2), ((1, 0, 0), 3), ((0, 0, 2), 4), ((0, 0, 1), 5), ((0, 0, 0), 6)]) == f + + R, = ring("", QQ) + assert R.ring_new([((), 7)]) == R(7) + +def test_PolyRing_drop(): + R, x,y,z = ring("x,y,z", ZZ) + + assert R.drop(x) == PolyRing("y,z", ZZ, lex) + assert R.drop(y) == PolyRing("x,z", ZZ, lex) + assert R.drop(z) == PolyRing("x,y", ZZ, lex) + + assert R.drop(0) == PolyRing("y,z", ZZ, lex) + assert R.drop(0).drop(0) == PolyRing("z", ZZ, lex) + assert R.drop(0).drop(0).drop(0) == ZZ + + assert R.drop(1) == PolyRing("x,z", ZZ, lex) + + assert R.drop(2) == PolyRing("x,y", ZZ, lex) + assert R.drop(2).drop(1) == PolyRing("x", ZZ, lex) + assert R.drop(2).drop(1).drop(0) == ZZ + + raises(ValueError, lambda: R.drop(3)) + raises(ValueError, lambda: R.drop(x).drop(y)) + +def test_PolyRing___getitem__(): + R, x,y,z = ring("x,y,z", ZZ) + + assert R[0:] == PolyRing("x,y,z", ZZ, lex) + assert R[1:] == PolyRing("y,z", ZZ, lex) + assert R[2:] == PolyRing("z", ZZ, lex) + assert R[3:] == ZZ + +def test_PolyRing_is_(): + R = PolyRing("x", QQ, lex) + + assert R.is_univariate is True + assert R.is_multivariate is False + + R = PolyRing("x,y,z", QQ, lex) + + assert R.is_univariate is False + assert R.is_multivariate is True + + R = PolyRing("", QQ, lex) + + assert R.is_univariate is False + assert R.is_multivariate is False + +def test_PolyRing_add(): + R, x = ring("x", ZZ) + F = [ x**2 + 2*i + 3 for i in range(4) ] + + assert R.add(F) == reduce(add, F) == 4*x**2 + 24 + + R, = ring("", ZZ) + + assert R.add([2, 5, 7]) == 14 + +def test_PolyRing_mul(): + R, x = ring("x", ZZ) + F = [ x**2 + 2*i + 3 for i in range(4) ] + + assert R.mul(F) == reduce(mul, F) == x**8 + 24*x**6 + 206*x**4 + 744*x**2 + 945 + + R, = ring("", ZZ) + + assert R.mul([2, 3, 5]) == 30 + +def test_PolyRing_symmetric_poly(): + R, x, y, z, t = ring("x,y,z,t", ZZ) + + raises(ValueError, lambda: R.symmetric_poly(-1)) + raises(ValueError, lambda: R.symmetric_poly(5)) + + assert R.symmetric_poly(0) == R.one + assert R.symmetric_poly(1) == x + y + z + t + assert R.symmetric_poly(2) == x*y + x*z + x*t + y*z + y*t + z*t + assert R.symmetric_poly(3) == x*y*z + x*y*t + x*z*t + y*z*t + assert R.symmetric_poly(4) == x*y*z*t + +def test_sring(): + x, y, z, t = symbols("x,y,z,t") + + R = PolyRing("x,y,z", ZZ, lex) + assert sring(x + 2*y + 3*z) == (R, R.x + 2*R.y + 3*R.z) + + R = PolyRing("x,y,z", QQ, lex) + assert sring(x + 2*y + z/3) == (R, R.x + 2*R.y + R.z/3) + assert sring([x, 2*y, z/3]) == (R, [R.x, 2*R.y, R.z/3]) + + Rt = PolyRing("t", ZZ, lex) + R = PolyRing("x,y,z", Rt, lex) + assert sring(x + 2*t*y + 3*t**2*z, x, y, z) == (R, R.x + 2*Rt.t*R.y + 3*Rt.t**2*R.z) + + Rt = PolyRing("t", QQ, lex) + R = PolyRing("x,y,z", Rt, lex) + assert sring(x + t*y/2 + t**2*z/3, x, y, z) == (R, R.x + Rt.t*R.y/2 + Rt.t**2*R.z/3) + + Rt = FracField("t", ZZ, lex) + R = PolyRing("x,y,z", Rt, lex) + assert sring(x + 2*y/t + t**2*z/3, x, y, z) == (R, R.x + 2*R.y/Rt.t + Rt.t**2*R.z/3) + + r = sqrt(2) - sqrt(3) + R, a = sring(r, extension=True) + assert R.domain == QQ.algebraic_field(sqrt(2) + sqrt(3)) + assert R.gens == () + assert a == R.domain.from_sympy(r) + +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 + + assert R.one == QQ(1, 1) == R.one + assert R.one == 1 == R.one + + Rt, t = ring("t", ZZ) + R, x, y = ring("x,y", Rt) + + assert (t**3*x/x == t**3) == True + assert (t**3*x/x == t**4) == False + +def test_PolyElement__lt_le_gt_ge__(): + R, x, y = ring("x,y", ZZ) + + assert R(1) < x < x**2 < x**3 + assert R(1) <= x <= x**2 <= x**3 + + assert x**3 > x**2 > x > R(1) + assert x**3 >= x**2 >= x >= R(1) + +def test_PolyElement__str__(): + x, y = symbols('x, y') + + for dom in [ZZ, QQ, ZZ[x], ZZ[x,y], ZZ[x][y]]: + R, t = ring('t', dom) + assert str(2*t**2 + 1) == '2*t**2 + 1' + + for dom in [EX, EX[x]]: + R, t = ring('t', dom) + assert str(2*t**2 + 1) == 'EX(2)*t**2 + EX(1)' + +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 + + U, V, W = symbols("u,v,w") + g = 3*U**2*V - U*V*W + 7*W**3 + 1 + + assert f != g + assert f.as_expr(U, V, W) == g + + raises(ValueError, lambda: f.as_expr(X)) + + R, = ring("", ZZ) + assert R(3).as_expr() == 3 + +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 R.is_element(f) + + f = R.from_expr(x) + assert f == X and R.is_element(f) + + f = R.from_expr(x*y*z) + assert f == X*Y*Z and R.is_element(f) + + f = R.from_expr(x*y*z + x*y + x) + assert f == X*Y*Z + X*Y + X and R.is_element(f) + + 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 R.is_element(f) + + r, F = sring([exp(2)]) + f = r.from_expr(exp(2)) + assert f == F[0] and r.is_element(f) + + 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))) + + R, = ring("", ZZ) + f = R.from_expr(1) + assert f == 1 and R.is_element(f) + +def test_PolyElement_degree(): + R, x,y,z = ring("x,y,z", ZZ) + + assert ninf == float('-inf') + + assert R(0).degree() is ninf + assert R(1).degree() == 0 + assert (x + 1).degree() == 1 + assert (2*y**3 + z).degree() == 0 + assert (x*y**3 + z).degree() == 1 + assert (x**5*y**3 + z).degree() == 5 + + assert R(0).degree(x) is ninf + assert R(1).degree(x) == 0 + assert (x + 1).degree(x) == 1 + assert (2*y**3 + z).degree(x) == 0 + assert (x*y**3 + z).degree(x) == 1 + assert (7*x**5*y**3 + z).degree(x) == 5 + + assert R(0).degree(y) is ninf + assert R(1).degree(y) == 0 + assert (x + 1).degree(y) == 0 + assert (2*y**3 + z).degree(y) == 3 + assert (x*y**3 + z).degree(y) == 3 + assert (7*x**5*y**3 + z).degree(y) == 3 + + assert R(0).degree(z) is ninf + assert R(1).degree(z) == 0 + assert (x + 1).degree(z) == 0 + assert (2*y**3 + z).degree(z) == 1 + assert (x*y**3 + z).degree(z) == 1 + assert (7*x**5*y**3 + z).degree(z) == 1 + + R, = ring("", ZZ) + assert R(0).degree() is ninf + assert R(1).degree() == 0 + +def test_PolyElement_tail_degree(): + R, x,y,z = ring("x,y,z", ZZ) + + assert R(0).tail_degree() is ninf + assert R(1).tail_degree() == 0 + assert (x + 1).tail_degree() == 0 + assert (2*y**3 + x**3*z).tail_degree() == 0 + assert (x*y**3 + x**3*z).tail_degree() == 1 + assert (x**5*y**3 + x**3*z).tail_degree() == 3 + + assert R(0).tail_degree(x) is ninf + assert R(1).tail_degree(x) == 0 + assert (x + 1).tail_degree(x) == 0 + assert (2*y**3 + x**3*z).tail_degree(x) == 0 + assert (x*y**3 + x**3*z).tail_degree(x) == 1 + assert (7*x**5*y**3 + x**3*z).tail_degree(x) == 3 + + assert R(0).tail_degree(y) is ninf + assert R(1).tail_degree(y) == 0 + assert (x + 1).tail_degree(y) == 0 + assert (2*y**3 + x**3*z).tail_degree(y) == 0 + assert (x*y**3 + x**3*z).tail_degree(y) == 0 + assert (7*x**5*y**3 + x**3*z).tail_degree(y) == 0 + + assert R(0).tail_degree(z) is ninf + assert R(1).tail_degree(z) == 0 + assert (x + 1).tail_degree(z) == 0 + assert (2*y**3 + x**3*z).tail_degree(z) == 0 + assert (x*y**3 + x**3*z).tail_degree(z) == 0 + assert (7*x**5*y**3 + x**3*z).tail_degree(z) == 0 + + R, = ring("", ZZ) + assert R(0).tail_degree() is ninf + assert R(1).tail_degree() == 0 + +def test_PolyElement_degrees(): + R, x,y,z = ring("x,y,z", ZZ) + + assert R(0).degrees() == (ninf, ninf, ninf) + assert R(1).degrees() == (0, 0, 0) + assert (x**2*y + x**3*z**2).degrees() == (3, 1, 2) + +def test_PolyElement_tail_degrees(): + R, x,y,z = ring("x,y,z", ZZ) + + assert R(0).tail_degrees() == (ninf, ninf, ninf) + assert R(1).tail_degrees() == (0, 0, 0) + assert (x**2*y + x**3*z**2).tail_degrees() == (2, 0, 0) + +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)) + + R, = ring("", ZZ) + assert R(3).coeff(1) == 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)) + + R, = ring("", ZZ) + assert R(0).LT == ((), 0) + assert R(1).LT == ((), 1) + +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 = (x**2/3 + y**3/4 + z**4/5).terms() + assert terms == [((2,0,0), QQ(1,3)), ((0,3,0), QQ(1,4)), ((0,0,4), QQ(1,5))] + + R, x,y = ring("x,y", ZZ, lex) + f = x*y**7 + 2*x**2*y**3 + + assert f.terms() == f.terms(lex) == f.terms('lex') == [((2, 3), 2), ((1, 7), 1)] + assert f.terms(grlex) == f.terms('grlex') == [((1, 7), 1), ((2, 3), 2)] + + R, x,y = ring("x,y", ZZ, grlex) + f = x*y**7 + 2*x**2*y**3 + + assert f.terms() == f.terms(grlex) == f.terms('grlex') == [((1, 7), 1), ((2, 3), 2)] + assert f.terms(lex) == f.terms('lex') == [((2, 3), 2), ((1, 7), 1)] + + R, = ring("", ZZ) + assert R(3).terms() == [((), 3)] + +def test_PolyElement_monoms(): + R, x,y,z = ring("x,y,z", QQ) + monoms = (x**2/3 + y**3/4 + z**4/5).monoms() + assert monoms == [(2,0,0), (0,3,0), (0,0,4)] + + R, x,y = ring("x,y", ZZ, lex) + f = x*y**7 + 2*x**2*y**3 + + assert f.monoms() == f.monoms(lex) == f.monoms('lex') == [(2, 3), (1, 7)] + assert f.monoms(grlex) == f.monoms('grlex') == [(1, 7), (2, 3)] + + R, x,y = ring("x,y", ZZ, grlex) + f = x*y**7 + 2*x**2*y**3 + + assert f.monoms() == f.monoms(grlex) == f.monoms('grlex') == [(1, 7), (2, 3)] + assert f.monoms(lex) == f.monoms('lex') == [(2, 3), (1, 7)] + +def test_PolyElement_coeffs(): + R, x,y,z = ring("x,y,z", QQ) + coeffs = (x**2/3 + y**3/4 + z**4/5).coeffs() + assert coeffs == [QQ(1,3), QQ(1,4), QQ(1,5)] + + R, x,y = ring("x,y", ZZ, lex) + f = x*y**7 + 2*x**2*y**3 + + assert f.coeffs() == f.coeffs(lex) == f.coeffs('lex') == [2, 1] + assert f.coeffs(grlex) == f.coeffs('grlex') == [1, 2] + + R, x,y = ring("x,y", ZZ, grlex) + f = x*y**7 + 2*x**2*y**3 + + assert f.coeffs() == f.coeffs(grlex) == f.coeffs('grlex') == [1, 2] + assert f.coeffs(lex) == f.coeffs('lex') == [2, 1] + +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) + + 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) + + assert dict(u + x) == dict(x + u) == {(1, 0, 0): 1, (0, 0, 0): u} + + Rxyz, x,y,z = ring("x,y,z", EX) + + assert dict(EX(pi) + x*y*z) == dict(x*y*z + EX(pi)) == {(1, 1, 1): EX(1), (0, 0, 0): EX(pi)} + +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) + + 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) + + assert dict(-u + x) == dict(x - u) == {(1, 0, 0): 1, (0, 0, 0): -u} + + Rxyz, x,y,z = ring("x,y,z", EX) + + assert dict(-EX(pi) + x*y*z) == dict(x*y*z - EX(pi)) == {(1, 1, 1): EX(1), (0, 0, 0): -EX(pi)} + +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) + + 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) + + assert dict(u*x) == dict(x*u) == {(1, 0, 0): u} + + Rxyz, x,y,z = ring("x,y,z", EX) + + assert dict(EX(pi)*x*y*z) == dict(x*y*z*EX(pi)) == {(1, 1, 1): EX(pi)} + +def test_PolyElement___truediv__(): + 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).quo(x) == x + assert (x**2 - x).quo(x) == x - 1 + + raises(ExactQuotientFailed, lambda: (x**2 - 1)/x) + assert (x**2 - x)/x == x - 1 + raises(ExactQuotientFailed, lambda: (x**2 - 1)/(2*x)) + + assert (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((x**2/3 + y**3/4 + z**4/5).terms()) == 0 + + R, x,y,z = ring("x,y,z", QQ) + assert len((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) + + assert dict((u**2*x + u)/u) == {(1, 0, 0): u, (0, 0, 0): 1} + raises(ExactQuotientFailed, lambda: u/(u**2*x + u)) + + raises(TypeError, lambda: t/x) + raises(TypeError, lambda: x/t) + raises(TypeError, lambda: t/u) + raises(TypeError, lambda: u/t) + + R, x = ring("x", ZZ) + f, g = x**2 + 2*x + 3, R(0) + + raises(ZeroDivisionError, lambda: f.div(g)) + raises(ZeroDivisionError, lambda: divmod(f, g)) + raises(ZeroDivisionError, lambda: f.rem(g)) + raises(ZeroDivisionError, lambda: f % g) + raises(ZeroDivisionError, lambda: f.quo(g)) + raises(ZeroDivisionError, lambda: f / g) + raises(ZeroDivisionError, lambda: f.exquo(g)) + + R, x, y = ring("x,y", ZZ) + f, g = x*y + 2*x + 3, R(0) + + raises(ZeroDivisionError, lambda: f.div(g)) + raises(ZeroDivisionError, lambda: divmod(f, g)) + raises(ZeroDivisionError, lambda: f.rem(g)) + raises(ZeroDivisionError, lambda: f % g) + raises(ZeroDivisionError, lambda: f.quo(g)) + raises(ZeroDivisionError, lambda: f / g) + raises(ZeroDivisionError, lambda: f.exquo(g)) + + R, x = ring("x", ZZ) + + f, g = x**2 + 1, 2*x - 4 + q, r = R(0), x**2 + 1 + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + f, g = 3*x**3 + x**2 + x + 5, 5*x**2 - 3*x + 1 + q, r = R(0), f + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + f, g = 5*x**4 + 4*x**3 + 3*x**2 + 2*x + 1, x**2 + 2*x + 3 + q, r = 5*x**2 - 6*x, 20*x + 1 + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + f, g = 5*x**5 + 4*x**4 + 3*x**3 + 2*x**2 + x, x**4 + 2*x**3 + 9 + q, r = 5*x - 6, 15*x**3 + 2*x**2 - 44*x + 54 + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + R, x = ring("x", QQ) + + f, g = x**2 + 1, 2*x - 4 + q, r = x/2 + 1, R(5) + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + f, g = 3*x**3 + x**2 + x + 5, 5*x**2 - 3*x + 1 + q, r = QQ(3, 5)*x + QQ(14, 25), QQ(52, 25)*x + QQ(111, 25) + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + R, x,y = ring("x,y", ZZ) + + f, g = x**2 - y**2, x - y + q, r = x + y, R(0) + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + assert f.exquo(g) == f / g == q + + f, g = x**2 + y**2, x - y + q, r = x + y, 2*y**2 + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + f, g = x**2 + y**2, -x + y + q, r = -x - y, 2*y**2 + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + f, g = x**2 + y**2, 2*x - 2*y + q, r = R(0), f + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + R, x,y = ring("x,y", QQ) + + f, g = x**2 - y**2, x - y + q, r = x + y, R(0) + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + assert f.exquo(g) == f / g == q + + f, g = x**2 + y**2, x - y + q, r = x + y, 2*y**2 + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + f, g = x**2 + y**2, -x + y + q, r = -x - y, 2*y**2 + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + + f, g = x**2 + y**2, 2*x - 2*y + q, r = x/2 + y/2, 2*y**2 + + assert f.div(g) == divmod(f, g) == (q, r) + assert f.rem(g) == f % g == r + assert f.quo(g) == q + raises(ExactQuotientFailed, lambda: f / g) + raises(ExactQuotientFailed, lambda: f.exquo(g)) + +def test_PolyElement___pow__(): + R, x = ring("x", ZZ, grlex) + f = 2*x + 3 + + assert f**0 == 1 + assert f**1 == f + raises(ValueError, lambda: f**(-1)) + + 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 + + R, t = ring("t", ZZ) + f = -11200*t**4 - 2604*t**2 + 49 + g = 15735193600000000*t**16 + 14633730048000000*t**14 + 4828147466240000*t**12 \ + + 598976863027200*t**10 + 3130812416256*t**8 - 2620523775744*t**6 \ + + 92413760096*t**4 - 1225431984*t**2 + 5764801 + + assert f**4 == f._pow_generic(4) == f._pow_multinomial(4) == g + +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) + + R, = ring("", ZZ) + assert R(3).div(R(2)) == (0, 3) + + R, = ring("", QQ) + assert R(3).div(R(2)) == (QQ(3, 2), 0) + +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_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) + + Fx, x = field("x", ZZ) + Rt, t = ring("t", Fx) + + f = (-x**2 - 4)/4*t + g = t**2 + (x**2 + 2)/2 + + assert f.cancel(g) == ((-x**2 - 4)*t, 4*t**2 + 2*x**2 + 4) + +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_l1_norm(): + R, x, y = ring("x,y", ZZ) + + assert R(0).l1_norm() == 0 + assert R(1).l1_norm() == 1 + + assert (x**3 + 4*x**2 + 2*x + 3).l1_norm() == 10 + +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___call__(): + R, x = ring("x", ZZ) + f = 3*x + 1 + + assert f(0) == 1 + assert f(1) == 4 + + raises(ValueError, lambda: f()) + raises(ValueError, lambda: f(0, 1)) + + raises(CoercionFailed, lambda: f(QQ(1,7))) + + R, x,y = ring("x,y", ZZ) + f = 3*x + y**2 + 1 + + assert f(0, 0) == 1 + assert f(1, 7) == 53 + + Ry = R.drop(x) + + assert f(0) == Ry.y**2 + 1 + assert f(1) == Ry.y**2 + 4 + + raises(ValueError, lambda: f()) + raises(ValueError, lambda: f(0, 1, 2)) + + raises(CoercionFailed, lambda: f(1, QQ(1,7))) + raises(CoercionFailed, lambda: f(QQ(1,7), 1)) + raises(CoercionFailed, lambda: f(QQ(1,7), QQ(1,7))) + +def test_PolyElement_evaluate(): + R, x = ring("x", ZZ) + f = x**3 + 4*x**2 + 2*x + 3 + + r = f.evaluate(x, 0) + assert r == 3 and not isinstance(r, PolyElement) + + raises(CoercionFailed, lambda: f.evaluate(x, QQ(1,7))) + + R, x, y, z = ring("x,y,z", ZZ) + f = (x*y)**3 + 4*(x*y)**2 + 2*x*y + 3 + + r = f.evaluate(x, 0) + assert r == 3 and R.drop(x).is_element(r) + r = f.evaluate([(x, 0), (y, 0)]) + assert r == 3 and R.drop(x, y).is_element(r) + r = f.evaluate(y, 0) + assert r == 3 and R.drop(y).is_element(r) + r = f.evaluate([(y, 0), (x, 0)]) + assert r == 3 and R.drop(y, x).is_element(r) + + r = f.evaluate([(x, 0), (y, 0), (z, 0)]) + assert r == 3 and not isinstance(r, PolyElement) + + raises(CoercionFailed, lambda: f.evaluate([(x, 1), (y, QQ(1,7))])) + raises(CoercionFailed, lambda: f.evaluate([(x, QQ(1,7)), (y, 1)])) + raises(CoercionFailed, lambda: f.evaluate([(x, QQ(1,7)), (y, QQ(1,7))])) + +def test_PolyElement_subs(): + R, x = ring("x", ZZ) + f = x**3 + 4*x**2 + 2*x + 3 + + r = f.subs(x, 0) + assert r == 3 and R.is_element(r) + + raises(CoercionFailed, lambda: f.subs(x, QQ(1,7))) + + R, x, y, z = ring("x,y,z", ZZ) + f = x**3 + 4*x**2 + 2*x + 3 + + r = f.subs(x, 0) + assert r == 3 and R.is_element(r) + r = f.subs([(x, 0), (y, 0)]) + assert r == 3 and R.is_element(r) + + raises(CoercionFailed, lambda: f.subs([(x, 1), (y, QQ(1,7))])) + raises(CoercionFailed, lambda: f.subs([(x, QQ(1,7)), (y, 1)])) + raises(CoercionFailed, lambda: f.subs([(x, QQ(1,7)), (y, QQ(1,7))])) + +def test_PolyElement_symmetrize(): + R, x, y = ring("x,y", ZZ) + + # Homogeneous, symmetric + f = x**2 + y**2 + sym, rem, m = f.symmetrize() + assert rem == 0 + assert sym.compose(m) + rem == f + + # Homogeneous, asymmetric + f = x**2 - y**2 + sym, rem, m = f.symmetrize() + assert rem != 0 + assert sym.compose(m) + rem == f + + # Inhomogeneous, symmetric + f = x*y + 7 + sym, rem, m = f.symmetrize() + assert rem == 0 + assert sym.compose(m) + rem == f + + # Inhomogeneous, asymmetric + f = y + 7 + sym, rem, m = f.symmetrize() + assert rem != 0 + assert sym.compose(m) + rem == f + + # Constant + f = R.from_expr(3) + sym, rem, m = f.symmetrize() + assert rem == 0 + assert sym.compose(m) + rem == f + + # Constant constructed from sring + R, f = sring(3) + sym, rem, m = f.symmetrize() + assert rem == 0 + assert sym.compose(m) + rem == f + +def test_PolyElement_compose(): + R, x = ring("x", ZZ) + f = x**3 + 4*x**2 + 2*x + 3 + + r = f.compose(x, 0) + assert r == 3 and R.is_element(r) + + assert f.compose(x, x) == f + assert f.compose(x, x**2) == x**6 + 4*x**4 + 2*x**2 + 3 + + raises(CoercionFailed, lambda: f.compose(x, QQ(1,7))) + + R, x, y, z = ring("x,y,z", ZZ) + f = x**3 + 4*x**2 + 2*x + 3 + + r = f.compose(x, 0) + assert r == 3 and R.is_element(r) + r = f.compose([(x, 0), (y, 0)]) + assert r == 3 and R.is_element(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 R.is_element(r) + +def test_PolyElement_is_(): + R, x,y,z = ring("x,y,z", 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 + + assert R(0).is_zero is True + assert R(1).is_zero is False + + assert R(0).is_one is False + assert R(1).is_one is True + + assert (x - 1).is_monic is True + assert (2*x - 1).is_monic is False + + assert (3*x + 2).is_primitive is True + assert (4*x + 2).is_primitive is False + + assert (x + y + z + 1).is_linear is True + assert (x*y*z + 1).is_linear is False + + assert (x*y + z + 1).is_quadratic is True + assert (x*y*z + 1).is_quadratic is False + + assert (x - 1).is_squarefree is True + assert ((x - 1)**2).is_squarefree is False + + assert (x**2 + x + 1).is_irreducible is True + assert (x**2 + 2*x + 1).is_irreducible is False + + _, t = ring("t", FF(11)) + + assert (7*t + 3).is_irreducible is True + assert (7*t**2 + 3*t + 1).is_irreducible is False + + _, u = ring("u", ZZ) + f = u**16 + u**14 - u**10 - u**8 - u**6 + u**2 + + assert f.is_cyclotomic is False + assert (f + 1).is_cyclotomic is True + + raises(MultivariatePolynomialError, lambda: x.is_cyclotomic) + + R, = ring("", ZZ) + assert R(4).is_squarefree is True + assert R(6).is_irreducible is True + +def test_PolyElement_drop(): + R, x,y,z = ring("x,y,z", ZZ) + + assert R(1).drop(0).ring == PolyRing("y,z", ZZ, lex) + assert R(1).drop(0).drop(0).ring == PolyRing("z", ZZ, lex) + assert R.is_element(R(1).drop(0).drop(0).drop(0)) is False + + raises(ValueError, lambda: z.drop(0).drop(0).drop(0)) + raises(ValueError, lambda: x.drop(0)) + +def test_PolyElement_coeff_wrt(): + R, x, y, z = ring("x, y, z", ZZ) + + p = 4*x**3 + 5*y**2 + 6*y**2*z + 7 + assert p.coeff_wrt(1, 2) == 6*z + 5 # using generator index + assert p.coeff_wrt(x, 3) == 4 # using generator + + p = 2*x**4 + 3*x*y**2*z + 10*y**2 + 10*x*z**2 + assert p.coeff_wrt(x, 1) == 3*y**2*z + 10*z**2 + assert p.coeff_wrt(y, 2) == 3*x*z + 10 + + p = 4*x**2 + 2*x*y + 5 + assert p.coeff_wrt(z, 1) == R(0) + assert p.coeff_wrt(y, 2) == R(0) + +def test_PolyElement_prem(): + R, x, y = ring("x, y", ZZ) + + f, g = x**2 + x*y, 2*x + 2 + assert f.prem(g) == -4*y + 4 # first generator is chosen by default if it is not given + + f, g = x**2 + 1, 2*x - 4 + assert f.prem(g) == f.prem(g, x) == 20 + assert f.prem(g, 1) == R(0) + + f, g = x*y + 2*x + 1, x + y + assert f.prem(g) == -y**2 - 2*y + 1 + assert f.prem(g, 1) == f.prem(g, y) == -x**2 + 2*x + 1 + + raises(ZeroDivisionError, lambda: f.prem(R(0))) + +def test_PolyElement_pdiv(): + R, x, y = ring("x,y", ZZ) + + f, g = x**4 + 5*x**3 + 7*x**2, 2*x**2 + 3 + assert f.pdiv(g) == f.pdiv(g, x) == (4*x**2 + 20*x + 22, -60*x - 66) + + f, g = x**2 - y**2, x - y + assert f.pdiv(g) == f.pdiv(g, 0) == (x + y, 0) + + f, g = x*y + 2*x + 1, x + y + assert f.pdiv(g) == (y + 2, -y**2 - 2*y + 1) + assert f.pdiv(g, y) == f.pdiv(g, 1) == (x + 1, -x**2 + 2*x + 1) + + assert R(0).pdiv(g) == (0, 0) + raises(ZeroDivisionError, lambda: f.prem(R(0))) + +def test_PolyElement_pquo(): + R, x, y = ring("x, y", ZZ) + + f, g = x**4 - 4*x**2*y + 4*y**2, x**2 - 2*y + assert f.pquo(g) == f.pquo(g, x) == x**2 - 2*y + assert f.pquo(g, y) == 4*x**2 - 8*y + 4 + + f, g = x**4 - y**4, x**2 - y**2 + assert f.pquo(g) == f.pquo(g, 0) == x**2 + y**2 + +def test_PolyElement_pexquo(): + R, x, y = ring("x, y", ZZ) + + f, g = x**2 - y**2, x - y + assert f.pexquo(g) == f.pexquo(g, x) == x + y + assert f.pexquo(g, y) == f.pexquo(g, 1) == x + y + 1 + + f, g = x**2 + 3*x + 6, x + 2 + raises(ExactQuotientFailed, lambda: f.pexquo(g)) + +def test_PolyElement_gcdex(): + _, x = ring("x", QQ) + + f, g = 2*x, x**2 - 16 + s, t, h = x/32, -QQ(1, 16), 1 + + assert f.half_gcdex(g) == (s, h) + assert f.gcdex(g) == (s, t, h) + +def test_PolyElement_subresultants(): + R, x, y = ring("x, y", ZZ) + + f, g = x**2*y + x*y, x + y # degree(f, x) > degree(g, x) + h = y**3 - y**2 + assert f.subresultants(g) == [f, g, h] # first generator is chosen default + + # generator index or generator is given + assert f.subresultants(g, 0) == f.subresultants(g, x) == [f, g, h] + + assert f.subresultants(g, y) == [x**2*y + x*y, x + y, x**3 + x**2] + + f, g = 2*x - y, x**2 + 2*y + x # degree(f, x) < degree(g, x) + assert f.subresultants(g) == [x**2 + x + 2*y, 2*x - y, y**2 + 10*y] + + f, g = R(0), y**3 - y**2 # f = 0 + assert f.subresultants(g) == [y**3 - y**2, 1] + + f, g = x**2*y + x*y, R(0) # g = 0 + assert f.subresultants(g) == [x**2*y + x*y, 1] + + f, g = R(0), R(0) # f = 0 and g = 0 + assert f.subresultants(g) == [0, 0] + + f, g = x**2 + x, x**2 + x # f and g are same polynomial + assert f.subresultants(g) == [x**2 + x, x**2 + x] + +def test_PolyElement_resultant(): + _, x = ring("x", ZZ) + f, g, h = x**2 - 2*x + 1, x**2 - 1, 0 + + assert f.resultant(g) == h + +def test_PolyElement_discriminant(): + _, x = ring("x", ZZ) + f, g = x**3 + 3*x**2 + 9*x - 13, -11664 + + assert f.discriminant() == g + + F, a, b, c = ring("a,b,c", ZZ) + _, x = ring("x", F) + + f, g = a*x**2 + b*x + c, b**2 - 4*a*c + + assert f.discriminant() == g + +def test_PolyElement_decompose(): + _, x = ring("x", ZZ) + + 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 + + assert g.compose(x, h) == f + assert f.decompose() == [g, h] + +def test_PolyElement_shift(): + _, x = ring("x", ZZ) + assert (x**2 - 2*x + 1).shift(2) == x**2 + 2*x + 1 + assert (x**2 - 2*x + 1).shift_list([2]) == x**2 + 2*x + 1 + + R, x, y = ring("x, y", ZZ) + assert (x*y).shift_list([1, 2]) == (x+1)*(y+2) + + raises(MultivariatePolynomialError, lambda: (x*y).shift(1)) + +def test_PolyElement_sturm(): + F, t = field("t", ZZ) + _, x = ring("x", F) + + f = 1024/(15625*t**8)*x**5 - 4096/(625*t**8)*x**4 + 32/(15625*t**4)*x**3 - 128/(625*t**4)*x**2 + F(1)/62500*x - F(1)/625 + + assert f.sturm() == [ + x**3 - 100*x**2 + t**4/64*x - 25*t**4/16, + 3*x**2 - 200*x + t**4/64, + (-t**4/96 + F(20000)/9)*x + 25*t**4/18, + (-9*t**12 - 11520000*t**8 - 3686400000000*t**4)/(576*t**8 - 245760000*t**4 + 26214400000000), + ] + +def test_PolyElement_gff_list(): + _, x = ring("x", ZZ) + + f = x**5 + 2*x**4 - x**3 - 2*x**2 + assert f.gff_list() == [(x, 1), (x + 2, 4)] + + f = x*(x - 1)**3*(x - 2)**2*(x - 4)**2*(x - 5) + assert f.gff_list() == [(x**2 - 5*x + 4, 1), (x**2 - 5*x + 4, 2), (x, 3)] + +def test_PolyElement_norm(): + k = QQ + K = QQ.algebraic_field(sqrt(2)) + sqrt2 = K.unit + _, X, Y = ring("x,y", k) + _, x, y = ring("x,y", K) + + assert (x*y + sqrt2).norm() == X**2*Y**2 - 2 + +def test_PolyElement_sqf_norm(): + R, x = ring("x", QQ.algebraic_field(sqrt(3))) + X = R.to_ground().x + + assert (x**2 - 2).sqf_norm() == ([1], x**2 - 2*sqrt(3)*x + 1, X**4 - 10*X**2 + 1) + + R, x = ring("x", QQ.algebraic_field(sqrt(2))) + X = R.to_ground().x + + assert (x**2 - 3).sqf_norm() == ([1], x**2 - 2*sqrt(2)*x - 1, X**4 - 10*X**2 + 1) + +def test_PolyElement_sqf_list(): + _, x = ring("x", ZZ) + + f = x**5 - x**3 - x**2 + 1 + g = x**3 + 2*x**2 + 2*x + 1 + h = x - 1 + p = x**4 + x**3 - x - 1 + + assert f.sqf_part() == p + assert f.sqf_list() == (1, [(g, 1), (h, 2)]) + +def test_issue_18894(): + items = [S(3)/16 + sqrt(3*sqrt(3) + 10)/8, S(1)/8 + 3*sqrt(3)/16, S(1)/8 + 3*sqrt(3)/16, -S(3)/16 + sqrt(3*sqrt(3) + 10)/8] + R, a = sring(items, extension=True) + assert R.domain == QQ.algebraic_field(sqrt(3)+sqrt(3*sqrt(3)+10)) + assert R.gens == () + result = [] + for item in items: + result.append(R.domain.from_sympy(item)) + assert a == result + +def test_PolyElement_factor_list(): + _, x = ring("x", ZZ) + + f = x**5 - x**3 - x**2 + 1 + + u = x + 1 + v = x - 1 + w = x**2 + x + 1 + + assert f.factor_list() == (1, [(u, 1), (v, 2), (w, 1)]) + + +def test_issue_21410(): + R, x = ring('x', FF(2)) + p = x**6 + x**5 + x**4 + x**3 + 1 + assert p._pow_multinomial(4) == x**24 + x**20 + x**16 + x**12 + 1 + + +def test_zero_polynomial_primitive(): + + x = symbols('x') + + R = ZZ[x] + zero_poly = R(0) + cont, prim = zero_poly.primitive() + assert cont == 0 + assert prim == zero_poly + assert prim.is_primitive is False diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rootisolation.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rootisolation.py new file mode 100644 index 0000000000000000000000000000000000000000..9661c1d6b63bfb941157c7e904ba4e048afbc538 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rootisolation.py @@ -0,0 +1,823 @@ +"""Tests for real and complex root isolation and refinement algorithms. """ + +from sympy.polys.rings import ring +from sympy.polys.domains import ZZ, QQ, ZZ_I, EX +from sympy.polys.polyerrors import DomainError, RefinementFailed, PolynomialError +from sympy.polys.rootisolation import ( + dup_cauchy_upper_bound, dup_cauchy_lower_bound, + dup_mignotte_sep_bound_squared, +) +from sympy.testing.pytest import raises + +def test_dup_sturm(): + R, x = ring("x", QQ) + + 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)] + + +def test_dup_cauchy_upper_bound(): + raises(PolynomialError, lambda: dup_cauchy_upper_bound([], QQ)) + raises(PolynomialError, lambda: dup_cauchy_upper_bound([QQ(1)], QQ)) + raises(DomainError, lambda: dup_cauchy_upper_bound([ZZ_I(1), ZZ_I(1)], ZZ_I)) + + assert dup_cauchy_upper_bound([QQ(1), QQ(0), QQ(0)], QQ) == QQ.zero + assert dup_cauchy_upper_bound([QQ(1), QQ(0), QQ(-2)], QQ) == QQ(3) + + +def test_dup_cauchy_lower_bound(): + raises(PolynomialError, lambda: dup_cauchy_lower_bound([], QQ)) + raises(PolynomialError, lambda: dup_cauchy_lower_bound([QQ(1)], QQ)) + raises(PolynomialError, lambda: dup_cauchy_lower_bound([QQ(1), QQ(0), QQ(0)], QQ)) + raises(DomainError, lambda: dup_cauchy_lower_bound([ZZ_I(1), ZZ_I(1)], ZZ_I)) + + assert dup_cauchy_lower_bound([QQ(1), QQ(0), QQ(-2)], QQ) == QQ(2, 3) + + +def test_dup_mignotte_sep_bound_squared(): + raises(PolynomialError, lambda: dup_mignotte_sep_bound_squared([], QQ)) + raises(PolynomialError, lambda: dup_mignotte_sep_bound_squared([QQ(1)], QQ)) + + assert dup_mignotte_sep_bound_squared([QQ(1), QQ(0), QQ(-2)], QQ) == QQ(3, 5) + + +def test_dup_refine_real_root(): + 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)) + + raises(ValueError, lambda: R.dup_refine_real_root(f, QQ(-2), QQ(2))) + + 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)) + + 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)) + + 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(27, 19)) + + 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)) + + raises(RefinementFailed, lambda: R.dup_refine_real_root(f, QQ(0), QQ(1))) + + 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 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) + + 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) + + 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) + + +def test_dup_isolate_real_roots_sqf(): + R, x = ring("x", ZZ) + + assert R.dup_isolate_real_roots_sqf(0) == [] + assert R.dup_isolate_real_roots_sqf(5) == [] + + 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)] + + assert R.dup_isolate_real_roots_sqf(x**4 + x + 1) == [] + + I = [(-2, -1), (1, 2)] + + assert R.dup_isolate_real_roots_sqf(x**2 - 2) == I + assert R.dup_isolate_real_roots_sqf(-x**2 + 2) == I + + 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*x**4 \ + + 1700135866278935491773999857*x**3 \ + - 2000179008931031182161141026995283662899200197*x**2 \ + - 800027600594323913802305066986600025*x \ + + 100000950000540000725000008 + + assert R.dup_isolate_real_roots_sqf(f) == \ + [(-a, -a), (-1, 0), (0, 1), (d, 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) = 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 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))] + + f = x - 1 + + assert R.dup_isolate_real_roots_sqf(f, inf=2) == [] + assert R.dup_isolate_real_roots_sqf(f, sup=0) == [] + + 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 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 R.dup_isolate_real_roots_sqf(f) == [(-1, 0), (14, 15)] + + R, x = ring("x", EX) + raises(DomainError, lambda: R.dup_isolate_real_roots_sqf(x + 3)) + +def test_dup_isolate_real_roots(): + 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 R.dup_isolate_real_roots(x**4 + x + 1) == [] + + I = [((-2, -1), 1), ((1, 2), 1)] + + 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 R.dup_isolate_real_roots(f, inf=-2) == I + assert R.dup_isolate_real_roots(f, sup=+2) == I + + assert R.dup_isolate_real_roots(f, inf=-2, sup=2) == I + + f = x**11 - 3*x**10 - x**9 + 11*x**8 - 8*x**7 - 8*x**6 + 12*x**5 - 4*x**4 + + assert R.dup_isolate_real_roots(f, basis=False) == \ + [((-2, -1), 2), ((0, 0), 4), ((1, 1), 3), ((1, 2), 2)] + 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])] + + f = (x**45 - 45*x**44 + 990*x**43 - 1) + g = (x**46 - 15180*x**43 + 9366819*x**40 - 53524680*x**39 + 260932815*x**38 - 1101716330*x**37 + 4076350421*x**36 - 13340783196*x**35 + 38910617655*x**34 - 101766230790*x**33 + 239877544005*x**32 - 511738760544*x**31 + 991493848554*x**30 - 1749695026860*x**29 + 2818953098830*x**28 - 4154246671960*x**27 + 5608233007146*x**26 - 6943526580276*x**25 + 7890371113950*x**24 - 8233430727600*x**23 + 7890371113950*x**22 - 6943526580276*x**21 + 5608233007146*x**20 - 4154246671960*x**19 + 2818953098830*x**18 - 1749695026860*x**17 + 991493848554*x**16 - 511738760544*x**15 + 239877544005*x**14 - 101766230790*x**13 + 38910617655*x**12 - 13340783196*x**11 + 4076350421*x**10 - 1101716330*x**9 + 260932815*x**8 - 53524680*x**7 + 9366819*x**6 - 1370754*x**5 + 163185*x**4 - 15180*x**3 + 1035*x**2 - 47*x + 1) + + assert R.dup_isolate_real_roots(f*g) == \ + [((0, QQ(1, 2)), 1), ((QQ(2, 3), QQ(3, 4)), 1), ((QQ(3, 4), 1), 1), ((6, 7), 1), ((24, 25), 1)] + + R, x = ring("x", EX) + raises(DomainError, lambda: R.dup_isolate_real_roots(x + 3)) + + +def test_dup_isolate_real_roots_list(): + R, x = ring("x", ZZ) + + 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 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 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 = x**4 - 4*x**2 + 4, x - 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 = x**2 - 2, x**3 - x**2 - 2*x + 2 + + 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 = x**3 - 2*x, x**5 - x**4 - 2*x**3 + 2*x**2 + + 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 = 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 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 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(309, 107), 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(309, 107), QQ(26, 9)), {1: 1})] + + +def test_dup_count_real_roots(): + R, x = ring("x", ZZ) + + assert R.dup_count_real_roots(0) == 0 + assert R.dup_count_real_roots(7) == 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 + 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 + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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) + 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 + 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) + 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 + 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) + 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 + 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) + 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) + 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 + 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) + 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 + 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) + 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 + 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) + 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) + 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) + 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) + 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 + 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) + 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 + 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) + 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 + 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) + 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 + 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 + 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(): + R, x = ring("x", ZZ) + + # z*(z-1)*(z+1)*(z-I)*(z+I) + f = x**5 - x + + 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 + + +def test_dup_count_complex_roots_exclude(): + 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 R.dup_count_complex_roots(f, a, b) == 4 + + 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 R.dup_count_complex_roots(f, a, b, exclude=['S', 'N']) == 2 + + 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 R.dup_count_complex_roots(f, a, b, exclude=['E', 'W']) == 4 + + assert R.dup_count_complex_roots(f, a, b, exclude=['N', 'S', 'E', 'W']) == 2 + + 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 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 R.dup_count_complex_roots(f, a, b, exclude=True) == 1 + + +def test_dup_isolate_complex_roots_sqf(): + R, x = ring("x", ZZ) + f = x**2 - 2*x + 3 + + assert R.dup_isolate_complex_roots_sqf(f) == \ + [((0, -6), (6, 0)), ((0, 0), (6, 6))] + 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 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)))] + + +def test_dup_isolate_all_roots_sqf(): + R, x = ring("x", ZZ) + f = 4*x**4 - x**3 + 2*x**2 + 5*x + + 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)))]) + + +def test_dup_isolate_all_roots(): + R, x = ring("x", ZZ) + f = 4*x**4 - x**3 + 2*x**2 + 5*x + + 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)]) + + f = x**5 + x**4 - 2*x**3 - 2*x**2 + x + 1 + raises(NotImplementedError, lambda: R.dup_isolate_all_roots(f)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rootoftools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rootoftools.py new file mode 100644 index 0000000000000000000000000000000000000000..de9dbcabd0a7e2bed0c5adb7127041b4be058379 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_rootoftools.py @@ -0,0 +1,697 @@ +"""Tests for the implementation of RootOf class and related tools. """ + +from sympy.polys.polytools import Poly +import sympy.polys.rootoftools as rootoftools +from sympy.polys.rootoftools import (rootof, RootOf, CRootOf, RootSum, + _pure_key_dict as D) + +from sympy.polys.polyerrors import ( + MultivariatePolynomialError, + GeneratorsNeeded, + PolynomialError, +) + +from sympy.core.function import (Function, Lambda) +from sympy.core.numbers import (Float, I, Rational) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import tan +from sympy.integrals.integrals import Integral +from sympy.polys.orthopolys import legendre_poly +from sympy.solvers.solvers import solve + + +from sympy.testing.pytest import raises, slow +from sympy.core.expr import unchanged + +from sympy.abc import a, b, x, y, z, r + + +def test_CRootOf___new__(): + assert rootof(x, 0) == 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, 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) + + r = rootof(x**2 + 2*x + 3, 0, radicals=False) + assert isinstance(r, RootOf) is True + + r = rootof(x**2 + 2*x + 3, 1, radicals=False) + assert isinstance(r, RootOf) is 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) is True + + 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), 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**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**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 + + raises(GeneratorsNeeded, lambda: rootof(0, 0)) + raises(GeneratorsNeeded, lambda: rootof(1, 0)) + + raises(PolynomialError, lambda: rootof(Poly(0, x), 0)) + raises(PolynomialError, lambda: rootof(Poly(1, x), 0)) + raises(PolynomialError, lambda: rootof(x - y, 0)) + # issue 8617 + raises(PolynomialError, lambda: rootof(exp(x), 0)) + + 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, 2)) + raises(IndexError, lambda: rootof(x**2 - 1, 3)) + raises(ValueError, lambda: rootof(x**2 - 1, x)) + + 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**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 is True + + +def test_CRootOf_attributes(): + r = rootof(x**3 + x + 3, 0) + assert r.is_number + assert r.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_CRootOf___eq__(): + 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_CRootOf___eval_Eq__(): + f = Function('f') + eq = x**3 + x + 3 + r = rootof(eq, 2) + r1 = rootof(eq, 1) + assert Eq(r, r1) is S.false + assert Eq(r, r) is S.true + assert unchanged(Eq, r, x) + assert Eq(r, 0) is S.false + assert Eq(r, S.Infinity) is S.false + assert Eq(r, I) is S.false + assert unchanged(Eq, r, f(0)) + sol = solve(eq) + for s in sol: + if s.is_real: + assert Eq(r, s) is S.false + r = rootof(eq, 0) + for s in sol: + if s.is_real: + assert Eq(r, s) is S.true + eq = x**3 + x + 1 + sol = solve(eq) + assert [Eq(rootof(eq, i), j) for i in range(3) for j in sol + ].count(True) == 3 + assert Eq(rootof(eq, 0), 1 + S.ImaginaryUnit) == False + + +def test_CRootOf_is_real(): + 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_CRootOf_is_complex(): + assert rootof(x**3 + x + 3, 0).is_complex is True + + +def test_CRootOf_is_algebraic(): + assert rootof(x**3 + x + 3, 0).is_algebraic is True + assert rootof(x**3 + x + 3, 1).is_algebraic is True + assert rootof(x**3 + x + 3, 2).is_algebraic is True + + +def test_CRootOf_subs(): + assert rootof(x**3 + x + 1, 0).subs(x, y) == rootof(y**3 + y + 1, 0) + + +def test_CRootOf_diff(): + assert rootof(x**3 + x + 1, 0).diff(x) == 0 + assert rootof(x**3 + x + 1, 0).diff(y) == 0 + +@slow +def test_CRootOf_evalf(): + real = rootof(x**3 + x + 3, 0).evalf(n=20) + + assert real.epsilon_eq(Float("-1.2134116627622296341")) + + re, im = rootof(x**3 + x + 3, 1).evalf(n=20).as_real_imag() + + assert re.epsilon_eq( Float("0.60670583138111481707")) + assert im.epsilon_eq(-Float("1.45061224918844152650")) + + re, im = rootof(x**3 + x + 3, 2).evalf(n=20).as_real_imag() + + 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()] + # magnitudes are given by + # sqrt(3/S(7) - 2*sqrt(6/S(5))/7) + # and + # sqrt(3/S(7) + 2*sqrt(6/S(5))/7) + 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")) + + # issue 6393 + assert str(rootof(x**5 + 2*x**4 + x**3 - 68719476736, 0).n(3)) == '147.' + eq = (531441*x**11 + 3857868*x**10 + 13730229*x**9 + 32597882*x**8 + + 55077472*x**7 + 60452000*x**6 + 32172064*x**5 - 4383808*x**4 - + 11942912*x**3 - 1506304*x**2 + 1453312*x + 512) + a, b = rootof(eq, 1).n(2).as_real_imag() + c, d = rootof(eq, 2).n(2).as_real_imag() + assert a == c + assert b < d + assert b == -d + # issue 6451 + r = rootof(legendre_poly(64, x), 7) + assert r.n(2) == r.n(100).n(2) + # issue 9019 + r0 = rootof(x**2 + 1, 0, radicals=False) + r1 = rootof(x**2 + 1, 1, radicals=False) + assert r0.n(4) == Float(-1.0, 4) * I + assert r1.n(4) == Float(1.0, 4) * I + + # make sure verification is used in case a max/min traps the "root" + assert str(rootof(4*x**5 + 16*x**3 + 12*x**2 + 7, 0).n(3)) == '-0.976' + + # watch out for UnboundLocalError + c = CRootOf(90720*x**6 - 4032*x**4 + 84*x**2 - 1, 0) + assert c._eval_evalf(2) # doesn't fail + + # watch out for imaginary parts that don't want to evaluate + assert str(RootOf(x**16 + 32*x**14 + 508*x**12 + 5440*x**10 + + 39510*x**8 + 204320*x**6 + 755548*x**4 + 1434496*x**2 + + 877969, 10).n(2)) == '-3.4*I' + assert abs(RootOf(x**4 + 10*x**2 + 1, 0).n(2)) < 0.4 + + # check reset and args + r = [RootOf(x**3 + x + 3, i) for i in range(3)] + r[0]._reset() + for ri in r: + i = ri._get_interval() + ri.n(2) + assert i != ri._get_interval() + ri._reset() + assert i == ri._get_interval() + assert i == i.func(*i.args) + + +def test_issue_24978(): + # Irreducible poly with negative leading coeff is normalized + # (factor of -1 is extracted), before being stored as CRootOf.poly. + f = -x**2 + 2 + r = CRootOf(f, 0) + assert r.poly.as_expr() == x**2 - 2 + # An action that prompts calculation of an interval puts r.poly in + # the cache. + r.n() + assert r.poly in rootoftools._reals_cache + + +def test_CRootOf_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_CRootOf_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)] + + # https://github.com/sympy/sympy/issues/20902 + p = Poly(-3*x**4 - 10*x**3 - 12*x**2 - 6*x - 1, x, domain='ZZ') + assert CRootOf.real_roots(p) == [S(-1), S(-1), S(-1), S(-1)/3] + + # with real algebraic coefficients + assert Poly(x**3 + sqrt(2)*x**2 - 1, x, extension=True).real_roots() == [ + rootof(x**6 - 2*x**4 - 2*x**3 + 1, 0) + ] + assert Poly(x**5 + sqrt(2) * x**3 - 1, x, extension=True).real_roots() == [ + rootof(x**10 - 2*x**6 - 2*x**5 + 1, 0) + ] + r = rootof(y**5 + y**3 - 1, 0) + assert Poly(x**5 + r*x - 1, x, extension=True).real_roots() ==\ + [ + rootof(x**25 - 5*x**20 + x**17 + 10*x**15 - 3*x**12 - + 10*x**10 + 3*x**7 + 6*x**5 - x**2 - 1, 0) + ] + # roots with multiplicity + assert Poly((x-1) * (x-sqrt(2))**2, x, extension=True).real_roots() ==\ + [ + S(1), sqrt(2), sqrt(2) + ] + + +def test_CRootOf_all_roots(): + assert Poly(x**5 + x + 1).all_roots() == [ + rootof(x**3 - x**2 + 1, 0), + Rational(-1, 2) - sqrt(3)*I/2, + Rational(-1, 2) + sqrt(3)*I/2, + rootof(x**3 - x**2 + 1, 1), + rootof(x**3 - x**2 + 1, 2), + ] + + assert Poly(x**5 + x + 1).all_roots(radicals=False) == [ + rootof(x**3 - x**2 + 1, 0), + rootof(x**2 + x + 1, 0, radicals=False), + rootof(x**2 + x + 1, 1, radicals=False), + rootof(x**3 - x**2 + 1, 1), + rootof(x**3 - x**2 + 1, 2), + ] + + # with real algebraic coefficients + assert Poly(x**3 + sqrt(2)*x**2 - 1, x, extension=True).all_roots() ==\ + [ + rootof(x**6 - 2*x**4 - 2*x**3 + 1, 0), + rootof(x**6 - 2*x**4 - 2*x**3 + 1, 2), + rootof(x**6 - 2*x**4 - 2*x**3 + 1, 3) + ] + # roots with multiplicity + assert Poly((x-1) * (x-sqrt(2))**2 * (x-I) * (x+I), x, extension=True).all_roots() ==\ + [ + S(1), sqrt(2), sqrt(2), -I, I + ] + + # imaginary algebraic coeffs (gaussian domain) + assert Poly(x**2 - I/2, x, extension=True).all_roots() ==\ + [ + S(1)/2 + I/2, + -S(1)/2 - I/2 + ] + + +def test_CRootOf_eval_rational(): + p = legendre_poly(4, x, polys=True) + roots = [r.eval_rational(n=18) for r in p.real_roots()] + for root in roots: + assert isinstance(root, Rational) + roots = [str(root.n(17)) for root in roots] + assert roots == [ + "-0.86113631159405258", + "-0.33998104358485626", + "0.33998104358485626", + "0.86113631159405258", + ] + + +def test_CRootOf_lazy(): + # irreducible poly with both real and complex roots: + f = Poly(x**3 + 2*x + 2) + + # real root: + CRootOf.clear_cache() + r = CRootOf(f, 0) + # Not yet in cache, after construction: + assert r.poly not in rootoftools._reals_cache + assert r.poly not in rootoftools._complexes_cache + r.evalf() + # In cache after evaluation: + assert r.poly in rootoftools._reals_cache + assert r.poly not in rootoftools._complexes_cache + + # complex root: + CRootOf.clear_cache() + r = CRootOf(f, 1) + # Not yet in cache, after construction: + assert r.poly not in rootoftools._reals_cache + assert r.poly not in rootoftools._complexes_cache + r.evalf() + # In cache after evaluation: + assert r.poly in rootoftools._reals_cache + assert r.poly in rootoftools._complexes_cache + + # composite poly with both real and complex roots: + f = Poly((x**2 - 2)*(x**2 + 1)) + + # real root: + CRootOf.clear_cache() + r = CRootOf(f, 0) + # In cache immediately after construction: + assert r.poly in rootoftools._reals_cache + assert r.poly not in rootoftools._complexes_cache + + # complex root: + CRootOf.clear_cache() + r = CRootOf(f, 2) + # In cache immediately after construction: + assert r.poly in rootoftools._reals_cache + assert r.poly in rootoftools._complexes_cache + + +def test_RootSum___new__(): + f = x**3 + x + 3 + + g = Lambda(r, log(r*x)) + s = RootSum(f, g) + + 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) + + # issue 5571 + assert hash(RootSum((x - 7)*f**3, g)) == hash(log(7*x) + 3*RootSum(f, g)) + + raises(MultivariatePolynomialError, lambda: RootSum(x**3 + x + y)) + raises(ValueError, lambda: RootSum(x**2 + 3, lambda x: x)) + + 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) is True + + assert RootSum(f) == 0 + assert RootSum(f, Lambda(x, x)) == 0 + assert RootSum(f, Lambda(x, x**2)) == -2 + + assert RootSum(f, Lambda(x, 1)) == 3 + assert RootSum(f, Lambda(x, 2)) == 6 + + assert RootSum(f, auto=False).is_commutative is True + + assert RootSum(f, Lambda(x, 1/(x + x**2))) == Rational(11, 3) + assert RootSum(f, Lambda(x, y/(x + x**2))) == Rational(11, 3)*y + + assert RootSum(x**2 - 1, Lambda(x, 3*x**2), x) == 6 + assert RootSum(x**2 - y, Lambda(x, 3*x**2), x) == 6*y + + 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**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 == {a} + assert RootSum( + x**3 + x + y, Lambda(r, exp(a*r)), x).free_symbols == {a, y} + + +def test_RootSum___eq__(): + f = Lambda(x, exp(x)) + + 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 + + +def test_RootSum_doit(): + rs = RootSum(x**2 + 1, exp) + + assert isinstance(rs, RootSum) is True + assert rs.doit() == exp(-I) + exp(I) + + rs = RootSum(x**2 + a, exp, x) + + 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")) + assert rs.evalf(n=15, chop=True).epsilon_eq(Float("1.08060461173628")) + + 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)) + 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)) + + F = y**3 + y + 3 + G = Lambda(r, exp(r*y)) + + 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) + + 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 - z*Rational(125, 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 + + +def test_RootSum_independent(): + f = (x**3 - a)**2*(x**4 - b)**3 + + g = Lambda(x, 5*tan(x) + 7) + h = Lambda(x, tan(x)) + + r0 = RootSum(x**3 - a, h, x) + r1 = RootSum(x**4 - b, h, x) + + assert RootSum(f, g, x).as_ordered_terms() == [10*r0, 15*r1, 126] + + +def test_issue_7876(): + l1 = Poly(x**6 - x + 1, x).all_roots() + l2 = [rootof(x**6 - x + 1, i) for i in range(6)] + assert frozenset(l1) == frozenset(l2) + + +def test_issue_8316(): + f = Poly(7*x**8 - 9) + assert len(f.all_roots()) == 8 + f = Poly(7*x**8 - 10) + assert len(f.all_roots()) == 8 + + +def test__imag_count(): + from sympy.polys.rootoftools import _imag_count_of_factor + def imag_count(p): + return sum(_imag_count_of_factor(f)*m for f, m in + p.factor_list()[1]) + assert imag_count(Poly(x**6 + 10*x**2 + 1)) == 2 + assert imag_count(Poly(x**2)) == 0 + assert imag_count(Poly([1]*3 + [-1], x)) == 0 + assert imag_count(Poly(x**3 + 1)) == 0 + assert imag_count(Poly(x**2 + 1)) == 2 + assert imag_count(Poly(x**2 - 1)) == 0 + assert imag_count(Poly(x**4 - 1)) == 2 + assert imag_count(Poly(x**4 + 1)) == 0 + assert imag_count(Poly([1, 2, 3], x)) == 0 + assert imag_count(Poly(x**3 + x + 1)) == 0 + assert imag_count(Poly(x**4 + x + 1)) == 0 + def q(r1, r2, p): + return Poly(((x - r1)*(x - r2)).subs(x, x**p), x) + assert imag_count(q(-1, -2, 2)) == 4 + assert imag_count(q(-1, 2, 2)) == 2 + assert imag_count(q(1, 2, 2)) == 0 + assert imag_count(q(1, 2, 4)) == 4 + assert imag_count(q(-1, 2, 4)) == 2 + assert imag_count(q(-1, -2, 4)) == 0 + + +def test_RootOf_is_imaginary(): + r = RootOf(x**4 + 4*x**2 + 1, 1) + i = r._get_interval() + assert r.is_imaginary and i.ax*i.bx <= 0 + + +def test_is_disjoint(): + eq = x**3 + 5*x + 1 + ir = rootof(eq, 0)._get_interval() + ii = rootof(eq, 1)._get_interval() + assert ir.is_disjoint(ii) + assert ii.is_disjoint(ir) + + +def test_pure_key_dict(): + p = D() + assert (x in p) is False + assert (1 in p) is False + p[x] = 1 + assert x in p + assert y in p + assert p[y] == 1 + raises(KeyError, lambda: p[1]) + def dont(k): + p[k] = 2 + raises(ValueError, lambda: dont(1)) + + +@slow +def test_eval_approx_relative(): + CRootOf.clear_cache() + t = [CRootOf(x**3 + 10*x + 1, i) for i in range(3)] + assert [i.eval_rational(1e-1) for i in t] == [ + Rational(-21, 220), Rational(15, 256) - I*805/256, + Rational(15, 256) + I*805/256] + t[0]._reset() + assert [i.eval_rational(1e-1, 1e-4) for i in t] == [ + Rational(-21, 220), Rational(3275, 65536) - I*414645/131072, + Rational(3275, 65536) + I*414645/131072] + assert S(t[0]._get_interval().dx) < 1e-1 + assert S(t[1]._get_interval().dx) < 1e-1 + assert S(t[1]._get_interval().dy) < 1e-4 + assert S(t[2]._get_interval().dx) < 1e-1 + assert S(t[2]._get_interval().dy) < 1e-4 + t[0]._reset() + assert [i.eval_rational(1e-4, 1e-4) for i in t] == [ + Rational(-2001, 20020), Rational(6545, 131072) - I*414645/131072, + Rational(6545, 131072) + I*414645/131072] + assert S(t[0]._get_interval().dx) < 1e-4 + assert S(t[1]._get_interval().dx) < 1e-4 + assert S(t[1]._get_interval().dy) < 1e-4 + assert S(t[2]._get_interval().dx) < 1e-4 + assert S(t[2]._get_interval().dy) < 1e-4 + # in the following, the actual relative precision is + # less than tested, but it should never be greater + t[0]._reset() + assert [i.eval_rational(n=2) for i in t] == [ + Rational(-202201, 2024022), Rational(104755, 2097152) - I*6634255/2097152, + Rational(104755, 2097152) + I*6634255/2097152] + assert abs(S(t[0]._get_interval().dx)/t[0]) < 1e-2 + assert abs(S(t[1]._get_interval().dx)/t[1]).n() < 1e-2 + assert abs(S(t[1]._get_interval().dy)/t[1]).n() < 1e-2 + assert abs(S(t[2]._get_interval().dx)/t[2]).n() < 1e-2 + assert abs(S(t[2]._get_interval().dy)/t[2]).n() < 1e-2 + t[0]._reset() + assert [i.eval_rational(n=3) for i in t] == [ + Rational(-202201, 2024022), Rational(1676045, 33554432) - I*106148135/33554432, + Rational(1676045, 33554432) + I*106148135/33554432] + assert abs(S(t[0]._get_interval().dx)/t[0]) < 1e-3 + assert abs(S(t[1]._get_interval().dx)/t[1]).n() < 1e-3 + assert abs(S(t[1]._get_interval().dy)/t[1]).n() < 1e-3 + assert abs(S(t[2]._get_interval().dx)/t[2]).n() < 1e-3 + assert abs(S(t[2]._get_interval().dy)/t[2]).n() < 1e-3 + + t[0]._reset() + a = [i.eval_approx(2) for i in t] + assert [str(i) for i in a] == [ + '-0.10', '0.05 - 3.2*I', '0.05 + 3.2*I'] + assert all(abs(((a[i] - t[i])/t[i]).n()) < 1e-2 for i in range(len(a))) + + +def test_issue_15920(): + r = rootof(x**5 - x + 1, 0) + p = Integral(x, (x, 1, y)) + assert unchanged(Eq, r, p) + + +def test_issue_19113(): + eq = y**3 - y + 1 + # generator is a canonical x in RootOf + assert str(Poly(eq).real_roots()) == '[CRootOf(x**3 - x + 1, 0)]' + assert str(Poly(eq.subs(y, tan(y))).real_roots() + ) == '[CRootOf(x**3 - x + 1, 0)]' + assert str(Poly(eq.subs(y, tan(x))).real_roots() + ) == '[CRootOf(x**3 - x + 1, 0)]' diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_solvers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_solvers.py new file mode 100644 index 0000000000000000000000000000000000000000..bf8708314466b6a8676ba1a4438eb84924d0030c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_solvers.py @@ -0,0 +1,112 @@ +"""Tests for low-level linear systems solver. """ + +from sympy.matrices import Matrix +from sympy.polys.domains import ZZ, QQ +from sympy.polys.fields import field +from sympy.polys.rings import ring +from sympy.polys.solvers import solve_lin_sys, eqs_to_matrix + + +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(s.ring == domain 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) is 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) is 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) + + 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) + + 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 + +def test_eqs_to_matrix(): + domain, x1,x2 = ring("x1,x2", QQ) + eqs_coeff = [{x1: QQ(1), x2: QQ(1)}, {x1: QQ(2), x2: QQ(-1)}] + eqs_rhs = [QQ(-5), QQ(0)] + M = eqs_to_matrix(eqs_coeff, eqs_rhs, [x1, x2], QQ) + assert M.to_Matrix() == Matrix([[1, 1, 5], [2, -1, 0]]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_specialpolys.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_specialpolys.py new file mode 100644 index 0000000000000000000000000000000000000000..39f551c9e70b5c2bae748ea681b9c8a8cb349fe1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_specialpolys.py @@ -0,0 +1,152 @@ +"""Tests for functions for generating interesting polynomials. """ + +from sympy.core.add import Add +from sympy.core.symbol import symbols +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.ntheory.generate import prime +from sympy.polys.domains.integerring import ZZ +from sympy.polys.polytools import Poly +from sympy.utilities.iterables import permute_signs +from sympy.testing.pytest import raises + +from sympy.polys.specialpolys import ( + swinnerton_dyer_poly, + cyclotomic_poly, + symmetric_poly, + random_poly, + interpolating_poly, + fateman_poly_F_1, + dmp_fateman_poly_F_1, + fateman_poly_F_2, + dmp_fateman_poly_F_2, + fateman_poly_F_3, + dmp_fateman_poly_F_3, +) + +from sympy.abc import x, y, z + + +def test_swinnerton_dyer_poly(): + raises(ValueError, lambda: swinnerton_dyer_poly(0, x)) + + assert swinnerton_dyer_poly(1, x, polys=True) == Poly(x**2 - 2) + + 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 + # we only need to check that the polys arg works but + # we may as well test that the roots are correct + p = [sqrt(prime(i)) for i in range(1, 5)] + assert str([i.n(3) for i in + swinnerton_dyer_poly(4, polys=True).all_roots()] + ) == str(sorted([Add(*i).n(3) for i in permute_signs(p)])) + + +def test_cyclotomic_poly(): + raises(ValueError, lambda: cyclotomic_poly(0, x)) + + assert cyclotomic_poly(1, x, polys=True) == Poly(x - 1) + + assert cyclotomic_poly(1, x) == x - 1 + assert cyclotomic_poly(2, x) == x + 1 + assert cyclotomic_poly(3, x) == x**2 + x + 1 + assert cyclotomic_poly(4, x) == x**2 + 1 + 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)) + + assert symmetric_poly(1, x, y, z, polys=True) == Poly(x + y + z) + assert symmetric_poly(1, (x, y, z), polys=True) == Poly(x + y + z) + + assert symmetric_poly(0, x, y, z) == 1 + assert symmetric_poly(1, x, y, z) == x + y + z + 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) + + assert Poly(poly).degree() == 10 + assert all(-100 <= coeff <= 100 for coeff in Poly(poly).coeffs()) is True + + poly = random_poly(x, 10, -100, 100, polys=True) + + assert poly.degree() == 10 + assert all(-100 <= coeff <= 100 for coeff in poly.coeffs()) is True + + +def test_interpolating_poly(): + x0, x1, x2, x3, y0, y1, y2, y3 = symbols('x:4, y:4') + + assert interpolating_poly(0, x) == 0 + assert interpolating_poly(1, x) == y0 + + assert interpolating_poly(2, x) == \ + y0*(x - x1)/(x0 - x1) + y1*(x - x0)/(x1 - x0) + + assert interpolating_poly(3, x) == \ + y0*(x - x1)*(x - x2)/((x0 - x1)*(x0 - x2)) + \ + y1*(x - x0)*(x - x2)/((x1 - x0)*(x1 - x2)) + \ + y2*(x - x0)*(x - x1)/((x2 - x0)*(x2 - x1)) + + assert interpolating_poly(4, x) == \ + y0*(x - x1)*(x - x2)*(x - x3)/((x0 - x1)*(x0 - x2)*(x0 - x3)) + \ + y1*(x - x0)*(x - x2)*(x - x3)/((x1 - x0)*(x1 - x2)*(x1 - x3)) + \ + y2*(x - x0)*(x - x1)*(x - x3)/((x2 - x0)*(x2 - x1)*(x2 - x3)) + \ + y3*(x - x0)*(x - x1)*(x - x2)/((x3 - x0)*(x3 - x1)*(x3 - x2)) + + raises(ValueError, lambda: + interpolating_poly(2, x, (x, 2), (1, 3))) + raises(ValueError, lambda: + interpolating_poly(2, x, (x + y, 2), (1, 3))) + raises(ValueError, lambda: + interpolating_poly(2, x + y, (x, 2), (1, 3))) + raises(ValueError, lambda: + interpolating_poly(2, 3, (4, 5), (6, 7))) + raises(ValueError, lambda: + interpolating_poly(2, 3, (4, 5), (6, 7, 8))) + assert interpolating_poly(0, x, (1, 2), (3, 4)) == 0 + assert interpolating_poly(1, x, (1, 2), (3, 4)) == 3 + assert interpolating_poly(2, x, (1, 2), (3, 4)) == x + 2 + + +def test_fateman_poly_F_1(): + f, g, h = fateman_poly_F_1(1) + F, G, H = dmp_fateman_poly_F_1(1, ZZ) + + assert [ t.rep.to_list() 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) + + assert [ t.rep.to_list() 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) + + assert [ t.rep.to_list() 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) + + assert [ t.rep.to_list() 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) + + assert [ t.rep.to_list() 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) + + assert [ t.rep.to_list() for t in [f, g, h] ] == [F, G, H] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_sqfreetools.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_sqfreetools.py new file mode 100644 index 0000000000000000000000000000000000000000..b772a05a50e2eacd5a7c80352b1eadd52c69c3fa --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_sqfreetools.py @@ -0,0 +1,160 @@ +"""Tests for square-free decomposition algorithms and related tools. """ + +from sympy.polys.rings import ring +from sympy.polys.domains import FF, ZZ, QQ +from sympy.polys.specialpolys import f_polys + +from sympy.testing.pytest import raises +from sympy.external.gmpy import MPQ + +f_0, f_1, f_2, f_3, f_4, f_5, f_6 = f_polys() + +def test_dup_sqf(): + R, x = ring("x", ZZ) + + assert R.dup_sqf_part(0) == 0 + assert R.dup_sqf_p(0) is True + + assert R.dup_sqf_part(7) == 1 + assert R.dup_sqf_p(7) is True + + assert R.dup_sqf_part(2*x + 2) == x + 1 + assert R.dup_sqf_p(2*x + 2) is True + + 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 R.dup_sqf_part(-x**3 + x + 1) == x**3 - x - 1 + assert R.dup_sqf_p(-x**3 + x + 1) is True + + 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 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 R.dup_sqf_list(0) == (0, []) + assert R.dup_sqf_list(1) == (1, []) + + 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)]) + + 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)]) + + assert R.dup_sqf_list(2*x**2 + 4*x + 2) == (2, [(x + 1, 2)]) + + R, x = ring("x", QQ) + assert R.dup_sqf_list(2*x**2 + 4*x + 2) == (2, [(x + 1, 2)]) + + R, x = ring("x", FF(2)) + assert R.dup_sqf_list(x**2 + 1) == (1, [(x + 1, 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)]) + + R1, x = ring("x", ZZ) + R2, y = ring("y", FF(3)) + + f = x**3 + 1 + g = y**3 + 1 + + assert R1.dup_sqf_part(f) == f + assert R2.dup_sqf_part(g) == y + 1 + + assert R1.dup_sqf_p(f) is True + assert R2.dup_sqf_p(g) is False + + R, x, y = ring("x,y", ZZ) + + A = x**4 - 3*x**2 + 6 + D = x**6 - 5*x**4 + 5*x**2 + 4 + + 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) + + assert R.drop(x).dup_sqf_list(res) == (45796, [(h, 3)]) + + Rt, t = ring("t", ZZ) + R, x = ring("x", Rt) + assert R.dup_sqf_list_include(t**3*x**2) == [(t**3, 1), (x, 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 + + 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 = -x**2 + 2*x - 1 + assert R.dmp_sqf_list_include(f) == [(-1, 1), (x - 1, 2)] + + f = (y**2 + 1)**2*(x**2 + 2*x + 2) + assert R.dmp_sqf_p(f) is False + assert R.dmp_sqf_list(f) == (1, [(x**2 + 2*x + 2, 1), (y**2 + 1, 2)]) + + R, x, y = ring("x,y", FF(2)) + raises(NotImplementedError, lambda: R.dmp_sqf_list(y**2 + 1)) + + +def test_dup_gff_list(): + R, x = ring("x", ZZ) + + f = x**5 + 2*x**4 - x**3 - 2*x**2 + assert R.dup_gff_list(f) == [(x, 1), (x + 2, 4)] + + 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: R.dup_gff_list(0)) + +def test_issue_26178(): + R, x, y, z = ring(['x', 'y', 'z'], QQ) + assert (x**2 - 2*y**2 + 1).sqf_list() == (MPQ(1,1), [(x**2 - 2*y**2 + 1, 1)]) + assert (x**2 - 2*z**2 + 1).sqf_list() == (MPQ(1,1), [(x**2 - 2*z**2 + 1, 1)]) + assert (y**2 - 2*z**2 + 1).sqf_list() == (MPQ(1,1), [(y**2 - 2*z**2 + 1, 1)]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_subresultants_qq_zz.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_subresultants_qq_zz.py new file mode 100644 index 0000000000000000000000000000000000000000..7f7560dfeaf93b20f7cf68cdc597c024cb519cca --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/polys/tests/test_subresultants_qq_zz.py @@ -0,0 +1,347 @@ +from sympy.core.symbol import Symbol +from sympy.polys.polytools import (pquo, prem, sturm, subresultants) +from sympy.matrices import Matrix +from sympy.polys.subresultants_qq_zz import (sylvester, res, res_q, res_z, bezout, + subresultants_sylv, modified_subresultants_sylv, + subresultants_bezout, modified_subresultants_bezout, + backward_eye, + sturm_pg, sturm_q, sturm_amv, euclid_pg, euclid_q, + euclid_amv, modified_subresultants_pg, subresultants_pg, + subresultants_amv_q, quo_z, rem_z, subresultants_amv, + modified_subresultants_amv, subresultants_rem, + subresultants_vv, subresultants_vv_2) + + +def test_sylvester(): + x = Symbol('x') + + assert sylvester(x**3 -7, 0, x) == sylvester(x**3 -7, 0, x, 1) == Matrix([[0]]) + assert sylvester(0, x**3 -7, x) == sylvester(0, x**3 -7, x, 1) == Matrix([[0]]) + assert sylvester(x**3 -7, 0, x, 2) == Matrix([[0]]) + assert sylvester(0, x**3 -7, x, 2) == Matrix([[0]]) + + assert sylvester(x**3 -7, 7, x).det() == sylvester(x**3 -7, 7, x, 1).det() == 343 + assert sylvester(7, x**3 -7, x).det() == sylvester(7, x**3 -7, x, 1).det() == 343 + assert sylvester(x**3 -7, 7, x, 2).det() == -343 + assert sylvester(7, x**3 -7, x, 2).det() == 343 + + assert sylvester(3, 7, x).det() == sylvester(3, 7, x, 1).det() == sylvester(3, 7, x, 2).det() == 1 + + assert sylvester(3, 0, x).det() == sylvester(3, 0, x, 1).det() == sylvester(3, 0, x, 2).det() == 1 + + assert sylvester(x - 3, x - 8, x) == sylvester(x - 3, x - 8, x, 1) == sylvester(x - 3, x - 8, x, 2) == Matrix([[1, -3], [1, -8]]) + + assert sylvester(x**3 - 7*x + 7, 3*x**2 - 7, x) == sylvester(x**3 - 7*x + 7, 3*x**2 - 7, x, 1) == Matrix([[1, 0, -7, 7, 0], [0, 1, 0, -7, 7], [3, 0, -7, 0, 0], [0, 3, 0, -7, 0], [0, 0, 3, 0, -7]]) + + assert sylvester(x**3 - 7*x + 7, 3*x**2 - 7, x, 2) == Matrix([ +[1, 0, -7, 7, 0, 0], [0, 3, 0, -7, 0, 0], [0, 1, 0, -7, 7, 0], [0, 0, 3, 0, -7, 0], [0, 0, 1, 0, -7, 7], [0, 0, 0, 3, 0, -7]]) + +def test_subresultants_sylv(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert subresultants_sylv(p, q, x) == subresultants(p, q, x) + assert subresultants_sylv(p, q, x)[-1] == res(p, q, x) + assert subresultants_sylv(p, q, x) != euclid_amv(p, q, x) + amv_factors = [1, 1, -1, 1, -1, 1] + assert subresultants_sylv(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert subresultants_sylv(p, q, x) == euclid_amv(p, q, x) + +def test_modified_subresultants_sylv(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + amv_factors = [1, 1, -1, 1, -1, 1] + assert modified_subresultants_sylv(p, q, x) == [i*j for i, j in zip(amv_factors, subresultants_amv(p, q, x))] + assert modified_subresultants_sylv(p, q, x)[-1] != res_q(p + x**8, q, x) + assert modified_subresultants_sylv(p, q, x) != sturm_amv(p, q, x) + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert modified_subresultants_sylv(p, q, x) == sturm_amv(p, q, x) + assert modified_subresultants_sylv(-p, q, x) != sturm_amv(-p, q, x) + +def test_res(): + x = Symbol('x') + + assert res(3, 5, x) == 1 + +def test_res_q(): + x = Symbol('x') + + assert res_q(3, 5, x) == 1 + +def test_res_z(): + x = Symbol('x') + + assert res_z(3, 5, x) == 1 + assert res(3, 5, x) == res_q(3, 5, x) == res_z(3, 5, x) + +def test_bezout(): + x = Symbol('x') + + p = -2*x**5+7*x**3+9*x**2-3*x+1 + q = -10*x**4+21*x**2+18*x-3 + assert bezout(p, q, x, 'bz').det() == sylvester(p, q, x, 2).det() + assert bezout(p, q, x, 'bz').det() != sylvester(p, q, x, 1).det() + assert bezout(p, q, x, 'prs') == backward_eye(5) * bezout(p, q, x, 'bz') * backward_eye(5) + +def test_subresultants_bezout(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert subresultants_bezout(p, q, x) == subresultants(p, q, x) + assert subresultants_bezout(p, q, x)[-1] == sylvester(p, q, x).det() + assert subresultants_bezout(p, q, x) != euclid_amv(p, q, x) + amv_factors = [1, 1, -1, 1, -1, 1] + assert subresultants_bezout(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert subresultants_bezout(p, q, x) == euclid_amv(p, q, x) + +def test_modified_subresultants_bezout(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + amv_factors = [1, 1, -1, 1, -1, 1] + assert modified_subresultants_bezout(p, q, x) == [i*j for i, j in zip(amv_factors, subresultants_amv(p, q, x))] + assert modified_subresultants_bezout(p, q, x)[-1] != sylvester(p + x**8, q, x).det() + assert modified_subresultants_bezout(p, q, x) != sturm_amv(p, q, x) + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert modified_subresultants_bezout(p, q, x) == sturm_amv(p, q, x) + assert modified_subresultants_bezout(-p, q, x) != sturm_amv(-p, q, x) + +def test_sturm_pg(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert sturm_pg(p, q, x)[-1] != sylvester(p, q, x, 2).det() + sam_factors = [1, 1, -1, -1, 1, 1] + assert sturm_pg(p, q, x) == [i*j for i,j in zip(sam_factors, euclid_pg(p, q, x))] + + p = -9*x**5 - 5*x**3 - 9 + q = -45*x**4 - 15*x**2 + assert sturm_pg(p, q, x, 1)[-1] == sylvester(p, q, x, 1).det() + assert sturm_pg(p, q, x)[-1] != sylvester(p, q, x, 2).det() + assert sturm_pg(-p, q, x)[-1] == sylvester(-p, q, x, 2).det() + assert sturm_pg(-p, q, x) == modified_subresultants_pg(-p, q, x) + +def test_sturm_q(): + x = Symbol('x') + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert sturm_q(p, q, x) == sturm(p) + assert sturm_q(-p, -q, x) != sturm(-p) + + +def test_sturm_amv(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert sturm_amv(p, q, x)[-1] != sylvester(p, q, x, 2).det() + sam_factors = [1, 1, -1, -1, 1, 1] + assert sturm_amv(p, q, x) == [i*j for i,j in zip(sam_factors, euclid_amv(p, q, x))] + + p = -9*x**5 - 5*x**3 - 9 + q = -45*x**4 - 15*x**2 + assert sturm_amv(p, q, x, 1)[-1] == sylvester(p, q, x, 1).det() + assert sturm_amv(p, q, x)[-1] != sylvester(p, q, x, 2).det() + assert sturm_amv(-p, q, x)[-1] == sylvester(-p, q, x, 2).det() + assert sturm_pg(-p, q, x) == modified_subresultants_pg(-p, q, x) + + +def test_euclid_pg(): + x = Symbol('x') + + p = x**6+x**5-x**4-x**3+x**2-x+1 + q = 6*x**5+5*x**4-4*x**3-3*x**2+2*x-1 + assert euclid_pg(p, q, x)[-1] == sylvester(p, q, x).det() + assert euclid_pg(p, q, x) == subresultants_pg(p, q, x) + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert euclid_pg(p, q, x)[-1] != sylvester(p, q, x, 2).det() + sam_factors = [1, 1, -1, -1, 1, 1] + assert euclid_pg(p, q, x) == [i*j for i,j in zip(sam_factors, sturm_pg(p, q, x))] + + +def test_euclid_q(): + x = Symbol('x') + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert euclid_q(p, q, x)[-1] == -sturm(p)[-1] + + +def test_euclid_amv(): + x = Symbol('x') + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert euclid_amv(p, q, x)[-1] == sylvester(p, q, x).det() + assert euclid_amv(p, q, x) == subresultants_amv(p, q, x) + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert euclid_amv(p, q, x)[-1] != sylvester(p, q, x, 2).det() + sam_factors = [1, 1, -1, -1, 1, 1] + assert euclid_amv(p, q, x) == [i*j for i,j in zip(sam_factors, sturm_amv(p, q, x))] + + +def test_modified_subresultants_pg(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + amv_factors = [1, 1, -1, 1, -1, 1] + assert modified_subresultants_pg(p, q, x) == [i*j for i, j in zip(amv_factors, subresultants_pg(p, q, x))] + assert modified_subresultants_pg(p, q, x)[-1] != sylvester(p + x**8, q, x).det() + assert modified_subresultants_pg(p, q, x) != sturm_pg(p, q, x) + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert modified_subresultants_pg(p, q, x) == sturm_pg(p, q, x) + assert modified_subresultants_pg(-p, q, x) != sturm_pg(-p, q, x) + + +def test_subresultants_pg(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert subresultants_pg(p, q, x) == subresultants(p, q, x) + assert subresultants_pg(p, q, x)[-1] == sylvester(p, q, x).det() + assert subresultants_pg(p, q, x) != euclid_pg(p, q, x) + amv_factors = [1, 1, -1, 1, -1, 1] + assert subresultants_pg(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert subresultants_pg(p, q, x) == euclid_pg(p, q, x) + + +def test_subresultants_amv_q(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert subresultants_amv_q(p, q, x) == subresultants(p, q, x) + assert subresultants_amv_q(p, q, x)[-1] == sylvester(p, q, x).det() + assert subresultants_amv_q(p, q, x) != euclid_amv(p, q, x) + amv_factors = [1, 1, -1, 1, -1, 1] + assert subresultants_amv_q(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert subresultants_amv(p, q, x) == euclid_amv(p, q, x) + + +def test_rem_z(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert rem_z(p, -q, x) != prem(p, -q, x) + +def test_quo_z(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert quo_z(p, -q, x) != pquo(p, -q, x) + + y = Symbol('y') + q = 3*x**6 + 5*y**4 - 4*x**2 - 9*x + 21 + assert quo_z(p, -q, x) == pquo(p, -q, x) + +def test_subresultants_amv(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert subresultants_amv(p, q, x) == subresultants(p, q, x) + assert subresultants_amv(p, q, x)[-1] == sylvester(p, q, x).det() + assert subresultants_amv(p, q, x) != euclid_amv(p, q, x) + amv_factors = [1, 1, -1, 1, -1, 1] + assert subresultants_amv(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert subresultants_amv(p, q, x) == euclid_amv(p, q, x) + + +def test_modified_subresultants_amv(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + amv_factors = [1, 1, -1, 1, -1, 1] + assert modified_subresultants_amv(p, q, x) == [i*j for i, j in zip(amv_factors, subresultants_amv(p, q, x))] + assert modified_subresultants_amv(p, q, x)[-1] != sylvester(p + x**8, q, x).det() + assert modified_subresultants_amv(p, q, x) != sturm_amv(p, q, x) + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert modified_subresultants_amv(p, q, x) == sturm_amv(p, q, x) + assert modified_subresultants_amv(-p, q, x) != sturm_amv(-p, q, x) + + +def test_subresultants_rem(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert subresultants_rem(p, q, x) == subresultants(p, q, x) + assert subresultants_rem(p, q, x)[-1] == sylvester(p, q, x).det() + assert subresultants_rem(p, q, x) != euclid_amv(p, q, x) + amv_factors = [1, 1, -1, 1, -1, 1] + assert subresultants_rem(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert subresultants_rem(p, q, x) == euclid_amv(p, q, x) + + +def test_subresultants_vv(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert subresultants_vv(p, q, x) == subresultants(p, q, x) + assert subresultants_vv(p, q, x)[-1] == sylvester(p, q, x).det() + assert subresultants_vv(p, q, x) != euclid_amv(p, q, x) + amv_factors = [1, 1, -1, 1, -1, 1] + assert subresultants_vv(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert subresultants_vv(p, q, x) == euclid_amv(p, q, x) + + +def test_subresultants_vv_2(): + x = Symbol('x') + + p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 + q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 + assert subresultants_vv_2(p, q, x) == subresultants(p, q, x) + assert subresultants_vv_2(p, q, x)[-1] == sylvester(p, q, x).det() + assert subresultants_vv_2(p, q, x) != euclid_amv(p, q, x) + amv_factors = [1, 1, -1, 1, -1, 1] + assert subresultants_vv_2(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] + + p = x**3 - 7*x + 7 + q = 3*x**2 - 7 + assert subresultants_vv_2(p, q, x) == euclid_amv(p, q, x) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4725992b4fe6742feefe0289e8e2c2d289a2f9c5 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/__pycache__/indexed_integrals.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/__pycache__/indexed_integrals.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9db196362de4f07ceee4d8b73de0d66c13ecb91e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/__pycache__/indexed_integrals.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b576c2c2deca526ef57ca978298ca31996d27ef6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/tests/__pycache__/test_indexed_integrals.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/tests/__pycache__/test_indexed_integrals.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0fe57ba4aed2bb8b004632dd0ee330e0a07628e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/tests/__pycache__/test_indexed_integrals.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/tests/test_indexed_integrals.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/tests/test_indexed_integrals.py new file mode 100644 index 0000000000000000000000000000000000000000..61b98f0ffec29e026f6dfe8e16fde8b5818b0b09 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/sandbox/tests/test_indexed_integrals.py @@ -0,0 +1,25 @@ +from sympy.sandbox.indexed_integrals import IndexedIntegral +from sympy.core.symbol import symbols +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.tensor.indexed import (Idx, IndexedBase) + + +def test_indexed_integrals(): + A = IndexedBase('A') + i, j = symbols('i j', integer=True) + a1, a2 = symbols('a1:3', cls=Idx) + assert isinstance(a1, Idx) + + assert IndexedIntegral(1, A[i]).doit() == A[i] + assert IndexedIntegral(A[i], A[i]).doit() == A[i] ** 2 / 2 + assert IndexedIntegral(A[j], A[i]).doit() == A[i] * A[j] + assert IndexedIntegral(A[i] * A[j], A[i]).doit() == A[i] ** 2 * A[j] / 2 + assert IndexedIntegral(sin(A[i]), A[i]).doit() == -cos(A[i]) + assert IndexedIntegral(sin(A[j]), A[i]).doit() == sin(A[j]) * A[i] + + assert IndexedIntegral(1, A[a1]).doit() == A[a1] + assert IndexedIntegral(A[a1], A[a1]).doit() == A[a1] ** 2 / 2 + assert IndexedIntegral(A[a2], A[a1]).doit() == A[a1] * A[a2] + assert IndexedIntegral(A[a1] * A[a2], A[a1]).doit() == A[a1] ** 2 * A[a2] / 2 + assert IndexedIntegral(sin(A[a1]), A[a1]).doit() == -cos(A[a1]) + assert IndexedIntegral(sin(A[a2]), A[a1]).doit() == sin(A[a2]) * A[a1] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b4361240047a79b883444b8fdb7669597bcb3b6c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/bivariate.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/bivariate.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3cccd72c9c79441c30656f59b9325fba045c1c1a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/bivariate.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/decompogen.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/decompogen.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..896266da56c405fd8610b3d7b6dab94a011f9862 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/decompogen.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/deutils.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/deutils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba37486281152ede7afb14bd60157f786bebe5c2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/deutils.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/inequalities.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/inequalities.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ce68998d6ef83ff1fdc6c8c2d21cb5190b20e5e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/inequalities.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/pde.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/pde.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99a5bab0cd6598db191c2ac8e81165750df56f7c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/pde.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/polysys.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/polysys.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..77e4171248280c9907500818017723690463e6d6 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/polysys.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/recurr.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/recurr.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e281c0742d3bbe71ab8e19cd420ff7b31ba69cad Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/recurr.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/simplex.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/simplex.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..631ac812ec6268e7d3fde4f76fca1747d0fe834b Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/__pycache__/simplex.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/benchmarks/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/benchmarks/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/benchmarks/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/benchmarks/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..79312e4e0bb8be50f4bf82448a1a2218ac5f636f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/benchmarks/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/benchmarks/__pycache__/bench_solvers.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/benchmarks/__pycache__/bench_solvers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34088c821eede615c10d31e3b3bb546796c68f87 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/benchmarks/__pycache__/bench_solvers.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/benchmarks/bench_solvers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/benchmarks/bench_solvers.py new file mode 100644 index 0000000000000000000000000000000000000000..d18102873f7efcde1d111e0e8eca12e208f94663 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/benchmarks/bench_solvers.py @@ -0,0 +1,12 @@ +from sympy.core.symbol import Symbol +from sympy.matrices.dense import (eye, zeros) +from sympy.solvers.solvers import solve_linear_system + +N = 8 +M = zeros(N, N + 1) +M[:, :N] = eye(N) +S = [Symbol('A%i' % i) for i in range(N)] + + +def timeit_linsolve_trivial(): + solve_linear_system(M, *S) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..23c21242208d6f520c130250ecdce43382b9d868 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/__init__.py @@ -0,0 +1,5 @@ +from .diophantine import diophantine, classify_diop, diop_solve + +__all__ = [ + 'diophantine', 'classify_diop', 'diop_solve' +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a210a3329e608a9663c31b5f6153bb186d8dfa2 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/diophantine.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/diophantine.py new file mode 100644 index 0000000000000000000000000000000000000000..ffdef6344451c96ed48dff099cf8f02494f4b504 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/diophantine.py @@ -0,0 +1,3980 @@ +from __future__ import annotations + +from sympy.core.add import Add +from sympy.core.assumptions import check_assumptions +from sympy.core.containers import Tuple +from sympy.core.exprtools import factor_terms +from sympy.core.function import _mexpand +from sympy.core.mul import Mul +from sympy.core.numbers import Rational, int_valued +from sympy.core.intfunc import igcdex, ilcm, igcd, integer_nthroot, isqrt +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.sorting import default_sort_key, ordered +from sympy.core.symbol import Symbol, symbols +from sympy.core.sympify import _sympify +from sympy.external.gmpy import jacobi, remove, invert, iroot +from sympy.functions.elementary.complexes import sign +from sympy.functions.elementary.integers import floor +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices.dense import MutableDenseMatrix as Matrix +from sympy.ntheory.factor_ import divisors, factorint, perfect_power +from sympy.ntheory.generate import nextprime +from sympy.ntheory.primetest import is_square, isprime +from sympy.ntheory.modular import symmetric_residue +from sympy.ntheory.residue_ntheory import sqrt_mod, sqrt_mod_iter +from sympy.polys.polyerrors import GeneratorsNeeded +from sympy.polys.polytools import Poly, factor_list +from sympy.simplify.simplify import signsimp +from sympy.solvers.solveset import solveset_real +from sympy.utilities import numbered_symbols +from sympy.utilities.misc import as_int, filldedent +from sympy.utilities.iterables import (is_sequence, subsets, permute_signs, + signed_permutations, ordered_partitions) + + +# these are imported with 'from sympy.solvers.diophantine import * +__all__ = ['diophantine', 'classify_diop'] + + +class DiophantineSolutionSet(set): + """ + Container for a set of solutions to a particular diophantine equation. + + The base representation is a set of tuples representing each of the solutions. + + Parameters + ========== + + symbols : list + List of free symbols in the original equation. + parameters: list + List of parameters to be used in the solution. + + Examples + ======== + + Adding solutions: + + >>> from sympy.solvers.diophantine.diophantine import DiophantineSolutionSet + >>> from sympy.abc import x, y, t, u + >>> s1 = DiophantineSolutionSet([x, y], [t, u]) + >>> s1 + set() + >>> s1.add((2, 3)) + >>> s1.add((-1, u)) + >>> s1 + {(-1, u), (2, 3)} + >>> s2 = DiophantineSolutionSet([x, y], [t, u]) + >>> s2.add((3, 4)) + >>> s1.update(*s2) + >>> s1 + {(-1, u), (2, 3), (3, 4)} + + Conversion of solutions into dicts: + + >>> list(s1.dict_iterator()) + [{x: -1, y: u}, {x: 2, y: 3}, {x: 3, y: 4}] + + Substituting values: + + >>> s3 = DiophantineSolutionSet([x, y], [t, u]) + >>> s3.add((t**2, t + u)) + >>> s3 + {(t**2, t + u)} + >>> s3.subs({t: 2, u: 3}) + {(4, 5)} + >>> s3.subs(t, -1) + {(1, u - 1)} + >>> s3.subs(t, 3) + {(9, u + 3)} + + Evaluation at specific values. Positional arguments are given in the same order as the parameters: + + >>> s3(-2, 3) + {(4, 1)} + >>> s3(5) + {(25, u + 5)} + >>> s3(None, 2) + {(t**2, t + 2)} + """ + + def __init__(self, symbols_seq, parameters): + super().__init__() + + if not is_sequence(symbols_seq): + raise ValueError("Symbols must be given as a sequence.") + + if not is_sequence(parameters): + raise ValueError("Parameters must be given as a sequence.") + + self.symbols = tuple(symbols_seq) + self.parameters = tuple(parameters) + + def add(self, solution): + if len(solution) != len(self.symbols): + raise ValueError("Solution should have a length of %s, not %s" % (len(self.symbols), len(solution))) + # make solution canonical wrt sign (i.e. no -x unless x is also present as an arg) + args = set(solution) + for i in range(len(solution)): + x = solution[i] + if not type(x) is int and (-x).is_Symbol and -x not in args: + solution = [_.subs(-x, x) for _ in solution] + super().add(Tuple(*solution)) + + def update(self, *solutions): + for solution in solutions: + self.add(solution) + + def dict_iterator(self): + for solution in ordered(self): + yield dict(zip(self.symbols, solution)) + + def subs(self, *args, **kwargs): + result = DiophantineSolutionSet(self.symbols, self.parameters) + for solution in self: + result.add(solution.subs(*args, **kwargs)) + return result + + def __call__(self, *args): + if len(args) > len(self.parameters): + raise ValueError("Evaluation should have at most %s values, not %s" % (len(self.parameters), len(args))) + rep = {p: v for p, v in zip(self.parameters, args) if v is not None} + return self.subs(rep) + + +class DiophantineEquationType: + """ + Internal representation of a particular diophantine equation type. + + Parameters + ========== + + equation : + The diophantine equation that is being solved. + free_symbols : list (optional) + The symbols being solved for. + + Attributes + ========== + + total_degree : + The maximum of the degrees of all terms in the equation + homogeneous : + Does the equation contain a term of degree 0 + homogeneous_order : + Does the equation contain any coefficient that is in the symbols being solved for + dimension : + The number of symbols being solved for + """ + name: str + + def __init__(self, equation, free_symbols=None): + self.equation = _sympify(equation).expand(force=True) + + if free_symbols is not None: + self.free_symbols = free_symbols + else: + self.free_symbols = list(self.equation.free_symbols) + self.free_symbols.sort(key=default_sort_key) + + if not self.free_symbols: + raise ValueError('equation should have 1 or more free symbols') + + self.coeff = self.equation.as_coefficients_dict() + if not all(int_valued(c) for c in self.coeff.values()): + raise TypeError("Coefficients should be Integers") + + self.total_degree = Poly(self.equation).total_degree() + self.homogeneous = 1 not in self.coeff + self.homogeneous_order = not (set(self.coeff) & set(self.free_symbols)) + self.dimension = len(self.free_symbols) + self._parameters = None + + def matches(self): + """ + Determine whether the given equation can be matched to the particular equation type. + """ + return False + + @property + def n_parameters(self): + return self.dimension + + @property + def parameters(self): + if self._parameters is None: + self._parameters = symbols('t_:%i' % (self.n_parameters,), integer=True) + return self._parameters + + def solve(self, parameters=None, limit=None) -> DiophantineSolutionSet: + raise NotImplementedError('No solver has been written for %s.' % self.name) + + def pre_solve(self, parameters=None): + if not self.matches(): + raise ValueError("This equation does not match the %s equation type." % self.name) + + if parameters is not None: + if len(parameters) != self.n_parameters: + raise ValueError("Expected %s parameter(s) but got %s" % (self.n_parameters, len(parameters))) + + self._parameters = parameters + + +class Univariate(DiophantineEquationType): + """ + Representation of a univariate diophantine equation. + + A univariate diophantine equation is an equation of the form + `a_{0} + a_{1}x + a_{2}x^2 + .. + a_{n}x^n = 0` where `a_{1}, a_{2}, ..a_{n}` are + integer constants and `x` is an integer variable. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import Univariate + >>> from sympy.abc import x + >>> Univariate((x - 2)*(x - 3)**2).solve() # solves equation (x - 2)*(x - 3)**2 == 0 + {(2,), (3,)} + + """ + + name = 'univariate' + + def matches(self): + return self.dimension == 1 + + def solve(self, parameters=None, limit=None): + self.pre_solve(parameters) + + result = DiophantineSolutionSet(self.free_symbols, parameters=self.parameters) + for i in solveset_real(self.equation, self.free_symbols[0]).intersect(S.Integers): + result.add((i,)) + return result + + +class Linear(DiophantineEquationType): + """ + Representation of a linear diophantine equation. + + A linear diophantine equation is an equation of the form `a_{1}x_{1} + + a_{2}x_{2} + .. + a_{n}x_{n} = 0` where `a_{1}, a_{2}, ..a_{n}` are + integer constants and `x_{1}, x_{2}, ..x_{n}` are integer variables. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import Linear + >>> from sympy.abc import x, y, z + >>> l1 = Linear(2*x - 3*y - 5) + >>> l1.matches() # is this equation linear + True + >>> l1.solve() # solves equation 2*x - 3*y - 5 == 0 + {(3*t_0 - 5, 2*t_0 - 5)} + + Here x = -3*t_0 - 5 and y = -2*t_0 - 5 + + >>> Linear(2*x - 3*y - 4*z -3).solve() + {(t_0, 2*t_0 + 4*t_1 + 3, -t_0 - 3*t_1 - 3)} + + """ + + name = 'linear' + + def matches(self): + return self.total_degree == 1 + + def solve(self, parameters=None, limit=None): + self.pre_solve(parameters) + + coeff = self.coeff + var = self.free_symbols + + if 1 in coeff: + # negate coeff[] because input is of the form: ax + by + c == 0 + # but is used as: ax + by == -c + c = -coeff[1] + else: + c = 0 + + result = DiophantineSolutionSet(var, parameters=self.parameters) + params = result.parameters + + if len(var) == 1: + q, r = divmod(c, coeff[var[0]]) + if not r: + result.add((q,)) + return result + + ''' + base_solution_linear() can solve diophantine equations of the form: + + a*x + b*y == c + + We break down multivariate linear diophantine equations into a + series of bivariate linear diophantine equations which can then + be solved individually by base_solution_linear(). + + Consider the following: + + a_0*x_0 + a_1*x_1 + a_2*x_2 == c + + which can be re-written as: + + a_0*x_0 + g_0*y_0 == c + + where + + g_0 == gcd(a_1, a_2) + + and + + y == (a_1*x_1)/g_0 + (a_2*x_2)/g_0 + + This leaves us with two binary linear diophantine equations. + For the first equation: + + a == a_0 + b == g_0 + c == c + + For the second: + + a == a_1/g_0 + b == a_2/g_0 + c == the solution we find for y_0 in the first equation. + + The arrays A and B are the arrays of integers used for + 'a' and 'b' in each of the n-1 bivariate equations we solve. + ''' + + A = [coeff[v] for v in var] + B = [] + if len(var) > 2: + B.append(igcd(A[-2], A[-1])) + A[-2] = A[-2] // B[0] + A[-1] = A[-1] // B[0] + for i in range(len(A) - 3, 0, -1): + gcd = igcd(B[0], A[i]) + B[0] = B[0] // gcd + A[i] = A[i] // gcd + B.insert(0, gcd) + B.append(A[-1]) + + ''' + Consider the trivariate linear equation: + + 4*x_0 + 6*x_1 + 3*x_2 == 2 + + This can be re-written as: + + 4*x_0 + 3*y_0 == 2 + + where + + y_0 == 2*x_1 + x_2 + (Note that gcd(3, 6) == 3) + + The complete integral solution to this equation is: + + x_0 == 2 + 3*t_0 + y_0 == -2 - 4*t_0 + + where 't_0' is any integer. + + Now that we have a solution for 'x_0', find 'x_1' and 'x_2': + + 2*x_1 + x_2 == -2 - 4*t_0 + + We can then solve for '-2' and '-4' independently, + and combine the results: + + 2*x_1a + x_2a == -2 + x_1a == 0 + t_0 + x_2a == -2 - 2*t_0 + + 2*x_1b + x_2b == -4*t_0 + x_1b == 0*t_0 + t_1 + x_2b == -4*t_0 - 2*t_1 + + ==> + + x_1 == t_0 + t_1 + x_2 == -2 - 6*t_0 - 2*t_1 + + where 't_0' and 't_1' are any integers. + + Note that: + + 4*(2 + 3*t_0) + 6*(t_0 + t_1) + 3*(-2 - 6*t_0 - 2*t_1) == 2 + + for any integral values of 't_0', 't_1'; as required. + + This method is generalised for many variables, below. + + ''' + solutions = [] + for Ai, Bi in zip(A, B): + tot_x, tot_y = [], [] + + for arg in Add.make_args(c): + if arg.is_Integer: + # example: 5 -> k = 5 + k, p = arg, S.One + pnew = params[0] + else: # arg is a Mul or Symbol + # example: 3*t_1 -> k = 3 + # example: t_0 -> k = 1 + k, p = arg.as_coeff_Mul() + pnew = params[params.index(p) + 1] + + sol = sol_x, sol_y = base_solution_linear(k, Ai, Bi, pnew) + + if p is S.One: + if None in sol: + return result + else: + # convert a + b*pnew -> a*p + b*pnew + if isinstance(sol_x, Add): + sol_x = sol_x.args[0]*p + sol_x.args[1] + if isinstance(sol_y, Add): + sol_y = sol_y.args[0]*p + sol_y.args[1] + + tot_x.append(sol_x) + tot_y.append(sol_y) + + solutions.append(Add(*tot_x)) + c = Add(*tot_y) + + solutions.append(c) + result.add(solutions) + return result + + +class BinaryQuadratic(DiophantineEquationType): + """ + Representation of a binary quadratic diophantine equation. + + A binary quadratic diophantine equation is an equation of the + form `Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0`, where `A, B, C, D, E, + F` are integer constants and `x` and `y` are integer variables. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.solvers.diophantine.diophantine import BinaryQuadratic + >>> b1 = BinaryQuadratic(x**3 + y**2 + 1) + >>> b1.matches() + False + >>> b2 = BinaryQuadratic(x**2 + y**2 + 2*x + 2*y + 2) + >>> b2.matches() + True + >>> b2.solve() + {(-1, -1)} + + References + ========== + + .. [1] Methods to solve Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0, [online], + Available: https://www.alpertron.com.ar/METHODS.HTM + .. [2] Solving the equation ax^2+ bxy + cy^2 + dx + ey + f= 0, [online], + Available: https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf + + """ + + name = 'binary_quadratic' + + def matches(self): + return self.total_degree == 2 and self.dimension == 2 + + def solve(self, parameters=None, limit=None) -> DiophantineSolutionSet: + self.pre_solve(parameters) + + var = self.free_symbols + coeff = self.coeff + + x, y = var + + A = coeff[x**2] + B = coeff[x*y] + C = coeff[y**2] + D = coeff[x] + E = coeff[y] + F = coeff[S.One] + + A, B, C, D, E, F = [as_int(i) for i in _remove_gcd(A, B, C, D, E, F)] + + # (1) Simple-Hyperbolic case: A = C = 0, B != 0 + # In this case equation can be converted to (Bx + E)(By + D) = DE - BF + # We consider two cases; DE - BF = 0 and DE - BF != 0 + # More details, https://www.alpertron.com.ar/METHODS.HTM#SHyperb + + result = DiophantineSolutionSet(var, self.parameters) + t, u = result.parameters + + discr = B**2 - 4*A*C + if A == 0 and C == 0 and B != 0: + + if D*E - B*F == 0: + q, r = divmod(E, B) + if not r: + result.add((-q, t)) + q, r = divmod(D, B) + if not r: + result.add((t, -q)) + else: + div = divisors(D*E - B*F) + div = div + [-term for term in div] + for d in div: + x0, r = divmod(d - E, B) + if not r: + q, r = divmod(D*E - B*F, d) + if not r: + y0, r = divmod(q - D, B) + if not r: + result.add((x0, y0)) + + # (2) Parabolic case: B**2 - 4*A*C = 0 + # There are two subcases to be considered in this case. + # sqrt(c)D - sqrt(a)E = 0 and sqrt(c)D - sqrt(a)E != 0 + # More Details, https://www.alpertron.com.ar/METHODS.HTM#Parabol + + elif discr == 0: + + if A == 0: + s = BinaryQuadratic(self.equation, free_symbols=[y, x]).solve(parameters=[t, u]) + for soln in s: + result.add((soln[1], soln[0])) + + else: + g = sign(A)*igcd(A, C) + a = A // g + c = C // g + e = sign(B / A) + + sqa = isqrt(a) + sqc = isqrt(c) + _c = e*sqc*D - sqa*E + if not _c: + z = Symbol("z", real=True) + eq = sqa*g*z**2 + D*z + sqa*F + roots = solveset_real(eq, z).intersect(S.Integers) + for root in roots: + ans = diop_solve(sqa*x + e*sqc*y - root) + result.add((ans[0], ans[1])) + + elif int_valued(c): + solve_x = lambda u: -e*sqc*g*_c*t**2 - (E + 2*e*sqc*g*u)*t \ + - (e*sqc*g*u**2 + E*u + e*sqc*F) // _c + + solve_y = lambda u: sqa*g*_c*t**2 + (D + 2*sqa*g*u)*t \ + + (sqa*g*u**2 + D*u + sqa*F) // _c + + for z0 in range(0, abs(_c)): + # Check if the coefficients of y and x obtained are integers or not + if (divisible(sqa*g*z0**2 + D*z0 + sqa*F, _c) and + divisible(e*sqc*g*z0**2 + E*z0 + e*sqc*F, _c)): + result.add((solve_x(z0), solve_y(z0))) + + # (3) Method used when B**2 - 4*A*C is a square, is described in p. 6 of the below paper + # by John P. Robertson. + # https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf + + elif is_square(discr): + if A != 0: + r = sqrt(discr) + u, v = symbols("u, v", integer=True) + eq = _mexpand( + 4*A*r*u*v + 4*A*D*(B*v + r*u + r*v - B*u) + + 2*A*4*A*E*(u - v) + 4*A*r*4*A*F) + + solution = diop_solve(eq, t) + + for s0, t0 in solution: + + num = B*t0 + r*s0 + r*t0 - B*s0 + x_0 = S(num) / (4*A*r) + y_0 = S(s0 - t0) / (2*r) + if isinstance(s0, Symbol) or isinstance(t0, Symbol): + if len(check_param(x_0, y_0, 4*A*r, parameters)) > 0: + ans = check_param(x_0, y_0, 4*A*r, parameters) + result.update(*ans) + elif x_0.is_Integer and y_0.is_Integer: + if is_solution_quad(var, coeff, x_0, y_0): + result.add((x_0, y_0)) + + else: + s = BinaryQuadratic(self.equation, free_symbols=var[::-1]).solve(parameters=[t, u]) # Interchange x and y + while s: + result.add(s.pop()[::-1]) # and solution <--------+ + + # (4) B**2 - 4*A*C > 0 and B**2 - 4*A*C not a square or B**2 - 4*A*C < 0 + + else: + + P, Q = _transformation_to_DN(var, coeff) + D, N = _find_DN(var, coeff) + solns_pell = diop_DN(D, N) + + if D < 0: + for x0, y0 in solns_pell: + for x in [-x0, x0]: + for y in [-y0, y0]: + s = P*Matrix([x, y]) + Q + try: + result.add([as_int(_) for _ in s]) + except ValueError: + pass + else: + # In this case equation can be transformed into a Pell equation + + solns_pell = set(solns_pell) + solns_pell.update((-X, -Y) for X, Y in list(solns_pell)) + + a = diop_DN(D, 1) + T = a[0][0] + U = a[0][1] + + if all(int_valued(_) for _ in P[:4] + Q[:2]): + for r, s in solns_pell: + _a = (r + s*sqrt(D))*(T + U*sqrt(D))**t + _b = (r - s*sqrt(D))*(T - U*sqrt(D))**t + x_n = _mexpand(S(_a + _b) / 2) + y_n = _mexpand(S(_a - _b) / (2*sqrt(D))) + s = P*Matrix([x_n, y_n]) + Q + result.add(s) + + else: + L = ilcm(*[_.q for _ in P[:4] + Q[:2]]) + + k = 1 + + T_k = T + U_k = U + + while (T_k - 1) % L != 0 or U_k % L != 0: + T_k, U_k = T_k*T + D*U_k*U, T_k*U + U_k*T + k += 1 + + for X, Y in solns_pell: + + for i in range(k): + if all(int_valued(_) for _ in P*Matrix([X, Y]) + Q): + _a = (X + sqrt(D)*Y)*(T_k + sqrt(D)*U_k)**t + _b = (X - sqrt(D)*Y)*(T_k - sqrt(D)*U_k)**t + Xt = S(_a + _b) / 2 + Yt = S(_a - _b) / (2*sqrt(D)) + s = P*Matrix([Xt, Yt]) + Q + result.add(s) + + X, Y = X*T + D*U*Y, X*U + Y*T + + return result + + +class InhomogeneousTernaryQuadratic(DiophantineEquationType): + """ + + Representation of an inhomogeneous ternary quadratic. + + No solver is currently implemented for this equation type. + + """ + + name = 'inhomogeneous_ternary_quadratic' + + def matches(self): + if not (self.total_degree == 2 and self.dimension == 3): + return False + if not self.homogeneous: + return False + return not self.homogeneous_order + + +class HomogeneousTernaryQuadraticNormal(DiophantineEquationType): + """ + Representation of a homogeneous ternary quadratic normal diophantine equation. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.solvers.diophantine.diophantine import HomogeneousTernaryQuadraticNormal + >>> HomogeneousTernaryQuadraticNormal(4*x**2 - 5*y**2 + z**2).solve() + {(1, 2, 4)} + + """ + + name = 'homogeneous_ternary_quadratic_normal' + + def matches(self): + if not (self.total_degree == 2 and self.dimension == 3): + return False + if not self.homogeneous: + return False + if not self.homogeneous_order: + return False + + nonzero = [k for k in self.coeff if self.coeff[k]] + return len(nonzero) == 3 and all(i**2 in nonzero for i in self.free_symbols) + + def solve(self, parameters=None, limit=None) -> DiophantineSolutionSet: + self.pre_solve(parameters) + + var = self.free_symbols + coeff = self.coeff + + x, y, z = var + + a = coeff[x**2] + b = coeff[y**2] + c = coeff[z**2] + + (sqf_of_a, sqf_of_b, sqf_of_c), (a_1, b_1, c_1), (a_2, b_2, c_2) = \ + sqf_normal(a, b, c, steps=True) + + A = -a_2*c_2 + B = -b_2*c_2 + + result = DiophantineSolutionSet(var, parameters=self.parameters) + + # If following two conditions are satisfied then there are no solutions + if A < 0 and B < 0: + return result + + if ( + sqrt_mod(-b_2*c_2, a_2) is None or + sqrt_mod(-c_2*a_2, b_2) is None or + sqrt_mod(-a_2*b_2, c_2) is None): + return result + + z_0, x_0, y_0 = descent(A, B) + + z_0, q = _rational_pq(z_0, abs(c_2)) + x_0 *= q + y_0 *= q + + x_0, y_0, z_0 = _remove_gcd(x_0, y_0, z_0) + + # Holzer reduction + if sign(a) == sign(b): + x_0, y_0, z_0 = holzer(x_0, y_0, z_0, abs(a_2), abs(b_2), abs(c_2)) + elif sign(a) == sign(c): + x_0, z_0, y_0 = holzer(x_0, z_0, y_0, abs(a_2), abs(c_2), abs(b_2)) + else: + y_0, z_0, x_0 = holzer(y_0, z_0, x_0, abs(b_2), abs(c_2), abs(a_2)) + + x_0 = reconstruct(b_1, c_1, x_0) + y_0 = reconstruct(a_1, c_1, y_0) + z_0 = reconstruct(a_1, b_1, z_0) + + sq_lcm = ilcm(sqf_of_a, sqf_of_b, sqf_of_c) + + x_0 = abs(x_0*sq_lcm // sqf_of_a) + y_0 = abs(y_0*sq_lcm // sqf_of_b) + z_0 = abs(z_0*sq_lcm // sqf_of_c) + + result.add(_remove_gcd(x_0, y_0, z_0)) + return result + + +class HomogeneousTernaryQuadratic(DiophantineEquationType): + """ + Representation of a homogeneous ternary quadratic diophantine equation. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.solvers.diophantine.diophantine import HomogeneousTernaryQuadratic + >>> HomogeneousTernaryQuadratic(x**2 + y**2 - 3*z**2 + x*y).solve() + {(-1, 2, 1)} + >>> HomogeneousTernaryQuadratic(3*x**2 + y**2 - 3*z**2 + 5*x*y + y*z).solve() + {(3, 12, 13)} + + """ + + name = 'homogeneous_ternary_quadratic' + + def matches(self): + if not (self.total_degree == 2 and self.dimension == 3): + return False + if not self.homogeneous: + return False + if not self.homogeneous_order: + return False + + nonzero = [k for k in self.coeff if self.coeff[k]] + return not (len(nonzero) == 3 and all(i**2 in nonzero for i in self.free_symbols)) + + def solve(self, parameters=None, limit=None): + self.pre_solve(parameters) + + _var = self.free_symbols + coeff = self.coeff + + x, y, z = _var + var = [x, y, z] + + # Equations of the form B*x*y + C*z*x + E*y*z = 0 and At least two of the + # coefficients A, B, C are non-zero. + # There are infinitely many solutions for the equation. + # Ex: (0, 0, t), (0, t, 0), (t, 0, 0) + # Equation can be re-written as y*(B*x + E*z) = -C*x*z and we can find rather + # unobvious solutions. Set y = -C and B*x + E*z = x*z. The latter can be solved by + # using methods for binary quadratic diophantine equations. Let's select the + # solution which minimizes |x| + |z| + + result = DiophantineSolutionSet(var, parameters=self.parameters) + + def unpack_sol(sol): + if len(sol) > 0: + return list(sol)[0] + return None, None, None + + if not any(coeff[i**2] for i in var): + if coeff[x*z]: + sols = diophantine(coeff[x*y]*x + coeff[y*z]*z - x*z) + s = min(sols, key=lambda r: abs(r[0]) + abs(r[1])) + result.add(_remove_gcd(s[0], -coeff[x*z], s[1])) + return result + + var[0], var[1] = _var[1], _var[0] + y_0, x_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, coeff)) + if x_0 is not None: + result.add((x_0, y_0, z_0)) + return result + + if coeff[x**2] == 0: + # If the coefficient of x is zero change the variables + if coeff[y**2] == 0: + var[0], var[2] = _var[2], _var[0] + z_0, y_0, x_0 = unpack_sol(_diop_ternary_quadratic(var, coeff)) + + else: + var[0], var[1] = _var[1], _var[0] + y_0, x_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, coeff)) + + else: + if coeff[x*y] or coeff[x*z]: + # Apply the transformation x --> X - (B*y + C*z)/(2*A) + A = coeff[x**2] + B = coeff[x*y] + C = coeff[x*z] + D = coeff[y**2] + E = coeff[y*z] + F = coeff[z**2] + + _coeff = {} + + _coeff[x**2] = 4*A**2 + _coeff[y**2] = 4*A*D - B**2 + _coeff[z**2] = 4*A*F - C**2 + _coeff[y*z] = 4*A*E - 2*B*C + _coeff[x*y] = 0 + _coeff[x*z] = 0 + + x_0, y_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, _coeff)) + + if x_0 is None: + return result + + p, q = _rational_pq(B*y_0 + C*z_0, 2*A) + x_0, y_0, z_0 = x_0*q - p, y_0*q, z_0*q + + elif coeff[z*y] != 0: + if coeff[y**2] == 0: + if coeff[z**2] == 0: + # Equations of the form A*x**2 + E*yz = 0. + A = coeff[x**2] + E = coeff[y*z] + + b, a = _rational_pq(-E, A) + + x_0, y_0, z_0 = b, a, b + + else: + # Ax**2 + E*y*z + F*z**2 = 0 + var[0], var[2] = _var[2], _var[0] + z_0, y_0, x_0 = unpack_sol(_diop_ternary_quadratic(var, coeff)) + + else: + # A*x**2 + D*y**2 + E*y*z + F*z**2 = 0, C may be zero + var[0], var[1] = _var[1], _var[0] + y_0, x_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, coeff)) + + else: + # Ax**2 + D*y**2 + F*z**2 = 0, C may be zero + x_0, y_0, z_0 = unpack_sol(_diop_ternary_quadratic_normal(var, coeff)) + + if x_0 is None: + return result + + result.add(_remove_gcd(x_0, y_0, z_0)) + return result + + +class InhomogeneousGeneralQuadratic(DiophantineEquationType): + """ + + Representation of an inhomogeneous general quadratic. + + No solver is currently implemented for this equation type. + + """ + + name = 'inhomogeneous_general_quadratic' + + def matches(self): + if not (self.total_degree == 2 and self.dimension >= 3): + return False + if not self.homogeneous_order: + return True + # there may be Pow keys like x**2 or Mul keys like x*y + return any(k.is_Mul for k in self.coeff) and not self.homogeneous + + +class HomogeneousGeneralQuadratic(DiophantineEquationType): + """ + + Representation of a homogeneous general quadratic. + + No solver is currently implemented for this equation type. + + """ + + name = 'homogeneous_general_quadratic' + + def matches(self): + if not (self.total_degree == 2 and self.dimension >= 3): + return False + if not self.homogeneous_order: + return False + # there may be Pow keys like x**2 or Mul keys like x*y + return any(k.is_Mul for k in self.coeff) and self.homogeneous + + +class GeneralSumOfSquares(DiophantineEquationType): + r""" + Representation of the diophantine equation + + `x_{1}^2 + x_{2}^2 + . . . + x_{n}^2 - k = 0`. + + Details + ======= + + When `n = 3` if `k = 4^a(8m + 7)` for some `a, m \in Z` then there will be + no solutions. Refer [1]_ for more details. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import GeneralSumOfSquares + >>> from sympy.abc import a, b, c, d, e + >>> GeneralSumOfSquares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345).solve() + {(15, 22, 22, 24, 24)} + + By default only 1 solution is returned. Use the `limit` keyword for more: + + >>> sorted(GeneralSumOfSquares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345).solve(limit=3)) + [(15, 22, 22, 24, 24), (16, 19, 24, 24, 24), (16, 20, 22, 23, 26)] + + References + ========== + + .. [1] Representing an integer as a sum of three squares, [online], + Available: + https://proofwiki.org/wiki/Integer_as_Sum_of_Three_Squares + """ + + name = 'general_sum_of_squares' + + def matches(self): + if not (self.total_degree == 2 and self.dimension >= 3): + return False + if not self.homogeneous_order: + return False + if any(k.is_Mul for k in self.coeff): + return False + return all(self.coeff[k] == 1 for k in self.coeff if k != 1) + + def solve(self, parameters=None, limit=1): + self.pre_solve(parameters) + + var = self.free_symbols + k = -int(self.coeff[1]) + n = self.dimension + + result = DiophantineSolutionSet(var, parameters=self.parameters) + + if k < 0 or limit < 1: + return result + + signs = [-1 if x.is_nonpositive else 1 for x in var] + negs = signs.count(-1) != 0 + + took = 0 + for t in sum_of_squares(k, n, zeros=True): + if negs: + result.add([signs[i]*j for i, j in enumerate(t)]) + else: + result.add(t) + took += 1 + if took == limit: + break + return result + + +class GeneralPythagorean(DiophantineEquationType): + """ + Representation of the general pythagorean equation, + `a_{1}^2x_{1}^2 + a_{2}^2x_{2}^2 + . . . + a_{n}^2x_{n}^2 - a_{n + 1}^2x_{n + 1}^2 = 0`. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import GeneralPythagorean + >>> from sympy.abc import a, b, c, d, e, x, y, z, t + >>> GeneralPythagorean(a**2 + b**2 + c**2 - d**2).solve() + {(t_0**2 + t_1**2 - t_2**2, 2*t_0*t_2, 2*t_1*t_2, t_0**2 + t_1**2 + t_2**2)} + >>> GeneralPythagorean(9*a**2 - 4*b**2 + 16*c**2 + 25*d**2 + e**2).solve(parameters=[x, y, z, t]) + {(-10*t**2 + 10*x**2 + 10*y**2 + 10*z**2, 15*t**2 + 15*x**2 + 15*y**2 + 15*z**2, 15*t*x, 12*t*y, 60*t*z)} + """ + + name = 'general_pythagorean' + + def matches(self): + if not (self.total_degree == 2 and self.dimension >= 3): + return False + if not self.homogeneous_order: + return False + if any(k.is_Mul for k in self.coeff): + return False + if all(self.coeff[k] == 1 for k in self.coeff if k != 1): + return False + if not all(is_square(abs(self.coeff[k])) for k in self.coeff): + return False + # all but one has the same sign + # e.g. 4*x**2 + y**2 - 4*z**2 + return abs(sum(sign(self.coeff[k]) for k in self.coeff)) == self.dimension - 2 + + @property + def n_parameters(self): + return self.dimension - 1 + + def solve(self, parameters=None, limit=1): + self.pre_solve(parameters) + + coeff = self.coeff + var = self.free_symbols + n = self.dimension + + if sign(coeff[var[0] ** 2]) + sign(coeff[var[1] ** 2]) + sign(coeff[var[2] ** 2]) < 0: + for key in coeff.keys(): + coeff[key] = -coeff[key] + + result = DiophantineSolutionSet(var, parameters=self.parameters) + + index = 0 + + for i, v in enumerate(var): + if sign(coeff[v ** 2]) == -1: + index = i + + m = result.parameters + + ith = sum(m_i ** 2 for m_i in m) + L = [ith - 2 * m[n - 2] ** 2] + L.extend([2 * m[i] * m[n - 2] for i in range(n - 2)]) + sol = L[:index] + [ith] + L[index:] + + lcm = 1 + for i, v in enumerate(var): + if i == index or (index > 0 and i == 0) or (index == 0 and i == 1): + lcm = ilcm(lcm, sqrt(abs(coeff[v ** 2]))) + else: + s = sqrt(coeff[v ** 2]) + lcm = ilcm(lcm, s if _odd(s) else s // 2) + + for i, v in enumerate(var): + sol[i] = (lcm * sol[i]) / sqrt(abs(coeff[v ** 2])) + + result.add(sol) + return result + + +class CubicThue(DiophantineEquationType): + """ + Representation of a cubic Thue diophantine equation. + + A cubic Thue diophantine equation is a polynomial of the form + `f(x, y) = r` of degree 3, where `x` and `y` are integers + and `r` is a rational number. + + No solver is currently implemented for this equation type. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.solvers.diophantine.diophantine import CubicThue + >>> c1 = CubicThue(x**3 + y**2 + 1) + >>> c1.matches() + True + + """ + + name = 'cubic_thue' + + def matches(self): + return self.total_degree == 3 and self.dimension == 2 + + +class GeneralSumOfEvenPowers(DiophantineEquationType): + """ + Representation of the diophantine equation + + `x_{1}^e + x_{2}^e + . . . + x_{n}^e - k = 0` + + where `e` is an even, integer power. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import GeneralSumOfEvenPowers + >>> from sympy.abc import a, b + >>> GeneralSumOfEvenPowers(a**4 + b**4 - (2**4 + 3**4)).solve() + {(2, 3)} + + """ + + name = 'general_sum_of_even_powers' + + def matches(self): + if not self.total_degree > 3: + return False + if self.total_degree % 2 != 0: + return False + if not all(k.is_Pow and k.exp == self.total_degree for k in self.coeff if k != 1): + return False + return all(self.coeff[k] == 1 for k in self.coeff if k != 1) + + def solve(self, parameters=None, limit=1): + self.pre_solve(parameters) + + var = self.free_symbols + coeff = self.coeff + + p = None + for q in coeff.keys(): + if q.is_Pow and coeff[q]: + p = q.exp + + k = len(var) + n = -coeff[1] + + result = DiophantineSolutionSet(var, parameters=self.parameters) + + if n < 0 or limit < 1: + return result + + sign = [-1 if x.is_nonpositive else 1 for x in var] + negs = sign.count(-1) != 0 + + took = 0 + for t in power_representation(n, p, k): + if negs: + result.add([sign[i]*j for i, j in enumerate(t)]) + else: + result.add(t) + took += 1 + if took == limit: + break + return result + +# these types are known (but not necessarily handled) +# note that order is important here (in the current solver state) +all_diop_classes = [ + Linear, + Univariate, + BinaryQuadratic, + InhomogeneousTernaryQuadratic, + HomogeneousTernaryQuadraticNormal, + HomogeneousTernaryQuadratic, + InhomogeneousGeneralQuadratic, + HomogeneousGeneralQuadratic, + GeneralSumOfSquares, + GeneralPythagorean, + CubicThue, + GeneralSumOfEvenPowers, +] + +diop_known = {diop_class.name for diop_class in all_diop_classes} + + +def _remove_gcd(*x): + try: + g = igcd(*x) + except ValueError: + fx = list(filter(None, x)) + if len(fx) < 2: + return x + g = igcd(*[i.as_content_primitive()[0] for i in fx]) + except TypeError: + raise TypeError('_remove_gcd(a,b,c) or _remove_gcd(*container)') + if g == 1: + return x + return tuple([i//g for i in x]) + + +def _rational_pq(a, b): + # return `(numer, denom)` for a/b; sign in numer and gcd removed + return _remove_gcd(sign(b)*a, abs(b)) + + +def _nint_or_floor(p, q): + # return nearest int to p/q; in case of tie return floor(p/q) + w, r = divmod(p, q) + if abs(r) <= abs(q)//2: + return w + return w + 1 + + +def _odd(i): + return i % 2 != 0 + + +def _even(i): + return i % 2 == 0 + + +def diophantine(eq, param=symbols("t", integer=True), syms=None, + permute=False): + """ + Simplify the solution procedure of diophantine equation ``eq`` by + converting it into a product of terms which should equal zero. + + Explanation + =========== + + For example, when solving, `x^2 - y^2 = 0` this is treated as + `(x + y)(x - y) = 0` and `x + y = 0` and `x - y = 0` are solved + independently and combined. Each term is solved by calling + ``diop_solve()``. (Although it is possible to call ``diop_solve()`` + directly, one must be careful to pass an equation in the correct + form and to interpret the output correctly; ``diophantine()`` is + the public-facing function to use in general.) + + Output of ``diophantine()`` is a set of tuples. The elements of the + tuple are the solutions for each variable in the equation and + are arranged according to the alphabetic ordering of the variables. + e.g. For an equation with two variables, `a` and `b`, the first + element of the tuple is the solution for `a` and the second for `b`. + + Usage + ===== + + ``diophantine(eq, t, syms)``: Solve the diophantine + equation ``eq``. + ``t`` is the optional parameter to be used by ``diop_solve()``. + ``syms`` is an optional list of symbols which determines the + order of the elements in the returned tuple. + + By default, only the base solution is returned. If ``permute`` is set to + True then permutations of the base solution and/or permutations of the + signs of the values will be returned when applicable. + + Details + ======= + + ``eq`` should be an expression which is assumed to be zero. + ``t`` is the parameter to be used in the solution. + + Examples + ======== + + >>> from sympy import diophantine + >>> from sympy.abc import a, b + >>> eq = a**4 + b**4 - (2**4 + 3**4) + >>> diophantine(eq) + {(2, 3)} + >>> diophantine(eq, permute=True) + {(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)} + + >>> from sympy.abc import x, y, z + >>> diophantine(x**2 - y**2) + {(t_0, -t_0), (t_0, t_0)} + + >>> diophantine(x*(2*x + 3*y - z)) + {(0, n1, n2), (t_0, t_1, 2*t_0 + 3*t_1)} + >>> diophantine(x**2 + 3*x*y + 4*x) + {(0, n1), (-3*t_0 - 4, t_0)} + + See Also + ======== + + diop_solve + sympy.utilities.iterables.permute_signs + sympy.utilities.iterables.signed_permutations + """ + + eq = _sympify(eq) + + if isinstance(eq, Eq): + eq = eq.lhs - eq.rhs + + try: + var = list(eq.expand(force=True).free_symbols) + var.sort(key=default_sort_key) + if syms: + if not is_sequence(syms): + raise TypeError( + 'syms should be given as a sequence, e.g. a list') + syms = [i for i in syms if i in var] + if syms != var: + dict_sym_index = dict(zip(syms, range(len(syms)))) + return {tuple([t[dict_sym_index[i]] for i in var]) + for t in diophantine(eq, param, permute=permute)} + n, d = eq.as_numer_denom() + if n.is_number: + return set() + if not d.is_number: + dsol = diophantine(d) + good = diophantine(n) - dsol + return {s for s in good if _mexpand(d.subs(zip(var, s)))} + eq = factor_terms(n) + assert not eq.is_number + eq = eq.as_independent(*var, as_Add=False)[1] + p = Poly(eq) + assert not any(g.is_number for g in p.gens) + eq = p.as_expr() + assert eq.is_polynomial() + except (GeneratorsNeeded, AssertionError): + raise TypeError(filldedent(''' + Equation should be a polynomial with Rational coefficients.''')) + + # permute only sign + do_permute_signs = False + # permute sign and values + do_permute_signs_var = False + # permute few signs + permute_few_signs = False + try: + # if we know that factoring should not be attempted, skip + # the factoring step + v, c, t = classify_diop(eq) + + # check for permute sign + if permute: + len_var = len(v) + permute_signs_for = [ + GeneralSumOfSquares.name, + GeneralSumOfEvenPowers.name] + permute_signs_check = [ + HomogeneousTernaryQuadratic.name, + HomogeneousTernaryQuadraticNormal.name, + BinaryQuadratic.name] + if t in permute_signs_for: + do_permute_signs_var = True + elif t in permute_signs_check: + # if all the variables in eq have even powers + # then do_permute_sign = True + if len_var == 3: + var_mul = list(subsets(v, 2)) + # here var_mul is like [(x, y), (x, z), (y, z)] + xy_coeff = True + x_coeff = True + var1_mul_var2 = (a[0]*a[1] for a in var_mul) + # if coeff(y*z), coeff(y*x), coeff(x*z) is not 0 then + # `xy_coeff` => True and do_permute_sign => False. + # Means no permuted solution. + for v1_mul_v2 in var1_mul_var2: + try: + coeff = c[v1_mul_v2] + except KeyError: + coeff = 0 + xy_coeff = bool(xy_coeff) and bool(coeff) + var_mul = list(subsets(v, 1)) + # here var_mul is like [(x,), (y, )] + for v1 in var_mul: + try: + coeff = c[v1[0]] + except KeyError: + coeff = 0 + x_coeff = bool(x_coeff) and bool(coeff) + if not any((xy_coeff, x_coeff)): + # means only x**2, y**2, z**2, const is present + do_permute_signs = True + elif not x_coeff: + permute_few_signs = True + elif len_var == 2: + var_mul = list(subsets(v, 2)) + # here var_mul is like [(x, y)] + xy_coeff = True + x_coeff = True + var1_mul_var2 = (x[0]*x[1] for x in var_mul) + for v1_mul_v2 in var1_mul_var2: + try: + coeff = c[v1_mul_v2] + except KeyError: + coeff = 0 + xy_coeff = bool(xy_coeff) and bool(coeff) + var_mul = list(subsets(v, 1)) + # here var_mul is like [(x,), (y, )] + for v1 in var_mul: + try: + coeff = c[v1[0]] + except KeyError: + coeff = 0 + x_coeff = bool(x_coeff) and bool(coeff) + if not any((xy_coeff, x_coeff)): + # means only x**2, y**2 and const is present + # so we can get more soln by permuting this soln. + do_permute_signs = True + elif not x_coeff: + # when coeff(x), coeff(y) is not present then signs of + # x, y can be permuted such that their sign are same + # as sign of x*y. + # e.g 1. (x_val,y_val)=> (x_val,y_val), (-x_val,-y_val) + # 2. (-x_vall, y_val)=> (-x_val,y_val), (x_val,-y_val) + permute_few_signs = True + if t == 'general_sum_of_squares': + # trying to factor such expressions will sometimes hang + terms = [(eq, 1)] + else: + raise TypeError + except (TypeError, NotImplementedError): + fl = factor_list(eq) + if fl[0].is_Rational and fl[0] != 1: + return diophantine(eq/fl[0], param=param, syms=syms, permute=permute) + terms = fl[1] + + sols = set() + + for term in terms: + + base, _ = term + var_t, _, eq_type = classify_diop(base, _dict=False) + _, base = signsimp(base, evaluate=False).as_coeff_Mul() + solution = diop_solve(base, param) + + if eq_type in [ + Linear.name, + HomogeneousTernaryQuadratic.name, + HomogeneousTernaryQuadraticNormal.name, + GeneralPythagorean.name]: + sols.add(merge_solution(var, var_t, solution)) + + elif eq_type in [ + BinaryQuadratic.name, + GeneralSumOfSquares.name, + GeneralSumOfEvenPowers.name, + Univariate.name]: + sols.update(merge_solution(var, var_t, sol) for sol in solution) + + else: + raise NotImplementedError('unhandled type: %s' % eq_type) + + sols.discard(()) + null = tuple([0]*len(var)) + # if there is no solution, return trivial solution + if not sols and eq.subs(zip(var, null)).is_zero: + if all(check_assumptions(val, **s.assumptions0) is not False for val, s in zip(null, var)): + sols.add(null) + + final_soln = set() + for sol in sols: + if all(int_valued(s) for s in sol): + if do_permute_signs: + permuted_sign = set(permute_signs(sol)) + final_soln.update(permuted_sign) + elif permute_few_signs: + lst = list(permute_signs(sol)) + lst = list(filter(lambda x: x[0]*x[1] == sol[1]*sol[0], lst)) + permuted_sign = set(lst) + final_soln.update(permuted_sign) + elif do_permute_signs_var: + permuted_sign_var = set(signed_permutations(sol)) + final_soln.update(permuted_sign_var) + else: + final_soln.add(sol) + else: + final_soln.add(sol) + return final_soln + + +def merge_solution(var, var_t, solution): + """ + This is used to construct the full solution from the solutions of sub + equations. + + Explanation + =========== + + For example when solving the equation `(x - y)(x^2 + y^2 - z^2) = 0`, + solutions for each of the equations `x - y = 0` and `x^2 + y^2 - z^2` are + found independently. Solutions for `x - y = 0` are `(x, y) = (t, t)`. But + we should introduce a value for z when we output the solution for the + original equation. This function converts `(t, t)` into `(t, t, n_{1})` + where `n_{1}` is an integer parameter. + """ + sol = [] + + if None in solution: + return () + + solution = iter(solution) + params = numbered_symbols("n", integer=True, start=1) + for v in var: + if v in var_t: + sol.append(next(solution)) + else: + sol.append(next(params)) + + for val, symb in zip(sol, var): + if check_assumptions(val, **symb.assumptions0) is False: + return () + + return tuple(sol) + + +def _diop_solve(eq, params=None): + for diop_type in all_diop_classes: + if diop_type(eq).matches(): + return diop_type(eq).solve(parameters=params) + + +def diop_solve(eq, param=symbols("t", integer=True)): + """ + Solves the diophantine equation ``eq``. + + Explanation + =========== + + Unlike ``diophantine()``, factoring of ``eq`` is not attempted. Uses + ``classify_diop()`` to determine the type of the equation and calls + the appropriate solver function. + + Use of ``diophantine()`` is recommended over other helper functions. + ``diop_solve()`` can return either a set or a tuple depending on the + nature of the equation. All non-trivial solutions are returned: assumptions + on symbols are ignored. + + Usage + ===== + + ``diop_solve(eq, t)``: Solve diophantine equation, ``eq`` using ``t`` + as a parameter if needed. + + Details + ======= + + ``eq`` should be an expression which is assumed to be zero. + ``t`` is a parameter to be used in the solution. + + Examples + ======== + + >>> from sympy.solvers.diophantine import diop_solve + >>> from sympy.abc import x, y, z, w + >>> diop_solve(2*x + 3*y - 5) + (3*t_0 - 5, 5 - 2*t_0) + >>> diop_solve(4*x + 3*y - 4*z + 5) + (t_0, 8*t_0 + 4*t_1 + 5, 7*t_0 + 3*t_1 + 5) + >>> diop_solve(x + 3*y - 4*z + w - 6) + (t_0, t_0 + t_1, 6*t_0 + 5*t_1 + 4*t_2 - 6, 5*t_0 + 4*t_1 + 3*t_2 - 6) + >>> diop_solve(x**2 + y**2 - 5) + {(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2, 1)} + + + See Also + ======== + + diophantine() + """ + var, coeff, eq_type = classify_diop(eq, _dict=False) + + if eq_type == Linear.name: + return diop_linear(eq, param) + + elif eq_type == BinaryQuadratic.name: + return diop_quadratic(eq, param) + + elif eq_type == HomogeneousTernaryQuadratic.name: + return diop_ternary_quadratic(eq, parameterize=True) + + elif eq_type == HomogeneousTernaryQuadraticNormal.name: + return diop_ternary_quadratic_normal(eq, parameterize=True) + + elif eq_type == GeneralPythagorean.name: + return diop_general_pythagorean(eq, param) + + elif eq_type == Univariate.name: + return diop_univariate(eq) + + elif eq_type == GeneralSumOfSquares.name: + return diop_general_sum_of_squares(eq, limit=S.Infinity) + + elif eq_type == GeneralSumOfEvenPowers.name: + return diop_general_sum_of_even_powers(eq, limit=S.Infinity) + + if eq_type is not None and eq_type not in diop_known: + raise ValueError(filldedent(''' + Although this type of equation was identified, it is not yet + handled. It should, however, be listed in `diop_known` at the + top of this file. Developers should see comments at the end of + `classify_diop`. + ''')) # pragma: no cover + else: + raise NotImplementedError( + 'No solver has been written for %s.' % eq_type) + + +def classify_diop(eq, _dict=True): + # docstring supplied externally + + matched = False + diop_type = None + for diop_class in all_diop_classes: + diop_type = diop_class(eq) + if diop_type.matches(): + matched = True + break + + if matched: + return diop_type.free_symbols, dict(diop_type.coeff) if _dict else diop_type.coeff, diop_type.name + + # new diop type instructions + # -------------------------- + # if this error raises and the equation *can* be classified, + # * it should be identified in the if-block above + # * the type should be added to the diop_known + # if a solver can be written for it, + # * a dedicated handler should be written (e.g. diop_linear) + # * it should be passed to that handler in diop_solve + raise NotImplementedError(filldedent(''' + This equation is not yet recognized or else has not been + simplified sufficiently to put it in a form recognized by + diop_classify().''')) + + +classify_diop.func_doc = ( # type: ignore + ''' + Helper routine used by diop_solve() to find information about ``eq``. + + Explanation + =========== + + Returns a tuple containing the type of the diophantine equation + along with the variables (free symbols) and their coefficients. + Variables are returned as a list and coefficients are returned + as a dict with the key being the respective term and the constant + term is keyed to 1. The type is one of the following: + + * %s + + Usage + ===== + + ``classify_diop(eq)``: Return variables, coefficients and type of the + ``eq``. + + Details + ======= + + ``eq`` should be an expression which is assumed to be zero. + ``_dict`` is for internal use: when True (default) a dict is returned, + otherwise a defaultdict which supplies 0 for missing keys is returned. + + Examples + ======== + + >>> from sympy.solvers.diophantine import classify_diop + >>> from sympy.abc import x, y, z, w, t + >>> classify_diop(4*x + 6*y - 4) + ([x, y], {1: -4, x: 4, y: 6}, 'linear') + >>> classify_diop(x + 3*y -4*z + 5) + ([x, y, z], {1: 5, x: 1, y: 3, z: -4}, 'linear') + >>> classify_diop(x**2 + y**2 - x*y + x + 5) + ([x, y], {1: 5, x: 1, x**2: 1, y**2: 1, x*y: -1}, 'binary_quadratic') + ''' % ('\n * '.join(sorted(diop_known)))) + + +def diop_linear(eq, param=symbols("t", integer=True)): + """ + Solves linear diophantine equations. + + A linear diophantine equation is an equation of the form `a_{1}x_{1} + + a_{2}x_{2} + .. + a_{n}x_{n} = 0` where `a_{1}, a_{2}, ..a_{n}` are + integer constants and `x_{1}, x_{2}, ..x_{n}` are integer variables. + + Usage + ===== + + ``diop_linear(eq)``: Returns a tuple containing solutions to the + diophantine equation ``eq``. Values in the tuple is arranged in the same + order as the sorted variables. + + Details + ======= + + ``eq`` is a linear diophantine equation which is assumed to be zero. + ``param`` is the parameter to be used in the solution. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import diop_linear + >>> from sympy.abc import x, y, z + >>> diop_linear(2*x - 3*y - 5) # solves equation 2*x - 3*y - 5 == 0 + (3*t_0 - 5, 2*t_0 - 5) + + Here x = -3*t_0 - 5 and y = -2*t_0 - 5 + + >>> diop_linear(2*x - 3*y - 4*z -3) + (t_0, 2*t_0 + 4*t_1 + 3, -t_0 - 3*t_1 - 3) + + See Also + ======== + + diop_quadratic(), diop_ternary_quadratic(), diop_general_pythagorean(), + diop_general_sum_of_squares() + """ + var, coeff, diop_type = classify_diop(eq, _dict=False) + + if diop_type == Linear.name: + parameters = None + if param is not None: + parameters = symbols('%s_0:%i' % (param, len(var)), integer=True) + + result = Linear(eq).solve(parameters=parameters) + + if param is None: + result = result(*[0]*len(result.parameters)) + + if len(result) > 0: + return list(result)[0] + else: + return tuple([None]*len(result.parameters)) + + +def base_solution_linear(c, a, b, t=None): + """ + Return the base solution for the linear equation, `ax + by = c`. + + Explanation + =========== + + Used by ``diop_linear()`` to find the base solution of a linear + Diophantine equation. If ``t`` is given then the parametrized solution is + returned. + + Usage + ===== + + ``base_solution_linear(c, a, b, t)``: ``a``, ``b``, ``c`` are coefficients + in `ax + by = c` and ``t`` is the parameter to be used in the solution. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import base_solution_linear + >>> from sympy.abc import t + >>> base_solution_linear(5, 2, 3) # equation 2*x + 3*y = 5 + (-5, 5) + >>> base_solution_linear(0, 5, 7) # equation 5*x + 7*y = 0 + (0, 0) + >>> base_solution_linear(5, 2, 3, t) # equation 2*x + 3*y = 5 + (3*t - 5, 5 - 2*t) + >>> base_solution_linear(0, 5, 7, t) # equation 5*x + 7*y = 0 + (7*t, -5*t) + """ + a, b, c = _remove_gcd(a, b, c) + + if c == 0: + if t is None: + return (0, 0) + if b < 0: + t = -t + return (b*t, -a*t) + + x0, y0, d = igcdex(abs(a), abs(b)) + x0 *= sign(a) + y0 *= sign(b) + if c % d: + return (None, None) + if t is None: + return (c*x0, c*y0) + if b < 0: + t = -t + return (c*x0 + b*t, c*y0 - a*t) + + +def diop_univariate(eq): + """ + Solves a univariate diophantine equations. + + Explanation + =========== + + A univariate diophantine equation is an equation of the form + `a_{0} + a_{1}x + a_{2}x^2 + .. + a_{n}x^n = 0` where `a_{1}, a_{2}, ..a_{n}` are + integer constants and `x` is an integer variable. + + Usage + ===== + + ``diop_univariate(eq)``: Returns a set containing solutions to the + diophantine equation ``eq``. + + Details + ======= + + ``eq`` is a univariate diophantine equation which is assumed to be zero. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import diop_univariate + >>> from sympy.abc import x + >>> diop_univariate((x - 2)*(x - 3)**2) # solves equation (x - 2)*(x - 3)**2 == 0 + {(2,), (3,)} + + """ + var, coeff, diop_type = classify_diop(eq, _dict=False) + + if diop_type == Univariate.name: + return {(int(i),) for i in solveset_real( + eq, var[0]).intersect(S.Integers)} + + +def divisible(a, b): + """ + Returns `True` if ``a`` is divisible by ``b`` and `False` otherwise. + """ + return not a % b + + +def diop_quadratic(eq, param=symbols("t", integer=True)): + """ + Solves quadratic diophantine equations. + + i.e. equations of the form `Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0`. Returns a + set containing the tuples `(x, y)` which contains the solutions. If there + are no solutions then `(None, None)` is returned. + + Usage + ===== + + ``diop_quadratic(eq, param)``: ``eq`` is a quadratic binary diophantine + equation. ``param`` is used to indicate the parameter to be used in the + solution. + + Details + ======= + + ``eq`` should be an expression which is assumed to be zero. + ``param`` is a parameter to be used in the solution. + + Examples + ======== + + >>> from sympy.abc import x, y, t + >>> from sympy.solvers.diophantine.diophantine import diop_quadratic + >>> diop_quadratic(x**2 + y**2 + 2*x + 2*y + 2, t) + {(-1, -1)} + + References + ========== + + .. [1] Methods to solve Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0, [online], + Available: https://www.alpertron.com.ar/METHODS.HTM + .. [2] Solving the equation ax^2+ bxy + cy^2 + dx + ey + f= 0, [online], + Available: https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf + + See Also + ======== + + diop_linear(), diop_ternary_quadratic(), diop_general_sum_of_squares(), + diop_general_pythagorean() + """ + var, coeff, diop_type = classify_diop(eq, _dict=False) + + if diop_type == BinaryQuadratic.name: + if param is not None: + parameters = [param, Symbol("u", integer=True)] + else: + parameters = None + return set(BinaryQuadratic(eq).solve(parameters=parameters)) + + +def is_solution_quad(var, coeff, u, v): + """ + Check whether `(u, v)` is solution to the quadratic binary diophantine + equation with the variable list ``var`` and coefficient dictionary + ``coeff``. + + Not intended for use by normal users. + """ + reps = dict(zip(var, (u, v))) + eq = Add(*[j*i.xreplace(reps) for i, j in coeff.items()]) + return _mexpand(eq) == 0 + + +def diop_DN(D, N, t=symbols("t", integer=True)): + """ + Solves the equation `x^2 - Dy^2 = N`. + + Explanation + =========== + + Mainly concerned with the case `D > 0, D` is not a perfect square, + which is the same as the generalized Pell equation. The LMM + algorithm [1]_ is used to solve this equation. + + Returns one solution tuple, (`x, y)` for each class of the solutions. + Other solutions of the class can be constructed according to the + values of ``D`` and ``N``. + + Usage + ===== + + ``diop_DN(D, N, t)``: D and N are integers as in `x^2 - Dy^2 = N` and + ``t`` is the parameter to be used in the solutions. + + Details + ======= + + ``D`` and ``N`` correspond to D and N in the equation. + ``t`` is the parameter to be used in the solutions. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import diop_DN + >>> diop_DN(13, -4) # Solves equation x**2 - 13*y**2 = -4 + [(3, 1), (393, 109), (36, 10)] + + The output can be interpreted as follows: There are three fundamental + solutions to the equation `x^2 - 13y^2 = -4` given by (3, 1), (393, 109) + and (36, 10). Each tuple is in the form (x, y), i.e. solution (3, 1) means + that `x = 3` and `y = 1`. + + >>> diop_DN(986, 1) # Solves equation x**2 - 986*y**2 = 1 + [(49299, 1570)] + + See Also + ======== + + find_DN(), diop_bf_DN() + + References + ========== + + .. [1] Solving the generalized Pell equation x**2 - D*y**2 = N, John P. + Robertson, July 31, 2004, Pages 16 - 17. [online], Available: + https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf + """ + if D < 0: + if N == 0: + return [(0, 0)] + if N < 0: + return [] + # N > 0: + sol = [] + for d in divisors(square_factor(N), generator=True): + for x, y in cornacchia(1, int(-D), int(N // d**2)): + sol.append((d*x, d*y)) + if D == -1: + sol.append((d*y, d*x)) + return sol + + if D == 0: + if N < 0: + return [] + if N == 0: + return [(0, t)] + sN, _exact = integer_nthroot(N, 2) + if _exact: + return [(sN, t)] + return [] + + # D > 0 + sD, _exact = integer_nthroot(D, 2) + if _exact: + if N == 0: + return [(sD*t, t)] + + sol = [] + for y in range(floor(sign(N)*(N - 1)/(2*sD)) + 1): + try: + sq, _exact = integer_nthroot(D*y**2 + N, 2) + except ValueError: + _exact = False + if _exact: + sol.append((sq, y)) + return sol + + if 1 < N**2 < D: + # It is much faster to call `_special_diop_DN`. + return _special_diop_DN(D, N) + + if N == 0: + return [(0, 0)] + + sol = [] + if abs(N) == 1: + pqa = PQa(0, 1, D) + *_, prev_B, prev_G = next(pqa) + for j, (*_, a, _, _B, _G) in enumerate(pqa): + if a == 2*sD: + break + prev_B, prev_G = _B, _G + if j % 2: + if N == 1: + sol.append((prev_G, prev_B)) + return sol + if N == -1: + return [(prev_G, prev_B)] + for _ in range(j): + *_, _B, _G = next(pqa) + return [(_G, _B)] + + for f in divisors(square_factor(N), generator=True): + m = N // f**2 + am = abs(m) + for sqm in sqrt_mod(D, am, all_roots=True): + z = symmetric_residue(sqm, am) + pqa = PQa(z, am, D) + *_, prev_B, prev_G = next(pqa) + for _ in range(length(z, am, D) - 1): + _, q, *_, _B, _G = next(pqa) + if abs(q) == 1: + if prev_G**2 - D*prev_B**2 == m: + sol.append((f*prev_G, f*prev_B)) + elif a := diop_DN(D, -1): + sol.append((f*(prev_G*a[0][0] + prev_B*D*a[0][1]), + f*(prev_G*a[0][1] + prev_B*a[0][0]))) + break + prev_B, prev_G = _B, _G + return sol + + +def _special_diop_DN(D, N): + """ + Solves the equation `x^2 - Dy^2 = N` for the special case where + `1 < N**2 < D` and `D` is not a perfect square. + It is better to call `diop_DN` rather than this function, as + the former checks the condition `1 < N**2 < D`, and calls the latter only + if appropriate. + + Usage + ===== + + WARNING: Internal method. Do not call directly! + + ``_special_diop_DN(D, N)``: D and N are integers as in `x^2 - Dy^2 = N`. + + Details + ======= + + ``D`` and ``N`` correspond to D and N in the equation. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import _special_diop_DN + >>> _special_diop_DN(13, -3) # Solves equation x**2 - 13*y**2 = -3 + [(7, 2), (137, 38)] + + The output can be interpreted as follows: There are two fundamental + solutions to the equation `x^2 - 13y^2 = -3` given by (7, 2) and + (137, 38). Each tuple is in the form (x, y), i.e. solution (7, 2) means + that `x = 7` and `y = 2`. + + >>> _special_diop_DN(2445, -20) # Solves equation x**2 - 2445*y**2 = -20 + [(445, 9), (17625560, 356454), (698095554475, 14118073569)] + + See Also + ======== + + diop_DN() + + References + ========== + + .. [1] Section 4.4.4 of the following book: + Quadratic Diophantine Equations, T. Andreescu and D. Andrica, + Springer, 2015. + """ + + # The following assertion was removed for efficiency, with the understanding + # that this method is not called directly. The parent method, `diop_DN` + # is responsible for performing the appropriate checks. + # + # assert (1 < N**2 < D) and (not integer_nthroot(D, 2)[1]) + + sqrt_D = isqrt(D) + F = {N // f**2: f for f in divisors(square_factor(abs(N)), generator=True)} + P = 0 + Q = 1 + G0, G1 = 0, 1 + B0, B1 = 1, 0 + + solutions = [] + while True: + for _ in range(2): + a = (P + sqrt_D) // Q + P = a*Q - P + Q = (D - P**2) // Q + G0, G1 = G1, a*G1 + G0 + B0, B1 = B1, a*B1 + B0 + if (s := G1**2 - D*B1**2) in F: + f = F[s] + solutions.append((f*G1, f*B1)) + if Q == 1: + break + return solutions + + +def cornacchia(a:int, b:int, m:int) -> set[tuple[int, int]]: + r""" + Solves `ax^2 + by^2 = m` where `\gcd(a, b) = 1 = gcd(a, m)` and `a, b > 0`. + + Explanation + =========== + + Uses the algorithm due to Cornacchia. The method only finds primitive + solutions, i.e. ones with `\gcd(x, y) = 1`. So this method cannot be used to + find the solutions of `x^2 + y^2 = 20` since the only solution to former is + `(x, y) = (4, 2)` and it is not primitive. When `a = b`, only the + solutions with `x \leq y` are found. For more details, see the References. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import cornacchia + >>> cornacchia(2, 3, 35) # equation 2x**2 + 3y**2 = 35 + {(2, 3), (4, 1)} + >>> cornacchia(1, 1, 25) # equation x**2 + y**2 = 25 + {(4, 3)} + + References + =========== + + .. [1] A. Nitaj, "L'algorithme de Cornacchia" + .. [2] Solving the diophantine equation ax**2 + by**2 = m by Cornacchia's + method, [online], Available: + http://www.numbertheory.org/php/cornacchia.html + + See Also + ======== + + sympy.utilities.iterables.signed_permutations + """ + # Assume gcd(a, b) = gcd(a, m) = 1 and a, b > 0 but no error checking + sols = set() + + if a + b > m: + # xy = 0 must hold if there exists a solution + if a == 1: + # y = 0 + s, _exact = iroot(m // a, 2) + if _exact: + sols.add((int(s), 0)) + if a == b: + # only keep one solution + return sols + if m % b == 0: + # x = 0 + s, _exact = iroot(m // b, 2) + if _exact: + sols.add((0, int(s))) + return sols + + # the original cornacchia + for t in sqrt_mod_iter(-b*invert(a, m), m): + if t < m // 2: + continue + u, r = m, t + while (m1 := m - a*r**2) <= 0: + u, r = r, u % r + m1, _r = divmod(m1, b) + if _r: + continue + s, _exact = iroot(m1, 2) + if _exact: + if a == b and r < s: + r, s = s, r + sols.add((int(r), int(s))) + return sols + + +def PQa(P_0, Q_0, D): + r""" + Returns useful information needed to solve the Pell equation. + + Explanation + =========== + + There are six sequences of integers defined related to the continued + fraction representation of `\\frac{P + \sqrt{D}}{Q}`, namely {`P_{i}`}, + {`Q_{i}`}, {`a_{i}`},{`A_{i}`}, {`B_{i}`}, {`G_{i}`}. ``PQa()`` Returns + these values as a 6-tuple in the same order as mentioned above. Refer [1]_ + for more detailed information. + + Usage + ===== + + ``PQa(P_0, Q_0, D)``: ``P_0``, ``Q_0`` and ``D`` are integers corresponding + to `P_{0}`, `Q_{0}` and `D` in the continued fraction + `\\frac{P_{0} + \sqrt{D}}{Q_{0}}`. + Also it's assumed that `P_{0}^2 == D mod(|Q_{0}|)` and `D` is square free. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import PQa + >>> pqa = PQa(13, 4, 5) # (13 + sqrt(5))/4 + >>> next(pqa) # (P_0, Q_0, a_0, A_0, B_0, G_0) + (13, 4, 3, 3, 1, -1) + >>> next(pqa) # (P_1, Q_1, a_1, A_1, B_1, G_1) + (-1, 1, 1, 4, 1, 3) + + References + ========== + + .. [1] Solving the generalized Pell equation x^2 - Dy^2 = N, John P. + Robertson, July 31, 2004, Pages 4 - 8. https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf + """ + sqD = isqrt(D) + A2 = B1 = 0 + A1 = B2 = 1 + G1 = Q_0 + G2 = -P_0 + P_i = P_0 + Q_i = Q_0 + + while True: + a_i = (P_i + sqD) // Q_i + A1, A2 = a_i*A1 + A2, A1 + B1, B2 = a_i*B1 + B2, B1 + G1, G2 = a_i*G1 + G2, G1 + yield P_i, Q_i, a_i, A1, B1, G1 + + P_i = a_i*Q_i - P_i + Q_i = (D - P_i**2) // Q_i + + +def diop_bf_DN(D, N, t=symbols("t", integer=True)): + r""" + Uses brute force to solve the equation, `x^2 - Dy^2 = N`. + + Explanation + =========== + + Mainly concerned with the generalized Pell equation which is the case when + `D > 0, D` is not a perfect square. For more information on the case refer + [1]_. Let `(t, u)` be the minimal positive solution of the equation + `x^2 - Dy^2 = 1`. Then this method requires + `\sqrt{\\frac{\mid N \mid (t \pm 1)}{2D}}` to be small. + + Usage + ===== + + ``diop_bf_DN(D, N, t)``: ``D`` and ``N`` are coefficients in + `x^2 - Dy^2 = N` and ``t`` is the parameter to be used in the solutions. + + Details + ======= + + ``D`` and ``N`` correspond to D and N in the equation. + ``t`` is the parameter to be used in the solutions. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import diop_bf_DN + >>> diop_bf_DN(13, -4) + [(3, 1), (-3, 1), (36, 10)] + >>> diop_bf_DN(986, 1) + [(49299, 1570)] + + See Also + ======== + + diop_DN() + + References + ========== + + .. [1] Solving the generalized Pell equation x**2 - D*y**2 = N, John P. + Robertson, July 31, 2004, Page 15. https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf + """ + D = as_int(D) + N = as_int(N) + + sol = [] + a = diop_DN(D, 1) + u = a[0][0] + + if N == 0: + if D < 0: + return [(0, 0)] + if D == 0: + return [(0, t)] + sD, _exact = integer_nthroot(D, 2) + if _exact: + return [(sD*t, t), (-sD*t, t)] + return [(0, 0)] + + if abs(N) == 1: + return diop_DN(D, N) + + if N > 1: + L1 = 0 + L2 = integer_nthroot(int(N*(u - 1)/(2*D)), 2)[0] + 1 + else: # N < -1 + L1, _exact = integer_nthroot(-int(N/D), 2) + if not _exact: + L1 += 1 + L2 = integer_nthroot(-int(N*(u + 1)/(2*D)), 2)[0] + 1 + + for y in range(L1, L2): + try: + x, _exact = integer_nthroot(N + D*y**2, 2) + except ValueError: + _exact = False + if _exact: + sol.append((x, y)) + if not equivalent(x, y, -x, y, D, N): + sol.append((-x, y)) + + return sol + + +def equivalent(u, v, r, s, D, N): + """ + Returns True if two solutions `(u, v)` and `(r, s)` of `x^2 - Dy^2 = N` + belongs to the same equivalence class and False otherwise. + + Explanation + =========== + + Two solutions `(u, v)` and `(r, s)` to the above equation fall to the same + equivalence class iff both `(ur - Dvs)` and `(us - vr)` are divisible by + `N`. See reference [1]_. No test is performed to test whether `(u, v)` and + `(r, s)` are actually solutions to the equation. User should take care of + this. + + Usage + ===== + + ``equivalent(u, v, r, s, D, N)``: `(u, v)` and `(r, s)` are two solutions + of the equation `x^2 - Dy^2 = N` and all parameters involved are integers. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import equivalent + >>> equivalent(18, 5, -18, -5, 13, -1) + True + >>> equivalent(3, 1, -18, 393, 109, -4) + False + + References + ========== + + .. [1] Solving the generalized Pell equation x**2 - D*y**2 = N, John P. + Robertson, July 31, 2004, Page 12. https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf + + """ + return divisible(u*r - D*v*s, N) and divisible(u*s - v*r, N) + + +def length(P, Q, D): + r""" + Returns the (length of aperiodic part + length of periodic part) of + continued fraction representation of `\\frac{P + \sqrt{D}}{Q}`. + + It is important to remember that this does NOT return the length of the + periodic part but the sum of the lengths of the two parts as mentioned + above. + + Usage + ===== + + ``length(P, Q, D)``: ``P``, ``Q`` and ``D`` are integers corresponding to + the continued fraction `\\frac{P + \sqrt{D}}{Q}`. + + Details + ======= + + ``P``, ``D`` and ``Q`` corresponds to P, D and Q in the continued fraction, + `\\frac{P + \sqrt{D}}{Q}`. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import length + >>> length(-2, 4, 5) # (-2 + sqrt(5))/4 + 3 + >>> length(-5, 4, 17) # (-5 + sqrt(17))/4 + 4 + + See Also + ======== + sympy.ntheory.continued_fraction.continued_fraction_periodic + """ + from sympy.ntheory.continued_fraction import continued_fraction_periodic + v = continued_fraction_periodic(P, Q, D) + if isinstance(v[-1], list): + rpt = len(v[-1]) + nonrpt = len(v) - 1 + else: + rpt = 0 + nonrpt = len(v) + return rpt + nonrpt + + +def transformation_to_DN(eq): + """ + This function transforms general quadratic, + `ax^2 + bxy + cy^2 + dx + ey + f = 0` + to more easy to deal with `X^2 - DY^2 = N` form. + + Explanation + =========== + + This is used to solve the general quadratic equation by transforming it to + the latter form. Refer to [1]_ for more detailed information on the + transformation. This function returns a tuple (A, B) where A is a 2 X 2 + matrix and B is a 2 X 1 matrix such that, + + Transpose([x y]) = A * Transpose([X Y]) + B + + Usage + ===== + + ``transformation_to_DN(eq)``: where ``eq`` is the quadratic to be + transformed. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.solvers.diophantine.diophantine import transformation_to_DN + >>> A, B = transformation_to_DN(x**2 - 3*x*y - y**2 - 2*y + 1) + >>> A + Matrix([ + [1/26, 3/26], + [ 0, 1/13]]) + >>> B + Matrix([ + [-6/13], + [-4/13]]) + + A, B returned are such that Transpose((x y)) = A * Transpose((X Y)) + B. + Substituting these values for `x` and `y` and a bit of simplifying work + will give an equation of the form `x^2 - Dy^2 = N`. + + >>> from sympy.abc import X, Y + >>> from sympy import Matrix, simplify + >>> u = (A*Matrix([X, Y]) + B)[0] # Transformation for x + >>> u + X/26 + 3*Y/26 - 6/13 + >>> v = (A*Matrix([X, Y]) + B)[1] # Transformation for y + >>> v + Y/13 - 4/13 + + Next we will substitute these formulas for `x` and `y` and do + ``simplify()``. + + >>> eq = simplify((x**2 - 3*x*y - y**2 - 2*y + 1).subs(zip((x, y), (u, v)))) + >>> eq + X**2/676 - Y**2/52 + 17/13 + + By multiplying the denominator appropriately, we can get a Pell equation + in the standard form. + + >>> eq * 676 + X**2 - 13*Y**2 + 884 + + If only the final equation is needed, ``find_DN()`` can be used. + + See Also + ======== + + find_DN() + + References + ========== + + .. [1] Solving the equation ax^2 + bxy + cy^2 + dx + ey + f = 0, + John P.Robertson, May 8, 2003, Page 7 - 11. + https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf + """ + + var, coeff, diop_type = classify_diop(eq, _dict=False) + if diop_type == BinaryQuadratic.name: + return _transformation_to_DN(var, coeff) + + +def _transformation_to_DN(var, coeff): + + x, y = var + + a = coeff[x**2] + b = coeff[x*y] + c = coeff[y**2] + d = coeff[x] + e = coeff[y] + f = coeff[1] + + a, b, c, d, e, f = [as_int(i) for i in _remove_gcd(a, b, c, d, e, f)] + + X, Y = symbols("X, Y", integer=True) + + if b: + B, C = _rational_pq(2*a, b) + A, T = _rational_pq(a, B**2) + + # eq_1 = A*B*X**2 + B*(c*T - A*C**2)*Y**2 + d*T*X + (B*e*T - d*T*C)*Y + f*T*B + coeff = {X**2: A*B, X*Y: 0, Y**2: B*(c*T - A*C**2), X: d*T, Y: B*e*T - d*T*C, 1: f*T*B} + A_0, B_0 = _transformation_to_DN([X, Y], coeff) + return Matrix(2, 2, [S.One/B, -S(C)/B, 0, 1])*A_0, Matrix(2, 2, [S.One/B, -S(C)/B, 0, 1])*B_0 + + if d: + B, C = _rational_pq(2*a, d) + A, T = _rational_pq(a, B**2) + + # eq_2 = A*X**2 + c*T*Y**2 + e*T*Y + f*T - A*C**2 + coeff = {X**2: A, X*Y: 0, Y**2: c*T, X: 0, Y: e*T, 1: f*T - A*C**2} + A_0, B_0 = _transformation_to_DN([X, Y], coeff) + return Matrix(2, 2, [S.One/B, 0, 0, 1])*A_0, Matrix(2, 2, [S.One/B, 0, 0, 1])*B_0 + Matrix([-S(C)/B, 0]) + + if e: + B, C = _rational_pq(2*c, e) + A, T = _rational_pq(c, B**2) + + # eq_3 = a*T*X**2 + A*Y**2 + f*T - A*C**2 + coeff = {X**2: a*T, X*Y: 0, Y**2: A, X: 0, Y: 0, 1: f*T - A*C**2} + A_0, B_0 = _transformation_to_DN([X, Y], coeff) + return Matrix(2, 2, [1, 0, 0, S.One/B])*A_0, Matrix(2, 2, [1, 0, 0, S.One/B])*B_0 + Matrix([0, -S(C)/B]) + + # TODO: pre-simplification: Not necessary but may simplify + # the equation. + return Matrix(2, 2, [S.One/a, 0, 0, 1]), Matrix([0, 0]) + + +def find_DN(eq): + """ + This function returns a tuple, `(D, N)` of the simplified form, + `x^2 - Dy^2 = N`, corresponding to the general quadratic, + `ax^2 + bxy + cy^2 + dx + ey + f = 0`. + + Solving the general quadratic is then equivalent to solving the equation + `X^2 - DY^2 = N` and transforming the solutions by using the transformation + matrices returned by ``transformation_to_DN()``. + + Usage + ===== + + ``find_DN(eq)``: where ``eq`` is the quadratic to be transformed. + + Examples + ======== + + >>> from sympy.abc import x, y + >>> from sympy.solvers.diophantine.diophantine import find_DN + >>> find_DN(x**2 - 3*x*y - y**2 - 2*y + 1) + (13, -884) + + Interpretation of the output is that we get `X^2 -13Y^2 = -884` after + transforming `x^2 - 3xy - y^2 - 2y + 1` using the transformation returned + by ``transformation_to_DN()``. + + See Also + ======== + + transformation_to_DN() + + References + ========== + + .. [1] Solving the equation ax^2 + bxy + cy^2 + dx + ey + f = 0, + John P.Robertson, May 8, 2003, Page 7 - 11. + https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf + """ + var, coeff, diop_type = classify_diop(eq, _dict=False) + if diop_type == BinaryQuadratic.name: + return _find_DN(var, coeff) + + +def _find_DN(var, coeff): + + x, y = var + X, Y = symbols("X, Y", integer=True) + A, B = _transformation_to_DN(var, coeff) + + u = (A*Matrix([X, Y]) + B)[0] + v = (A*Matrix([X, Y]) + B)[1] + eq = x**2*coeff[x**2] + x*y*coeff[x*y] + y**2*coeff[y**2] + x*coeff[x] + y*coeff[y] + coeff[1] + + simplified = _mexpand(eq.subs(zip((x, y), (u, v)))) + + coeff = simplified.as_coefficients_dict() + + return -coeff[Y**2]/coeff[X**2], -coeff[1]/coeff[X**2] + + +def check_param(x, y, a, params): + """ + If there is a number modulo ``a`` such that ``x`` and ``y`` are both + integers, then return a parametric representation for ``x`` and ``y`` + else return (None, None). + + Here ``x`` and ``y`` are functions of ``t``. + """ + from sympy.simplify.simplify import clear_coefficients + + if x.is_number and not x.is_Integer: + return DiophantineSolutionSet([x, y], parameters=params) + + if y.is_number and not y.is_Integer: + return DiophantineSolutionSet([x, y], parameters=params) + + m, n = symbols("m, n", integer=True) + c, p = (m*x + n*y).as_content_primitive() + if a % c.q: + return DiophantineSolutionSet([x, y], parameters=params) + + # clear_coefficients(mx + b, R)[1] -> (R - b)/m + eq = clear_coefficients(x, m)[1] - clear_coefficients(y, n)[1] + junk, eq = eq.as_content_primitive() + + return _diop_solve(eq, params=params) + + +def diop_ternary_quadratic(eq, parameterize=False): + """ + Solves the general quadratic ternary form, + `ax^2 + by^2 + cz^2 + fxy + gyz + hxz = 0`. + + Returns a tuple `(x, y, z)` which is a base solution for the above + equation. If there are no solutions, `(None, None, None)` is returned. + + Usage + ===== + + ``diop_ternary_quadratic(eq)``: Return a tuple containing a basic solution + to ``eq``. + + Details + ======= + + ``eq`` should be an homogeneous expression of degree two in three variables + and it is assumed to be zero. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.solvers.diophantine.diophantine import diop_ternary_quadratic + >>> diop_ternary_quadratic(x**2 + 3*y**2 - z**2) + (1, 0, 1) + >>> diop_ternary_quadratic(4*x**2 + 5*y**2 - z**2) + (1, 0, 2) + >>> diop_ternary_quadratic(45*x**2 - 7*y**2 - 8*x*y - z**2) + (28, 45, 105) + >>> diop_ternary_quadratic(x**2 - 49*y**2 - z**2 + 13*z*y -8*x*y) + (9, 1, 5) + """ + var, coeff, diop_type = classify_diop(eq, _dict=False) + + if diop_type in ( + HomogeneousTernaryQuadratic.name, + HomogeneousTernaryQuadraticNormal.name): + sol = _diop_ternary_quadratic(var, coeff) + if len(sol) > 0: + x_0, y_0, z_0 = list(sol)[0] + else: + x_0, y_0, z_0 = None, None, None + + if parameterize: + return _parametrize_ternary_quadratic( + (x_0, y_0, z_0), var, coeff) + return x_0, y_0, z_0 + + +def _diop_ternary_quadratic(_var, coeff): + eq = sum(i*coeff[i] for i in coeff) + if HomogeneousTernaryQuadratic(eq).matches(): + return HomogeneousTernaryQuadratic(eq, free_symbols=_var).solve() + elif HomogeneousTernaryQuadraticNormal(eq).matches(): + return HomogeneousTernaryQuadraticNormal(eq, free_symbols=_var).solve() + + +def transformation_to_normal(eq): + """ + Returns the transformation Matrix that converts a general ternary + quadratic equation ``eq`` (`ax^2 + by^2 + cz^2 + dxy + eyz + fxz`) + to a form without cross terms: `ax^2 + by^2 + cz^2 = 0`. This is + not used in solving ternary quadratics; it is only implemented for + the sake of completeness. + """ + var, coeff, diop_type = classify_diop(eq, _dict=False) + + if diop_type in ( + "homogeneous_ternary_quadratic", + "homogeneous_ternary_quadratic_normal"): + return _transformation_to_normal(var, coeff) + + +def _transformation_to_normal(var, coeff): + + _var = list(var) # copy + x, y, z = var + + if not any(coeff[i**2] for i in var): + # https://math.stackexchange.com/questions/448051/transform-quadratic-ternary-form-to-normal-form/448065#448065 + a = coeff[x*y] + b = coeff[y*z] + c = coeff[x*z] + swap = False + if not a: # b can't be 0 or else there aren't 3 vars + swap = True + a, b = b, a + T = Matrix(((1, 1, -b/a), (1, -1, -c/a), (0, 0, 1))) + if swap: + T.row_swap(0, 1) + T.col_swap(0, 1) + return T + + if coeff[x**2] == 0: + # If the coefficient of x is zero change the variables + if coeff[y**2] == 0: + _var[0], _var[2] = var[2], var[0] + T = _transformation_to_normal(_var, coeff) + T.row_swap(0, 2) + T.col_swap(0, 2) + return T + + _var[0], _var[1] = var[1], var[0] + T = _transformation_to_normal(_var, coeff) + T.row_swap(0, 1) + T.col_swap(0, 1) + return T + + # Apply the transformation x --> X - (B*Y + C*Z)/(2*A) + if coeff[x*y] != 0 or coeff[x*z] != 0: + A = coeff[x**2] + B = coeff[x*y] + C = coeff[x*z] + D = coeff[y**2] + E = coeff[y*z] + F = coeff[z**2] + + _coeff = {} + + _coeff[x**2] = 4*A**2 + _coeff[y**2] = 4*A*D - B**2 + _coeff[z**2] = 4*A*F - C**2 + _coeff[y*z] = 4*A*E - 2*B*C + _coeff[x*y] = 0 + _coeff[x*z] = 0 + + T_0 = _transformation_to_normal(_var, _coeff) + return Matrix(3, 3, [1, S(-B)/(2*A), S(-C)/(2*A), 0, 1, 0, 0, 0, 1])*T_0 + + elif coeff[y*z] != 0: + if coeff[y**2] == 0: + if coeff[z**2] == 0: + # Equations of the form A*x**2 + E*yz = 0. + # Apply transformation y -> Y + Z ans z -> Y - Z + return Matrix(3, 3, [1, 0, 0, 0, 1, 1, 0, 1, -1]) + + # Ax**2 + E*y*z + F*z**2 = 0 + _var[0], _var[2] = var[2], var[0] + T = _transformation_to_normal(_var, coeff) + T.row_swap(0, 2) + T.col_swap(0, 2) + return T + + # A*x**2 + D*y**2 + E*y*z + F*z**2 = 0, F may be zero + _var[0], _var[1] = var[1], var[0] + T = _transformation_to_normal(_var, coeff) + T.row_swap(0, 1) + T.col_swap(0, 1) + return T + + return Matrix.eye(3) + + +def parametrize_ternary_quadratic(eq): + """ + Returns the parametrized general solution for the ternary quadratic + equation ``eq`` which has the form + `ax^2 + by^2 + cz^2 + fxy + gyz + hxz = 0`. + + Examples + ======== + + >>> from sympy import Tuple, ordered + >>> from sympy.abc import x, y, z + >>> from sympy.solvers.diophantine.diophantine import parametrize_ternary_quadratic + + The parametrized solution may be returned with three parameters: + + >>> parametrize_ternary_quadratic(2*x**2 + y**2 - 2*z**2) + (p**2 - 2*q**2, -2*p**2 + 4*p*q - 4*p*r - 4*q**2, p**2 - 4*p*q + 2*q**2 - 4*q*r) + + There might also be only two parameters: + + >>> parametrize_ternary_quadratic(4*x**2 + 2*y**2 - 3*z**2) + (2*p**2 - 3*q**2, -4*p**2 + 12*p*q - 6*q**2, 4*p**2 - 8*p*q + 6*q**2) + + Notes + ===== + + Consider ``p`` and ``q`` in the previous 2-parameter + solution and observe that more than one solution can be represented + by a given pair of parameters. If `p` and ``q`` are not coprime, this is + trivially true since the common factor will also be a common factor of the + solution values. But it may also be true even when ``p`` and + ``q`` are coprime: + + >>> sol = Tuple(*_) + >>> p, q = ordered(sol.free_symbols) + >>> sol.subs([(p, 3), (q, 2)]) + (6, 12, 12) + >>> sol.subs([(q, 1), (p, 1)]) + (-1, 2, 2) + >>> sol.subs([(q, 0), (p, 1)]) + (2, -4, 4) + >>> sol.subs([(q, 1), (p, 0)]) + (-3, -6, 6) + + Except for sign and a common factor, these are equivalent to + the solution of (1, 2, 2). + + References + ========== + + .. [1] The algorithmic resolution of Diophantine equations, Nigel P. Smart, + London Mathematical Society Student Texts 41, Cambridge University + Press, Cambridge, 1998. + + """ + var, coeff, diop_type = classify_diop(eq, _dict=False) + + if diop_type in ( + "homogeneous_ternary_quadratic", + "homogeneous_ternary_quadratic_normal"): + x_0, y_0, z_0 = list(_diop_ternary_quadratic(var, coeff))[0] + return _parametrize_ternary_quadratic( + (x_0, y_0, z_0), var, coeff) + + +def _parametrize_ternary_quadratic(solution, _var, coeff): + # called for a*x**2 + b*y**2 + c*z**2 + d*x*y + e*y*z + f*x*z = 0 + assert 1 not in coeff + + x_0, y_0, z_0 = solution + + v = list(_var) # copy + + if x_0 is None: + return (None, None, None) + + if solution.count(0) >= 2: + # if there are 2 zeros the equation reduces + # to k*X**2 == 0 where X is x, y, or z so X must + # be zero, too. So there is only the trivial + # solution. + return (None, None, None) + + if x_0 == 0: + v[0], v[1] = v[1], v[0] + y_p, x_p, z_p = _parametrize_ternary_quadratic( + (y_0, x_0, z_0), v, coeff) + return x_p, y_p, z_p + + x, y, z = v + r, p, q = symbols("r, p, q", integer=True) + + eq = sum(k*v for k, v in coeff.items()) + eq_1 = _mexpand(eq.subs(zip( + (x, y, z), (r*x_0, r*y_0 + p, r*z_0 + q)))) + A, B = eq_1.as_independent(r, as_Add=True) + + + x = A*x_0 + y = (A*y_0 - _mexpand(B/r*p)) + z = (A*z_0 - _mexpand(B/r*q)) + + return _remove_gcd(x, y, z) + + +def diop_ternary_quadratic_normal(eq, parameterize=False): + """ + Solves the quadratic ternary diophantine equation, + `ax^2 + by^2 + cz^2 = 0`. + + Explanation + =========== + + Here the coefficients `a`, `b`, and `c` should be non zero. Otherwise the + equation will be a quadratic binary or univariate equation. If solvable, + returns a tuple `(x, y, z)` that satisfies the given equation. If the + equation does not have integer solutions, `(None, None, None)` is returned. + + Usage + ===== + + ``diop_ternary_quadratic_normal(eq)``: where ``eq`` is an equation of the form + `ax^2 + by^2 + cz^2 = 0`. + + Examples + ======== + + >>> from sympy.abc import x, y, z + >>> from sympy.solvers.diophantine.diophantine import diop_ternary_quadratic_normal + >>> diop_ternary_quadratic_normal(x**2 + 3*y**2 - z**2) + (1, 0, 1) + >>> diop_ternary_quadratic_normal(4*x**2 + 5*y**2 - z**2) + (1, 0, 2) + >>> diop_ternary_quadratic_normal(34*x**2 - 3*y**2 - 301*z**2) + (4, 9, 1) + """ + var, coeff, diop_type = classify_diop(eq, _dict=False) + if diop_type == HomogeneousTernaryQuadraticNormal.name: + sol = _diop_ternary_quadratic_normal(var, coeff) + if len(sol) > 0: + x_0, y_0, z_0 = list(sol)[0] + else: + x_0, y_0, z_0 = None, None, None + if parameterize: + return _parametrize_ternary_quadratic( + (x_0, y_0, z_0), var, coeff) + return x_0, y_0, z_0 + + +def _diop_ternary_quadratic_normal(var, coeff): + eq = sum(i * coeff[i] for i in coeff) + return HomogeneousTernaryQuadraticNormal(eq, free_symbols=var).solve() + + +def sqf_normal(a, b, c, steps=False): + """ + Return `a', b', c'`, the coefficients of the square-free normal + form of `ax^2 + by^2 + cz^2 = 0`, where `a', b', c'` are pairwise + prime. If `steps` is True then also return three tuples: + `sq`, `sqf`, and `(a', b', c')` where `sq` contains the square + factors of `a`, `b` and `c` after removing the `gcd(a, b, c)`; + `sqf` contains the values of `a`, `b` and `c` after removing + both the `gcd(a, b, c)` and the square factors. + + The solutions for `ax^2 + by^2 + cz^2 = 0` can be + recovered from the solutions of `a'x^2 + b'y^2 + c'z^2 = 0`. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import sqf_normal + >>> sqf_normal(2 * 3**2 * 5, 2 * 5 * 11, 2 * 7**2 * 11) + (11, 1, 5) + >>> sqf_normal(2 * 3**2 * 5, 2 * 5 * 11, 2 * 7**2 * 11, True) + ((3, 1, 7), (5, 55, 11), (11, 1, 5)) + + References + ========== + + .. [1] Legendre's Theorem, Legrange's Descent, + https://public.csusm.edu/aitken_html/notes/legendre.pdf + + + See Also + ======== + + reconstruct() + """ + ABC = _remove_gcd(a, b, c) + sq = tuple(square_factor(i) for i in ABC) + sqf = A, B, C = tuple([i//j**2 for i,j in zip(ABC, sq)]) + pc = igcd(A, B) + A /= pc + B /= pc + pa = igcd(B, C) + B /= pa + C /= pa + pb = igcd(A, C) + A /= pb + B /= pb + + A *= pa + B *= pb + C *= pc + + if steps: + return (sq, sqf, (A, B, C)) + else: + return A, B, C + + +def square_factor(a): + r""" + Returns an integer `c` s.t. `a = c^2k, \ c,k \in Z`. Here `k` is square + free. `a` can be given as an integer or a dictionary of factors. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import square_factor + >>> square_factor(24) + 2 + >>> square_factor(-36*3) + 6 + >>> square_factor(1) + 1 + >>> square_factor({3: 2, 2: 1, -1: 1}) # -18 + 3 + + See Also + ======== + sympy.ntheory.factor_.core + """ + f = a if isinstance(a, dict) else factorint(a) + return Mul(*[p**(e//2) for p, e in f.items()]) + + +def reconstruct(A, B, z): + """ + Reconstruct the `z` value of an equivalent solution of `ax^2 + by^2 + cz^2` + from the `z` value of a solution of the square-free normal form of the + equation, `a'*x^2 + b'*y^2 + c'*z^2`, where `a'`, `b'` and `c'` are square + free and `gcd(a', b', c') == 1`. + """ + f = factorint(igcd(A, B)) + for p, e in f.items(): + if e != 1: + raise ValueError('a and b should be square-free') + z *= p + return z + + +def ldescent(A, B): + """ + Return a non-trivial solution to `w^2 = Ax^2 + By^2` using + Lagrange's method; return None if there is no such solution. + + Parameters + ========== + + A : Integer + B : Integer + non-zero integer + + Returns + ======= + + (int, int, int) | None : a tuple `(w_0, x_0, y_0)` which is a solution to the above equation. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import ldescent + >>> ldescent(1, 1) # w^2 = x^2 + y^2 + (1, 1, 0) + >>> ldescent(4, -7) # w^2 = 4x^2 - 7y^2 + (2, -1, 0) + + This means that `x = -1, y = 0` and `w = 2` is a solution to the equation + `w^2 = 4x^2 - 7y^2` + + >>> ldescent(5, -1) # w^2 = 5x^2 - y^2 + (2, 1, -1) + + References + ========== + + .. [1] The algorithmic resolution of Diophantine equations, Nigel P. Smart, + London Mathematical Society Student Texts 41, Cambridge University + Press, Cambridge, 1998. + .. [2] Cremona, J. E., Rusin, D. (2003). Efficient Solution of Rational Conics. + Mathematics of Computation, 72(243), 1417-1441. + https://doi.org/10.1090/S0025-5718-02-01480-1 + """ + if A == 0 or B == 0: + raise ValueError("A and B must be non-zero integers") + if abs(A) > abs(B): + w, y, x = ldescent(B, A) + return w, x, y + if A == 1: + return (1, 1, 0) + if B == 1: + return (1, 0, 1) + if B == -1: # and A == -1 + return + + r = sqrt_mod(A, B) + if r is None: + return + Q = (r**2 - A) // B + if Q == 0: + return r, -1, 0 + for i in divisors(Q): + d, _exact = integer_nthroot(abs(Q) // i, 2) + if _exact: + B_0 = sign(Q)*i + W, X, Y = ldescent(A, B_0) + return _remove_gcd(-A*X + r*W, r*X - W, Y*B_0*d) + + +def descent(A, B): + """ + Returns a non-trivial solution, (x, y, z), to `x^2 = Ay^2 + Bz^2` + using Lagrange's descent method with lattice-reduction. `A` and `B` + are assumed to be valid for such a solution to exist. + + This is faster than the normal Lagrange's descent algorithm because + the Gaussian reduction is used. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import descent + >>> descent(3, 1) # x**2 = 3*y**2 + z**2 + (1, 0, 1) + + `(x, y, z) = (1, 0, 1)` is a solution to the above equation. + + >>> descent(41, -113) + (-16, -3, 1) + + References + ========== + + .. [1] Cremona, J. E., Rusin, D. (2003). Efficient Solution of Rational Conics. + Mathematics of Computation, 72(243), 1417-1441. + https://doi.org/10.1090/S0025-5718-02-01480-1 + """ + if abs(A) > abs(B): + x, y, z = descent(B, A) + return x, z, y + + if B == 1: + return (1, 0, 1) + if A == 1: + return (1, 1, 0) + if B == -A: + return (0, 1, 1) + if B == A: + x, z, y = descent(-1, A) + return (A*y, z, x) + + w = sqrt_mod(A, B) + x_0, z_0 = gaussian_reduce(w, A, B) + + t = (x_0**2 - A*z_0**2) // B + t_2 = square_factor(t) + t_1 = t // t_2**2 + + x_1, z_1, y_1 = descent(A, t_1) + + return _remove_gcd(x_0*x_1 + A*z_0*z_1, z_0*x_1 + x_0*z_1, t_1*t_2*y_1) + + +def gaussian_reduce(w:int, a:int, b:int) -> tuple[int, int]: + r""" + Returns a reduced solution `(x, z)` to the congruence + `X^2 - aZ^2 \equiv 0 \pmod{b}` so that `x^2 + |a|z^2` is as small as possible. + Here ``w`` is a solution of the congruence `x^2 \equiv a \pmod{b}`. + + This function is intended to be used only for ``descent()``. + + Explanation + =========== + + The Gaussian reduction can find the shortest vector for any norm. + So we define the special norm for the vectors `u = (u_1, u_2)` and `v = (v_1, v_2)` as follows. + + .. math :: + u \cdot v := (wu_1 + bu_2)(wv_1 + bv_2) + |a|u_1v_1 + + Note that, given the mapping `f: (u_1, u_2) \to (wu_1 + bu_2, u_1)`, + `f((u_1,u_2))` is the solution to `X^2 - aZ^2 \equiv 0 \pmod{b}`. + In other words, finding the shortest vector in this norm will yield a solution with smaller `X^2 + |a|Z^2`. + The algorithm starts from basis vectors `(0, 1)` and `(1, 0)` + (corresponding to solutions `(b, 0)` and `(w, 1)`, respectively) and finds the shortest vector. + The shortest vector does not necessarily correspond to the smallest solution, + but since ``descent()`` only wants the smallest possible solution, it is sufficient. + + Parameters + ========== + + w : int + ``w`` s.t. `w^2 \equiv a \pmod{b}` + a : int + square-free nonzero integer + b : int + square-free nonzero integer + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import gaussian_reduce + >>> from sympy.ntheory.residue_ntheory import sqrt_mod + >>> a, b = 19, 101 + >>> gaussian_reduce(sqrt_mod(a, b), a, b) # 1**2 - 19*(-4)**2 = -303 + (1, -4) + >>> a, b = 11, 14 + >>> x, z = gaussian_reduce(sqrt_mod(a, b), a, b) + >>> (x**2 - a*z**2) % b == 0 + True + + It does not always return the smallest solution. + + >>> a, b = 6, 95 + >>> min_x, min_z = 1, 4 + >>> x, z = gaussian_reduce(sqrt_mod(a, b), a, b) + >>> (x**2 - a*z**2) % b == 0 and (min_x**2 - a*min_z**2) % b == 0 + True + >>> min_x**2 + abs(a)*min_z**2 < x**2 + abs(a)*z**2 + True + + References + ========== + + .. [1] Gaussian lattice Reduction [online]. Available: + https://web.archive.org/web/20201021115213/http://home.ie.cuhk.edu.hk/~wkshum/wordpress/?p=404 + .. [2] Cremona, J. E., Rusin, D. (2003). Efficient Solution of Rational Conics. + Mathematics of Computation, 72(243), 1417-1441. + https://doi.org/10.1090/S0025-5718-02-01480-1 + """ + a = abs(a) + def _dot(u, v): + return u[0]*v[0] + a*u[1]*v[1] + + u = (b, 0) + v = (w, 1) if b*w >= 0 else (-w, -1) + # i.e., _dot(u, v) >= 0 + + if b**2 < w**2 + a: + u, v = v, u + # i.e., norm(u) >= norm(v), where norm(u) := sqrt(_dot(u, u)) + + while _dot(u, u) > (dv := _dot(v, v)): + k = _dot(u, v) // dv + u, v = v, (u[0] - k*v[0], u[1] - k*v[1]) + c = (v[0] - u[0], v[1] - u[1]) + if _dot(c, c) <= _dot(u, u) <= 2*_dot(u, v): + return c + return u + + +def holzer(x, y, z, a, b, c): + r""" + Simplify the solution `(x, y, z)` of the equation + `ax^2 + by^2 = cz^2` with `a, b, c > 0` and `z^2 \geq \mid ab \mid` to + a new reduced solution `(x', y', z')` such that `z'^2 \leq \mid ab \mid`. + + The algorithm is an interpretation of Mordell's reduction as described + on page 8 of Cremona and Rusin's paper [1]_ and the work of Mordell in + reference [2]_. + + References + ========== + + .. [1] Cremona, J. E., Rusin, D. (2003). Efficient Solution of Rational Conics. + Mathematics of Computation, 72(243), 1417-1441. + https://doi.org/10.1090/S0025-5718-02-01480-1 + .. [2] Diophantine Equations, L. J. Mordell, page 48. + + """ + + if _odd(c): + k = 2*c + else: + k = c//2 + + small = a*b*c + step = 0 + while True: + t1, t2, t3 = a*x**2, b*y**2, c*z**2 + # check that it's a solution + if t1 + t2 != t3: + if step == 0: + raise ValueError('bad starting solution') + break + x_0, y_0, z_0 = x, y, z + if max(t1, t2, t3) <= small: + # Holzer condition + break + + uv = u, v = base_solution_linear(k, y_0, -x_0) + if None in uv: + break + + p, q = -(a*u*x_0 + b*v*y_0), c*z_0 + r = Rational(p, q) + if _even(c): + w = _nint_or_floor(p, q) + assert abs(w - r) <= S.Half + else: + w = p//q # floor + if _odd(a*u + b*v + c*w): + w += 1 + assert abs(w - r) <= S.One + + A = (a*u**2 + b*v**2 + c*w**2) + B = (a*u*x_0 + b*v*y_0 + c*w*z_0) + x = Rational(x_0*A - 2*u*B, k) + y = Rational(y_0*A - 2*v*B, k) + z = Rational(z_0*A - 2*w*B, k) + assert all(i.is_Integer for i in (x, y, z)) + step += 1 + + return tuple([int(i) for i in (x_0, y_0, z_0)]) + + +def diop_general_pythagorean(eq, param=symbols("m", integer=True)): + """ + Solves the general pythagorean equation, + `a_{1}^2x_{1}^2 + a_{2}^2x_{2}^2 + . . . + a_{n}^2x_{n}^2 - a_{n + 1}^2x_{n + 1}^2 = 0`. + + Returns a tuple which contains a parametrized solution to the equation, + sorted in the same order as the input variables. + + Usage + ===== + + ``diop_general_pythagorean(eq, param)``: where ``eq`` is a general + pythagorean equation which is assumed to be zero and ``param`` is the base + parameter used to construct other parameters by subscripting. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import diop_general_pythagorean + >>> from sympy.abc import a, b, c, d, e + >>> diop_general_pythagorean(a**2 + b**2 + c**2 - d**2) + (m1**2 + m2**2 - m3**2, 2*m1*m3, 2*m2*m3, m1**2 + m2**2 + m3**2) + >>> diop_general_pythagorean(9*a**2 - 4*b**2 + 16*c**2 + 25*d**2 + e**2) + (10*m1**2 + 10*m2**2 + 10*m3**2 - 10*m4**2, 15*m1**2 + 15*m2**2 + 15*m3**2 + 15*m4**2, 15*m1*m4, 12*m2*m4, 60*m3*m4) + """ + var, coeff, diop_type = classify_diop(eq, _dict=False) + + if diop_type == GeneralPythagorean.name: + if param is None: + params = None + else: + params = symbols('%s1:%i' % (param, len(var)), integer=True) + return list(GeneralPythagorean(eq).solve(parameters=params))[0] + + +def diop_general_sum_of_squares(eq, limit=1): + r""" + Solves the equation `x_{1}^2 + x_{2}^2 + . . . + x_{n}^2 - k = 0`. + + Returns at most ``limit`` number of solutions. + + Usage + ===== + + ``general_sum_of_squares(eq, limit)`` : Here ``eq`` is an expression which + is assumed to be zero. Also, ``eq`` should be in the form, + `x_{1}^2 + x_{2}^2 + . . . + x_{n}^2 - k = 0`. + + Details + ======= + + When `n = 3` if `k = 4^a(8m + 7)` for some `a, m \in Z` then there will be + no solutions. Refer to [1]_ for more details. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import diop_general_sum_of_squares + >>> from sympy.abc import a, b, c, d, e + >>> diop_general_sum_of_squares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345) + {(15, 22, 22, 24, 24)} + + Reference + ========= + + .. [1] Representing an integer as a sum of three squares, [online], + Available: + https://proofwiki.org/wiki/Integer_as_Sum_of_Three_Squares + """ + var, coeff, diop_type = classify_diop(eq, _dict=False) + + if diop_type == GeneralSumOfSquares.name: + return set(GeneralSumOfSquares(eq).solve(limit=limit)) + + +def diop_general_sum_of_even_powers(eq, limit=1): + """ + Solves the equation `x_{1}^e + x_{2}^e + . . . + x_{n}^e - k = 0` + where `e` is an even, integer power. + + Returns at most ``limit`` number of solutions. + + Usage + ===== + + ``general_sum_of_even_powers(eq, limit)`` : Here ``eq`` is an expression which + is assumed to be zero. Also, ``eq`` should be in the form, + `x_{1}^e + x_{2}^e + . . . + x_{n}^e - k = 0`. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import diop_general_sum_of_even_powers + >>> from sympy.abc import a, b + >>> diop_general_sum_of_even_powers(a**4 + b**4 - (2**4 + 3**4)) + {(2, 3)} + + See Also + ======== + + power_representation + """ + var, coeff, diop_type = classify_diop(eq, _dict=False) + + if diop_type == GeneralSumOfEvenPowers.name: + return set(GeneralSumOfEvenPowers(eq).solve(limit=limit)) + + +## Functions below this comment can be more suitably grouped under +## an Additive number theory module rather than the Diophantine +## equation module. + + +def partition(n, k=None, zeros=False): + """ + Returns a generator that can be used to generate partitions of an integer + `n`. + + Explanation + =========== + + A partition of `n` is a set of positive integers which add up to `n`. For + example, partitions of 3 are 3, 1 + 2, 1 + 1 + 1. A partition is returned + as a tuple. If ``k`` equals None, then all possible partitions are returned + irrespective of their size, otherwise only the partitions of size ``k`` are + returned. If the ``zero`` parameter is set to True then a suitable + number of zeros are added at the end of every partition of size less than + ``k``. + + ``zero`` parameter is considered only if ``k`` is not None. When the + partitions are over, the last `next()` call throws the ``StopIteration`` + exception, so this function should always be used inside a try - except + block. + + Details + ======= + + ``partition(n, k)``: Here ``n`` is a positive integer and ``k`` is the size + of the partition which is also positive integer. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import partition + >>> f = partition(5) + >>> next(f) + (1, 1, 1, 1, 1) + >>> next(f) + (1, 1, 1, 2) + >>> g = partition(5, 3) + >>> next(g) + (1, 1, 3) + >>> next(g) + (1, 2, 2) + >>> g = partition(5, 3, zeros=True) + >>> next(g) + (0, 0, 5) + + """ + if not zeros or k is None: + for i in ordered_partitions(n, k): + yield tuple(i) + else: + for m in range(1, k + 1): + for i in ordered_partitions(n, m): + i = tuple(i) + yield (0,)*(k - len(i)) + i + + +def prime_as_sum_of_two_squares(p): + """ + Represent a prime `p` as a unique sum of two squares; this can + only be done if the prime is congruent to 1 mod 4. + + Parameters + ========== + + p : Integer + A prime that is congruent to 1 mod 4 + + Returns + ======= + + (int, int) | None : Pair of positive integers ``(x, y)`` satisfying ``x**2 + y**2 = p``. + None if ``p`` is not congruent to 1 mod 4. + + Raises + ====== + + ValueError + If ``p`` is not prime number + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import prime_as_sum_of_two_squares + >>> prime_as_sum_of_two_squares(7) # can't be done + >>> prime_as_sum_of_two_squares(5) + (1, 2) + + Reference + ========= + + .. [1] Representing a number as a sum of four squares, [online], + Available: https://schorn.ch/lagrange.html + + See Also + ======== + + sum_of_squares + + """ + p = as_int(p) + if p % 4 != 1: + return + if not isprime(p): + raise ValueError("p should be a prime number") + + if p % 8 == 5: + # Legendre symbol (2/p) == -1 if p % 8 in [3, 5] + b = 2 + elif p % 12 == 5: + # Legendre symbol (3/p) == -1 if p % 12 in [5, 7] + b = 3 + elif p % 5 in [2, 3]: + # Legendre symbol (5/p) == -1 if p % 5 in [2, 3] + b = 5 + else: + b = 7 + while jacobi(b, p) == 1: + b = nextprime(b) + + b = pow(b, p >> 2, p) + a = p + while b**2 > p: + a, b = b, a % b + return (int(a % b), int(b)) # convert from long + + +def sum_of_three_squares(n): + r""" + Returns a 3-tuple $(a, b, c)$ such that $a^2 + b^2 + c^2 = n$ and + $a, b, c \geq 0$. + + Returns None if $n = 4^a(8m + 7)$ for some `a, m \in \mathbb{Z}`. See + [1]_ for more details. + + Parameters + ========== + + n : Integer + non-negative integer + + Returns + ======= + + (int, int, int) | None : 3-tuple non-negative integers ``(a, b, c)`` satisfying ``a**2 + b**2 + c**2 = n``. + a,b,c are sorted in ascending order. ``None`` if no such ``(a,b,c)``. + + Raises + ====== + + ValueError + If ``n`` is a negative integer + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import sum_of_three_squares + >>> sum_of_three_squares(44542) + (18, 37, 207) + + References + ========== + + .. [1] Representing a number as a sum of three squares, [online], + Available: https://schorn.ch/lagrange.html + + See Also + ======== + + power_representation : + ``sum_of_three_squares(n)`` is one of the solutions output by ``power_representation(n, 2, 3, zeros=True)`` + + """ + # https://math.stackexchange.com/questions/483101/rabin-and-shallit-algorithm/651425#651425 + # discusses these numbers (except for 1, 2, 3) as the exceptions of H&L's conjecture that + # Every sufficiently large number n is either a square or the sum of a prime and a square. + special = {1: (0, 0, 1), 2: (0, 1, 1), 3: (1, 1, 1), 10: (0, 1, 3), 34: (3, 3, 4), + 58: (0, 3, 7), 85: (0, 6, 7), 130: (0, 3, 11), 214: (3, 6, 13), 226: (8, 9, 9), + 370: (8, 9, 15), 526: (6, 7, 21), 706: (15, 15, 16), 730: (0, 1, 27), + 1414: (6, 17, 33), 1906: (13, 21, 36), 2986: (21, 32, 39), 9634: (56, 57, 57)} + n = as_int(n) + if n < 0: + raise ValueError("n should be a non-negative integer") + if n == 0: + return (0, 0, 0) + n, v = remove(n, 4) + v = 1 << v + if n % 8 == 7: + return + if n in special: + return tuple([v*i for i in special[n]]) + + s, _exact = integer_nthroot(n, 2) + if _exact: + return (0, 0, v*s) + if n % 8 == 3: + if not s % 2: + s -= 1 + for x in range(s, -1, -2): + N = (n - x**2) // 2 + if isprime(N): + # n % 8 == 3 and x % 2 == 1 => N % 4 == 1 + y, z = prime_as_sum_of_two_squares(N) + return tuple(sorted([v*x, v*(y + z), v*abs(y - z)])) + # We will never reach this point because there must be a solution. + assert False + + # assert n % 4 in [1, 2] + if not((n % 2) ^ (s % 2)): + s -= 1 + for x in range(s, -1, -2): + N = n - x**2 + if isprime(N): + # assert N % 4 == 1 + y, z = prime_as_sum_of_two_squares(N) + return tuple(sorted([v*x, v*y, v*z])) + # We will never reach this point because there must be a solution. + assert False + + +def sum_of_four_squares(n): + r""" + Returns a 4-tuple `(a, b, c, d)` such that `a^2 + b^2 + c^2 + d^2 = n`. + Here `a, b, c, d \geq 0`. + + Parameters + ========== + + n : Integer + non-negative integer + + Returns + ======= + + (int, int, int, int) : 4-tuple non-negative integers ``(a, b, c, d)`` satisfying ``a**2 + b**2 + c**2 + d**2 = n``. + a,b,c,d are sorted in ascending order. + + Raises + ====== + + ValueError + If ``n`` is a negative integer + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import sum_of_four_squares + >>> sum_of_four_squares(3456) + (8, 8, 32, 48) + >>> sum_of_four_squares(1294585930293) + (0, 1234, 2161, 1137796) + + References + ========== + + .. [1] Representing a number as a sum of four squares, [online], + Available: https://schorn.ch/lagrange.html + + See Also + ======== + + power_representation : + ``sum_of_four_squares(n)`` is one of the solutions output by ``power_representation(n, 2, 4, zeros=True)`` + + """ + n = as_int(n) + if n < 0: + raise ValueError("n should be a non-negative integer") + if n == 0: + return (0, 0, 0, 0) + # remove factors of 4 since a solution in terms of 3 squares is + # going to be returned; this is also done in sum_of_three_squares, + # but it needs to be done here to select d + n, v = remove(n, 4) + v = 1 << v + if n % 8 == 7: + d = 2 + n = n - 4 + elif n % 8 in (2, 6): + d = 1 + n = n - 1 + else: + d = 0 + x, y, z = sum_of_three_squares(n) # sorted + return tuple(sorted([v*d, v*x, v*y, v*z])) + + +def power_representation(n, p, k, zeros=False): + r""" + Returns a generator for finding k-tuples of integers, + `(n_{1}, n_{2}, . . . n_{k})`, such that + `n = n_{1}^p + n_{2}^p + . . . n_{k}^p`. + + Usage + ===== + + ``power_representation(n, p, k, zeros)``: Represent non-negative number + ``n`` as a sum of ``k`` ``p``\ th powers. If ``zeros`` is true, then the + solutions is allowed to contain zeros. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import power_representation + + Represent 1729 as a sum of two cubes: + + >>> f = power_representation(1729, 3, 2) + >>> next(f) + (9, 10) + >>> next(f) + (1, 12) + + If the flag `zeros` is True, the solution may contain tuples with + zeros; any such solutions will be generated after the solutions + without zeros: + + >>> list(power_representation(125, 2, 3, zeros=True)) + [(5, 6, 8), (3, 4, 10), (0, 5, 10), (0, 2, 11)] + + For even `p` the `permute_sign` function can be used to get all + signed values: + + >>> from sympy.utilities.iterables import permute_signs + >>> list(permute_signs((1, 12))) + [(1, 12), (-1, 12), (1, -12), (-1, -12)] + + All possible signed permutations can also be obtained: + + >>> from sympy.utilities.iterables import signed_permutations + >>> list(signed_permutations((1, 12))) + [(1, 12), (-1, 12), (1, -12), (-1, -12), (12, 1), (-12, 1), (12, -1), (-12, -1)] + """ + n, p, k = [as_int(i) for i in (n, p, k)] + + if n < 0: + if p % 2: + for t in power_representation(-n, p, k, zeros): + yield tuple(-i for i in t) + return + + if p < 1 or k < 1: + raise ValueError(filldedent(''' + Expecting positive integers for `(p, k)`, but got `(%s, %s)`''' + % (p, k))) + + if n == 0: + if zeros: + yield (0,)*k + return + + if k == 1: + if p == 1: + yield (n,) + elif n == 1: + yield (1,) + else: + be = perfect_power(n) + if be: + b, e = be + d, r = divmod(e, p) + if not r: + yield (b**d,) + return + + if p == 1: + yield from partition(n, k, zeros=zeros) + return + + if p == 2: + if k == 3: + n, v = remove(n, 4) + if v: + v = 1 << v + for t in power_representation(n, p, k, zeros): + yield tuple(i*v for i in t) + return + feasible = _can_do_sum_of_squares(n, k) + if not feasible: + return + if not zeros: + if n > 33 and k >= 5 and k <= n and n - k in ( + 13, 10, 7, 5, 4, 2, 1): + '''Todd G. Will, "When Is n^2 a Sum of k Squares?", [online]. + Available: https://www.maa.org/sites/default/files/Will-MMz-201037918.pdf''' + return + # quick tests since feasibility includes the possibility of 0 + if k == 4 and (n in (1, 3, 5, 9, 11, 17, 29, 41) or remove(n, 4)[0] in (2, 6, 14)): + # A000534 + return + if k == 3 and n in (1, 2, 5, 10, 13, 25, 37, 58, 85, 130): # or n = some number >= 5*10**10 + # A051952 + return + if feasible is not True: # it's prime and k == 2 + yield prime_as_sum_of_two_squares(n) + return + + if k == 2 and p > 2: + be = perfect_power(n) + if be and be[1] % p == 0: + return # Fermat: a**n + b**n = c**n has no solution for n > 2 + + if n >= k: + a = integer_nthroot(n - (k - 1), p)[0] + for t in pow_rep_recursive(a, k, n, [], p): + yield tuple(reversed(t)) + + if zeros: + a = integer_nthroot(n, p)[0] + for i in range(1, k): + for t in pow_rep_recursive(a, i, n, [], p): + yield tuple(reversed(t + (0,)*(k - i))) + + +sum_of_powers = power_representation + + +def pow_rep_recursive(n_i, k, n_remaining, terms, p): + # Invalid arguments + if n_i <= 0 or k <= 0: + return + + # No solutions may exist + if n_remaining < k: + return + if k * pow(n_i, p) < n_remaining: + return + + if k == 0 and n_remaining == 0: + yield tuple(terms) + + elif k == 1: + # next_term^p must equal to n_remaining + next_term, exact = integer_nthroot(n_remaining, p) + if exact and next_term <= n_i: + yield tuple(terms + [next_term]) + return + + else: + # TODO: Fall back to diop_DN when k = 2 + if n_i >= 1 and k > 0: + for next_term in range(1, n_i + 1): + residual = n_remaining - pow(next_term, p) + if residual < 0: + break + yield from pow_rep_recursive(next_term, k - 1, residual, terms + [next_term], p) + + +def sum_of_squares(n, k, zeros=False): + """Return a generator that yields the k-tuples of nonnegative + values, the squares of which sum to n. If zeros is False (default) + then the solution will not contain zeros. The nonnegative + elements of a tuple are sorted. + + * If k == 1 and n is square, (n,) is returned. + + * If k == 2 then n can only be written as a sum of squares if + every prime in the factorization of n that has the form + 4*k + 3 has an even multiplicity. If n is prime then + it can only be written as a sum of two squares if it is + in the form 4*k + 1. + + * if k == 3 then n can be written as a sum of squares if it does + not have the form 4**m*(8*k + 7). + + * all integers can be written as the sum of 4 squares. + + * if k > 4 then n can be partitioned and each partition can + be written as a sum of 4 squares; if n is not evenly divisible + by 4 then n can be written as a sum of squares only if the + an additional partition can be written as sum of squares. + For example, if k = 6 then n is partitioned into two parts, + the first being written as a sum of 4 squares and the second + being written as a sum of 2 squares -- which can only be + done if the condition above for k = 2 can be met, so this will + automatically reject certain partitions of n. + + Examples + ======== + + >>> from sympy.solvers.diophantine.diophantine import sum_of_squares + >>> list(sum_of_squares(25, 2)) + [(3, 4)] + >>> list(sum_of_squares(25, 2, True)) + [(3, 4), (0, 5)] + >>> list(sum_of_squares(25, 4)) + [(1, 2, 2, 4)] + + See Also + ======== + + sympy.utilities.iterables.signed_permutations + """ + yield from power_representation(n, 2, k, zeros) + + +def _can_do_sum_of_squares(n, k): + """Return True if n can be written as the sum of k squares, + False if it cannot, or 1 if ``k == 2`` and ``n`` is prime (in which + case it *can* be written as a sum of two squares). A False + is returned only if it cannot be written as ``k``-squares, even + if 0s are allowed. + """ + if k < 1: + return False + if n < 0: + return False + if n == 0: + return True + if k == 1: + return is_square(n) + if k == 2: + if n in (1, 2): + return True + if isprime(n): + if n % 4 == 1: + return 1 # signal that it was prime + return False + # n is a composite number + # we can proceed iff no prime factor in the form 4*k + 3 + # has an odd multiplicity + return all(p % 4 !=3 or m % 2 == 0 for p, m in factorint(n).items()) + if k == 3: + return remove(n, 4)[0] % 8 != 7 + # every number can be written as a sum of 4 squares; for k > 4 partitions + # can be 0 + return True diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7007d308babbc7e61f89161e1cd73f2e65d81d95 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/tests/__pycache__/test_diophantine.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/tests/__pycache__/test_diophantine.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..98f97b74c221fe77b016b28a454dd584977fdebe Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/tests/__pycache__/test_diophantine.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/tests/test_diophantine.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/tests/test_diophantine.py new file mode 100644 index 0000000000000000000000000000000000000000..b8b031a1e63fa445e3dbb0b425f84cfe88888667 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/diophantine/tests/test_diophantine.py @@ -0,0 +1,1071 @@ +from sympy.core.add import Add +from sympy.core.mul import Mul +from sympy.core.numbers import (Rational, oo, pi) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.matrices.dense import Matrix +from sympy.ntheory.factor_ import factorint +from sympy.simplify.powsimp import powsimp +from sympy.core.function import _mexpand +from sympy.core.sorting import default_sort_key, ordered +from sympy.functions.elementary.trigonometric import sin +from sympy.solvers.diophantine import diophantine +from sympy.solvers.diophantine.diophantine import (diop_DN, + diop_solve, diop_ternary_quadratic_normal, + diop_general_pythagorean, diop_ternary_quadratic, diop_linear, + diop_quadratic, diop_general_sum_of_squares, diop_general_sum_of_even_powers, + descent, diop_bf_DN, divisible, equivalent, find_DN, ldescent, length, + reconstruct, partition, power_representation, + prime_as_sum_of_two_squares, square_factor, sum_of_four_squares, + sum_of_three_squares, transformation_to_DN, transformation_to_normal, + classify_diop, base_solution_linear, cornacchia, sqf_normal, gaussian_reduce, holzer, + check_param, parametrize_ternary_quadratic, sum_of_powers, sum_of_squares, + _diop_ternary_quadratic_normal, _nint_or_floor, + _odd, _even, _remove_gcd, _can_do_sum_of_squares, DiophantineSolutionSet, GeneralPythagorean, + BinaryQuadratic) + +from sympy.testing.pytest import slow, raises, XFAIL +from sympy.utilities.iterables import ( + signed_permutations) + +a, b, c, d, p, q, x, y, z, w, t, u, v, X, Y, Z = symbols( + "a, b, c, d, p, q, x, y, z, w, t, u, v, X, Y, Z", integer=True) +t_0, t_1, t_2, t_3, t_4, t_5, t_6 = symbols("t_:7", integer=True) +m1, m2, m3 = symbols('m1:4', integer=True) +n1 = symbols('n1', integer=True) + + +def diop_simplify(eq): + return _mexpand(powsimp(_mexpand(eq))) + + +def test_input_format(): + raises(TypeError, lambda: diophantine(sin(x))) + raises(TypeError, lambda: diophantine(x/pi - 3)) + + +def test_nosols(): + # diophantine should sympify eq so that these are equivalent + assert diophantine(3) == set() + assert diophantine(S(3)) == set() + + +def test_univariate(): + assert diop_solve((x - 1)*(x - 2)**2) == {(1,), (2,)} + assert diop_solve((x - 1)*(x - 2)) == {(1,), (2,)} + + +def test_classify_diop(): + raises(TypeError, lambda: classify_diop(x**2/3 - 1)) + raises(ValueError, lambda: classify_diop(1)) + raises(NotImplementedError, lambda: classify_diop(w*x*y*z - 1)) + raises(NotImplementedError, lambda: classify_diop(x**3 + y**3 + z**4 - 90)) + assert classify_diop(14*x**2 + 15*x - 42) == ( + [x], {1: -42, x: 15, x**2: 14}, 'univariate') + assert classify_diop(x*y + z) == ( + [x, y, z], {x*y: 1, z: 1}, 'inhomogeneous_ternary_quadratic') + assert classify_diop(x*y + z + w + x**2) == ( + [w, x, y, z], {x*y: 1, w: 1, x**2: 1, z: 1}, 'inhomogeneous_general_quadratic') + assert classify_diop(x*y + x*z + x**2 + 1) == ( + [x, y, z], {x*y: 1, x*z: 1, x**2: 1, 1: 1}, 'inhomogeneous_general_quadratic') + assert classify_diop(x*y + z + w + 42) == ( + [w, x, y, z], {x*y: 1, w: 1, 1: 42, z: 1}, 'inhomogeneous_general_quadratic') + assert classify_diop(x*y + z*w) == ( + [w, x, y, z], {x*y: 1, w*z: 1}, 'homogeneous_general_quadratic') + assert classify_diop(x*y**2 + 1) == ( + [x, y], {x*y**2: 1, 1: 1}, 'cubic_thue') + assert classify_diop(x**4 + y**4 + z**4 - (1 + 16 + 81)) == ( + [x, y, z], {1: -98, x**4: 1, z**4: 1, y**4: 1}, 'general_sum_of_even_powers') + assert classify_diop(x**2 + y**2 + z**2) == ( + [x, y, z], {x**2: 1, y**2: 1, z**2: 1}, 'homogeneous_ternary_quadratic_normal') + + +def test_linear(): + assert diop_solve(x) == (0,) + assert diop_solve(1*x) == (0,) + assert diop_solve(3*x) == (0,) + assert diop_solve(x + 1) == (-1,) + assert diop_solve(2*x + 1) == (None,) + assert diop_solve(2*x + 4) == (-2,) + assert diop_solve(y + x) == (t_0, -t_0) + assert diop_solve(y + x + 0) == (t_0, -t_0) + assert diop_solve(y + x - 0) == (t_0, -t_0) + assert diop_solve(0*x - y - 5) == (-5,) + assert diop_solve(3*y + 2*x - 5) == (3*t_0 - 5, -2*t_0 + 5) + assert diop_solve(2*x - 3*y - 5) == (3*t_0 - 5, 2*t_0 - 5) + assert diop_solve(-2*x - 3*y - 5) == (3*t_0 + 5, -2*t_0 - 5) + assert diop_solve(7*x + 5*y) == (5*t_0, -7*t_0) + assert diop_solve(2*x + 4*y) == (-2*t_0, t_0) + assert diop_solve(4*x + 6*y - 4) == (3*t_0 - 2, -2*t_0 + 2) + assert diop_solve(4*x + 6*y - 3) == (None, None) + assert diop_solve(0*x + 3*y - 4*z + 5) == (4*t_0 + 5, 3*t_0 + 5) + assert diop_solve(4*x + 3*y - 4*z + 5) == (t_0, 8*t_0 + 4*t_1 + 5, 7*t_0 + 3*t_1 + 5) + assert diop_solve(4*x + 3*y - 4*z + 5, None) == (0, 5, 5) + assert diop_solve(4*x + 2*y + 8*z - 5) == (None, None, None) + assert diop_solve(5*x + 7*y - 2*z - 6) == (t_0, -3*t_0 + 2*t_1 + 6, -8*t_0 + 7*t_1 + 18) + assert diop_solve(3*x - 6*y + 12*z - 9) == (2*t_0 + 3, t_0 + 2*t_1, t_1) + assert diop_solve(6*w + 9*x + 20*y - z) == (t_0, t_1, t_1 + t_2, 6*t_0 + 29*t_1 + 20*t_2) + + # to ignore constant factors, use diophantine + raises(TypeError, lambda: diop_solve(x/2)) + + +def test_quadratic_simple_hyperbolic_case(): + # Simple Hyperbolic case: A = C = 0 and B != 0 + assert diop_solve(3*x*y + 34*x - 12*y + 1) == \ + {(-133, -11), (5, -57)} + assert diop_solve(6*x*y + 2*x + 3*y + 1) == set() + assert diop_solve(-13*x*y + 2*x - 4*y - 54) == {(27, 0)} + assert diop_solve(-27*x*y - 30*x - 12*y - 54) == {(-14, -1)} + assert diop_solve(2*x*y + 5*x + 56*y + 7) == {(-161, -3), (-47, -6), (-35, -12), + (-29, -69), (-27, 64), (-21, 7), + (-9, 1), (105, -2)} + assert diop_solve(6*x*y + 9*x + 2*y + 3) == set() + assert diop_solve(x*y + x + y + 1) == {(-1, t), (t, -1)} + assert diophantine(48*x*y) + + +def test_quadratic_elliptical_case(): + # Elliptical case: B**2 - 4AC < 0 + + assert diop_solve(42*x**2 + 8*x*y + 15*y**2 + 23*x + 17*y - 4915) == {(-11, -1)} + assert diop_solve(4*x**2 + 3*y**2 + 5*x - 11*y + 12) == set() + assert diop_solve(x**2 + y**2 + 2*x + 2*y + 2) == {(-1, -1)} + assert diop_solve(15*x**2 - 9*x*y + 14*y**2 - 23*x - 14*y - 4950) == {(-15, 6)} + assert diop_solve(10*x**2 + 12*x*y + 12*y**2 - 34) == \ + {(-1, -1), (-1, 2), (1, -2), (1, 1)} + + +def test_quadratic_parabolic_case(): + # Parabolic case: B**2 - 4AC = 0 + assert check_solutions(8*x**2 - 24*x*y + 18*y**2 + 5*x + 7*y + 16) + assert check_solutions(8*x**2 - 24*x*y + 18*y**2 + 6*x + 12*y - 6) + assert check_solutions(8*x**2 + 24*x*y + 18*y**2 + 4*x + 6*y - 7) + assert check_solutions(-4*x**2 + 4*x*y - y**2 + 2*x - 3) + assert check_solutions(x**2 + 2*x*y + y**2 + 2*x + 2*y + 1) + assert check_solutions(x**2 - 2*x*y + y**2 + 2*x + 2*y + 1) + assert check_solutions(y**2 - 41*x + 40) + + +def test_quadratic_perfect_square(): + # B**2 - 4*A*C > 0 + # B**2 - 4*A*C is a perfect square + assert check_solutions(48*x*y) + assert check_solutions(4*x**2 - 5*x*y + y**2 + 2) + assert check_solutions(-2*x**2 - 3*x*y + 2*y**2 -2*x - 17*y + 25) + assert check_solutions(12*x**2 + 13*x*y + 3*y**2 - 2*x + 3*y - 12) + assert check_solutions(8*x**2 + 10*x*y + 2*y**2 - 32*x - 13*y - 23) + assert check_solutions(4*x**2 - 4*x*y - 3*y- 8*x - 3) + assert check_solutions(- 4*x*y - 4*y**2 - 3*y- 5*x - 10) + assert check_solutions(x**2 - y**2 - 2*x - 2*y) + assert check_solutions(x**2 - 9*y**2 - 2*x - 6*y) + assert check_solutions(4*x**2 - 9*y**2 - 4*x - 12*y - 3) + + +def test_quadratic_non_perfect_square(): + # B**2 - 4*A*C is not a perfect square + # Used check_solutions() since the solutions are complex expressions involving + # square roots and exponents + assert check_solutions(x**2 - 2*x - 5*y**2) + assert check_solutions(3*x**2 - 2*y**2 - 2*x - 2*y) + assert check_solutions(x**2 - x*y - y**2 - 3*y) + assert check_solutions(x**2 - 9*y**2 - 2*x - 6*y) + assert BinaryQuadratic(x**2 + y**2 + 2*x + 2*y + 2).solve() == {(-1, -1)} + + +def test_issue_9106(): + eq = -48 - 2*x*(3*x - 1) + y*(3*y - 1) + v = (x, y) + for sol in diophantine(eq): + assert not diop_simplify(eq.xreplace(dict(zip(v, sol)))) + + +def test_issue_18138(): + eq = x**2 - x - y**2 + v = (x, y) + for sol in diophantine(eq): + assert not diop_simplify(eq.xreplace(dict(zip(v, sol)))) + + +@slow +def test_quadratic_non_perfect_slow(): + assert check_solutions(8*x**2 + 10*x*y - 2*y**2 - 32*x - 13*y - 23) + # This leads to very large numbers. + # assert check_solutions(5*x**2 - 13*x*y + y**2 - 4*x - 4*y - 15) + assert check_solutions(-3*x**2 - 2*x*y + 7*y**2 - 5*x - 7) + assert check_solutions(-4 - x + 4*x**2 - y - 3*x*y - 4*y**2) + assert check_solutions(1 + 2*x + 2*x**2 + 2*y + x*y - 2*y**2) + + +def test_DN(): + # Most of the test cases were adapted from, + # Solving the generalized Pell equation x**2 - D*y**2 = N, John P. Robertson, July 31, 2004. + # https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf + # others are verified using Wolfram Alpha. + + # Covers cases where D <= 0 or D > 0 and D is a square or N = 0 + # Solutions are straightforward in these cases. + assert diop_DN(3, 0) == [(0, 0)] + assert diop_DN(-17, -5) == [] + assert diop_DN(-19, 23) == [(2, 1)] + assert diop_DN(-13, 17) == [(2, 1)] + assert diop_DN(-15, 13) == [] + assert diop_DN(0, 5) == [] + assert diop_DN(0, 9) == [(3, t)] + assert diop_DN(9, 0) == [(3*t, t)] + assert diop_DN(16, 24) == [] + assert diop_DN(9, 180) == [(18, 4)] + assert diop_DN(9, -180) == [(12, 6)] + assert diop_DN(7, 0) == [(0, 0)] + + # When equation is x**2 + y**2 = N + # Solutions are interchangeable + assert diop_DN(-1, 5) == [(2, 1), (1, 2)] + assert diop_DN(-1, 169) == [(12, 5), (5, 12), (13, 0), (0, 13)] + + # D > 0 and D is not a square + + # N = 1 + assert diop_DN(13, 1) == [(649, 180)] + assert diop_DN(980, 1) == [(51841, 1656)] + assert diop_DN(981, 1) == [(158070671986249, 5046808151700)] + assert diop_DN(986, 1) == [(49299, 1570)] + assert diop_DN(991, 1) == [(379516400906811930638014896080, 12055735790331359447442538767)] + assert diop_DN(17, 1) == [(33, 8)] + assert diop_DN(19, 1) == [(170, 39)] + + # N = -1 + assert diop_DN(13, -1) == [(18, 5)] + assert diop_DN(991, -1) == [] + assert diop_DN(41, -1) == [(32, 5)] + assert diop_DN(290, -1) == [(17, 1)] + assert diop_DN(21257, -1) == [(13913102721304, 95427381109)] + assert diop_DN(32, -1) == [] + + # |N| > 1 + # Some tests were created using calculator at + # http://www.numbertheory.org/php/patz.html + + assert diop_DN(13, -4) == [(3, 1), (393, 109), (36, 10)] + # Source I referred returned (3, 1), (393, 109) and (-3, 1) as fundamental solutions + # So (-3, 1) and (393, 109) should be in the same equivalent class + assert equivalent(-3, 1, 393, 109, 13, -4) == True + + assert diop_DN(13, 27) == [(220, 61), (40, 11), (768, 213), (12, 3)] + assert set(diop_DN(157, 12)) == {(13, 1), (10663, 851), (579160, 46222), + (483790960, 38610722), (26277068347, 2097138361), + (21950079635497, 1751807067011)} + assert diop_DN(13, 25) == [(3245, 900)] + assert diop_DN(192, 18) == [] + assert diop_DN(23, 13) == [(-6, 1), (6, 1)] + assert diop_DN(167, 2) == [(13, 1)] + assert diop_DN(167, -2) == [] + + assert diop_DN(123, -2) == [(11, 1)] + # One calculator returned [(11, 1), (-11, 1)] but both of these are in + # the same equivalence class + assert equivalent(11, 1, -11, 1, 123, -2) + + assert diop_DN(123, -23) == [(-10, 1), (10, 1)] + + assert diop_DN(0, 0, t) == [(0, t)] + assert diop_DN(0, -1, t) == [] + + +def test_bf_pell(): + assert diop_bf_DN(13, -4) == [(3, 1), (-3, 1), (36, 10)] + assert diop_bf_DN(13, 27) == [(12, 3), (-12, 3), (40, 11), (-40, 11)] + assert diop_bf_DN(167, -2) == [] + assert diop_bf_DN(1729, 1) == [(44611924489705, 1072885712316)] + assert diop_bf_DN(89, -8) == [(9, 1), (-9, 1)] + assert diop_bf_DN(21257, -1) == [(13913102721304, 95427381109)] + assert diop_bf_DN(340, -4) == [(756, 41)] + assert diop_bf_DN(-1, 0, t) == [(0, 0)] + assert diop_bf_DN(0, 0, t) == [(0, t)] + assert diop_bf_DN(4, 0, t) == [(2*t, t), (-2*t, t)] + assert diop_bf_DN(3, 0, t) == [(0, 0)] + assert diop_bf_DN(1, -2, t) == [] + + +def test_length(): + assert length(2, 1, 0) == 1 + assert length(-2, 4, 5) == 3 + assert length(-5, 4, 17) == 4 + assert length(0, 4, 13) == 6 + assert length(7, 13, 11) == 23 + assert length(1, 6, 4) == 2 + + +def is_pell_transformation_ok(eq): + """ + Test whether X*Y, X, or Y terms are present in the equation + after transforming the equation using the transformation returned + by transformation_to_pell(). If they are not present we are good. + Moreover, coefficient of X**2 should be a divisor of coefficient of + Y**2 and the constant term. + """ + A, B = transformation_to_DN(eq) + u = (A*Matrix([X, Y]) + B)[0] + v = (A*Matrix([X, Y]) + B)[1] + simplified = diop_simplify(eq.subs(zip((x, y), (u, v)))) + + coeff = dict([reversed(t.as_independent(*[X, Y])) for t in simplified.args]) + + for term in [X*Y, X, Y]: + if term in coeff.keys(): + return False + + for term in [X**2, Y**2, 1]: + if term not in coeff.keys(): + coeff[term] = 0 + + if coeff[X**2] != 0: + return divisible(coeff[Y**2], coeff[X**2]) and \ + divisible(coeff[1], coeff[X**2]) + + return True + + +def test_transformation_to_pell(): + assert is_pell_transformation_ok(-13*x**2 - 7*x*y + y**2 + 2*x - 2*y - 14) + assert is_pell_transformation_ok(-17*x**2 + 19*x*y - 7*y**2 - 5*x - 13*y - 23) + assert is_pell_transformation_ok(x**2 - y**2 + 17) + assert is_pell_transformation_ok(-x**2 + 7*y**2 - 23) + assert is_pell_transformation_ok(25*x**2 - 45*x*y + 5*y**2 - 5*x - 10*y + 5) + assert is_pell_transformation_ok(190*x**2 + 30*x*y + y**2 - 3*y - 170*x - 130) + assert is_pell_transformation_ok(x**2 - 2*x*y -190*y**2 - 7*y - 23*x - 89) + assert is_pell_transformation_ok(15*x**2 - 9*x*y + 14*y**2 - 23*x - 14*y - 4950) + + +def test_find_DN(): + assert find_DN(x**2 - 2*x - y**2) == (1, 1) + assert find_DN(x**2 - 3*y**2 - 5) == (3, 5) + assert find_DN(x**2 - 2*x*y - 4*y**2 - 7) == (5, 7) + assert find_DN(4*x**2 - 8*x*y - y**2 - 9) == (20, 36) + assert find_DN(7*x**2 - 2*x*y - y**2 - 12) == (8, 84) + assert find_DN(-3*x**2 + 4*x*y -y**2) == (1, 0) + assert find_DN(-13*x**2 - 7*x*y + y**2 + 2*x - 2*y -14) == (101, -7825480) + + +def test_ldescent(): + # Equations which have solutions + u = ([(13, 23), (3, -11), (41, -113), (4, -7), (-7, 4), (91, -3), (1, 1), (1, -1), + (4, 32), (17, 13), (123689, 1), (19, -570)]) + for a, b in u: + w, x, y = ldescent(a, b) + assert a*x**2 + b*y**2 == w**2 + assert ldescent(-1, -1) is None + assert ldescent(2, 6) is None + + +def test_diop_ternary_quadratic_normal(): + assert check_solutions(234*x**2 - 65601*y**2 - z**2) + assert check_solutions(23*x**2 + 616*y**2 - z**2) + assert check_solutions(5*x**2 + 4*y**2 - z**2) + assert check_solutions(3*x**2 + 6*y**2 - 3*z**2) + assert check_solutions(x**2 + 3*y**2 - z**2) + assert check_solutions(4*x**2 + 5*y**2 - z**2) + assert check_solutions(x**2 + y**2 - z**2) + assert check_solutions(16*x**2 + y**2 - 25*z**2) + assert check_solutions(6*x**2 - y**2 + 10*z**2) + assert check_solutions(213*x**2 + 12*y**2 - 9*z**2) + assert check_solutions(34*x**2 - 3*y**2 - 301*z**2) + assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2) + + +def is_normal_transformation_ok(eq): + A = transformation_to_normal(eq) + X, Y, Z = A*Matrix([x, y, z]) + simplified = diop_simplify(eq.subs(zip((x, y, z), (X, Y, Z)))) + + coeff = dict([reversed(t.as_independent(*[X, Y, Z])) for t in simplified.args]) + for term in [X*Y, Y*Z, X*Z]: + if term in coeff.keys(): + return False + + return True + + +def test_transformation_to_normal(): + assert is_normal_transformation_ok(x**2 + 3*y**2 + z**2 - 13*x*y - 16*y*z + 12*x*z) + assert is_normal_transformation_ok(x**2 + 3*y**2 - 100*z**2) + assert is_normal_transformation_ok(x**2 + 23*y*z) + assert is_normal_transformation_ok(3*y**2 - 100*z**2 - 12*x*y) + assert is_normal_transformation_ok(x**2 + 23*x*y - 34*y*z + 12*x*z) + assert is_normal_transformation_ok(z**2 + 34*x*y - 23*y*z + x*z) + assert is_normal_transformation_ok(x**2 + y**2 + z**2 - x*y - y*z - x*z) + assert is_normal_transformation_ok(x**2 + 2*y*z + 3*z**2) + assert is_normal_transformation_ok(x*y + 2*x*z + 3*y*z) + assert is_normal_transformation_ok(2*x*z + 3*y*z) + + +def test_diop_ternary_quadratic(): + assert check_solutions(2*x**2 + z**2 + y**2 - 4*x*y) + assert check_solutions(x**2 - y**2 - z**2 - x*y - y*z) + assert check_solutions(3*x**2 - x*y - y*z - x*z) + assert check_solutions(x**2 - y*z - x*z) + assert check_solutions(5*x**2 - 3*x*y - x*z) + assert check_solutions(4*x**2 - 5*y**2 - x*z) + assert check_solutions(3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z) + assert check_solutions(8*x**2 - 12*y*z) + assert check_solutions(45*x**2 - 7*y**2 - 8*x*y - z**2) + assert check_solutions(x**2 - 49*y**2 - z**2 + 13*z*y -8*x*y) + assert check_solutions(90*x**2 + 3*y**2 + 5*x*y + 2*z*y + 5*x*z) + assert check_solutions(x**2 + 3*y**2 + z**2 - x*y - 17*y*z) + assert check_solutions(x**2 + 3*y**2 + z**2 - x*y - 16*y*z + 12*x*z) + assert check_solutions(x**2 + 3*y**2 + z**2 - 13*x*y - 16*y*z + 12*x*z) + assert check_solutions(x*y - 7*y*z + 13*x*z) + + assert diop_ternary_quadratic_normal(x**2 + y**2 + z**2) == (None, None, None) + assert diop_ternary_quadratic_normal(x**2 + y**2) is None + raises(ValueError, lambda: + _diop_ternary_quadratic_normal((x, y, z), + {x*y: 1, x**2: 2, y**2: 3, z**2: 0})) + eq = -2*x*y - 6*x*z + 7*y**2 - 3*y*z + 4*z**2 + assert diop_ternary_quadratic(eq) == (7, 2, 0) + assert diop_ternary_quadratic_normal(4*x**2 + 5*y**2 - z**2) == \ + (1, 0, 2) + assert diop_ternary_quadratic(x*y + 2*y*z) == \ + (-2, 0, n1) + eq = -5*x*y - 8*x*z - 3*y*z + 8*z**2 + assert parametrize_ternary_quadratic(eq) == \ + (8*p**2 - 3*p*q, -8*p*q + 8*q**2, 5*p*q) + # this cannot be tested with diophantine because it will + # factor into a product + assert diop_solve(x*y + 2*y*z) == (-2*p*q, -n1*p**2 + p**2, p*q) + + +def test_square_factor(): + assert square_factor(1) == square_factor(-1) == 1 + assert square_factor(0) == 1 + assert square_factor(5) == square_factor(-5) == 1 + assert square_factor(4) == square_factor(-4) == 2 + assert square_factor(12) == square_factor(-12) == 2 + assert square_factor(6) == 1 + assert square_factor(18) == 3 + assert square_factor(52) == 2 + assert square_factor(49) == 7 + assert square_factor(392) == 14 + assert square_factor(factorint(-12)) == 2 + + +def test_parametrize_ternary_quadratic(): + assert check_solutions(x**2 + y**2 - z**2) + assert check_solutions(x**2 + 2*x*y + z**2) + assert check_solutions(234*x**2 - 65601*y**2 - z**2) + assert check_solutions(3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z) + assert check_solutions(x**2 - y**2 - z**2) + assert check_solutions(x**2 - 49*y**2 - z**2 + 13*z*y - 8*x*y) + assert check_solutions(8*x*y + z**2) + assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2) + assert check_solutions(236*x**2 - 225*y**2 - 11*x*y - 13*y*z - 17*x*z) + assert check_solutions(90*x**2 + 3*y**2 + 5*x*y + 2*z*y + 5*x*z) + assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2) + + +def test_no_square_ternary_quadratic(): + assert check_solutions(2*x*y + y*z - 3*x*z) + assert check_solutions(189*x*y - 345*y*z - 12*x*z) + assert check_solutions(23*x*y + 34*y*z) + assert check_solutions(x*y + y*z + z*x) + assert check_solutions(23*x*y + 23*y*z + 23*x*z) + + +def test_descent(): + + u = ([(13, 23), (3, -11), (41, -113), (91, -3), (1, 1), (1, -1), (17, 13), (123689, 1), (19, -570)]) + for a, b in u: + w, x, y = descent(a, b) + assert a*x**2 + b*y**2 == w**2 + # the docstring warns against bad input, so these are expected results + # - can't both be negative + raises(TypeError, lambda: descent(-1, -3)) + # A can't be zero unless B != 1 + raises(ZeroDivisionError, lambda: descent(0, 3)) + # supposed to be square-free + raises(TypeError, lambda: descent(4, 3)) + + +def test_diophantine(): + assert check_solutions((x - y)*(y - z)*(z - x)) + assert check_solutions((x - y)*(x**2 + y**2 - z**2)) + assert check_solutions((x - 3*y + 7*z)*(x**2 + y**2 - z**2)) + assert check_solutions(x**2 - 3*y**2 - 1) + assert check_solutions(y**2 + 7*x*y) + assert check_solutions(x**2 - 3*x*y + y**2) + assert check_solutions(z*(x**2 - y**2 - 15)) + assert check_solutions(x*(2*y - 2*z + 5)) + assert check_solutions((x**2 - 3*y**2 - 1)*(x**2 - y**2 - 15)) + assert check_solutions((x**2 - 3*y**2 - 1)*(y - 7*z)) + assert check_solutions((x**2 + y**2 - z**2)*(x - 7*y - 3*z + 4*w)) + # Following test case caused problems in parametric representation + # But this can be solved by factoring out y. + # No need to use methods for ternary quadratic equations. + assert check_solutions(y**2 - 7*x*y + 4*y*z) + assert check_solutions(x**2 - 2*x + 1) + + assert diophantine(x - y) == diophantine(Eq(x, y)) + # 18196 + eq = x**4 + y**4 - 97 + assert diophantine(eq, permute=True) == diophantine(-eq, permute=True) + assert diophantine(3*x*pi - 2*y*pi) == {(2*t_0, 3*t_0)} + eq = x**2 + y**2 + z**2 - 14 + base_sol = {(1, 2, 3)} + assert diophantine(eq) == base_sol + complete_soln = set(signed_permutations(base_sol.pop())) + assert diophantine(eq, permute=True) == complete_soln + + assert diophantine(x**2 + x*Rational(15, 14) - 3) == set() + # test issue 11049 + eq = 92*x**2 - 99*y**2 - z**2 + coeff = eq.as_coefficients_dict() + assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \ + {(9, 7, 51)} + assert diophantine(eq) == {( + 891*p**2 + 9*q**2, -693*p**2 - 102*p*q + 7*q**2, + 5049*p**2 - 1386*p*q - 51*q**2)} + eq = 2*x**2 + 2*y**2 - z**2 + coeff = eq.as_coefficients_dict() + assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \ + {(1, 1, 2)} + assert diophantine(eq) == {( + 2*p**2 - q**2, -2*p**2 + 4*p*q - q**2, + 4*p**2 - 4*p*q + 2*q**2)} + eq = 411*x**2+57*y**2-221*z**2 + coeff = eq.as_coefficients_dict() + assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \ + {(2021, 2645, 3066)} + assert diophantine(eq) == \ + {(115197*p**2 - 446641*q**2, -150765*p**2 + 1355172*p*q - + 584545*q**2, 174762*p**2 - 301530*p*q + 677586*q**2)} + eq = 573*x**2+267*y**2-984*z**2 + coeff = eq.as_coefficients_dict() + assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \ + {(49, 233, 127)} + assert diophantine(eq) == \ + {(4361*p**2 - 16072*q**2, -20737*p**2 + 83312*p*q - 76424*q**2, + 11303*p**2 - 41474*p*q + 41656*q**2)} + # this produces factors during reconstruction + eq = x**2 + 3*y**2 - 12*z**2 + coeff = eq.as_coefficients_dict() + assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \ + {(0, 2, 1)} + assert diophantine(eq) == \ + {(24*p*q, 2*p**2 - 24*q**2, p**2 + 12*q**2)} + # solvers have not been written for every type + raises(NotImplementedError, lambda: diophantine(x*y**2 + 1)) + + # rational expressions + assert diophantine(1/x) == set() + assert diophantine(1/x + 1/y - S.Half) == {(6, 3), (-2, 1), (4, 4), (1, -2), (3, 6)} + assert diophantine(x**2 + y**2 +3*x- 5, permute=True) == \ + {(-1, 1), (-4, -1), (1, -1), (1, 1), (-4, 1), (-1, -1), (4, 1), (4, -1)} + + + #test issue 18186 + assert diophantine(y**4 + x**4 - 2**4 - 3**4, syms=(x, y), permute=True) == \ + {(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)} + assert diophantine(y**4 + x**4 - 2**4 - 3**4, syms=(y, x), permute=True) == \ + {(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)} + + # issue 18122 + assert check_solutions(x**2 - y) + assert check_solutions(y**2 - x) + assert diophantine((x**2 - y), t) == {(t, t**2)} + assert diophantine((y**2 - x), t) == {(t**2, t)} + + +def test_general_pythagorean(): + from sympy.abc import a, b, c, d, e + + assert check_solutions(a**2 + b**2 + c**2 - d**2) + assert check_solutions(a**2 + 4*b**2 + 4*c**2 - d**2) + assert check_solutions(9*a**2 + 4*b**2 + 4*c**2 - d**2) + assert check_solutions(9*a**2 + 4*b**2 - 25*d**2 + 4*c**2 ) + assert check_solutions(9*a**2 - 16*d**2 + 4*b**2 + 4*c**2) + assert check_solutions(-e**2 + 9*a**2 + 4*b**2 + 4*c**2 + 25*d**2) + assert check_solutions(16*a**2 - b**2 + 9*c**2 + d**2 + 25*e**2) + + assert GeneralPythagorean(a**2 + b**2 + c**2 - d**2).solve(parameters=[x, y, z]) == \ + {(x**2 + y**2 - z**2, 2*x*z, 2*y*z, x**2 + y**2 + z**2)} + + +def test_diop_general_sum_of_squares_quick(): + for i in range(3, 10): + assert check_solutions(sum(i**2 for i in symbols(':%i' % i)) - i) + + assert diop_general_sum_of_squares(x**2 + y**2 - 2) is None + assert diop_general_sum_of_squares(x**2 + y**2 + z**2 + 2) == set() + eq = x**2 + y**2 + z**2 - (1 + 4 + 9) + assert diop_general_sum_of_squares(eq) == \ + {(1, 2, 3)} + eq = u**2 + v**2 + x**2 + y**2 + z**2 - 1313 + assert len(diop_general_sum_of_squares(eq, 3)) == 3 + # issue 11016 + var = symbols(':5') + (symbols('6', negative=True),) + eq = Add(*[i**2 for i in var]) - 112 + + base_soln = {(0, 1, 1, 5, 6, -7), (1, 1, 1, 3, 6, -8), (2, 3, 3, 4, 5, -7), (0, 1, 1, 1, 3, -10), + (0, 0, 4, 4, 4, -8), (1, 2, 3, 3, 5, -8), (0, 1, 2, 3, 7, -7), (2, 2, 4, 4, 6, -6), + (1, 1, 3, 4, 6, -7), (0, 2, 3, 3, 3, -9), (0, 0, 2, 2, 2, -10), (1, 1, 2, 3, 4, -9), + (0, 1, 1, 2, 5, -9), (0, 0, 2, 6, 6, -6), (1, 3, 4, 5, 5, -6), (0, 2, 2, 2, 6, -8), + (0, 3, 3, 3, 6, -7), (0, 2, 3, 5, 5, -7), (0, 1, 5, 5, 5, -6)} + assert diophantine(eq) == base_soln + assert len(diophantine(eq, permute=True)) == 196800 + + # handle negated squares with signsimp + assert diophantine(12 - x**2 - y**2 - z**2) == {(2, 2, 2)} + # diophantine handles simplification, so classify_diop should + # not have to look for additional patterns that are removed + # by diophantine + eq = a**2 + b**2 + c**2 + d**2 - 4 + raises(NotImplementedError, lambda: classify_diop(-eq)) + + +def test_issue_23807(): + # fixes recursion error + eq = x**2 + y**2 + z**2 - 1000000 + base_soln = {(0, 0, 1000), (0, 352, 936), (480, 600, 640), (24, 640, 768), (192, 640, 744), + (192, 480, 856), (168, 224, 960), (0, 600, 800), (280, 576, 768), (152, 480, 864), + (0, 280, 960), (352, 360, 864), (424, 480, 768), (360, 480, 800), (224, 600, 768), + (96, 360, 928), (168, 576, 800), (96, 480, 872)} + + assert diophantine(eq) == base_soln + + +def test_diop_partition(): + for n in [8, 10]: + for k in range(1, 8): + for p in partition(n, k): + assert len(p) == k + assert list(partition(3, 5)) == [] + assert [list(p) for p in partition(3, 5, 1)] == [ + [0, 0, 0, 0, 3], [0, 0, 0, 1, 2], [0, 0, 1, 1, 1]] + assert list(partition(0)) == [()] + assert list(partition(1, 0)) == [()] + assert [list(i) for i in partition(3)] == [[1, 1, 1], [1, 2], [3]] + + +def test_prime_as_sum_of_two_squares(): + for i in [5, 13, 17, 29, 37, 41, 2341, 3557, 34841, 64601]: + a, b = prime_as_sum_of_two_squares(i) + assert a**2 + b**2 == i + assert prime_as_sum_of_two_squares(7) is None + ans = prime_as_sum_of_two_squares(800029) + assert ans == (450, 773) and type(ans[0]) is int + + +def test_sum_of_three_squares(): + for i in [0, 1, 2, 34, 123, 34304595905, 34304595905394941, 343045959052344, + 800, 801, 802, 803, 804, 805, 806]: + a, b, c = sum_of_three_squares(i) + assert a**2 + b**2 + c**2 == i + assert a >= 0 + + # error + raises(ValueError, lambda: sum_of_three_squares(-1)) + + assert sum_of_three_squares(7) is None + assert sum_of_three_squares((4**5)*15) is None + # if there are two zeros, there might be a solution + # with only one zero, e.g. 25 => (0, 3, 4) or + # with no zeros, e.g. 49 => (2, 3, 6) + assert sum_of_three_squares(25) == (0, 0, 5) + assert sum_of_three_squares(4) == (0, 0, 2) + + +def test_sum_of_four_squares(): + from sympy.core.random import randint + + # this should never fail + n = randint(1, 100000000000000) + assert sum(i**2 for i in sum_of_four_squares(n)) == n + + # error + raises(ValueError, lambda: sum_of_four_squares(-1)) + + for n in range(1000): + result = sum_of_four_squares(n) + assert len(result) == 4 + assert all(r >= 0 for r in result) + assert sum(r**2 for r in result) == n + assert list(result) == sorted(result) + + +def test_power_representation(): + tests = [(1729, 3, 2), (234, 2, 4), (2, 1, 2), (3, 1, 3), (5, 2, 2), (12352, 2, 4), + (32760, 2, 3)] + + for test in tests: + n, p, k = test + f = power_representation(n, p, k) + + while True: + try: + l = next(f) + assert len(l) == k + + chk_sum = 0 + for l_i in l: + chk_sum = chk_sum + l_i**p + assert chk_sum == n + + except StopIteration: + break + + assert list(power_representation(20, 2, 4, True)) == \ + [(1, 1, 3, 3), (0, 0, 2, 4)] + raises(ValueError, lambda: list(power_representation(1.2, 2, 2))) + raises(ValueError, lambda: list(power_representation(2, 0, 2))) + raises(ValueError, lambda: list(power_representation(2, 2, 0))) + assert list(power_representation(-1, 2, 2)) == [] + assert list(power_representation(1, 1, 1)) == [(1,)] + assert list(power_representation(3, 2, 1)) == [] + assert list(power_representation(4, 2, 1)) == [(2,)] + assert list(power_representation(3**4, 4, 6, zeros=True)) == \ + [(1, 2, 2, 2, 2, 2), (0, 0, 0, 0, 0, 3)] + assert list(power_representation(3**4, 4, 5, zeros=False)) == [] + assert list(power_representation(-2, 3, 2)) == [(-1, -1)] + assert list(power_representation(-2, 4, 2)) == [] + assert list(power_representation(0, 3, 2, True)) == [(0, 0)] + assert list(power_representation(0, 3, 2, False)) == [] + # when we are dealing with squares, do feasibility checks + assert len(list(power_representation(4**10*(8*10 + 7), 2, 3))) == 0 + # there will be a recursion error if these aren't recognized + big = 2**30 + for i in [13, 10, 7, 5, 4, 2, 1]: + assert list(sum_of_powers(big, 2, big - i)) == [] + + +def test_assumptions(): + """ + Test whether diophantine respects the assumptions. + """ + #Test case taken from the below so question regarding assumptions in diophantine module + #https://stackoverflow.com/questions/23301941/how-can-i-declare-natural-symbols-with-sympy + m, n = symbols('m n', integer=True, positive=True) + diof = diophantine(n**2 + m*n - 500) + assert diof == {(5, 20), (40, 10), (95, 5), (121, 4), (248, 2), (499, 1)} + + a, b = symbols('a b', integer=True, positive=False) + diof = diophantine(a*b + 2*a + 3*b - 6) + assert diof == {(-15, -3), (-9, -4), (-7, -5), (-6, -6), (-5, -8), (-4, -14)} + + x, y = symbols('x y', integer=True) + diof = diophantine(10*x**2 + 5*x*y - 3*y) + assert diof == {(1, -5), (-3, 5), (0, 0)} + + x, y = symbols('x y', integer=True, positive=True) + diof = diophantine(10*x**2 + 5*x*y - 3*y) + assert diof == set() + + x, y = symbols('x y', integer=True, negative=False) + diof = diophantine(10*x**2 + 5*x*y - 3*y) + assert diof == {(0, 0)} + + +def check_solutions(eq): + """ + Determines whether solutions returned by diophantine() satisfy the original + equation. Hope to generalize this so we can remove functions like check_ternay_quadratic, + check_solutions_normal, check_solutions() + """ + s = diophantine(eq) + + factors = Mul.make_args(eq) + + var = list(eq.free_symbols) + var.sort(key=default_sort_key) + + while s: + solution = s.pop() + for f in factors: + if diop_simplify(f.subs(zip(var, solution))) == 0: + break + else: + return False + return True + + +def test_diopcoverage(): + eq = (2*x + y + 1)**2 + assert diop_solve(eq) == {(t_0, -2*t_0 - 1)} + eq = 2*x**2 + 6*x*y + 12*x + 4*y**2 + 18*y + 18 + assert diop_solve(eq) == {(t, -t - 3), (-2*t - 3, t)} + assert diop_quadratic(x + y**2 - 3) == {(-t**2 + 3, t)} + + assert diop_linear(x + y - 3) == (t_0, 3 - t_0) + + assert base_solution_linear(0, 1, 2, t=None) == (0, 0) + ans = (3*t - 1, -2*t + 1) + assert base_solution_linear(4, 8, 12, t) == ans + assert base_solution_linear(4, 8, 12, t=None) == tuple(_.subs(t, 0) for _ in ans) + + assert cornacchia(1, 1, 20) == set() + assert cornacchia(1, 1, 5) == {(2, 1)} + assert cornacchia(1, 2, 17) == {(3, 2)} + + raises(ValueError, lambda: reconstruct(4, 20, 1)) + + assert gaussian_reduce(4, 1, 3) == (1, 1) + eq = -w**2 - x**2 - y**2 + z**2 + + assert diop_general_pythagorean(eq) == \ + diop_general_pythagorean(-eq) == \ + (m1**2 + m2**2 - m3**2, 2*m1*m3, + 2*m2*m3, m1**2 + m2**2 + m3**2) + + assert len(check_param(S(3) + x/3, S(4) + x/2, S(2), [x])) == 0 + assert len(check_param(Rational(3, 2), S(4) + x, S(2), [x])) == 0 + assert len(check_param(S(4) + x, Rational(3, 2), S(2), [x])) == 0 + + assert _nint_or_floor(16, 10) == 2 + assert _odd(1) == (not _even(1)) == True + assert _odd(0) == (not _even(0)) == False + assert _remove_gcd(2, 4, 6) == (1, 2, 3) + raises(TypeError, lambda: _remove_gcd((2, 4, 6))) + assert sqf_normal(2*3**2*5, 2*5*11, 2*7**2*11) == \ + (11, 1, 5) + + # it's ok if these pass some day when the solvers are implemented + raises(NotImplementedError, lambda: diophantine(x**2 + y**2 + x*y + 2*y*z - 12)) + raises(NotImplementedError, lambda: diophantine(x**3 + y**2)) + assert diop_quadratic(x**2 + y**2 - 1**2 - 3**4) == \ + {(-9, -1), (-9, 1), (-1, -9), (-1, 9), (1, -9), (1, 9), (9, -1), (9, 1)} + + +def test_holzer(): + # if the input is good, don't let it diverge in holzer() + # (but see test_fail_holzer below) + assert holzer(2, 7, 13, 4, 79, 23) == (2, 7, 13) + + # None in uv condition met; solution is not Holzer reduced + # so this will hopefully change but is here for coverage + assert holzer(2, 6, 2, 1, 1, 10) == (2, 6, 2) + + raises(ValueError, lambda: holzer(2, 7, 14, 4, 79, 23)) + + +@XFAIL +def test_fail_holzer(): + eq = lambda x, y, z: a*x**2 + b*y**2 - c*z**2 + a, b, c = 4, 79, 23 + x, y, z = xyz = 26, 1, 11 + X, Y, Z = ans = 2, 7, 13 + assert eq(*xyz) == 0 + assert eq(*ans) == 0 + assert max(a*x**2, b*y**2, c*z**2) <= a*b*c + assert max(a*X**2, b*Y**2, c*Z**2) <= a*b*c + h = holzer(x, y, z, a, b, c) + assert h == ans # it would be nice to get the smaller soln + + +def test_issue_9539(): + assert diophantine(6*w + 9*y + 20*x - z) == \ + {(t_0, t_1, t_1 + t_2, 6*t_0 + 29*t_1 + 9*t_2)} + + +def test_issue_8943(): + assert diophantine( + 3*(x**2 + y**2 + z**2) - 14*(x*y + y*z + z*x)) == \ + {(0, 0, 0)} + + +def test_diop_sum_of_even_powers(): + eq = x**4 + y**4 + z**4 - 2673 + assert diop_solve(eq) == {(3, 6, 6), (2, 4, 7)} + assert diop_general_sum_of_even_powers(eq, 2) == {(3, 6, 6), (2, 4, 7)} + raises(NotImplementedError, lambda: diop_general_sum_of_even_powers(-eq, 2)) + neg = symbols('neg', negative=True) + eq = x**4 + y**4 + neg**4 - 2673 + assert diop_general_sum_of_even_powers(eq) == {(-3, 6, 6)} + assert diophantine(x**4 + y**4 + 2) == set() + assert diop_general_sum_of_even_powers(x**4 + y**4 - 2, limit=0) == set() + + +def test_sum_of_squares_powers(): + tru = {(0, 0, 1, 1, 11), (0, 0, 5, 7, 7), (0, 1, 3, 7, 8), (0, 1, 4, 5, 9), (0, 3, 4, 7, 7), (0, 3, 5, 5, 8), + (1, 1, 2, 6, 9), (1, 1, 6, 6, 7), (1, 2, 3, 3, 10), (1, 3, 4, 4, 9), (1, 5, 5, 6, 6), (2, 2, 3, 5, 9), + (2, 3, 5, 6, 7), (3, 3, 4, 5, 8)} + eq = u**2 + v**2 + x**2 + y**2 + z**2 - 123 + ans = diop_general_sum_of_squares(eq, oo) # allow oo to be used + assert len(ans) == 14 + assert ans == tru + + raises(ValueError, lambda: list(sum_of_squares(10, -1))) + assert list(sum_of_squares(1, 1)) == [(1,)] + assert list(sum_of_squares(1, 2)) == [] + assert list(sum_of_squares(1, 2, True)) == [(0, 1)] + assert list(sum_of_squares(-10, 2)) == [] + assert list(sum_of_squares(2, 3)) == [] + assert list(sum_of_squares(0, 3, True)) == [(0, 0, 0)] + assert list(sum_of_squares(0, 3)) == [] + assert list(sum_of_squares(4, 1)) == [(2,)] + assert list(sum_of_squares(5, 1)) == [] + assert list(sum_of_squares(50, 2)) == [(5, 5), (1, 7)] + assert list(sum_of_squares(11, 5, True)) == [ + (1, 1, 1, 2, 2), (0, 0, 1, 1, 3)] + assert list(sum_of_squares(8, 8)) == [(1, 1, 1, 1, 1, 1, 1, 1)] + + assert [len(list(sum_of_squares(i, 5, True))) for i in range(30)] == [ + 1, 1, 1, 1, 2, + 2, 1, 1, 2, 2, + 2, 2, 2, 3, 2, + 1, 3, 3, 3, 3, + 4, 3, 3, 2, 2, + 4, 4, 4, 4, 5] + assert [len(list(sum_of_squares(i, 5))) for i in range(30)] == [ + 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, + 0, 1, 0, 1, 1, + 0, 1, 1, 0, 1, + 2, 1, 1, 1, 1, + 1, 1, 1, 1, 3] + for i in range(30): + s1 = set(sum_of_squares(i, 5, True)) + assert not s1 or all(sum(j**2 for j in t) == i for t in s1) + s2 = set(sum_of_squares(i, 5)) + assert all(sum(j**2 for j in t) == i for t in s2) + + raises(ValueError, lambda: list(sum_of_powers(2, -1, 1))) + raises(ValueError, lambda: list(sum_of_powers(2, 1, -1))) + assert list(sum_of_powers(-2, 3, 2)) == [(-1, -1)] + assert list(sum_of_powers(-2, 4, 2)) == [] + assert list(sum_of_powers(2, 1, 1)) == [(2,)] + assert list(sum_of_powers(2, 1, 3, True)) == [(0, 0, 2), (0, 1, 1)] + assert list(sum_of_powers(5, 1, 2, True)) == [(0, 5), (1, 4), (2, 3)] + assert list(sum_of_powers(6, 2, 2)) == [] + assert list(sum_of_powers(3**5, 3, 1)) == [] + assert list(sum_of_powers(3**6, 3, 1)) == [(9,)] and (9**3 == 3**6) + assert list(sum_of_powers(2**1000, 5, 2)) == [] + + +def test__can_do_sum_of_squares(): + assert _can_do_sum_of_squares(3, -1) is False + assert _can_do_sum_of_squares(-3, 1) is False + assert _can_do_sum_of_squares(0, 1) + assert _can_do_sum_of_squares(4, 1) + assert _can_do_sum_of_squares(1, 2) + assert _can_do_sum_of_squares(2, 2) + assert _can_do_sum_of_squares(3, 2) is False + + +def test_diophantine_permute_sign(): + from sympy.abc import a, b, c, d, e + eq = a**4 + b**4 - (2**4 + 3**4) + base_sol = {(2, 3)} + assert diophantine(eq) == base_sol + complete_soln = set(signed_permutations(base_sol.pop())) + assert diophantine(eq, permute=True) == complete_soln + + eq = a**2 + b**2 + c**2 + d**2 + e**2 - 234 + assert len(diophantine(eq)) == 35 + assert len(diophantine(eq, permute=True)) == 62000 + soln = {(-1, -1), (-1, 2), (1, -2), (1, 1)} + assert diophantine(10*x**2 + 12*x*y + 12*y**2 - 34, permute=True) == soln + + +@XFAIL +def test_not_implemented(): + eq = x**2 + y**4 - 1**2 - 3**4 + assert diophantine(eq, syms=[x, y]) == {(9, 1), (1, 3)} + + +def test_issue_9538(): + eq = x - 3*y + 2 + assert diophantine(eq, syms=[y,x]) == {(t_0, 3*t_0 - 2)} + raises(TypeError, lambda: diophantine(eq, syms={y, x})) + + +def test_ternary_quadratic(): + # solution with 3 parameters + s = diophantine(2*x**2 + y**2 - 2*z**2) + p, q, r = ordered(S(s).free_symbols) + assert s == {( + p**2 - 2*q**2, + -2*p**2 + 4*p*q - 4*p*r - 4*q**2, + p**2 - 4*p*q + 2*q**2 - 4*q*r)} + # solution with Mul in solution + s = diophantine(x**2 + 2*y**2 - 2*z**2) + assert s == {(4*p*q, p**2 - 2*q**2, p**2 + 2*q**2)} + # solution with no Mul in solution + s = diophantine(2*x**2 + 2*y**2 - z**2) + assert s == {(2*p**2 - q**2, -2*p**2 + 4*p*q - q**2, + 4*p**2 - 4*p*q + 2*q**2)} + # reduced form when parametrized + s = diophantine(3*x**2 + 72*y**2 - 27*z**2) + assert s == {(24*p**2 - 9*q**2, 6*p*q, 8*p**2 + 3*q**2)} + assert parametrize_ternary_quadratic( + 3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z) == ( + 2*p**2 - 2*p*q - q**2, 2*p**2 + 2*p*q - q**2, 2*p**2 - + 2*p*q + 3*q**2) + assert parametrize_ternary_quadratic( + 124*x**2 - 30*y**2 - 7729*z**2) == ( + -1410*p**2 - 363263*q**2, 2700*p**2 + 30916*p*q - + 695610*q**2, -60*p**2 + 5400*p*q + 15458*q**2) + + +def test_diophantine_solution_set(): + s1 = DiophantineSolutionSet([], []) + assert set(s1) == set() + assert s1.symbols == () + assert s1.parameters == () + raises(ValueError, lambda: s1.add((x,))) + assert list(s1.dict_iterator()) == [] + + s2 = DiophantineSolutionSet([x, y], [t, u]) + assert s2.symbols == (x, y) + assert s2.parameters == (t, u) + raises(ValueError, lambda: s2.add((1,))) + s2.add((3, 4)) + assert set(s2) == {(3, 4)} + s2.update((3, 4), (-1, u)) + assert set(s2) == {(3, 4), (-1, u)} + raises(ValueError, lambda: s1.update(s2)) + assert list(s2.dict_iterator()) == [{x: -1, y: u}, {x: 3, y: 4}] + + s3 = DiophantineSolutionSet([x, y, z], [t, u]) + assert len(s3.parameters) == 2 + s3.add((t**2 + u, t - u, 1)) + assert set(s3) == {(t**2 + u, t - u, 1)} + assert s3.subs(t, 2) == {(u + 4, 2 - u, 1)} + assert s3(2) == {(u + 4, 2 - u, 1)} + assert s3.subs({t: 7, u: 8}) == {(57, -1, 1)} + assert s3(7, 8) == {(57, -1, 1)} + assert s3.subs({t: 5}) == {(u + 25, 5 - u, 1)} + assert s3(5) == {(u + 25, 5 - u, 1)} + assert s3.subs(u, -3) == {(t**2 - 3, t + 3, 1)} + assert s3(None, -3) == {(t**2 - 3, t + 3, 1)} + assert s3.subs({t: 2, u: 8}) == {(12, -6, 1)} + assert s3(2, 8) == {(12, -6, 1)} + assert s3.subs({t: 5, u: -3}) == {(22, 8, 1)} + assert s3(5, -3) == {(22, 8, 1)} + raises(TypeError, lambda: s3.subs(x=1)) + raises(TypeError, lambda: s3.subs(1, 2, 3)) + raises(ValueError, lambda: s3.add(())) + raises(ValueError, lambda: s3.add((1, 2, 3, 4))) + raises(ValueError, lambda: s3.add((1, 2))) + raises(ValueError, lambda: s3(1, 2, 3)) + raises(TypeError, lambda: s3(t=1)) + + s4 = DiophantineSolutionSet([x, y], [t, u]) + s4.add((t, 11*t)) + s4.add((-t, 22*t)) + assert s4(0, 0) == {(0, 0)} + + +def test_quadratic_parameter_passing(): + eq = -33*x*y + 3*y**2 + solution = BinaryQuadratic(eq).solve(parameters=[t, u]) + # test that parameters are passed all the way to the final solution + assert solution == {(t, 11*t), (t, -22*t)} + assert solution(0, 0) == {(0, 0)} + +def test_issue_18628(): + eq1 = x**2 - 15*x + y**2 - 8*y + sol = diophantine(eq1) + assert sol == {(15, 0), (15, 8), (-1, 4), (0, 0), (0, 8), (16, 4)} + eq2 = 2*x**2 - 9*x + 4*y**2 - 8*y + 14 + sol = diophantine(eq2) + assert sol == {(2, 1)} diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2b543425251dea6380a1860279cb6d636f3dd629 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__init__.py @@ -0,0 +1,16 @@ +from .ode import (allhints, checkinfsol, classify_ode, + constantsimp, dsolve, homogeneous_order) + +from .lie_group import infinitesimals + +from .subscheck import checkodesol + +from .systems import (canonical_odes, linear_ode_to_matrix, + linodesolve) + + +__all__ = [ + 'allhints', 'checkinfsol', 'checkodesol', 'classify_ode', 'constantsimp', + 'dsolve', 'homogeneous_order', 'infinitesimals', 'canonical_odes', 'linear_ode_to_matrix', + 'linodesolve' +] diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..16a445c1bfde1f0ac2dad2b539377cc168bfe635 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/hypergeometric.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/hypergeometric.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d41b2b29bbab51e862fe2d23bdb4f79ecee5820c Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/hypergeometric.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/lie_group.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/lie_group.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d8492f6ea120ac0993cbcab9bee9e6dcd8c62aa Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/lie_group.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/nonhomogeneous.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/nonhomogeneous.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..efe8c87a05a90905dc359d3650631467fa73f909 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/nonhomogeneous.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/riccati.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/riccati.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2cdf2de535c960397d4a1c3b36c2343e669dd9f1 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/riccati.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/subscheck.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/subscheck.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1bad9f7dab025ddf1be9728a928c81269a229d67 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/subscheck.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/systems.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/systems.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f4b0a790d14453de590354e9c13b26a2af53dcee Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/__pycache__/systems.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/hypergeometric.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/hypergeometric.py new file mode 100644 index 0000000000000000000000000000000000000000..5699d2418058acaf48d1e4f87f6635a7b1f7284c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/hypergeometric.py @@ -0,0 +1,272 @@ +r''' +This module contains the implementation of the 2nd_hypergeometric hint for +dsolve. This is an incomplete implementation of the algorithm described in [1]. +The algorithm solves 2nd order linear ODEs of the form + +.. math:: y'' + A(x) y' + B(x) y = 0\text{,} + +where `A` and `B` are rational functions. The algorithm should find any +solution of the form + +.. math:: y = P(x) _pF_q(..; ..;\frac{\alpha x^k + \beta}{\gamma x^k + \delta})\text{,} + +where pFq is any of 2F1, 1F1 or 0F1 and `P` is an "arbitrary function". +Currently only the 2F1 case is implemented in SymPy but the other cases are +described in the paper and could be implemented in future (contributions +welcome!). + +References +========== + +.. [1] L. Chan, E.S. Cheb-Terrab, Non-Liouvillian solutions for second order + linear ODEs, (2004). + https://arxiv.org/abs/math-ph/0402063 +''' + +from sympy.core import S, Pow +from sympy.core.function import expand +from sympy.core.relational import Eq +from sympy.core.symbol import Symbol, Wild +from sympy.functions import exp, sqrt, hyper +from sympy.integrals import Integral +from sympy.polys import roots, gcd +from sympy.polys.polytools import cancel, factor +from sympy.simplify import collect, simplify, logcombine # type: ignore +from sympy.simplify.powsimp import powdenest +from sympy.solvers.ode.ode import get_numbered_constants + + +def match_2nd_hypergeometric(eq, func): + x = func.args[0] + df = func.diff(x) + a3 = Wild('a3', exclude=[func, func.diff(x), func.diff(x, 2)]) + b3 = Wild('b3', exclude=[func, func.diff(x), func.diff(x, 2)]) + c3 = Wild('c3', exclude=[func, func.diff(x), func.diff(x, 2)]) + deq = a3*(func.diff(x, 2)) + b3*df + c3*func + r = collect(eq, + [func.diff(x, 2), func.diff(x), func]).match(deq) + if r: + if not all(val.is_polynomial() for val in r.values()): + n, d = eq.as_numer_denom() + eq = expand(n) + r = collect(eq, [func.diff(x, 2), func.diff(x), func]).match(deq) + + if r and r[a3]!=0: + A = cancel(r[b3]/r[a3]) + B = cancel(r[c3]/r[a3]) + return [A, B] + else: + return [] + + +def equivalence_hypergeometric(A, B, func): + # This method for finding the equivalence is only for 2F1 type. + # We can extend it for 1F1 and 0F1 type also. + x = func.args[0] + + # making given equation in normal form + I1 = factor(cancel(A.diff(x)/2 + A**2/4 - B)) + + # computing shifted invariant(J1) of the equation + J1 = factor(cancel(x**2*I1 + S(1)/4)) + num, dem = J1.as_numer_denom() + num = powdenest(expand(num)) + dem = powdenest(expand(dem)) + # this function will compute the different powers of variable(x) in J1. + # then it will help in finding value of k. k is power of x such that we can express + # J1 = x**k * J0(x**k) then all the powers in J0 become integers. + def _power_counting(num): + _pow = {0} + for val in num: + if val.has(x): + if isinstance(val, Pow) and val.as_base_exp()[0] == x: + _pow.add(val.as_base_exp()[1]) + elif val == x: + _pow.add(val.as_base_exp()[1]) + else: + _pow.update(_power_counting(val.args)) + return _pow + + pow_num = _power_counting((num, )) + pow_dem = _power_counting((dem, )) + pow_dem.update(pow_num) + + _pow = pow_dem + k = gcd(_pow) + + # computing I0 of the given equation + I0 = powdenest(simplify(factor(((J1/k**2) - S(1)/4)/((x**k)**2))), force=True) + I0 = factor(cancel(powdenest(I0.subs(x, x**(S(1)/k)), force=True))) + + # Before this point I0, J1 might be functions of e.g. sqrt(x) but replacing + # x with x**(1/k) should result in I0 being a rational function of x or + # otherwise the hypergeometric solver cannot be used. Note that k can be a + # non-integer rational such as 2/7. + if not I0.is_rational_function(x): + return None + + num, dem = I0.as_numer_denom() + + max_num_pow = max(_power_counting((num, ))) + dem_args = dem.args + sing_point = [] + dem_pow = [] + # calculating singular point of I0. + for arg in dem_args: + if arg.has(x): + if isinstance(arg, Pow): + # (x-a)**n + dem_pow.append(arg.as_base_exp()[1]) + sing_point.append(list(roots(arg.as_base_exp()[0], x).keys())[0]) + else: + # (x-a) type + dem_pow.append(arg.as_base_exp()[1]) + sing_point.append(list(roots(arg, x).keys())[0]) + + dem_pow.sort() + # checking if equivalence is exists or not. + + if equivalence(max_num_pow, dem_pow) == "2F1": + return {'I0':I0, 'k':k, 'sing_point':sing_point, 'type':"2F1"} + else: + return None + + +def match_2nd_2F1_hypergeometric(I, k, sing_point, func): + x = func.args[0] + a = Wild("a") + b = Wild("b") + c = Wild("c") + t = Wild("t") + s = Wild("s") + r = Wild("r") + alpha = Wild("alpha") + beta = Wild("beta") + gamma = Wild("gamma") + delta = Wild("delta") + # I0 of the standard 2F1 equation. + I0 = ((a-b+1)*(a-b-1)*x**2 + 2*((1-a-b)*c + 2*a*b)*x + c*(c-2))/(4*x**2*(x-1)**2) + if sing_point != [0, 1]: + # If singular point is [0, 1] then we have standard equation. + eqs = [] + sing_eqs = [-beta/alpha, -delta/gamma, (delta-beta)/(alpha-gamma)] + # making equations for the finding the mobius transformation + for i in range(3): + if i>> from sympy import Function, Eq, pprint + >>> from sympy.abc import x, y + >>> xi, eta, h = 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 d d + |--(eta(x, y)) - --(xi(x, y))|*h(x, y) - eta(x, y)*--(h(x, y)) - h (x, y)*--(xi(x, y)) - xi(x, y)*--(h(x, y)) + --(eta(x, y)) = 0 + \dy dx / dy dy dx dx + + Solving the above mentioned PDE is not trivial, and can be solved only by + making intelligent assumptions for `\xi` and `\eta` (heuristics). Once an + infinitesimal is found, the attempt to find more heuristics stops. This is done to + optimise the speed of solving the differential equation. If a list of all the + infinitesimals is needed, ``hint`` should be flagged as ``all``, which gives + the complete list of infinitesimals. If the infinitesimals for a particular + heuristic needs to be found, it can be passed as a flag to ``hint``. + + Examples + ======== + + >>> from sympy import Function + >>> from sympy.solvers.ode.lie_group 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}] + + References + ========== + + - Solving differential equations by Symmetry Groups, + John Starrett, pp. 1 - pp. 14 + + """ + + 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', exclude = [df]) + if match: # Used by lie_group hint + h = match['h'] + y = match['y'] + else: + match = collect(expand(eq), df).match(a*df + b) + if match: + h = -simplify(match[b]/match[a]) + else: + try: + sol = solve(eq, df) + except NotImplementedError: + raise NotImplementedError("Infinitesimals for the " + "first order ODE could not be found") + else: + h = sol[0] # Find infinitesimals for one solution + y = Dummy("y") + h = h.subs(func, y) + + u = Dummy("u") + hx = h.diff(x) + hy = h.diff(y) + hinv = ((1/h).subs([(x, u), (y, x)])).subs(u, y) # Inverse ODE + match = {'h': h, 'func': func, 'hx': hx, 'hy': hy, 'y': y, 'hinv': hinv} + if hint == 'all': + xieta = [] + for heuristic in lie_heuristics: + function = globals()['lie_heuristic_' + heuristic] + inflist = function(match, comp=True) + if inflist: + xieta.extend([inf for inf in inflist if inf not in xieta]) + if xieta: + return xieta + else: + raise NotImplementedError("Infinitesimals could not be found for " + "the given ODE") + + elif hint == 'default': + for heuristic in lie_heuristics: + function = globals()['lie_heuristic_' + heuristic] + xieta = function(match, comp=False) + if xieta: + return xieta + + raise NotImplementedError("Infinitesimals could not be found for" + " the given ODE") + + elif hint not in lie_heuristics: + raise ValueError("Heuristic not recognized: " + hint) + + else: + function = globals()['lie_heuristic_' + hint] + xieta = function(match, comp=True) + if xieta: + return xieta + else: + raise ValueError("Infinitesimals could not be found using the" + " given heuristic") + + +def lie_heuristic_abaco1_simple(match, comp=False): + r""" + The first heuristic uses the following four sets of + assumptions on `\xi` and `\eta` + + .. math:: \xi = 0, \eta = f(x) + + .. math:: \xi = 0, \eta = f(y) + + .. math:: \xi = f(x), \eta = 0 + + .. math:: \xi = f(y), \eta = 0 + + The success of this heuristic is determined by algebraic factorisation. + For the first assumption `\xi = 0` and `\eta` to be a function of `x`, the PDE + + .. math:: \frac{\partial \eta}{\partial x} + (\frac{\partial \eta}{\partial y} + - \frac{\partial \xi}{\partial x})*h + - \frac{\partial \xi}{\partial y}*h^{2} + - \xi*\frac{\partial h}{\partial x} - \eta*\frac{\partial h}{\partial y} = 0 + + reduces to `f'(x) - f\frac{\partial h}{\partial y} = 0` + If `\frac{\partial h}{\partial y}` is a function of `x`, then this can usually + be integrated easily. A similar idea is applied to the other 3 assumptions as well. + + + References + ========== + + - E.S Cheb-Terrab, L.G.S Duarte and L.A,C.P da Mota, Computer Algebra + Solving of First Order ODEs Using Symmetry Methods, pp. 8 + + + """ + + xieta = [] + y = match['y'] + h = match['h'] + func = match['func'] + x = func.args[0] + hx = match['hx'] + hy = match['hy'] + xi = Function('xi')(x, func) + eta = Function('eta')(x, func) + + hysym = hy.free_symbols + if y not in hysym: + try: + fx = exp(integrate(hy, x)) + except NotImplementedError: + pass + else: + inf = {xi: S.Zero, eta: fx} + if not comp: + return [inf] + if comp and inf not in xieta: + xieta.append(inf) + + factor = hy/h + facsym = factor.free_symbols + if x not in facsym: + try: + fy = exp(integrate(factor, y)) + except NotImplementedError: + pass + else: + inf = {xi: S.Zero, eta: fy.subs(y, func)} + if not comp: + return [inf] + if comp and inf not in xieta: + xieta.append(inf) + + 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, eta: S.Zero} + if not comp: + return [inf] + if comp and inf not in xieta: + xieta.append(inf) + + 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: S.Zero} + if not comp: + return [inf] + if comp and inf not in xieta: + xieta.append(inf) + + if xieta: + return xieta + +def lie_heuristic_abaco1_product(match, comp=False): + r""" + The second heuristic uses the following two assumptions on `\xi` and `\eta` + + .. math:: \eta = 0, \xi = f(x)*g(y) + + .. math:: \eta = f(x)*g(y), \xi = 0 + + The first assumption of this heuristic holds good if + `\frac{1}{h^{2}}\frac{\partial^2}{\partial x \partial y}\log(h)` is + separable in `x` and `y`, then the separated factors containing `x` + is `f(x)`, and `g(y)` is obtained by + + .. math:: e^{\int f\frac{\partial}{\partial x}\left(\frac{1}{f*h}\right)\,dy} + + provided `f\frac{\partial}{\partial x}\left(\frac{1}{f*h}\right)` is a function + of `y` only. + + The second assumption holds good if `\frac{dy}{dx} = h(x, y)` is rewritten as + `\frac{dy}{dx} = \frac{1}{h(y, x)}` and the same properties of the first assumption + satisfies. After obtaining `f(x)` and `g(y)`, the coordinates are again + interchanged, to get `\eta` as `f(x)*g(y)` + + + References + ========== + - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order + ODE Patterns, pp. 7 - pp. 8 + + """ + + xieta = [] + y = match['y'] + h = match['h'] + hinv = match['hinv'] + func = match['func'] + x = func.args[0] + xi = Function('xi')(x, func) + eta = Function('eta')(x, func) + + + inf = separatevars(((log(h).diff(y)).diff(x))/h**2, dict=True, symbols=[x, y]) + if inf and inf['coeff']: + fx = inf[x] + gy = simplify(fx*((1/(fx*h)).diff(x))) + gysyms = gy.free_symbols + if x not in gysyms: + gy = exp(integrate(gy, y)) + inf = {eta: S.Zero, xi: (fx*gy).subs(y, func)} + if not comp: + return [inf] + if comp and inf not in xieta: + xieta.append(inf) + + u1 = Dummy("u1") + inf = separatevars(((log(hinv).diff(y)).diff(x))/hinv**2, dict=True, symbols=[x, y]) + if inf and inf['coeff']: + fx = inf[x] + gy = simplify(fx*((1/(fx*hinv)).diff(x))) + gysyms = gy.free_symbols + if x not in gysyms: + gy = exp(integrate(gy, y)) + etaval = fx*gy + etaval = (etaval.subs([(x, u1), (y, x)])).subs(u1, y) + inf = {eta: etaval.subs(y, func), xi: S.Zero} + if not comp: + return [inf] + if comp and inf not in xieta: + xieta.append(inf) + + if xieta: + return xieta + +def lie_heuristic_bivariate(match, comp=False): + r""" + 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 + bivariate polynomials. The coefficients of the infinitesimals + are found out by substituting them in the PDE and grouping similar terms + that are polynomials and since they form a linear system, solve and check + for non trivial solutions. The degree of the assumed bivariates + are increased till a certain maximum value. + + References + ========== + - Lie Groups and Differential Equations + pp. 327 - pp. 329 + + """ + + h = match['h'] + hx = match['hx'] + hy = match['hy'] + func = match['func'] + x = func.args[0] + y = match['y'] + xi = Function('xi')(x, func) + eta = Function('eta')(x, func) + + if h.is_rational_function(): + # The maximum degree that the infinitesimals can take is + # calculated by this technique. + etax, etay, etad, xix, xiy, xid = symbols("etax etay etad xix xiy xid") + ipde = etax + (etay - xix)*h - xiy*h**2 - xid*hx - etad*hy + num, denom = cancel(ipde).as_numer_denom() + deg = Poly(num, x, y).total_degree() + 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) - {x, y} + soldict = solve(polyy.values(), *symset) + if isinstance(soldict, list): + soldict = soldict[0] + if any(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.fromkeys(symset, 1) + inf = {eta: etared.subs(dict_).subs(y, func), + xi: xired.subs(dict_).subs(y, func)} + return [inf] + +def lie_heuristic_chi(match, comp=False): + r""" + The aim of the fourth heuristic is to find the function `\chi(x, y)` + that satisfies the PDE `\frac{d\chi}{dx} + h\frac{d\chi}{dx} + - \frac{\partial h}{\partial y}\chi = 0`. + + This assumes `\chi` to be a bivariate polynomial in `x` and `y`. By intuition, + `h` should be a rational function in `x` and `y`. The method used here is + to substitute a general binomial for `\chi` up to a certain maximum degree + is reached. The coefficients of the polynomials, are calculated by by collecting + terms of the same order in `x` and `y`. + + After finding `\chi`, the next step is to use `\eta = \xi*h + \chi`, to + determine `\xi` and `\eta`. This can be done by dividing `\chi` by `h` + which would give `-\xi` as the quotient and `\eta` as the remainder. + + + References + ========== + - E.S Cheb-Terrab, L.G.S Duarte and L.A,C.P da Mota, Computer Algebra + Solving of First Order ODEs Using Symmetry Methods, pp. 8 + + """ + + h = match['h'] + hy = match['hy'] + func = match['func'] + x = func.args[0] + y = match['y'] + xi = Function('xi')(x, func) + eta = Function('eta')(x, func) + + if h.is_rational_function(): + schi, schix, schiy = symbols("schi, schix, schiy") + cpde = schix + h*schiy - hy*schi + num, denom = cancel(cpde).as_numer_denom() + deg = Poly(num, x, y).total_degree() + + chi = Function('chi')(x, y) + chix = chi.diff(x) + chiy = chi.diff(y) + cpde = chix + h*chiy - hy*chi + chieq = Symbol("chi") + for i in range(1, deg + 1): + chieq += Add(*[ + Symbol("chi_" + str(power) + "_" + str(i - power))*x**power*y**(i - power) + for power in range(i + 1)]) + cnum, cden = cancel(cpde.subs({chi : chieq}).doit()).as_numer_denom() + cnum = expand(cnum) + if cnum.is_polynomial(x, y) and cnum.is_Add: + cpoly = Poly(cnum, x, y).as_dict() + if cpoly: + solsyms = chieq.free_symbols - {x, y} + soldict = solve(cpoly.values(), *solsyms) + if isinstance(soldict, list): + soldict = soldict[0] + if any(soldict.values()): + chieq = chieq.subs(soldict) + dict_ = dict.fromkeys(solsyms, 1) + chieq = chieq.subs(dict_) + # After finding chi, the main aim is to find out + # eta, xi by the equation eta = xi*h + chi + # One method to set xi, would be rearranging it to + # (eta/h) - xi = (chi/h). This would mean dividing + # chi by h would give -xi as the quotient and eta + # as the remainder. Thanks to Sean Vig for suggesting + # this method. + xic, etac = div(chieq, h) + inf = {eta: etac.subs(y, func), xi: -xic.subs(y, func)} + return [inf] + +def lie_heuristic_function_sum(match, comp=False): + r""" + This heuristic uses the following two assumptions on `\xi` and `\eta` + + .. math:: \eta = 0, \xi = f(x) + g(y) + + .. math:: \eta = f(x) + g(y), \xi = 0 + + The first assumption of this heuristic holds good if + + .. math:: \frac{\partial}{\partial y}[(h\frac{\partial^{2}}{ + \partial x^{2}}(h^{-1}))^{-1}] + + is separable in `x` and `y`, + + 1. The separated factors containing `y` is `\frac{\partial g}{\partial y}`. + From this `g(y)` can be determined. + 2. The separated factors containing `x` is `f''(x)`. + 3. `h\frac{\partial^{2}}{\partial x^{2}}(h^{-1})` equals + `\frac{f''(x)}{f(x) + g(y)}`. From this `f(x)` can be determined. + + The second assumption holds good if `\frac{dy}{dx} = h(x, y)` is rewritten as + `\frac{dy}{dx} = \frac{1}{h(y, x)}` and the same properties of the first + assumption satisfies. After obtaining `f(x)` and `g(y)`, the coordinates + are again interchanged, to get `\eta` as `f(x) + g(y)`. + + For both assumptions, the constant factors are separated among `g(y)` + and `f''(x)`, such that `f''(x)` obtained from 3] is the same as that + obtained from 2]. If not possible, then this heuristic fails. + + + References + ========== + - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order + ODE Patterns, pp. 7 - pp. 8 + + """ + + xieta = [] + h = match['h'] + func = match['func'] + hinv = match['hinv'] + x = func.args[0] + y = match['y'] + xi = Function('xi')(x, func) + eta = Function('eta')(x, func) + + for odefac in [h, hinv]: + factor = odefac*((1/odefac).diff(x, 2)) + sep = separatevars((1/factor).diff(y), dict=True, symbols=[x, y]) + if sep and sep['coeff'] and sep[x].has(x) and sep[y].has(y): + k = Dummy("k") + try: + gy = k*integrate(sep[y], y) + except NotImplementedError: + pass + else: + fdd = 1/(k*sep[x]*sep['coeff']) + fx = simplify(fdd/factor - gy) + check = simplify(fx.diff(x, 2) - fdd) + if fx: + if not check: + fx = fx.subs(k, 1) + gy = (gy/k) + else: + sol = solve(check, k) + if sol: + sol = sol[0] + fx = fx.subs(k, sol) + gy = (gy/k)*sol + else: + continue + if odefac == hinv: # Inverse ODE + fx = fx.subs(x, y) + gy = gy.subs(y, x) + etaval = factor_terms(fx + gy) + if etaval.is_Mul: + etaval = Mul(*[arg for arg in etaval.args if arg.has(x, y)]) + if odefac == hinv: # Inverse ODE + inf = {eta: etaval.subs(y, func), xi : S.Zero} + else: + inf = {xi: etaval.subs(y, func), eta : S.Zero} + if not comp: + return [inf] + else: + xieta.append(inf) + + if xieta: + return xieta + +def lie_heuristic_abaco2_similar(match, comp=False): + r""" + This heuristic uses the following two assumptions on `\xi` and `\eta` + + .. math:: \eta = g(x), \xi = f(x) + + .. math:: \eta = f(y), \xi = g(y) + + For the first assumption, + + 1. First `\frac{\frac{\partial h}{\partial y}}{\frac{\partial^{2} h}{ + \partial yy}}` is calculated. Let us say this value is A + + 2. If this is constant, then `h` is matched to the form `A(x) + B(x)e^{ + \frac{y}{C}}` then, `\frac{e^{\int \frac{A(x)}{C} \,dx}}{B(x)}` gives `f(x)` + and `A(x)*f(x)` gives `g(x)` + + 3. Otherwise `\frac{\frac{\partial A}{\partial X}}{\frac{\partial A}{ + \partial Y}} = \gamma` is calculated. If + + a] `\gamma` is a function of `x` alone + + b] `\frac{\gamma\frac{\partial h}{\partial y} - \gamma'(x) - \frac{ + \partial h}{\partial x}}{h + \gamma} = G` is a function of `x` alone. + then, `e^{\int G \,dx}` gives `f(x)` and `-\gamma*f(x)` gives `g(x)` + + The second assumption holds good if `\frac{dy}{dx} = h(x, y)` is rewritten as + `\frac{dy}{dx} = \frac{1}{h(y, x)}` and the same properties of the first assumption + satisfies. After obtaining `f(x)` and `g(x)`, the coordinates are again + interchanged, to get `\xi` as `f(x^*)` and `\eta` as `g(y^*)` + + References + ========== + - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order + ODE Patterns, pp. 10 - pp. 12 + + """ + + h = match['h'] + hx = match['hx'] + hy = match['hy'] + func = match['func'] + hinv = match['hinv'] + x = func.args[0] + y = match['y'] + xi = Function('xi')(x, func) + eta = Function('eta')(x, func) + + factor = cancel(h.diff(y)/h.diff(y, 2)) + factorx = factor.diff(x) + factory = factor.diff(y) + if not factor.has(x) and not factor.has(y): + A = Wild('A', exclude=[y]) + B = Wild('B', exclude=[y]) + C = Wild('C', exclude=[x, y]) + match = h.match(A + B*exp(y/C)) + try: + tau = exp(-integrate(match[A]/match[C]), x)/match[B] + except NotImplementedError: + pass + else: + gx = match[A]*tau + return [{xi: tau, eta: gx}] + + else: + gamma = cancel(factorx/factory) + if not gamma.has(y): + tauint = cancel((gamma*hy - gamma.diff(x) - hx)/(h + gamma)) + if not tauint.has(y): + try: + tau = exp(integrate(tauint, x)) + except NotImplementedError: + pass + else: + gx = -tau*gamma + return [{xi: tau, eta: gx}] + + factor = cancel(hinv.diff(y)/hinv.diff(y, 2)) + factorx = factor.diff(x) + factory = factor.diff(y) + if not factor.has(x) and not factor.has(y): + A = Wild('A', exclude=[y]) + B = Wild('B', exclude=[y]) + C = Wild('C', exclude=[x, y]) + match = h.match(A + B*exp(y/C)) + try: + tau = exp(-integrate(match[A]/match[C]), x)/match[B] + except NotImplementedError: + pass + else: + gx = match[A]*tau + return [{eta: tau.subs(x, func), xi: gx.subs(x, func)}] + + else: + gamma = cancel(factorx/factory) + if not gamma.has(y): + tauint = cancel((gamma*hinv.diff(y) - gamma.diff(x) - hinv.diff(x))/( + hinv + gamma)) + if not tauint.has(y): + try: + tau = exp(integrate(tauint, x)) + except NotImplementedError: + pass + else: + gx = -tau*gamma + return [{eta: tau.subs(x, func), xi: gx.subs(x, func)}] + + +def lie_heuristic_abaco2_unique_unknown(match, comp=False): + r""" + This heuristic assumes the presence of unknown functions or known functions + with non-integer powers. + + 1. A list of all functions and non-integer powers containing x and y + 2. Loop over each element `f` in the list, find `\frac{\frac{\partial f}{\partial x}}{ + \frac{\partial f}{\partial x}} = R` + + If it is separable in `x` and `y`, let `X` be the factors containing `x`. Then + + a] Check if `\xi = X` and `\eta = -\frac{X}{R}` satisfy the PDE. If yes, then return + `\xi` and `\eta` + b] Check if `\xi = \frac{-R}{X}` and `\eta = -\frac{1}{X}` satisfy the PDE. + If yes, then return `\xi` and `\eta` + + If not, then check if + + a] :math:`\xi = -R,\eta = 1` + + b] :math:`\xi = 1, \eta = -\frac{1}{R}` + + are solutions. + + References + ========== + - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order + ODE Patterns, pp. 10 - pp. 12 + + """ + + h = match['h'] + hx = match['hx'] + hy = match['hy'] + func = match['func'] + x = func.args[0] + y = match['y'] + xi = Function('xi')(x, func) + eta = Function('eta')(x, func) + + funclist = [] + for atom in h.atoms(Pow): + base, exp = atom.as_base_exp() + if base.has(x) and base.has(y): + if not exp.is_Integer: + funclist.append(atom) + + for function in h.atoms(AppliedUndef): + syms = function.free_symbols + if x in syms and y in syms: + funclist.append(function) + + for f in funclist: + frac = cancel(f.diff(y)/f.diff(x)) + sep = separatevars(frac, dict=True, symbols=[x, y]) + if sep and sep['coeff']: + xitry1 = sep[x] + etatry1 = -1/(sep[y]*sep['coeff']) + pde1 = etatry1.diff(y)*h - xitry1.diff(x)*h - xitry1*hx - etatry1*hy + if not simplify(pde1): + return [{xi: xitry1, eta: etatry1.subs(y, func)}] + xitry2 = 1/etatry1 + etatry2 = 1/xitry1 + pde2 = etatry2.diff(x) - (xitry2.diff(y))*h**2 - xitry2*hx - etatry2*hy + if not simplify(expand(pde2)): + return [{xi: xitry2.subs(y, func), eta: etatry2}] + + else: + etatry = -1/frac + pde = etatry.diff(x) + etatry.diff(y)*h - hx - etatry*hy + if not simplify(pde): + return [{xi: S.One, eta: etatry.subs(y, func)}] + xitry = -frac + pde = -xitry.diff(x)*h -xitry.diff(y)*h**2 - xitry*hx -hy + if not simplify(expand(pde)): + return [{xi: xitry.subs(y, func), eta: S.One}] + + +def lie_heuristic_abaco2_unique_general(match, comp=False): + r""" + This heuristic finds if infinitesimals of the form `\eta = f(x)`, `\xi = g(y)` + without making any assumptions on `h`. + + The complete sequence of steps is given in the paper mentioned below. + + References + ========== + - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order + ODE Patterns, pp. 10 - pp. 12 + + """ + hx = match['hx'] + hy = match['hy'] + func = match['func'] + x = func.args[0] + y = match['y'] + xi = Function('xi')(x, func) + eta = Function('eta')(x, func) + + A = hx.diff(y) + B = hy.diff(y) + hy**2 + C = hx.diff(x) - hx**2 + + if not (A and B and C): + return + + Ax = A.diff(x) + Ay = A.diff(y) + Axy = Ax.diff(y) + Axx = Ax.diff(x) + Ayy = Ay.diff(y) + D = simplify(2*Axy + hx*Ay - Ax*hy + (hx*hy + 2*A)*A)*A - 3*Ax*Ay + if not D: + E1 = simplify(3*Ax**2 + ((hx**2 + 2*C)*A - 2*Axx)*A) + if E1: + E2 = simplify((2*Ayy + (2*B - hy**2)*A)*A - 3*Ay**2) + if not E2: + E3 = simplify( + E1*((28*Ax + 4*hx*A)*A**3 - E1*(hy*A + Ay)) - E1.diff(x)*8*A**4) + if not E3: + etaval = cancel((4*A**3*(Ax - hx*A) + E1*(hy*A - Ay))/(S(2)*A*E1)) + if x not in etaval: + try: + etaval = exp(integrate(etaval, y)) + except NotImplementedError: + pass + else: + xival = -4*A**3*etaval/E1 + if y not in xival: + return [{xi: xival, eta: etaval.subs(y, func)}] + + else: + E1 = simplify((2*Ayy + (2*B - hy**2)*A)*A - 3*Ay**2) + if E1: + E2 = simplify( + 4*A**3*D - D**2 + E1*((2*Axx - (hx**2 + 2*C)*A)*A - 3*Ax**2)) + if not E2: + E3 = simplify( + -(A*D)*E1.diff(y) + ((E1.diff(x) - hy*D)*A + 3*Ay*D + + (A*hx - 3*Ax)*E1)*E1) + if not E3: + etaval = cancel(((A*hx - Ax)*E1 - (Ay + A*hy)*D)/(S(2)*A*D)) + if x not in etaval: + try: + etaval = exp(integrate(etaval, y)) + except NotImplementedError: + pass + else: + xival = -E1*etaval/D + if y not in xival: + return [{xi: xival, eta: etaval.subs(y, func)}] + + +def lie_heuristic_linear(match, comp=False): + r""" + This heuristic assumes + + 1. `\xi = ax + by + c` and + 2. `\eta = fx + gy + h` + + After substituting the following assumptions in the determining PDE, it + reduces to + + .. math:: f + (g - a)h - bh^{2} - (ax + by + c)\frac{\partial h}{\partial x} + - (fx + gy + c)\frac{\partial h}{\partial y} + + Solving the reduced PDE obtained, using the method of characteristics, becomes + impractical. The method followed is grouping similar terms and solving the system + of linear equations obtained. The difference between the bivariate heuristic is that + `h` need not be a rational function in this case. + + References + ========== + - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order + ODE Patterns, pp. 10 - pp. 12 + + """ + h = match['h'] + hx = match['hx'] + hy = match['hy'] + func = match['func'] + x = func.args[0] + y = match['y'] + xi = Function('xi')(x, func) + eta = Function('eta')(x, func) + + coeffdict = {} + symbols = numbered_symbols("c", cls=Dummy) + symlist = [next(symbols) for _ in islice(symbols, 6)] + C0, C1, C2, C3, C4, C5 = symlist + pde = C3 + (C4 - C0)*h - (C0*x + C1*y + C2)*hx - (C3*x + C4*y + C5)*hy - C1*h**2 + pde, denom = pde.as_numer_denom() + pde = powsimp(expand(pde)) + if pde.is_Add: + terms = pde.args + for term in terms: + if term.is_Mul: + rem = Mul(*[m for m in term.args if not m.has(x, y)]) + xypart = term/rem + if xypart not in coeffdict: + coeffdict[xypart] = rem + else: + coeffdict[xypart] += rem + else: + if term not in coeffdict: + coeffdict[term] = S.One + else: + coeffdict[term] += S.One + + sollist = coeffdict.values() + soldict = solve(sollist, symlist) + if soldict: + if isinstance(soldict, list): + soldict = soldict[0] + subval = soldict.values() + if any(t for t in subval): + onedict = dict(zip(symlist, [1]*6)) + xival = C0*x + C1*func + C2 + etaval = C3*x + C4*func + C5 + xival = xival.subs(soldict) + etaval = etaval.subs(soldict) + xival = xival.subs(onedict) + etaval = etaval.subs(onedict) + return [{xi: xival, eta: etaval}] + + +def _lie_group_remove(coords): + r""" + This function is strictly meant for internal use by the Lie group ODE solving + method. It replaces arbitrary functions returned by pdsolve as follows: + + 1] If coords is an arbitrary function, then its argument is returned. + 2] An arbitrary function in an Add object is replaced by zero. + 3] An arbitrary function in a Mul object is replaced by one. + 4] If there is no arbitrary function coords is returned unchanged. + + Examples + ======== + + >>> from sympy.solvers.ode.lie_group import _lie_group_remove + >>> from sympy import Function + >>> from sympy.abc import x, y + >>> F = Function("F") + >>> eq = x**2*y + >>> _lie_group_remove(eq) + x**2*y + >>> eq = F(x**2*y) + >>> _lie_group_remove(eq) + x**2*y + >>> eq = x*y**2 + F(x**3) + >>> _lie_group_remove(eq) + x*y**2 + >>> eq = (F(x**3) + y)*x**4 + >>> _lie_group_remove(eq) + x**4*y + + """ + if isinstance(coords, AppliedUndef): + return coords.args[0] + elif coords.is_Add: + subfunc = coords.atoms(AppliedUndef) + if subfunc: + for func in subfunc: + coords = coords.subs(func, 0) + return coords + elif coords.is_Pow: + base, expr = coords.as_base_exp() + base = _lie_group_remove(base) + expr = _lie_group_remove(expr) + return base**expr + elif coords.is_Mul: + mulargs = [] + coordargs = coords.args + for arg in coordargs: + if not isinstance(coords, AppliedUndef): + mulargs.append(_lie_group_remove(arg)) + return Mul(*mulargs) + return coords diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/nonhomogeneous.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/nonhomogeneous.py new file mode 100644 index 0000000000000000000000000000000000000000..ae39d55664e4850168ca7d68f65cf02171979957 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/nonhomogeneous.py @@ -0,0 +1,484 @@ +r""" +This File contains helper functions for nth_linear_constant_coeff_undetermined_coefficients, +nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients, +nth_linear_constant_coeff_variation_of_parameters, +and nth_linear_euler_eq_nonhomogeneous_variation_of_parameters. + +All the functions in this file are used by more than one solvers so, instead of creating +instances in other classes for using them it is better to keep it here as separate helpers. + +""" +from collections import Counter +from sympy.core import Add, S +from sympy.core.function import diff, expand, _mexpand, expand_mul +from sympy.core.relational import Eq +from sympy.core.sorting import default_sort_key +from sympy.core.symbol import Dummy, Wild +from sympy.functions import exp, cos, cosh, im, log, re, sin, sinh, \ + atan2, conjugate +from sympy.integrals import Integral +from sympy.polys import (Poly, RootOf, rootof, roots) +from sympy.simplify import collect, simplify, separatevars, powsimp, trigsimp # type: ignore +from sympy.utilities import numbered_symbols +from sympy.solvers.solvers import solve +from sympy.matrices import wronskian +from .subscheck import sub_func_doit +from sympy.solvers.ode.ode import get_numbered_constants + + +def _test_term(coeff, func, order): + r""" + Linear Euler ODEs have the form K*x**order*diff(y(x), x, order) = F(x), + 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. + """ + x = func.args[0] + f = func.func + if order < 0: + raise ValueError("order should be greater than 0") + if coeff == 0: + return True + if order == 0: + if x in coeff.free_symbols: + return False + return True + 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 + + +def _get_euler_characteristic_eq_sols(eq, func, match_obj): + r""" + Returns the solution of homogeneous part of the linear euler ODE and + the list of roots of characteristic equation. + + The parameter ``match_obj`` is 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. + + """ + x = func.args[0] + f = func.func + + # First, set up characteristic equation. + chareq, symbol = S.Zero, Dummy('x') + + for i in match_obj: + if i >= 0: + chareq += (match_obj[i]*diff(x**symbol, x, i)*x**-symbol).expand() + + chareq = Poly(chareq, symbol) + chareqroots = [rootof(chareq, k) for k in range(chareq.degree())] + collectterms = [] + + # A generator of constants + constants = list(get_numbered_constants(eq, num=chareq.degree()*2)) + constants.reverse() + + # Create a dict root: multiplicity or charroots + charroots = Counter(chareqroots) + gsol = S.Zero + ln = log + for root, multiplicity in charroots.items(): + for i in range(multiplicity): + if isinstance(root, RootOf): + gsol += (x**root) * constants.pop() + if multiplicity != 1: + raise ValueError("Value should be 1") + collectterms = [(0, root, 0)] + collectterms + elif root.is_real: + gsol += ln(x)**i*(x**root) * constants.pop() + collectterms = [(i, root, 0)] + collectterms + else: + reroot = re(root) + imroot = im(root) + gsol += ln(x)**i * (x**reroot) * ( + constants.pop() * sin(abs(imroot)*ln(x)) + + constants.pop() * cos(imroot*ln(x))) + collectterms = [(i, reroot, imroot)] + collectterms + + gsol = Eq(f(x), gsol) + + 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) + return gsol, gensols + + +def _solve_variation_of_parameters(eq, func, roots, homogen_sol, order, match_obj, simplify_flag=True): + r""" + Helper function for the method of variation of parameters and nonhomogeneous euler eq. + + See the + :py:meth:`~sympy.solvers.ode.single.NthLinearConstantCoeffVariationOfParameters` + docstring for more information on this method. + + The parameter are ``match_obj`` should be a dictionary that has the following + keys: + + ``list`` + A list of solutions to the homogeneous equation. + + ``sol`` + The general solution. + + """ + f = func.func + x = func.args[0] + r = match_obj + psol = 0 + wr = wronskian(roots, x) + + if simplify_flag: + wr = simplify(wr) # We need much better simplification for + # some ODEs. See issue 4662, for example. + # To reduce commonly occurring 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 necessary to apply " + + "variation of parameters to " + str(eq) + " (Wronskian == 0)") + if len(roots) != order: + raise NotImplementedError("Cannot find " + str(order) + + " solutions to the homogeneous equation necessary to apply " + + "variation of parameters to " + + str(eq) + " (number of terms != order)") + negoneterm = S.NegativeOne**(order) + for i in roots: + psol += negoneterm*Integral(wronskian([sol for sol in roots if sol != i], x)*r[-1]/wr, x)*i/r[order] + negoneterm *= -1 + + if simplify_flag: + psol = simplify(psol) + psol = trigsimp(psol, deep=True) + return Eq(f(x), homogen_sol.rhs + psol) + + +def _get_const_characteristic_eq_sols(r, func, order): + r""" + Returns the roots of characteristic equation of constant coefficient + linear ODE and list of collectterms which is later on used by simplification + to use collect on solution. + + The parameter `r` is 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. + + """ + x = func.args[0] + # First, set up characteristic equation. + chareq, symbol = S.Zero, Dummy('x') + + for i in r.keys(): + if isinstance(i, str) or i < 0: + pass + else: + chareq += r[i]*symbol**i + + chareq = Poly(chareq, symbol) + # Can't just call roots because it doesn't return rootof for unsolveable + # polynomials. + chareqroots = roots(chareq, multiple=True) + if len(chareqroots) != order: + chareqroots = [rootof(chareq, k) for k in range(chareq.degree())] + + chareq_is_complex = not all(i.is_real for i in chareq.all_coeffs()) + + # Create a dict root: multiplicity or charroots + charroots = Counter(chareqroots) + # We need to keep track of terms so we can run collect() at the end. + # This is necessary for constantsimp to work properly. + collectterms = [] + gensols = [] + conjugate_roots = [] # used to prevent double-use of conjugate roots + # Loop over roots in theorder provided by roots/rootof... + for root in chareqroots: + # but don't repoeat multiple roots. + if root not in charroots: + continue + multiplicity = charroots.pop(root) + for i in range(multiplicity): + if chareq_is_complex: + gensols.append(x**i*exp(root*x)) + collectterms = [(i, root, 0)] + collectterms + continue + reroot = re(root) + imroot = im(root) + if imroot.has(atan2) and reroot.has(atan2): + # Remove this condition when re and im stop returning + # circular atan2 usages. + gensols.append(x**i*exp(root*x)) + collectterms = [(i, root, 0)] + collectterms + else: + if root in conjugate_roots: + collectterms = [(i, reroot, imroot)] + collectterms + continue + if imroot == 0: + gensols.append(x**i*exp(reroot*x)) + collectterms = [(i, reroot, 0)] + collectterms + continue + conjugate_roots.append(conjugate(root)) + gensols.append(x**i*exp(reroot*x) * sin(abs(imroot) * x)) + gensols.append(x**i*exp(reroot*x) * cos( imroot * x)) + + # This ordering is important + collectterms = [(i, reroot, imroot)] + collectterms + return gensols, collectterms + + +# Ideally these kind of simplification functions shouldn't be part of solvers. +# odesimp should be improved to handle these kind of specific simplifications. +def _get_simplified_sol(sol, func, collectterms): + r""" + Helper function which collects the solution on + collectterms. Ideally this should be handled by odesimp.It is used + only when the simplify is set to True in dsolve. + + The parameter ``collectterms`` is a list of tuple (i, reroot, imroot) where `i` is + the multiplicity of the root, reroot is real part and imroot being the imaginary part. + + """ + f = func.func + x = func.args[0] + collectterms.sort(key=default_sort_key) + collectterms.reverse() + assert len(sol) == 1 and sol[0].lhs == f(x) + sol = sol[0].rhs + sol = expand_mul(sol) + for i, reroot, imroot in collectterms: + sol = collect(sol, x**i*exp(reroot*x)*sin(abs(imroot)*x)) + sol = collect(sol, x**i*exp(reroot*x)*cos(imroot*x)) + for i, reroot, imroot in collectterms: + sol = collect(sol, x**i*exp(reroot*x)) + sol = powsimp(sol) + return Eq(f(x), sol) + + +def _undetermined_coefficients_match(expr, x, func=None, eq_homogeneous=S.Zero): + 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 + `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. + + This is intended for internal use by ``undetermined_coefficients`` hints. + + 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 + ======== + + >>> from sympy import log, exp + >>> from sympy.solvers.ode.nonhomogeneous import _undetermined_coefficients_match + >>> from sympy.abc import x + >>> _undetermined_coefficients_match(9*x*exp(x) + exp(-x), x) + {'test': True, 'trialset': {x*exp(x), exp(-x), exp(x)}} + >>> _undetermined_coefficients_match(log(x), x) + {'test': False} + + """ + 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) + retdict = {} + + def _test_term(expr, x) -> bool: + r""" + Test if ``expr`` fits the proper form for undetermined coefficients. + """ + if not expr.has(x): + return True + if expr.is_Add: + return all(_test_term(i, x) for i in expr.args) + if expr.is_Mul: + if expr.has(sin, cos): + foundtrig = False + # Make sure that there is only one trig function in the args. + # See the docstring. + for i in expr.args: + if i.has(sin, cos): + if foundtrig: + return False + else: + foundtrig = True + return all(_test_term(i, x) for i in expr.args) + if expr.is_Function: + return expr.func in (sin, cos, exp, sinh, cosh) and \ + bool(expr.args[0].match(a*x + b)) + if expr.is_Pow and expr.base.is_Symbol and expr.exp.is_Integer and \ + expr.exp >= 0: + return True + if expr.is_Pow and expr.base.is_number: + return bool(expr.exp.match(a*x + b)) + return expr.is_Symbol or bool(expr.is_number) + + 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. + """ + def _remove_coefficient(expr, x): + r""" + Returns the expression without a coefficient. + + Similar to expr.as_independent(x)[1], except it only works + multiplicatively. + """ + term = S.One + if expr.is_Mul: + for i in expr.args: + if i.has(x): + term *= i + elif expr.has(x): + term = expr + return term + + expr = expand_mul(expr) + if expr.is_Add: + for term in expr.args: + if _remove_coefficient(term, x) in exprs: + pass + else: + exprs.add(_remove_coefficient(term, x)) + exprs = exprs.union(_get_trial_set(term, x, exprs)) + else: + term = _remove_coefficient(expr, x) + tmpset = exprs.union({term}) + oldset = set() + while tmpset != oldset: + # 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) + if term.is_Add: + tmpset = tmpset.union(_get_trial_set(term, x, tmpset)) + else: + tmpset.add(term) + exprs = tmpset + return exprs + + def is_homogeneous_solution(term): + r""" This function checks whether the given trialset contains any root + of homogeneous equation""" + return expand(sub_func_doit(eq_homogeneous, func, term)).is_zero + + 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). + temp_set = set() + for i in Add.make_args(expr): + act = _get_trial_set(i, x) + if eq_homogeneous is not S.Zero: + while any(is_homogeneous_solution(ts) for ts in act): + act = {x*ts for ts in act} + temp_set = temp_set.union(act) + + retdict['trialset'] = temp_set + return retdict + + +def _solve_undetermined_coefficients(eq, func, order, match, trialset): + r""" + Helper function for the method of undetermined coefficients. + + See the + :py:meth:`~sympy.solvers.ode.single.NthLinearConstantCoeffUndeterminedCoefficients` + docstring for more information on this method. + + The parameter ``trialset`` is 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. + + ``sol`` + The general solution. + + """ + r = match + coeffs = numbered_symbols('a', cls=Dummy) + coefflist = [] + gensols = r['list'] + gsol = r['sol'] + f = func.func + x = func.args[0] + + if len(gensols) != order: + raise NotImplementedError("Cannot find " + str(order) + + " solutions to the homogeneous equation necessary to apply" + + " undetermined coefficients to " + str(eq) + + " (number of terms != order)") + + trialfunc = 0 + for i in trialset: + c = next(coeffs) + coefflist.append(c) + trialfunc += c*i + + eqs = sub_func_doit(eq, f(x), trialfunc) + + coeffsdict = dict(list(zip(trialset, [0]*(len(trialset) + 1)))) + + eqs = _mexpand(eqs) + + for i in Add.make_args(eqs): + s = separatevars(i, dict=True, symbols=[x]) + if coeffsdict.get(s[x]): + coeffsdict[s[x]] += s['coeff'] + else: + coeffsdict[s[x]] = s['coeff'] + + coeffvals = solve(list(coeffsdict.values()), coefflist) + + if not coeffvals: + 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) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/ode.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/ode.py new file mode 100644 index 0000000000000000000000000000000000000000..6a28b2162b38a2dd8612c14e91fd588912f6756a --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/ode.py @@ -0,0 +1,3572 @@ +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: + + - :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. + - :py:meth:`~sympy.solvers.ode.infinitesimals` - Returns the infinitesimals + of the Lie group of point transformations of an ODE, such that it is + invariant. + - :py:meth:`~sympy.solvers.ode.checkinfsol` - Checks if the given infinitesimals + are the actual infinitesimals of a first order ODE. + + 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.ode.odesimp` - Does all forms of ODE + simplification. + - :py:meth:`~sympy.solvers.ode.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.ode.constant_renumber` - Renumber arbitrary + constants. + - :py:meth:`~sympy.solvers.ode.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 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 exact differential equations. + - 1st order linear differential equations. + - 1st order Bernoulli differential equations. + - Power series solutions for first order differential equations. + - Lie Group method of solving first order differential equations. + - 2nd order Liouville differential equations. + - Power series solutions for second order differential equations + at ordinary and regular singular points. + - `n`\th order differential equation that can be solved with algebraic + rearrangement and integration. + - `n`\th order linear homogeneous differential equation with constant + coefficients. + - `n`\th order linear inhomogeneous differential equation with constant + coefficients using the method of undetermined coefficients. + - `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 :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.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.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 :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 +:obj:`~sympy.solvers.ode.single.HomogeneousCoeffBest`, 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 does not 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. 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:obj:`~.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.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_()`` function. :py:meth:`~sympy.solvers.ode.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.ode.odesimp` for it. For +example, solutions returned from the ``1st_homogeneous_coeff`` hints often +have many :obj:`~sympy.functions.elementary.exponential.log` terms, so +:py:meth:`~sympy.solvers.ode.ode.odesimp` calls +:py:meth:`~sympy.simplify.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 +:py:meth:`~sympy.solvers.ode.constantsimp` take better advantage of it. It is +better to put simplification in :py:meth:`~sympy.solvers.ode.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/does not work). Be sure to call your +hint specifically in :py:meth:`~sympy.solvers.ode.dsolve`, that way the test +will not 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 sympy.core import Add, S, Mul, Pow, oo +from sympy.core.containers import Tuple +from sympy.core.expr import AtomicExpr, Expr +from sympy.core.function import (Function, Derivative, AppliedUndef, diff, + expand, expand_mul, Subs) +from sympy.core.multidimensional import vectorize +from sympy.core.numbers import nan, zoo, Number +from sympy.core.relational import Equality, Eq +from sympy.core.sorting import default_sort_key, ordered +from sympy.core.symbol import Symbol, Wild, Dummy, symbols +from sympy.core.sympify import sympify +from sympy.core.traversal import preorder_traversal + +from sympy.logic.boolalg import (BooleanAtom, BooleanTrue, + BooleanFalse) +from sympy.functions import exp, log, sqrt +from sympy.functions.combinatorial.factorials import factorial +from sympy.integrals.integrals import Integral +from sympy.polys import (Poly, terms_gcd, PolynomialError, lcm) +from sympy.polys.polytools import cancel +from sympy.series import Order +from sympy.series.series import series +from sympy.simplify import (collect, logcombine, powsimp, # type: ignore + separatevars, simplify, cse) +from sympy.simplify.radsimp import collect_const +from sympy.solvers import checksol, solve + +from sympy.utilities import numbered_symbols +from sympy.utilities.iterables import uniq, sift, iterable +from sympy.solvers.deutils import _preprocess, ode_order, _desolve + + +#: 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 = ( + "factorable", + "nth_algebraic", + "separable", + "1st_exact", + "1st_linear", + "Bernoulli", + "1st_rational_riccati", + "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", + "1st_power_series", + "lie_group", + "nth_linear_constant_coeff_homogeneous", + "nth_linear_euler_eq_homogeneous", + "nth_linear_constant_coeff_undetermined_coefficients", + "nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients", + "nth_linear_constant_coeff_variation_of_parameters", + "nth_linear_euler_eq_nonhomogeneous_variation_of_parameters", + "Liouville", + "2nd_linear_airy", + "2nd_linear_bessel", + "2nd_hypergeometric", + "2nd_hypergeometric_Integral", + "nth_order_reducible", + "2nd_power_series_ordinary", + "2nd_power_series_regular", + "nth_algebraic_Integral", + "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", + "nth_linear_euler_eq_nonhomogeneous_variation_of_parameters_Integral", + "Liouville_Integral", + "2nd_nonlinear_autonomous_conserved", + "2nd_nonlinear_autonomous_conserved_Integral", + ) + + + +def get_numbered_constants(eq, num=1, start=1, prefix='C'): + """ + Returns a list of constants that do not occur + in eq already. + """ + + ncs = iter_numbered_constants(eq, start, prefix) + Cs = [next(ncs) for i in range(num)] + return (Cs[0] if num == 1 else tuple(Cs)) + + +def iter_numbered_constants(eq, start=1, prefix='C'): + """ + Returns an iterator of constants that do not occur + in eq already. + """ + + if isinstance(eq, (Expr, Eq)): + eq = [eq] + elif not iterable(eq): + raise ValueError("Expected Expr or iterable but got %s" % eq) + + atom_set = set().union(*[i.free_symbols for i in eq]) + func_set = set().union(*[i.atoms(Function) for i in eq]) + if func_set: + atom_set |= {Symbol(str(f.func)) for f in func_set} + return numbered_symbols(start=start, prefix=prefix, exclude=atom_set) + + +def dsolve(eq, func=None, hint="default", simplify=True, + ics= None, xi=None, eta=None, x0=0, n=6, **kwargs): + r""" + Solves any (supported) kind of ordinary differential equation and + system of ordinary differential equations. + + For single ordinary differential equation + ========================================= + + It is classified under this when number of equation in ``eq`` is one. + **Usage** + + ``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 + :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 could not 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 :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.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. + + ``xi`` and ``eta`` are the infinitesimal functions of an ordinary + differential equation. They are the infinitesimals of the Lie group + of point transformations for which the differential equation is + invariant. The user can specify values for the infinitesimals. If + nothing is specified, ``xi`` and ``eta`` are calculated using + :py:meth:`~sympy.solvers.ode.infinitesimals` with the help of various + heuristics. + + ``ics`` is the set of initial/boundary conditions for the differential equation. + It should be given in the form of ``{f(x0): x1, f(x).diff(x).subs(x, x2): + x3}`` and so on. For power series solutions, if no initial + conditions are specified ``f(0)`` is assumed to be ``C0`` and the power + series solution is calculated about 0. + + ``x0`` is the point about which the power series solution of a differential + equation is to be evaluated. + + ``n`` gives the exponent of the dependent variable up to which the power series + solution of a differential equation is to be evaluated. + + **Hints** + + Aside from the various solving methods, there are also some meta-hints + that you can pass to :py:meth:`~sympy.solvers.ode.dsolve`: + + ``default``: + This uses whatever hint is returned first by + :py:meth:`~sympy.solvers.ode.classify_ode`. This is the + default argument to :py:meth:`~sympy.solvers.ode.dsolve`. + + ``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 :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 :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``. + + For system of ordinary differential equations + ============================================= + + **Usage** + ``dsolve(eq, func)`` -> Solve a system of ordinary differential + equations ``eq`` for ``func`` being list of functions including + `x(t)`, `y(t)`, `z(t)` where number of functions in the list depends + upon the number of equations provided in ``eq``. + + **Details** + + ``eq`` can be any supported system of ordinary differential equations + This can either be an :py:class:`~sympy.core.relational.Equality`, + or an expression, which is assumed to be equal to ``0``. + + ``func`` holds ``x(t)`` and ``y(t)`` being functions of one variable which + together with some of their derivatives make up the system of ordinary + differential equation ``eq``. It is not necessary to provide this; it + will be autodetected (and an error raised if it could not be detected). + + **Hints** + + The hints are formed by parameters returned by classify_sysode, combining + them give hints name used later for forming method name. + + Examples + ======== + + >>> from sympy import Function, dsolve, Eq, Derivative, sin, cos, symbols + >>> from sympy.abc import x + >>> f = Function('f') + >>> dsolve(Derivative(f(x), x, x) + 9*f(x), f(x)) + Eq(f(x), C1*sin(3*x) + C2*cos(3*x)) + + >>> eq = sin(x)*cos(f(x)) + cos(x)*sin(f(x))*f(x).diff(x) + >>> dsolve(eq, hint='1st_exact') + [Eq(f(x), -acos(C1/cos(x)) + 2*pi), Eq(f(x), acos(C1/cos(x)))] + >>> dsolve(eq, hint='almost_linear') + [Eq(f(x), -acos(C1/cos(x)) + 2*pi), Eq(f(x), acos(C1/cos(x)))] + >>> t = symbols('t') + >>> x, y = symbols('x, y', cls=Function) + >>> eq = (Eq(Derivative(x(t),t), 12*t*x(t) + 8*y(t)), Eq(Derivative(y(t),t), 21*x(t) + 7*t*y(t))) + >>> dsolve(eq) + [Eq(x(t), C1*x0(t) + C2*x0(t)*Integral(8*exp(Integral(7*t, t))*exp(Integral(12*t, t))/x0(t)**2, t)), + Eq(y(t), C1*y0(t) + C2*(y0(t)*Integral(8*exp(Integral(7*t, t))*exp(Integral(12*t, t))/x0(t)**2, t) + + exp(Integral(7*t, t))*exp(Integral(12*t, t))/x0(t)))] + >>> eq = (Eq(Derivative(x(t),t),x(t)*y(t)*sin(t)), Eq(Derivative(y(t),t),y(t)**2*sin(t))) + >>> dsolve(eq) + {Eq(x(t), -exp(C1)/(C2*exp(C1) - cos(t))), Eq(y(t), -1/(C1 - cos(t)))} + """ + if iterable(eq): + from sympy.solvers.ode.systems import dsolve_system + + # This may have to be changed in future + # when we have weakly and strongly + # connected components. This have to + # changed to show the systems that haven't + # been solved. + try: + sol = dsolve_system(eq, funcs=func, ics=ics, doit=True) + return sol[0] if len(sol) == 1 else sol + except NotImplementedError: + pass + + match = classify_sysode(eq, func) + + eq = match['eq'] + order = match['order'] + func = match['func'] + t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] + + # keep highest order term coefficient positive + for i in range(len(eq)): + for func_ in func: + if isinstance(func_, list): + pass + else: + if eq[i].coeff(diff(func[i],t,ode_order(eq[i], func[i]))).is_negative: + eq[i] = -eq[i] + match['eq'] = eq + if len(set(order.values()))!=1: + raise ValueError("It solves only those systems of equations whose orders are equal") + match['order'] = list(order.values())[0] + def recur_len(l): + return sum(recur_len(item) if isinstance(item,list) else 1 for item in l) + if recur_len(func) != len(eq): + raise ValueError("dsolve() and classify_sysode() work with " + "number of functions being equal to number of equations") + if match['type_of_equation'] is None: + raise NotImplementedError + else: + if match['is_linear'] == True: + solvefunc = globals()['sysode_linear_%(no_of_equation)seq_order%(order)s' % match] + else: + solvefunc = globals()['sysode_nonlinear_%(no_of_equation)seq_order%(order)s' % match] + sols = solvefunc(match) + if ics: + constants = Tuple(*sols).free_symbols - Tuple(*eq).free_symbols + solved_constants = solve_ics(sols, func, constants, ics) + return [sol.subs(solved_constants) for sol in sols] + return sols + else: + 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, xi=xi, eta=eta, type='ode', ics=ics, + x0=x0, n=n, **kwargs) + eq = hints.pop('eq', eq) + all_ = hints.pop('all', False) + if all_: + retdict = {} + failed_hints = {} + gethints = classify_ode(eq, dict=True, hint='all') + orderedhints = gethints['ordered_hints'] + for hint in hints: + try: + rv = _helper_simplify(eq, hint, hints[hint], simplify) + except NotImplementedError as detail: + failed_hints[hint] = detail + else: + 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 given_hint == 'best': + return retdict['best'] + for i in orderedhints: + if retdict['best'] == retdict.get(i, None): + retdict['best_hint'] = i + break + retdict['default'] = gethints['default'] + retdict['order'] = gethints['order'] + retdict.update(failed_hints) + return retdict + + else: + # The key 'hint' stores the hint needed to be solved for. + hint = hints['hint'] + return _helper_simplify(eq, hint, hints, simplify, ics=ics) + + +def _helper_simplify(eq, hint, match, simplify=True, ics=None, **kwargs): + r""" + Helper function of dsolve that calls the respective + :py:mod:`~sympy.solvers.ode` functions to solve for the ordinary + differential equations. This minimizes the computation in calling + :py:meth:`~sympy.solvers.deutils._desolve` multiple times. + """ + r = match + func = r['func'] + order = r['order'] + match = r[hint] + + if isinstance(match, SingleODESolver): + solvefunc = match + else: + solvefunc = globals()['ode_' + hint.removesuffix('_Integral')] + + free = eq.free_symbols + cons = lambda s: s.free_symbols.difference(free) + + if simplify: + # odesimp() will attempt to integrate, if necessary, apply constantsimp(), + # attempt to solve for func, and apply any other hint specific + # simplifications + if isinstance(solvefunc, SingleODESolver): + sols = solvefunc.get_general_solution() + else: + sols = solvefunc(eq, func, order, match) + if iterable(sols): + rv = [] + for s in sols: + simp = odesimp(eq, s, func, hint) + if iterable(simp): + rv.extend(simp) + else: + rv.append(simp) + else: + rv = odesimp(eq, sols, func, hint) + else: + # We still want to integrate (you can disable it separately with the hint) + if isinstance(solvefunc, SingleODESolver): + exprs = solvefunc.get_general_solution(simplify=False) + else: + match['simplify'] = False # Some hints can take advantage of this option + exprs = solvefunc(eq, func, order, match) + if isinstance(exprs, list): + rv = [_handle_Integral(expr, func, hint) for expr in exprs] + else: + rv = _handle_Integral(exprs, func, hint) + + if isinstance(rv, list): + assert all(isinstance(i, Eq) for i in rv), rv # if not => internal error + if simplify: + rv = _remove_redundant_solutions(eq, rv, order, func.args[0]) + if len(rv) == 1: + rv = rv[0] + if ics and 'power_series' not in hint: + if isinstance(rv, (Expr, Eq)): + solved_constants = solve_ics([rv], [r['func']], cons(rv), ics) + rv = rv.subs(solved_constants) + else: + rv1 = [] + for s in rv: + try: + solved_constants = solve_ics([s], [r['func']], cons(s), ics) + except ValueError: + continue + rv1.append(s.subs(solved_constants)) + if len(rv1) == 1: + return rv1[0] + rv = rv1 + return rv + + +def solve_ics(sols, funcs, constants, ics): + """ + Solve for the constants given initial conditions + + ``sols`` is a list of solutions. + + ``funcs`` is a list of functions. + + ``constants`` is a list of constants. + + ``ics`` is the set of initial/boundary conditions for the differential + equation. It should be given in the form of ``{f(x0): x1, + f(x).diff(x).subs(x, x2): x3}`` and so on. + + Returns a dictionary mapping constants to values. + ``solution.subs(constants)`` will replace the constants in ``solution``. + + Example + ======= + >>> # From dsolve(f(x).diff(x) - f(x), f(x)) + >>> from sympy import symbols, Eq, exp, Function + >>> from sympy.solvers.ode.ode import solve_ics + >>> f = Function('f') + >>> x, C1 = symbols('x C1') + >>> sols = [Eq(f(x), C1*exp(x))] + >>> funcs = [f(x)] + >>> constants = [C1] + >>> ics = {f(0): 2} + >>> solved_constants = solve_ics(sols, funcs, constants, ics) + >>> solved_constants + {C1: 2} + >>> sols[0].subs(solved_constants) + Eq(f(x), 2*exp(x)) + + """ + # Assume ics are of the form f(x0): value or Subs(diff(f(x), x, n), (x, + # x0)): value (currently checked by classify_ode). To solve, replace x + # with x0, f(x0) with value, then solve for constants. For f^(n)(x0), + # differentiate the solution n times, so that f^(n)(x) appears. + x = funcs[0].args[0] + diff_sols = [] + subs_sols = [] + diff_variables = set() + for funcarg, value in ics.items(): + if isinstance(funcarg, AppliedUndef): + x0 = funcarg.args[0] + matching_func = [f for f in funcs if f.func == funcarg.func][0] + S = sols + elif isinstance(funcarg, (Subs, Derivative)): + if isinstance(funcarg, Subs): + # Make sure it stays a subs. Otherwise subs below will produce + # a different looking term. + funcarg = funcarg.doit() + if isinstance(funcarg, Subs): + deriv = funcarg.expr + x0 = funcarg.point[0] + variables = funcarg.expr.variables + matching_func = deriv + elif isinstance(funcarg, Derivative): + deriv = funcarg + x0 = funcarg.variables[0] + variables = (x,)*len(funcarg.variables) + matching_func = deriv.subs(x0, x) + for sol in sols: + if sol.has(deriv.expr.func): + diff_sols.append(Eq(sol.lhs.diff(*variables), sol.rhs.diff(*variables))) + diff_variables.add(variables) + S = diff_sols + else: + raise NotImplementedError("Unrecognized initial condition") + + for sol in S: + if sol.has(matching_func): + sol2 = sol + sol2 = sol2.subs(x, x0) + sol2 = sol2.subs(funcarg, value) + # This check is necessary because of issue #15724 + if not isinstance(sol2, BooleanAtom) or not subs_sols: + subs_sols = [s for s in subs_sols if not isinstance(s, BooleanAtom)] + subs_sols.append(sol2) + + # TODO: Use solveset here + try: + solved_constants = solve(subs_sols, constants, dict=True) + except NotImplementedError: + solved_constants = [] + + # XXX: We can't differentiate between the solution not existing because of + # invalid initial conditions, and not existing because solve is not smart + # enough. If we could use solveset, this might be improvable, but for now, + # we use NotImplementedError in this case. + if not solved_constants: + raise ValueError("Couldn't solve for initial conditions") + + if solved_constants == True: + raise ValueError("Initial conditions did not produce any solutions for constants. Perhaps they are degenerate.") + + if len(solved_constants) > 1: + raise NotImplementedError("Initial conditions produced too many solutions for constants") + + return solved_constants[0] + +def classify_ode(eq, func=None, dict=False, ics=None, *, prep=True, xi=None, eta=None, n=None, **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 + :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`` + + If a classification has ``_Integral`` at the end, it will return the + expression with an unevaluated :py:class:`~.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:func:`~sympy.integrals.integrals.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.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 that 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 + ======== + + >>> from sympy import Function, classify_ode, Eq + >>> from sympy.abc import x + >>> f = Function('f') + >>> classify_ode(Eq(f(x).diff(x), 0), f(x)) + ('nth_algebraic', + 'separable', + '1st_exact', + '1st_linear', + 'Bernoulli', + '1st_homogeneous_coeff_best', + '1st_homogeneous_coeff_subs_indep_div_dep', + '1st_homogeneous_coeff_subs_dep_div_indep', + '1st_power_series', 'lie_group', 'nth_linear_constant_coeff_homogeneous', + 'nth_linear_euler_eq_homogeneous', + 'nth_algebraic_Integral', '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') + >>> classify_ode(f(x).diff(x, 2) + 3*f(x).diff(x) + 2*f(x) - 4) + ('factorable', 'nth_linear_constant_coeff_undetermined_coefficients', + 'nth_linear_constant_coeff_variation_of_parameters', + 'nth_linear_constant_coeff_variation_of_parameters_Integral') + + """ + ics = sympify(ics) + + if func and len(func.args) != 1: + raise ValueError("dsolve() and classify_ode() only " + "work with functions of one variable, not %s" % func) + + if isinstance(eq, Equality): + eq = eq.lhs - eq.rhs + + # Some methods want the unprocessed equation + eq_orig = eq + + if prep or func is None: + eq, func_ = _preprocess(eq, func) + if func is None: + func = func_ + x = func.args[0] + f = func.func + y = Dummy('y') + terms = 5 if n is None else n + + order = ode_order(eq, f(x)) + # hint:matchdict or hint:(tuple of matchdicts) + # Also will contain "default": and "order":order items. + matching_hints = {"order": order} + + df = f(x).diff(x) + a = Wild('a', exclude=[f(x)]) + d = Wild('d', exclude=[df, f(x).diff(x, 2)]) + e = Wild('e', exclude=[df]) + n = Wild('n', exclude=[x, f(x), df]) + c1 = Wild('c1', exclude=[x]) + a3 = Wild('a3', exclude=[f(x), df, f(x).diff(x, 2)]) + b3 = Wild('b3', exclude=[f(x), df, f(x).diff(x, 2)]) + c3 = Wild('c3', exclude=[f(x), df, f(x).diff(x, 2)]) + boundary = {} # Used to extract initial conditions + C1 = Symbol("C1") + + # Preprocessing to get the initial conditions out + if ics is not None: + for funcarg in ics: + # Separating derivatives + if isinstance(funcarg, (Subs, Derivative)): + # f(x).diff(x).subs(x, 0) is a Subs, but f(x).diff(x).subs(x, + # y) is a Derivative + if isinstance(funcarg, Subs): + deriv = funcarg.expr + old = funcarg.variables[0] + new = funcarg.point[0] + elif isinstance(funcarg, Derivative): + deriv = funcarg + # No information on this. Just assume it was x + old = x + new = funcarg.variables[0] + + if (isinstance(deriv, Derivative) and isinstance(deriv.args[0], + AppliedUndef) and deriv.args[0].func == f and + len(deriv.args[0].args) == 1 and old == x and not + new.has(x) and all(i == deriv.variables[0] for i in + deriv.variables) and x not in ics[funcarg].free_symbols): + + dorder = ode_order(deriv, x) + temp = 'f' + str(dorder) + boundary.update({temp: new, temp + 'val': ics[funcarg]}) + else: + raise ValueError("Invalid boundary conditions for Derivatives") + + + # Separating functions + elif isinstance(funcarg, AppliedUndef): + if (funcarg.func == f and len(funcarg.args) == 1 and + not funcarg.args[0].has(x) and x not in ics[funcarg].free_symbols): + boundary.update({'f0': funcarg.args[0], 'f0val': ics[funcarg]}) + else: + raise ValueError("Invalid boundary conditions for Function") + + else: + raise ValueError("Enter boundary conditions of the form ics={f(point): value, f(x).diff(x, order).subs(x, point): value}") + + ode = SingleODEProblem(eq_orig, func, x, prep=prep, xi=xi, eta=eta) + user_hint = kwargs.get('hint', 'default') + # Used when dsolve is called without an explicit hint. + # We exit early to return the first valid match + early_exit = (user_hint=='default') + user_hint = user_hint.removesuffix('_Integral') + user_map = solver_map + # An explicit hint has been given to dsolve + # Skip matching code for other hints + if user_hint not in ['default', 'all', 'all_Integral', 'best'] and user_hint in solver_map: + user_map = {user_hint: solver_map[user_hint]} + + for hint in user_map: + solver = user_map[hint](ode) + if solver.matches(): + matching_hints[hint] = solver + if user_map[hint].has_integral: + matching_hints[hint + "_Integral"] = solver + if dict and early_exit: + matching_hints["default"] = hint + return matching_hints + + eq = expand(eq) + # Precondition to try remove f(x) from highest order derivative + reduced_eq = None + if eq.is_Add: + deriv_coef = eq.coeff(f(x).diff(x, order)) + if deriv_coef not in (1, 0): + r = deriv_coef.match(a*f(x)**c1) + if r and r[c1]: + den = f(x)**r[c1] + reduced_eq = Add(*[arg/den for arg in eq.args]) + if not reduced_eq: + reduced_eq = eq + + if order == 1: + + # 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) + + # FIRST ORDER POWER SERIES WHICH NEEDS INITIAL CONDITIONS + # TODO: Hint first order series should match only if d/e is analytic. + # For now, only d/e and (d/e).diff(arg) is checked for existence at + # at a given point. + # This is currently done internally in ode_1st_power_series. + point = boundary.get('f0', 0) + value = boundary.get('f0val', C1) + check = cancel(r[d]/r[e]) + check1 = check.subs({x: point, y: value}) + if not check1.has(oo) and not check1.has(zoo) and \ + not check1.has(nan) and not check1.has(-oo): + check2 = (check1.diff(x)).subs({x: point, y: value}) + if not check2.has(oo) and not check2.has(zoo) and \ + not check2.has(nan) and not check2.has(-oo): + rseries = r.copy() + rseries.update({'terms': terms, 'f0': point, 'f0val': value}) + matching_hints["1st_power_series"] = rseries + + elif order == 2: + # Homogeneous second order differential equation of the form + # a3*f(x).diff(x, 2) + b3*f(x).diff(x) + c3 + # It has a definite power series solution at point x0 if, b3/a3 and c3/a3 + # are analytic at x0. + deq = a3*(f(x).diff(x, 2)) + b3*df + c3*f(x) + r = collect(reduced_eq, + [f(x).diff(x, 2), f(x).diff(x), f(x)]).match(deq) + ordinary = False + if r: + if not all(r[key].is_polynomial() for key in r): + n, d = reduced_eq.as_numer_denom() + reduced_eq = expand(n) + r = collect(reduced_eq, + [f(x).diff(x, 2), f(x).diff(x), f(x)]).match(deq) + if r and r[a3] != 0: + p = cancel(r[b3]/r[a3]) # Used below + q = cancel(r[c3]/r[a3]) # Used below + point = kwargs.get('x0', 0) + check = p.subs(x, point) + if not check.has(oo, nan, zoo, -oo): + check = q.subs(x, point) + if not check.has(oo, nan, zoo, -oo): + ordinary = True + r.update({'a3': a3, 'b3': b3, 'c3': c3, 'x0': point, 'terms': terms}) + matching_hints["2nd_power_series_ordinary"] = r + + # Checking if the differential equation has a regular singular point + # at x0. It has a regular singular point at x0, if (b3/a3)*(x - x0) + # and (c3/a3)*((x - x0)**2) are analytic at x0. + if not ordinary: + p = cancel((x - point)*p) + check = p.subs(x, point) + if not check.has(oo, nan, zoo, -oo): + q = cancel(((x - point)**2)*q) + check = q.subs(x, point) + if not check.has(oo, nan, zoo, -oo): + coeff_dict = {'p': p, 'q': q, 'x0': point, 'terms': terms} + matching_hints["2nd_power_series_regular"] = coeff_dict + + + # Order keys based on allhints. + retlist = [i for i in allhints if i in matching_hints] + if dict: + # 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) + return matching_hints + else: + return tuple(retlist) + + +def classify_sysode(eq, funcs=None, **kwargs): + r""" + Returns a dictionary of parameter names and values that define the system + of ordinary differential equations in ``eq``. + The parameters are further used in + :py:meth:`~sympy.solvers.ode.dsolve` for solving that system. + + Some parameter names and values are: + + 'is_linear' (boolean), which tells whether the given system is linear. + Note that "linear" here refers to the operator: terms such as ``x*diff(x,t)`` are + nonlinear, whereas terms like ``sin(t)*diff(x,t)`` are still linear operators. + + 'func' (list) contains the :py:class:`~sympy.core.function.Function`s that + appear with a derivative in the ODE, i.e. those that we are trying to solve + the ODE for. + + 'order' (dict) with the maximum derivative for each element of the 'func' + parameter. + + 'func_coeff' (dict or Matrix) with the coefficient for each triple ``(equation number, + function, order)```. The coefficients are those subexpressions that do not + appear in 'func', and hence can be considered constant for purposes of ODE + solving. The value of this parameter can also be a Matrix if the system of ODEs are + linear first order of the form X' = AX where X is the vector of dependent variables. + Here, this function returns the coefficient matrix A. + + 'eq' (list) with the equations from ``eq``, sympified and transformed into + expressions (we are solving for these expressions to be zero). + + 'no_of_equations' (int) is the number of equations (same as ``len(eq)``). + + 'type_of_equation' (string) is an internal classification of the type of + ODE. + + 'is_constant' (boolean), which tells if the system of ODEs is constant coefficient + or not. This key is temporary addition for now and is in the match dict only when + the system of ODEs is linear first order constant coefficient homogeneous. So, this + key's value is True for now if it is available else it does not exist. + + 'is_homogeneous' (boolean), which tells if the system of ODEs is homogeneous. Like the + key 'is_constant', this key is a temporary addition and it is True since this key value + is available only when the system is linear first order constant coefficient homogeneous. + + References + ========== + -https://eqworld.ipmnet.ru/en/solutions/sysode/sode-toc1.htm + -A. D. Polyanin and A. V. Manzhirov, Handbook of Mathematics for Engineers and Scientists + + Examples + ======== + + >>> from sympy import Function, Eq, symbols, diff + >>> from sympy.solvers.ode.ode import classify_sysode + >>> from sympy.abc import t + >>> f, x, y = symbols('f, x, y', cls=Function) + >>> k, l, m, n = symbols('k, l, m, n', Integer=True) + >>> x1 = diff(x(t), t) ; y1 = diff(y(t), t) + >>> x2 = diff(x(t), t, t) ; y2 = diff(y(t), t, t) + >>> eq = (Eq(x1, 12*x(t) - 6*y(t)), Eq(y1, 11*x(t) + 3*y(t))) + >>> classify_sysode(eq) + {'eq': [-12*x(t) + 6*y(t) + Derivative(x(t), t), -11*x(t) - 3*y(t) + Derivative(y(t), t)], 'func': [x(t), y(t)], + 'func_coeff': {(0, x(t), 0): -12, (0, x(t), 1): 1, (0, y(t), 0): 6, (0, y(t), 1): 0, (1, x(t), 0): -11, (1, x(t), 1): 0, (1, y(t), 0): -3, (1, y(t), 1): 1}, 'is_linear': True, 'no_of_equation': 2, 'order': {x(t): 1, y(t): 1}, 'type_of_equation': None} + >>> eq = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t) + 2), Eq(diff(y(t),t), -t**2*x(t) + 5*t*y(t))) + >>> classify_sysode(eq) + {'eq': [-t**2*y(t) - 5*t*x(t) + Derivative(x(t), t) - 2, t**2*x(t) - 5*t*y(t) + Derivative(y(t), t)], + 'func': [x(t), y(t)], 'func_coeff': {(0, x(t), 0): -5*t, (0, x(t), 1): 1, (0, y(t), 0): -t**2, (0, y(t), 1): 0, + (1, x(t), 0): t**2, (1, x(t), 1): 0, (1, y(t), 0): -5*t, (1, y(t), 1): 1}, 'is_linear': True, 'no_of_equation': 2, + 'order': {x(t): 1, y(t): 1}, 'type_of_equation': None} + + """ + + # Sympify equations and convert iterables of equations into + # a list of equations + def _sympify(eq): + return list(map(sympify, eq if iterable(eq) else [eq])) + + eq, funcs = (_sympify(w) for w in [eq, funcs]) + for i, fi in enumerate(eq): + if isinstance(fi, Equality): + eq[i] = fi.lhs - fi.rhs + + t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] + matching_hints = {"no_of_equation":i+1} + matching_hints['eq'] = eq + if i==0: + raise ValueError("classify_sysode() works for systems of ODEs. " + "For scalar ODEs, classify_ode should be used") + + # find all the functions if not given + order = {} + if funcs==[None]: + funcs = _extract_funcs(eq) + + funcs = list(set(funcs)) + if len(funcs) != len(eq): + raise ValueError("Number of functions given is not equal to the number of equations %s" % funcs) + + # This logic of list of lists in funcs to + # be replaced later. + func_dict = {} + for func in funcs: + if not order.get(func, False): + max_order = 0 + for i, eqs_ in enumerate(eq): + order_ = ode_order(eqs_,func) + if max_order < order_: + max_order = order_ + eq_no = i + if eq_no in func_dict: + func_dict[eq_no] = [func_dict[eq_no], func] + else: + func_dict[eq_no] = func + order[func] = max_order + + funcs = [func_dict[i] for i in range(len(func_dict))] + matching_hints['func'] = funcs + for func in funcs: + if isinstance(func, list): + for func_elem in func: + if len(func_elem.args) != 1: + raise ValueError("dsolve() and classify_sysode() work with " + "functions of one variable only, not %s" % func) + else: + if func and len(func.args) != 1: + raise ValueError("dsolve() and classify_sysode() work with " + "functions of one variable only, not %s" % func) + + # find the order of all equation in system of odes + matching_hints["order"] = order + + # find coefficients of terms f(t), diff(f(t),t) and higher derivatives + # and similarly for other functions g(t), diff(g(t),t) in all equations. + # Here j denotes the equation number, funcs[l] denotes the function about + # which we are talking about and k denotes the order of function funcs[l] + # whose coefficient we are calculating. + def linearity_check(eqs, j, func, is_linear_): + for k in range(order[func] + 1): + func_coef[j, func, k] = collect(eqs.expand(), [diff(func, t, k)]).coeff(diff(func, t, k)) + if is_linear_ == True: + if func_coef[j, func, k] == 0: + if k == 0: + coef = eqs.as_independent(func, as_Add=True)[1] + for xr in range(1, ode_order(eqs,func) + 1): + coef -= eqs.as_independent(diff(func, t, xr), as_Add=True)[1] + if coef != 0: + is_linear_ = False + else: + if eqs.as_independent(diff(func, t, k), as_Add=True)[1]: + is_linear_ = False + else: + for func_ in funcs: + if isinstance(func_, list): + for elem_func_ in func_: + dep = func_coef[j, func, k].as_independent(elem_func_, as_Add=True)[1] + if dep != 0: + is_linear_ = False + else: + dep = func_coef[j, func, k].as_independent(func_, as_Add=True)[1] + if dep != 0: + is_linear_ = False + return is_linear_ + + func_coef = {} + is_linear = True + for j, eqs in enumerate(eq): + for func in funcs: + if isinstance(func, list): + for func_elem in func: + is_linear = linearity_check(eqs, j, func_elem, is_linear) + else: + is_linear = linearity_check(eqs, j, func, is_linear) + matching_hints['func_coeff'] = func_coef + matching_hints['is_linear'] = is_linear + + + if len(set(order.values())) == 1: + order_eq = list(matching_hints['order'].values())[0] + if matching_hints['is_linear'] == True: + if matching_hints['no_of_equation'] == 2: + if order_eq == 1: + type_of_equation = check_linear_2eq_order1(eq, funcs, func_coef) + else: + type_of_equation = None + # If the equation does not match up with any of the + # general case solvers in systems.py and the number + # of equations is greater than 2, then NotImplementedError + # should be raised. + else: + type_of_equation = None + + else: + if matching_hints['no_of_equation'] == 2: + if order_eq == 1: + type_of_equation = check_nonlinear_2eq_order1(eq, funcs, func_coef) + else: + type_of_equation = None + elif matching_hints['no_of_equation'] == 3: + if order_eq == 1: + type_of_equation = check_nonlinear_3eq_order1(eq, funcs, func_coef) + else: + type_of_equation = None + else: + type_of_equation = None + else: + type_of_equation = None + + matching_hints['type_of_equation'] = type_of_equation + + return matching_hints + + +def check_linear_2eq_order1(eq, func, func_coef): + x = func[0].func + y = func[1].func + fc = func_coef + t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] + r = {} + # for equations Eq(a1*diff(x(t),t), b1*x(t) + c1*y(t) + d1) + # and Eq(a2*diff(y(t),t), b2*x(t) + c2*y(t) + d2) + r['a1'] = fc[0,x(t),1] ; r['a2'] = fc[1,y(t),1] + r['b1'] = -fc[0,x(t),0]/fc[0,x(t),1] ; r['b2'] = -fc[1,x(t),0]/fc[1,y(t),1] + r['c1'] = -fc[0,y(t),0]/fc[0,x(t),1] ; r['c2'] = -fc[1,y(t),0]/fc[1,y(t),1] + forcing = [S.Zero,S.Zero] + for i in range(2): + for j in Add.make_args(eq[i]): + if not j.has(x(t), y(t)): + forcing[i] += j + if not (forcing[0].has(t) or forcing[1].has(t)): + # We can handle homogeneous case and simple constant forcings + r['d1'] = forcing[0] + r['d2'] = forcing[1] + else: + # Issue #9244: nonhomogeneous linear systems are not supported + return None + + # Conditions to check for type 6 whose equations are Eq(diff(x(t),t), f(t)*x(t) + g(t)*y(t)) and + # Eq(diff(y(t),t), a*[f(t) + a*h(t)]x(t) + a*[g(t) - h(t)]*y(t)) + p = 0 + q = 0 + p1 = cancel(r['b2']/(cancel(r['b2']/r['c2']).as_numer_denom()[0])) + p2 = cancel(r['b1']/(cancel(r['b1']/r['c1']).as_numer_denom()[0])) + for n, i in enumerate([p1, p2]): + for j in Mul.make_args(collect_const(i)): + if not j.has(t): + q = j + if q and n==0: + if ((r['b2']/j - r['b1'])/(r['c1'] - r['c2']/j)) == j: + p = 1 + elif q and n==1: + if ((r['b1']/j - r['b2'])/(r['c2'] - r['c1']/j)) == j: + p = 2 + # End of condition for type 6 + + if r['d1']!=0 or r['d2']!=0: + return None + else: + if not any(r[k].has(t) for k in 'a1 a2 b1 b2 c1 c2'.split()): + return None + else: + r['b1'] = r['b1']/r['a1'] ; r['b2'] = r['b2']/r['a2'] + r['c1'] = r['c1']/r['a1'] ; r['c2'] = r['c2']/r['a2'] + if p: + return "type6" + else: + # Equations for type 7 are Eq(diff(x(t),t), f(t)*x(t) + g(t)*y(t)) and Eq(diff(y(t),t), h(t)*x(t) + p(t)*y(t)) + return "type7" +def check_nonlinear_2eq_order1(eq, func, func_coef): + t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] + f = Wild('f') + g = Wild('g') + u, v = symbols('u, v', cls=Dummy) + def check_type(x, y): + r1 = eq[0].match(t*diff(x(t),t) - x(t) + f) + r2 = eq[1].match(t*diff(y(t),t) - y(t) + g) + if not (r1 and r2): + r1 = eq[0].match(diff(x(t),t) - x(t)/t + f/t) + r2 = eq[1].match(diff(y(t),t) - y(t)/t + g/t) + if not (r1 and r2): + r1 = (-eq[0]).match(t*diff(x(t),t) - x(t) + f) + r2 = (-eq[1]).match(t*diff(y(t),t) - y(t) + g) + if not (r1 and r2): + r1 = (-eq[0]).match(diff(x(t),t) - x(t)/t + f/t) + r2 = (-eq[1]).match(diff(y(t),t) - y(t)/t + g/t) + if r1 and r2 and not (r1[f].subs(diff(x(t),t),u).subs(diff(y(t),t),v).has(t) \ + or r2[g].subs(diff(x(t),t),u).subs(diff(y(t),t),v).has(t)): + return 'type5' + else: + return None + for func_ in func: + if isinstance(func_, list): + x = func[0][0].func + y = func[0][1].func + eq_type = check_type(x, y) + if not eq_type: + eq_type = check_type(y, x) + return eq_type + x = func[0].func + y = func[1].func + fc = func_coef + n = Wild('n', exclude=[x(t),y(t)]) + f1 = Wild('f1', exclude=[v,t]) + f2 = Wild('f2', exclude=[v,t]) + g1 = Wild('g1', exclude=[u,t]) + g2 = Wild('g2', exclude=[u,t]) + for i in range(2): + eqs = 0 + for terms in Add.make_args(eq[i]): + eqs += terms/fc[i,func[i],1] + eq[i] = eqs + r = eq[0].match(diff(x(t),t) - x(t)**n*f) + if r: + g = (diff(y(t),t) - eq[1])/r[f] + if r and not (g.has(x(t)) or g.subs(y(t),v).has(t) or r[f].subs(x(t),u).subs(y(t),v).has(t)): + return 'type1' + r = eq[0].match(diff(x(t),t) - exp(n*x(t))*f) + if r: + g = (diff(y(t),t) - eq[1])/r[f] + if r and not (g.has(x(t)) or g.subs(y(t),v).has(t) or r[f].subs(x(t),u).subs(y(t),v).has(t)): + return 'type2' + g = Wild('g') + r1 = eq[0].match(diff(x(t),t) - f) + r2 = eq[1].match(diff(y(t),t) - g) + if r1 and r2 and not (r1[f].subs(x(t),u).subs(y(t),v).has(t) or \ + r2[g].subs(x(t),u).subs(y(t),v).has(t)): + return 'type3' + r1 = eq[0].match(diff(x(t),t) - f) + r2 = eq[1].match(diff(y(t),t) - g) + num, den = ( + (r1[f].subs(x(t),u).subs(y(t),v))/ + (r2[g].subs(x(t),u).subs(y(t),v))).as_numer_denom() + R1 = num.match(f1*g1) + R2 = den.match(f2*g2) + # phi = (r1[f].subs(x(t),u).subs(y(t),v))/num + if R1 and R2: + return 'type4' + return None + + +def check_nonlinear_2eq_order2(eq, func, func_coef): + return None + +def check_nonlinear_3eq_order1(eq, func, func_coef): + x = func[0].func + y = func[1].func + z = func[2].func + fc = func_coef + t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] + u, v, w = symbols('u, v, w', cls=Dummy) + a = Wild('a', exclude=[x(t), y(t), z(t), t]) + b = Wild('b', exclude=[x(t), y(t), z(t), t]) + c = Wild('c', exclude=[x(t), y(t), z(t), t]) + f = Wild('f') + F1 = Wild('F1') + F2 = Wild('F2') + F3 = Wild('F3') + for i in range(3): + eqs = 0 + for terms in Add.make_args(eq[i]): + eqs += terms/fc[i,func[i],1] + eq[i] = eqs + r1 = eq[0].match(diff(x(t),t) - a*y(t)*z(t)) + r2 = eq[1].match(diff(y(t),t) - b*z(t)*x(t)) + r3 = eq[2].match(diff(z(t),t) - c*x(t)*y(t)) + if r1 and r2 and r3: + num1, den1 = r1[a].as_numer_denom() + num2, den2 = r2[b].as_numer_denom() + num3, den3 = r3[c].as_numer_denom() + if solve([num1*u-den1*(v-w), num2*v-den2*(w-u), num3*w-den3*(u-v)],[u, v]): + return 'type1' + r = eq[0].match(diff(x(t),t) - y(t)*z(t)*f) + if r: + r1 = collect_const(r[f]).match(a*f) + r2 = ((diff(y(t),t) - eq[1])/r1[f]).match(b*z(t)*x(t)) + r3 = ((diff(z(t),t) - eq[2])/r1[f]).match(c*x(t)*y(t)) + if r1 and r2 and r3: + num1, den1 = r1[a].as_numer_denom() + num2, den2 = r2[b].as_numer_denom() + num3, den3 = r3[c].as_numer_denom() + if solve([num1*u-den1*(v-w), num2*v-den2*(w-u), num3*w-den3*(u-v)],[u, v]): + return 'type2' + r = eq[0].match(diff(x(t),t) - (F2-F3)) + if r: + r1 = collect_const(r[F2]).match(c*F2) + r1.update(collect_const(r[F3]).match(b*F3)) + if r1: + if eq[1].has(r1[F2]) and not eq[1].has(r1[F3]): + r1[F2], r1[F3] = r1[F3], r1[F2] + r1[c], r1[b] = -r1[b], -r1[c] + r2 = eq[1].match(diff(y(t),t) - a*r1[F3] + r1[c]*F1) + if r2: + r3 = (eq[2] == diff(z(t),t) - r1[b]*r2[F1] + r2[a]*r1[F2]) + if r1 and r2 and r3: + return 'type3' + r = eq[0].match(diff(x(t),t) - z(t)*F2 + y(t)*F3) + if r: + r1 = collect_const(r[F2]).match(c*F2) + r1.update(collect_const(r[F3]).match(b*F3)) + if r1: + if eq[1].has(r1[F2]) and not eq[1].has(r1[F3]): + r1[F2], r1[F3] = r1[F3], r1[F2] + r1[c], r1[b] = -r1[b], -r1[c] + r2 = (diff(y(t),t) - eq[1]).match(a*x(t)*r1[F3] - r1[c]*z(t)*F1) + if r2: + r3 = (diff(z(t),t) - eq[2] == r1[b]*y(t)*r2[F1] - r2[a]*x(t)*r1[F2]) + if r1 and r2 and r3: + return 'type4' + r = (diff(x(t),t) - eq[0]).match(x(t)*(F2 - F3)) + if r: + r1 = collect_const(r[F2]).match(c*F2) + r1.update(collect_const(r[F3]).match(b*F3)) + if r1: + if eq[1].has(r1[F2]) and not eq[1].has(r1[F3]): + r1[F2], r1[F3] = r1[F3], r1[F2] + r1[c], r1[b] = -r1[b], -r1[c] + r2 = (diff(y(t),t) - eq[1]).match(y(t)*(a*r1[F3] - r1[c]*F1)) + if r2: + r3 = (diff(z(t),t) - eq[2] == z(t)*(r1[b]*r2[F1] - r2[a]*r1[F2])) + if r1 and r2 and r3: + return 'type5' + return None + + +def check_nonlinear_3eq_order2(eq, func, func_coef): + return None + + +@vectorize(0) +def odesimp(ode, eq, func, hint): + r""" + Simplifies solutions of 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 the hint returns to + apply additional simplifications. + + It also attempts to integrate any :py:class:`~sympy.integrals.integrals.Integral`\s + in the expression, if the hint is not an ``_Integral`` hint. + + This function should have no effect on expressions returned by + :py:meth:`~sympy.solvers.ode.dsolve`, as + :py:meth:`~sympy.solvers.ode.dsolve` already calls + :py:meth:`~sympy.solvers.ode.ode.odesimp`, but the individual hint functions + do not call :py:meth:`~sympy.solvers.ode.ode.odesimp` (because the + :py:meth:`~sympy.solvers.ode.dsolve` wrapper does). Therefore, this + function is designed for mainly internal use. + + Examples + ======== + + >>> from sympy import sin, symbols, dsolve, pprint, Function + >>> from sympy.solvers.ode.ode import odesimp + >>> x, u2, C1= symbols('x,u2,C1') + >>> f = Function('f') + + >>> 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, wrap_line=False) + x + ---- + f(x) + / + | + | / 1 \ + | -|u1 + -------| + | | /1 \| + | | sin|--|| + | \ \u1// + log(f(x)) = log(C1) + | ---------------- d(u1) + | 2 + | u1 + | + / + + >>> pprint(odesimp(eq, f(x), 1, {C1}, + ... hint='1st_homogeneous_coeff_subs_indep_div_dep' + ... )) #doctest: +SKIP + x + --------- = C1 + /f(x)\ + tan|----| + \2*x / + + """ + x = func.args[0] + f = func.func + C1 = get_numbered_constants(eq, num=1) + constants = eq.free_symbols - ode.free_symbols + + # First, integrate if the hint allows it. + eq = _handle_Integral(eq, func, hint) + if hint.startswith("nth_linear_euler_eq_nonhomogeneous"): + eq = simplify(eq) + if not isinstance(eq, Equality): + raise TypeError("eq should be an instance of Equality") + + # allow simplifications under assumption that symbols are nonzero + eq = eq.xreplace((_:={i: Dummy(nonzero=True) for i in constants})).xreplace({_[i]: i for i in _}) + + # Second, clean up the arbitrary constants. + # Right now, nth linear hints can put as many as 2*order constants in an + # expression. If that number grows with another hint, the third argument + # here should be raised accordingly, or constantsimp() rewritten to handle + # an arbitrary number of constants. + eq = constantsimp(eq, constants) + + # Lastly, now that we have cleaned up the expression, try solving for func. + # When CRootOf is implemented in solve(), we will want to return a CRootOf + # every time instead of an Equality. + + # Get the f(x) on the left if possible. + if eq.rhs == func and not eq.lhs.has(func): + eq = [Eq(eq.rhs, eq.lhs)] + + # make sure we are working with lists of solutions in simplified form. + if eq.lhs == func and not eq.rhs.has(func): + # The solution is already solved + eq = [eq] + + else: + # The solution is not solved, so try to solve it + try: + floats = any(i.is_Float for i in eq.atoms(Number)) + eqsol = solve(eq, func, force=True, rational=False if floats else None) + if not eqsol: + raise NotImplementedError + except (NotImplementedError, PolynomialError): + eq = [eq] + else: + def _expand(expr): + numer, denom = expr.as_numer_denom() + + if denom.is_Add: + return expr + else: + return powsimp(expr.expand(), combine='exp', deep=True) + + # XXX: the rest of odesimp() expects each ``t`` to be in a + # specific normal form: rational expression with numerator + # expanded, but with combined exponential functions (at + # least in this setup all tests pass). + eq = [Eq(f(x), _expand(t)) for t in eqsol] + + # special simplification of the lhs. + if hint.startswith("1st_homogeneous_coeff"): + for j, eqi in enumerate(eq): + newi = logcombine(eqi, force=True) + if isinstance(newi.lhs, log) and newi.rhs == 0: + newi = Eq(newi.lhs.args[0]/C1, C1) + eq[j] = newi + + # We cleaned up the constants before solving to help the solve engine with + # 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] = constantsimp(eqi, constants) + eq[i] = constant_renumber(eq[i], ode.free_symbols) + + # If there is only 1 solution, return it; + # otherwise return the list of solutions. + if len(eq) == 1: + eq = eq[0] + return eq + + +def ode_sol_simplicity(sol, func, trysolving=True): + 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 :py:class:`~sympy.integrals.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`` | + | :obj:`~sympy.integrals.integrals.Integral` | | + +----------------------------------------------+-------------------+ + + ``oo`` here means the SymPy infinity, which should compare greater than + any integer. + + 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)))``. + + >>> from sympy import symbols, Function, Eq, tan, Integral + >>> from sympy.solvers.ode.ode import ode_sol_simplicity + >>> x, C1, C2 = symbols('x, C1, C2') + >>> f = Function('f') + + >>> ode_sol_simplicity(Eq(f(x), C1*x**2), f(x)) + -2 + >>> ode_sol_simplicity(Eq(x**2 + f(x), C1), f(x)) + -1 + >>> ode_sol_simplicity(Eq(f(x), C1*Integral(2*x, x)), f(x)) + oo + >>> eq1 = Eq(f(x)/tan(f(x)/(2*x)), C1) + >>> eq2 = Eq(f(x)/tan(f(x)/(2*x) + f(x)), C2) + >>> [ode_sol_simplicity(eq, f(x)) for eq in [eq1, eq2]] + [28, 35] + >>> min([eq1, eq2], key=lambda i: ode_sol_simplicity(i, f(x))) + Eq(f(x)/tan(f(x)/(2*x)), C1) + + """ + # 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. + + if iterable(sol): + # See if there are Integrals + for i in sol: + if ode_sol_simplicity(i, func, trysolving=trysolving) == oo: + return oo + + return len(str(sol)) + + if sol.has(Integral): + return oo + + # Next, try to solve for func. This code will change slightly when CRootOf + # is implemented in solve(). Probably a CRootOf 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): + return -2 + # We are not so lucky, try solving manually + if trysolving: + try: + sols = solve(sol, func) + if not sols: + raise NotImplementedError + except NotImplementedError: + pass + else: + return -1 + + # Finally, a naive computation based on the length of the string version + # of the expression. This may favor combined fractions because they + # will not have duplicate denominators, and may slightly favor expressions + # with fewer additions and subtractions, as those are separated by spaces + # by the printer. + + # 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. + return len(str(sol)) + + +def _extract_funcs(eqs): + funcs = [] + for eq in eqs: + derivs = [node for node in preorder_traversal(eq) if isinstance(node, Derivative)] + func = [] + for d in derivs: + func += list(d.atoms(AppliedUndef)) + for func_ in func: + funcs.append(func_) + funcs = list(uniq(funcs)) + + return funcs + + +def _get_constant_subexpressions(expr, Cs): + Cs = set(Cs) + Ces = [] + def _recursive_walk(expr): + expr_syms = expr.free_symbols + if expr_syms and expr_syms.issubset(Cs): + Ces.append(expr) + else: + if expr.func == exp: + expr = expr.expand(mul=True) + if expr.func in (Add, Mul): + d = sift(expr.args, lambda i : i.free_symbols.issubset(Cs)) + if len(d[True]) > 1: + x = expr.func(*d[True]) + if not x.is_number: + Ces.append(x) + elif isinstance(expr, Integral): + if expr.free_symbols.issubset(Cs) and \ + all(len(x) == 3 for x in expr.limits): + Ces.append(expr) + for i in expr.args: + _recursive_walk(i) + return + _recursive_walk(expr) + return Ces + +def __remove_linear_redundancies(expr, Cs): + cnts = {i: expr.count(i) for i in Cs} + Cs = [i for i in Cs if cnts[i] > 0] + + def _linear(expr): + if isinstance(expr, Add): + xs = [i for i in Cs if expr.count(i)==cnts[i] \ + and 0 == expr.diff(i, 2)] + d = {} + for x in xs: + y = expr.diff(x) + if y not in d: + d[y]=[] + d[y].append(x) + for y in d: + if len(d[y]) > 1: + d[y].sort(key=str) + for x in d[y][1:]: + expr = expr.subs(x, 0) + return expr + + def _recursive_walk(expr): + if len(expr.args) != 0: + expr = expr.func(*[_recursive_walk(i) for i in expr.args]) + expr = _linear(expr) + return expr + + if isinstance(expr, Equality): + lhs, rhs = [_recursive_walk(i) for i in expr.args] + f = lambda i: isinstance(i, Number) or i in Cs + if isinstance(lhs, Symbol) and lhs in Cs: + rhs, lhs = lhs, rhs + if lhs.func in (Add, Symbol) and rhs.func in (Add, Symbol): + dlhs = sift([lhs] if isinstance(lhs, AtomicExpr) else lhs.args, f) + drhs = sift([rhs] if isinstance(rhs, AtomicExpr) else rhs.args, f) + for i in [True, False]: + for hs in [dlhs, drhs]: + if i not in hs: + hs[i] = [0] + # this calculation can be simplified + lhs = Add(*dlhs[False]) - Add(*drhs[False]) + rhs = Add(*drhs[True]) - Add(*dlhs[True]) + elif lhs.func in (Mul, Symbol) and rhs.func in (Mul, Symbol): + dlhs = sift([lhs] if isinstance(lhs, AtomicExpr) else lhs.args, f) + if True in dlhs: + if False not in dlhs: + dlhs[False] = [1] + lhs = Mul(*dlhs[False]) + rhs = rhs/Mul(*dlhs[True]) + return Eq(lhs, rhs) + else: + return _recursive_walk(expr) + +@vectorize(0) +def constantsimp(expr, constants): + r""" + Simplifies an expression with arbitrary constants in it. + + 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 into 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 ``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 of constants is done with limited assistance: + + 1. terms of :py:class:`~sympy.core.add.Add`\s are collected to try join + constants so `e^x (C_1 \cos(x) + C_2 \cos(x))` will simplify to `e^x + C_1 \cos(x)`; + + 2. powers with exponents that are :py:class:`~sympy.core.add.Add`\s are + expanded so `e^{C_1 + x}` will be simplified to `C_1 e^x`. + + Use :py:meth:`~sympy.solvers.ode.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 + ======== + + >>> from sympy import symbols + >>> from sympy.solvers.ode.ode import constantsimp + >>> C1, C2, C3, x, y = symbols('C1, C2, C3, x, y') + >>> constantsimp(2*C1*x, {C1, C2, C3}) + C1*x + >>> constantsimp(C1 + 2 + x, {C1, C2, C3}) + C1 + x + >>> constantsimp(C1*C2 + 2 + C2 + C3*x, {C1, C2, C3}) + C1 + C3*x + + """ + # This function works recursively. The idea is that, for Mul, + # Add, Pow, and Function, if the class has a constant in it, then + # we can simplify it, which we do by recursing down and + # simplifying up. Otherwise, we can skip that part of the + # expression. + + Cs = constants + + orig_expr = expr + + constant_subexprs = _get_constant_subexpressions(expr, Cs) + for xe in constant_subexprs: + xes = list(xe.free_symbols) + if not xes: + continue + if all(expr.count(c) == xe.count(c) for c in xes): + xes.sort(key=str) + expr = expr.subs(xe, xes[0]) + + # try to perform common sub-expression elimination of constant terms + try: + commons, rexpr = cse(expr) + commons.reverse() + rexpr = rexpr[0] + for s in commons: + cs = list(s[1].atoms(Symbol)) + if len(cs) == 1 and cs[0] in Cs and \ + cs[0] not in rexpr.atoms(Symbol) and \ + not any(cs[0] in ex for ex in commons if ex != s): + rexpr = rexpr.subs(s[0], cs[0]) + else: + rexpr = rexpr.subs(*s) + expr = rexpr + except IndexError: + pass + expr = __remove_linear_redundancies(expr, Cs) + + def _conditional_term_factoring(expr): + new_expr = terms_gcd(expr, clear=False, deep=True, expand=False) + + # we do not want to factor exponentials, so handle this separately + if new_expr.is_Mul: + infac = False + asfac = False + for m in new_expr.args: + if isinstance(m, exp): + asfac = True + elif m.is_Add: + infac = any(isinstance(fi, exp) for t in m.args + for fi in Mul.make_args(t)) + if asfac and infac: + new_expr = expr + break + return new_expr + + expr = _conditional_term_factoring(expr) + + # call recursively if more simplification is possible + if orig_expr != expr: + return constantsimp(expr, Cs) + return expr + + +def constant_renumber(expr, variables=None, newconstants=None): + r""" + Renumber arbitrary constants in ``expr`` to use the symbol names as given + in ``newconstants``. In the process, this reorders expression terms in a + standard way. + + If ``newconstants`` is not provided then the new constant names will be + ``C1``, ``C2`` etc. Otherwise ``newconstants`` should be an iterable + giving the new symbols to use for the constants in order. + + The ``variables`` argument is a list of non-constant symbols. All other + free symbols found in ``expr`` are assumed to be constants and will be + renumbered. If ``variables`` is not given then any numbered symbol + beginning with ``C`` (e.g. ``C1``) is assumed to be a constant. + + 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. + + The structure of this function is very similar to that of + :py:meth:`~sympy.solvers.ode.constantsimp`. + + Examples + ======== + + >>> from sympy import symbols + >>> from sympy.solvers.ode.ode import constant_renumber + >>> x, C1, C2, C3 = symbols('x,C1:4') + >>> expr = C3 + C2*x + C1*x**2 + >>> expr + C1*x**2 + C2*x + C3 + >>> constant_renumber(expr) + C1 + C2*x + C3*x**2 + + The ``variables`` argument specifies which are constants so that the + other symbols will not be renumbered: + + >>> constant_renumber(expr, [C1, x]) + C1*x**2 + C2 + C3*x + + The ``newconstants`` argument is used to specify what symbols to use when + replacing the constants: + + >>> constant_renumber(expr, [x], newconstants=symbols('E1:4')) + E1 + E2*x + E3*x**2 + + """ + + # System of expressions + if isinstance(expr, (set, list, tuple)): + return type(expr)(constant_renumber(Tuple(*expr), + variables=variables, newconstants=newconstants)) + + # Symbols in solution but not ODE are constants + if variables is not None: + variables = set(variables) + free_symbols = expr.free_symbols + constantsymbols = list(free_symbols - variables) + # Any Cn is a constant... + else: + variables = set() + isconstant = lambda s: s.startswith('C') and s[1:].isdigit() + constantsymbols = [sym for sym in expr.free_symbols if isconstant(sym.name)] + + # Find new constants checking that they aren't already in the ODE + if newconstants is None: + iter_constants = numbered_symbols(start=1, prefix='C', exclude=variables) + else: + iter_constants = (sym for sym in newconstants if sym not in variables) + + constants_found = [] + + # make a mapping to send all constantsymbols to S.One and use + # 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] + sort_key=lambda arg: default_sort_key(arg.subs(C_1)) + + def _constant_renumber(expr): + r""" + We need to have an internal recursive function + """ + + # For system of expressions + if isinstance(expr, Tuple): + renumbered = [_constant_renumber(e) for e in expr] + return Tuple(*renumbered) + + if isinstance(expr, Equality): + return Eq( + _constant_renumber(expr.lhs), + _constant_renumber(expr.rhs)) + + 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: + if expr not in constants_found: + constants_found.append(expr) + return expr + elif expr.is_Function or expr.is_Pow: + return expr.func( + *[_constant_renumber(x) for x in expr.args]) + else: + sortedargs = list(expr.args) + sortedargs.sort(key=sort_key) + return expr.func(*[_constant_renumber(x) for x in sortedargs]) + expr = _constant_renumber(expr) + + # Don't renumber symbols present in the ODE. + constants_found = [c for c in constants_found if c not in variables] + + # Renumbering happens here + subs_dict = dict(zip(constants_found, iter_constants)) + expr = expr.subs(subs_dict, simultaneous=True) + + return expr + + +def _handle_Integral(expr, func, hint): + r""" + Converts a solution with Integrals in it into an actual solution. + + For most hints, this simply runs ``expr.doit()``. + + """ + if hint == "nth_linear_constant_coeff_homogeneous": + sol = expr + elif not hint.endswith("_Integral"): + sol = expr.doit() + else: + sol = expr + return sol + + +# XXX: Should this function maybe go somewhere else? + + +def homogeneous_order(eq, *symbols): + 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, \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 + :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsDepDivIndep` and + :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsIndepDivDep`). + + 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 + ======== + + >>> from sympy import Function, homogeneous_order, sqrt + >>> from sympy.abc import x, y + >>> f = Function('f') + >>> homogeneous_order(f(x), f(x)) is None + True + >>> homogeneous_order(f(x,y), f(y, x), x, y) is None + True + >>> homogeneous_order(f(x), f(x), x) + 1 + >>> homogeneous_order(x**2*f(x)/sqrt(x**2+f(x)**2), x, f(x)) + 2 + >>> homogeneous_order(x**2+f(x), x, f(x)) is None + True + + """ + + if not symbols: + raise ValueError("homogeneous_order: no symbols were given.") + symset = set(symbols) + eq = sympify(eq) + + # The following are not supported + if eq.has(Order, Derivative): + return None + + # These are all constants + if (eq.is_Number or + eq.is_NumberSymbol or + eq.is_number + ): + return S.Zero + + # Replace all functions with dummy variables + dum = numbered_symbols(prefix='d', cls=Dummy) + newsyms = set() + for i in [j for j in symset if getattr(j, 'is_Function')]: + iargs = set(i.args) + if iargs.difference(symset): + return None + else: + dummyvar = next(dum) + eq = eq.subs(i, dummyvar) + symset.remove(i) + newsyms.add(dummyvar) + symset.update(newsyms) + + 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 + 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 + i, d = eqs.as_independent(t, as_Add=False) + b, e = d.as_base_exp() + if b == t: + return e + + +def ode_2nd_power_series_ordinary(eq, func, order, match): + r""" + Gives a power series solution to a second order homogeneous differential + equation with polynomial coefficients at an ordinary point. A homogeneous + differential equation is of the form + + .. math :: P(x)\frac{d^2y}{dx^2} + Q(x)\frac{dy}{dx} + R(x) y(x) = 0 + + For simplicity it is assumed that `P(x)`, `Q(x)` and `R(x)` are polynomials, + it is sufficient that `\frac{Q(x)}{P(x)}` and `\frac{R(x)}{P(x)}` exists at + `x_{0}`. A recurrence relation is obtained by substituting `y` as `\sum_{n=0}^\infty a_{n}x^{n}`, + in the differential equation, and equating the nth term. Using this relation + various terms can be generated. + + + Examples + ======== + + >>> from sympy import dsolve, Function, pprint + >>> from sympy.abc import x + >>> f = Function("f") + >>> eq = f(x).diff(x, 2) + f(x) + >>> pprint(dsolve(eq, hint='2nd_power_series_ordinary')) + / 4 2 \ / 2\ + |x x | | x | / 6\ + f(x) = C2*|-- - -- + 1| + C1*x*|1 - --| + O\x / + \24 2 / \ 6 / + + + References + ========== + - https://tutorial.math.lamar.edu/Classes/DE/SeriesSolutions.aspx + - George E. Simmons, "Differential Equations with Applications and + Historical Notes", p.p 176 - 184 + + """ + x = func.args[0] + f = func.func + C0, C1 = get_numbered_constants(eq, num=2) + n = Dummy("n", integer=True) + s = Wild("s") + k = Wild("k", exclude=[x]) + x0 = match['x0'] + terms = match['terms'] + p = match[match['a3']] + q = match[match['b3']] + r = match[match['c3']] + seriesdict = {} + recurr = Function("r") + + # Generating the recurrence relation which works this way: + # for the second order term the summation begins at n = 2. The coefficients + # p is multiplied with an*(n - 1)*(n - 2)*x**n-2 and a substitution is made such that + # the exponent of x becomes n. + # For example, if p is x, then the second degree recurrence term is + # an*(n - 1)*(n - 2)*x**n-1, substituting (n - 1) as n, it transforms to + # an+1*n*(n - 1)*x**n. + # A similar process is done with the first order and zeroth order term. + + coefflist = [(recurr(n), r), (n*recurr(n), q), (n*(n - 1)*recurr(n), p)] + for index, coeff in enumerate(coefflist): + if coeff[1]: + f2 = powsimp(expand((coeff[1]*(x - x0)**(n - index)).subs(x, x + x0))) + if f2.is_Add: + addargs = f2.args + else: + addargs = [f2] + for arg in addargs: + powm = arg.match(s*x**k) + term = coeff[0]*powm[s] + if not powm[k].is_Symbol: + term = term.subs(n, n - powm[k].as_independent(n)[0]) + startind = powm[k].subs(n, index) + # Seeing if the startterm can be reduced further. + # If it vanishes for n lesser than startind, it is + # equal to summation from n. + if startind: + for i in reversed(range(startind)): + if not term.subs(n, i): + seriesdict[term] = i + else: + seriesdict[term] = i + 1 + break + else: + seriesdict[term] = S.Zero + + # Stripping of terms so that the sum starts with the same number. + teq = S.Zero + suminit = seriesdict.values() + rkeys = seriesdict.keys() + req = Add(*rkeys) + if any(suminit): + maxval = max(suminit) + for term in seriesdict: + val = seriesdict[term] + if val != maxval: + for i in range(val, maxval): + teq += term.subs(n, val) + + finaldict = {} + if teq: + fargs = teq.atoms(AppliedUndef) + if len(fargs) == 1: + finaldict[fargs.pop()] = 0 + else: + maxf = max(fargs, key = lambda x: x.args[0]) + sol = solve(teq, maxf) + if isinstance(sol, list): + sol = sol[0] + finaldict[maxf] = sol + + # Finding the recurrence relation in terms of the largest term. + fargs = req.atoms(AppliedUndef) + maxf = max(fargs, key = lambda x: x.args[0]) + minf = min(fargs, key = lambda x: x.args[0]) + if minf.args[0].is_Symbol: + startiter = 0 + else: + startiter = -minf.args[0].as_independent(n)[0] + lhs = maxf + rhs = solve(req, maxf) + if isinstance(rhs, list): + rhs = rhs[0] + + # Checking how many values are already present + tcounter = len([t for t in finaldict.values() if t]) + + for _ in range(tcounter, terms - 3): # Assuming c0 and c1 to be arbitrary + check = rhs.subs(n, startiter) + nlhs = lhs.subs(n, startiter) + nrhs = check.subs(finaldict) + finaldict[nlhs] = nrhs + startiter += 1 + + # Post processing + series = C0 + C1*(x - x0) + for term in finaldict: + if finaldict[term]: + fact = term.args[0] + series += (finaldict[term].subs([(recurr(0), C0), (recurr(1), C1)])*( + x - x0)**fact) + series = collect(expand_mul(series), [C0, C1]) + Order(x**terms) + return Eq(f(x), series) + + +def ode_2nd_power_series_regular(eq, func, order, match): + r""" + Gives a power series solution to a second order homogeneous differential + equation with polynomial coefficients at a regular point. A second order + homogeneous differential equation is of the form + + .. math :: P(x)\frac{d^2y}{dx^2} + Q(x)\frac{dy}{dx} + R(x) y(x) = 0 + + A point is said to regular singular at `x0` if `x - x0\frac{Q(x)}{P(x)}` + and `(x - x0)^{2}\frac{R(x)}{P(x)}` are analytic at `x0`. For simplicity + `P(x)`, `Q(x)` and `R(x)` are assumed to be polynomials. The algorithm for + finding the power series solutions is: + + 1. Try expressing `(x - x0)P(x)` and `((x - x0)^{2})Q(x)` as power series + solutions about x0. Find `p0` and `q0` which are the constants of the + power series expansions. + 2. Solve the indicial equation `f(m) = m(m - 1) + m*p0 + q0`, to obtain the + roots `m1` and `m2` of the indicial equation. + 3. If `m1 - m2` is a non integer there exists two series solutions. If + `m1 = m2`, there exists only one solution. If `m1 - m2` is an integer, + then the existence of one solution is confirmed. The other solution may + or may not exist. + + The power series solution is of the form `x^{m}\sum_{n=0}^\infty a_{n}x^{n}`. The + coefficients are determined by the following recurrence relation. + `a_{n} = -\frac{\sum_{k=0}^{n-1} q_{n-k} + (m + k)p_{n-k}}{f(m + n)}`. For the case + in which `m1 - m2` is an integer, it can be seen from the recurrence relation + that for the lower root `m`, when `n` equals the difference of both the + roots, the denominator becomes zero. So if the numerator is not equal to zero, + a second series solution exists. + + + Examples + ======== + + >>> from sympy import dsolve, Function, pprint + >>> from sympy.abc import x + >>> f = Function("f") + >>> eq = x*(f(x).diff(x, 2)) + 2*(f(x).diff(x)) + x*f(x) + >>> pprint(dsolve(eq, hint='2nd_power_series_regular')) + / 6 4 2 \ + | x x x | + / 4 2 \ C1*|- --- + -- - -- + 1| + |x x | \ 720 24 2 / / 6\ + f(x) = C2*|--- - -- + 1| + ------------------------ + O\x / + \120 6 / x + + + References + ========== + - George E. Simmons, "Differential Equations with Applications and + Historical Notes", p.p 176 - 184 + + """ + x = func.args[0] + f = func.func + C0, C1 = get_numbered_constants(eq, num=2) + m = Dummy("m") # for solving the indicial equation + x0 = match['x0'] + terms = match['terms'] + p = match['p'] + q = match['q'] + + # Generating the indicial equation + indicial = [] + for term in [p, q]: + if not term.has(x): + indicial.append(term) + else: + term = series(term, x=x, n=1, x0=x0) + if isinstance(term, Order): + indicial.append(S.Zero) + else: + for arg in term.args: + if not arg.has(x): + indicial.append(arg) + break + + p0, q0 = indicial + sollist = solve(m*(m - 1) + m*p0 + q0, m) + if sollist and isinstance(sollist, list) and all( + sol.is_real for sol in sollist): + serdict1 = {} + serdict2 = {} + if len(sollist) == 1: + # Only one series solution exists in this case. + m1 = m2 = sollist.pop() + if terms-m1-1 <= 0: + return Eq(f(x), Order(terms)) + serdict1 = _frobenius(terms-m1-1, m1, p0, q0, p, q, x0, x, C0) + + else: + m1 = sollist[0] + m2 = sollist[1] + if m1 < m2: + m1, m2 = m2, m1 + # Irrespective of whether m1 - m2 is an integer or not, one + # Frobenius series solution exists. + serdict1 = _frobenius(terms-m1-1, m1, p0, q0, p, q, x0, x, C0) + if not (m1 - m2).is_integer: + # Second frobenius series solution exists. + serdict2 = _frobenius(terms-m2-1, m2, p0, q0, p, q, x0, x, C1) + else: + # Check if second frobenius series solution exists. + serdict2 = _frobenius(terms-m2-1, m2, p0, q0, p, q, x0, x, C1, check=m1) + + if serdict1: + finalseries1 = C0 + for key in serdict1: + power = int(key.name[1:]) + finalseries1 += serdict1[key]*(x - x0)**power + finalseries1 = (x - x0)**m1*finalseries1 + finalseries2 = S.Zero + if serdict2: + for key in serdict2: + power = int(key.name[1:]) + finalseries2 += serdict2[key]*(x - x0)**power + finalseries2 += C1 + finalseries2 = (x - x0)**m2*finalseries2 + return Eq(f(x), collect(finalseries1 + finalseries2, + [C0, C1]) + Order(x**terms)) + + +def _frobenius(n, m, p0, q0, p, q, x0, x, c, check=None): + r""" + Returns a dict with keys as coefficients and values as their values in terms of C0 + """ + n = int(n) + # In cases where m1 - m2 is not an integer + m2 = check + + d = Dummy("d") + numsyms = numbered_symbols("C", start=0) + numsyms = [next(numsyms) for i in range(n + 1)] + serlist = [] + for ser in [p, q]: + # Order term not present + if ser.is_polynomial(x) and Poly(ser, x).degree() <= n: + if x0: + ser = ser.subs(x, x + x0) + dict_ = Poly(ser, x).as_dict() + # Order term present + else: + tseries = series(ser, x=x0, n=n+1) + # Removing order + dict_ = Poly(list(ordered(tseries.args))[: -1], x).as_dict() + # Fill in with zeros, if coefficients are zero. + for i in range(n + 1): + if (i,) not in dict_: + dict_[(i,)] = S.Zero + serlist.append(dict_) + + pseries = serlist[0] + qseries = serlist[1] + indicial = d*(d - 1) + d*p0 + q0 + frobdict = {} + for i in range(1, n + 1): + num = c*(m*pseries[(i,)] + qseries[(i,)]) + for j in range(1, i): + sym = Symbol("C" + str(j)) + num += frobdict[sym]*((m + j)*pseries[(i - j,)] + qseries[(i - j,)]) + + # Checking for cases when m1 - m2 is an integer. If num equals zero + # then a second Frobenius series solution cannot be found. If num is not zero + # then set constant as zero and proceed. + if m2 is not None and i == m2 - m: + if num: + return False + else: + frobdict[numsyms[i]] = S.Zero + else: + frobdict[numsyms[i]] = -num/(indicial.subs(d, m+i)) + + return frobdict + +def _remove_redundant_solutions(eq, solns, order, var): + r""" + Remove redundant solutions from the set of solutions. + + This function is needed because otherwise dsolve can return + redundant solutions. As an example consider: + + eq = Eq((f(x).diff(x, 2))*f(x).diff(x), 0) + + There are two ways to find solutions to eq. The first is to solve f(x).diff(x, 2) = 0 + leading to solution f(x)=C1 + C2*x. The second is to solve the equation f(x).diff(x) = 0 + leading to the solution f(x) = C1. In this particular case we then see + that the second solution is a special case of the first and we do not + want to return it. + + This does not always happen. If we have + + eq = Eq((f(x)**2-4)*(f(x).diff(x)-4), 0) + + then we get the algebraic solution f(x) = [-2, 2] and the integral solution + f(x) = x + C1 and in this case the two solutions are not equivalent wrt + initial conditions so both should be returned. + """ + def is_special_case_of(soln1, soln2): + return _is_special_case_of(soln1, soln2, eq, order, var) + + unique_solns = [] + for soln1 in solns: + for soln2 in unique_solns.copy(): + if is_special_case_of(soln1, soln2): + break + elif is_special_case_of(soln2, soln1): + unique_solns.remove(soln2) + else: + unique_solns.append(soln1) + + return unique_solns + +def _is_special_case_of(soln1, soln2, eq, order, var): + r""" + True if soln1 is found to be a special case of soln2 wrt some value of the + constants that appear in soln2. False otherwise. + """ + # The solutions returned by dsolve may be given explicitly or implicitly. + # We will equate the sol1=(soln1.rhs - soln1.lhs), sol2=(soln2.rhs - soln2.lhs) + # of the two solutions. + # + # Since this is supposed to hold for all x it also holds for derivatives. + # For an order n ode we should be able to differentiate + # each solution n times to get n+1 equations. + # + # We then try to solve those n+1 equations for the integrations constants + # in sol2. If we can find a solution that does not depend on x then it + # means that some value of the constants in sol1 is a special case of + # sol2 corresponding to a particular choice of the integration constants. + + # In case the solution is in implicit form we subtract the sides + soln1 = soln1.rhs - soln1.lhs + soln2 = soln2.rhs - soln2.lhs + + # Work for the series solution + if soln1.has(Order) and soln2.has(Order): + if soln1.getO() == soln2.getO(): + soln1 = soln1.removeO() + soln2 = soln2.removeO() + else: + return False + elif soln1.has(Order) or soln2.has(Order): + return False + + constants1 = soln1.free_symbols.difference(eq.free_symbols) + constants2 = soln2.free_symbols.difference(eq.free_symbols) + + constants1_new = get_numbered_constants(Tuple(soln1, soln2), len(constants1)) + if len(constants1) == 1: + constants1_new = {constants1_new} + for c_old, c_new in zip(constants1, constants1_new): + soln1 = soln1.subs(c_old, c_new) + + # n equations for sol1 = sol2, sol1'=sol2', ... + lhs = soln1 + rhs = soln2 + eqns = [Eq(lhs, rhs)] + for n in range(1, order): + lhs = lhs.diff(var) + rhs = rhs.diff(var) + eq = Eq(lhs, rhs) + eqns.append(eq) + + # BooleanTrue/False awkwardly show up for trivial equations + if any(isinstance(eq, BooleanFalse) for eq in eqns): + return False + eqns = [eq for eq in eqns if not isinstance(eq, BooleanTrue)] + + try: + constant_solns = solve(eqns, constants2) + except NotImplementedError: + return False + + # Sometimes returns a dict and sometimes a list of dicts + if isinstance(constant_solns, dict): + constant_solns = [constant_solns] + + # after solving the issue 17418, maybe we don't need the following checksol code. + for constant_soln in constant_solns: + for eq in eqns: + eq=eq.rhs-eq.lhs + if checksol(eq, constant_soln) is not True: + return False + + # If any solution gives all constants as expressions that don't depend on + # x then there exists constants for soln2 that give soln1 + for constant_soln in constant_solns: + if not any(c.has(var) for c in constant_soln.values()): + return True + + return False + + +def ode_1st_power_series(eq, func, order, match): + r""" + The power series solution is a method which gives the Taylor series expansion + to the solution of a differential equation. + + For a first order differential equation `\frac{dy}{dx} = h(x, y)`, a power + series solution exists at a point `x = x_{0}` if `h(x, y)` is analytic at `x_{0}`. + The solution is given by + + .. math:: y(x) = y(x_{0}) + \sum_{n = 1}^{\infty} \frac{F_{n}(x_{0},b)(x - x_{0})^n}{n!}, + + where `y(x_{0}) = b` is the value of y at the initial value of `x_{0}`. + To compute the values of the `F_{n}(x_{0},b)` the following algorithm is + followed, until the required number of terms are generated. + + 1. `F_1 = h(x_{0}, b)` + 2. `F_{n+1} = \frac{\partial F_{n}}{\partial x} + \frac{\partial F_{n}}{\partial y}F_{1}` + + Examples + ======== + + >>> from sympy import Function, pprint, exp, dsolve + >>> from sympy.abc import x + >>> f = Function('f') + >>> eq = exp(x)*(f(x).diff(x)) - f(x) + >>> pprint(dsolve(eq, hint='1st_power_series')) + 3 4 5 + C1*x C1*x C1*x / 6\ + f(x) = C1 + C1*x - ----- + ----- + ----- + O\x / + 6 24 60 + + + References + ========== + + - Travis W. Walker, Analytic power series technique for solving first-order + differential equations, p.p 17, 18 + + """ + x = func.args[0] + y = match['y'] + f = func.func + h = -match[match['d']]/match[match['e']] + point = match['f0'] + value = match['f0val'] + terms = match['terms'] + + # First term + F = h + if not h: + return Eq(f(x), value) + + # Initialization + series = value + if terms > 1: + hc = h.subs({x: point, y: value}) + if hc.has(oo) or hc.has(nan) or hc.has(zoo): + # Derivative does not exist, not analytic + return Eq(f(x), oo) + elif hc: + series += hc*(x - point) + + for factcount in range(2, terms): + Fnew = F.diff(x) + F.diff(y)*h + Fnewc = Fnew.subs({x: point, y: value}) + # Same logic as above + if Fnewc.has(oo) or Fnewc.has(nan) or Fnewc.has(-oo) or Fnewc.has(zoo): + return Eq(f(x), oo) + series += Fnewc*((x - point)**factcount)/factorial(factcount) + F = Fnew + series += Order(x**terms) + return Eq(f(x), series) + + +def checkinfsol(eq, infinitesimals, func=None, order=None): + r""" + This function is used to check if the given infinitesimals are the + actual infinitesimals of the given first order differential equation. + This method is specific to the Lie Group Solver of ODEs. + + As of now, it simply checks, by substituting the infinitesimals in the + partial differential equation. + + + .. math:: \frac{\partial \eta}{\partial x} + \left(\frac{\partial \eta}{\partial y} + - \frac{\partial \xi}{\partial x}\right)*h + - \frac{\partial \xi}{\partial y}*h^{2} + - \xi\frac{\partial h}{\partial x} - \eta\frac{\partial h}{\partial y} = 0 + + + where `\eta`, and `\xi` are the infinitesimals and `h(x,y) = \frac{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 0. + + """ + 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', exclude = [df]) + match = collect(expand(eq), df).match(a*df + b) + + if match: + h = -simplify(match[b]/match[a]) + else: + try: + sol = solve(eq, df) + except NotImplementedError: + raise NotImplementedError("Infinitesimals for the " + "first order ODE could not be found") + else: + h = sol[0] # Find infinitesimals for one solution + + y = Dummy('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.subs(y, func))) + else: + soltup.append((True, 0)) + return soltup + + +def sysode_linear_2eq_order1(match_): + x = match_['func'][0].func + y = match_['func'][1].func + func = match_['func'] + fc = match_['func_coeff'] + eq = match_['eq'] + r = {} + t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] + for i in range(2): + eq[i] = Add(*[terms/fc[i,func[i],1] for terms in Add.make_args(eq[i])]) + + # for equations Eq(a1*diff(x(t),t), a*x(t) + b*y(t) + k1) + # and Eq(a2*diff(x(t),t), c*x(t) + d*y(t) + k2) + r['a'] = -fc[0,x(t),0]/fc[0,x(t),1] + r['c'] = -fc[1,x(t),0]/fc[1,y(t),1] + r['b'] = -fc[0,y(t),0]/fc[0,x(t),1] + r['d'] = -fc[1,y(t),0]/fc[1,y(t),1] + forcing = [S.Zero,S.Zero] + for i in range(2): + for j in Add.make_args(eq[i]): + if not j.has(x(t), y(t)): + forcing[i] += j + if not (forcing[0].has(t) or forcing[1].has(t)): + r['k1'] = forcing[0] + r['k2'] = forcing[1] + else: + raise NotImplementedError("Only homogeneous problems are supported" + + " (and constant inhomogeneity)") + + if match_['type_of_equation'] == 'type6': + sol = _linear_2eq_order1_type6(x, y, t, r, eq) + if match_['type_of_equation'] == 'type7': + sol = _linear_2eq_order1_type7(x, y, t, r, eq) + return sol + +def _linear_2eq_order1_type6(x, y, t, r, eq): + r""" + The equations of this type of ode are . + + .. math:: x' = f(t) x + g(t) y + + .. math:: y' = a [f(t) + a h(t)] x + a [g(t) - h(t)] y + + This is solved by first multiplying the first equation by `-a` and adding + it to the second equation to obtain + + .. math:: y' - a x' = -a h(t) (y - a x) + + Setting `U = y - ax` and integrating the equation we arrive at + + .. math:: y - ax = C_1 e^{-a \int h(t) \,dt} + + and on substituting the value of y in first equation give rise to first order ODEs. After solving for + `x`, we can obtain `y` by substituting the value of `x` in second equation. + + """ + C1, C2, C3, C4 = get_numbered_constants(eq, num=4) + p = 0 + q = 0 + p1 = cancel(r['c']/cancel(r['c']/r['d']).as_numer_denom()[0]) + p2 = cancel(r['a']/cancel(r['a']/r['b']).as_numer_denom()[0]) + for n, i in enumerate([p1, p2]): + for j in Mul.make_args(collect_const(i)): + if not j.has(t): + q = j + if q!=0 and n==0: + if ((r['c']/j - r['a'])/(r['b'] - r['d']/j)) == j: + p = 1 + s = j + break + if q!=0 and n==1: + if ((r['a']/j - r['c'])/(r['d'] - r['b']/j)) == j: + p = 2 + s = j + break + + if p == 1: + equ = diff(x(t),t) - r['a']*x(t) - r['b']*(s*x(t) + C1*exp(-s*Integral(r['b'] - r['d']/s, t))) + hint1 = classify_ode(equ)[1] + sol1 = dsolve(equ, hint=hint1+'_Integral').rhs + sol2 = s*sol1 + C1*exp(-s*Integral(r['b'] - r['d']/s, t)) + elif p ==2: + equ = diff(y(t),t) - r['c']*y(t) - r['d']*s*y(t) + C1*exp(-s*Integral(r['d'] - r['b']/s, t)) + hint1 = classify_ode(equ)[1] + sol2 = dsolve(equ, hint=hint1+'_Integral').rhs + sol1 = s*sol2 + C1*exp(-s*Integral(r['d'] - r['b']/s, t)) + return [Eq(x(t), sol1), Eq(y(t), sol2)] + +def _linear_2eq_order1_type7(x, y, t, r, eq): + r""" + The equations of this type of ode are . + + .. math:: x' = f(t) x + g(t) y + + .. math:: y' = h(t) x + p(t) y + + Differentiating the first equation and substituting the value of `y` + from second equation will give a second-order linear equation + + .. math:: g x'' - (fg + gp + g') x' + (fgp - g^{2} h + f g' - f' g) x = 0 + + This above equation can be easily integrated if following conditions are satisfied. + + 1. `fgp - g^{2} h + f g' - f' g = 0` + + 2. `fgp - g^{2} h + f g' - f' g = ag, fg + gp + g' = bg` + + If first condition is satisfied then it is solved by current dsolve solver and in second case it becomes + a constant coefficient differential equation which is also solved by current solver. + + Otherwise if the above condition fails then, + a particular solution is assumed as `x = x_0(t)` and `y = y_0(t)` + Then the general solution is expressed as + + .. math:: x = C_1 x_0(t) + C_2 x_0(t) \int \frac{g(t) F(t) P(t)}{x_0^{2}(t)} \,dt + + .. math:: y = C_1 y_0(t) + C_2 [\frac{F(t) P(t)}{x_0(t)} + y_0(t) \int \frac{g(t) F(t) P(t)}{x_0^{2}(t)} \,dt] + + where C1 and C2 are arbitrary constants and + + .. math:: F(t) = e^{\int f(t) \,dt}, P(t) = e^{\int p(t) \,dt} + + """ + C1, C2, C3, C4 = get_numbered_constants(eq, num=4) + e1 = r['a']*r['b']*r['c'] - r['b']**2*r['c'] + r['a']*diff(r['b'],t) - diff(r['a'],t)*r['b'] + e2 = r['a']*r['c']*r['d'] - r['b']*r['c']**2 + diff(r['c'],t)*r['d'] - r['c']*diff(r['d'],t) + m1 = r['a']*r['b'] + r['b']*r['d'] + diff(r['b'],t) + m2 = r['a']*r['c'] + r['c']*r['d'] + diff(r['c'],t) + if e1 == 0: + sol1 = dsolve(r['b']*diff(x(t),t,t) - m1*diff(x(t),t)).rhs + sol2 = dsolve(diff(y(t),t) - r['c']*sol1 - r['d']*y(t)).rhs + elif e2 == 0: + sol2 = dsolve(r['c']*diff(y(t),t,t) - m2*diff(y(t),t)).rhs + sol1 = dsolve(diff(x(t),t) - r['a']*x(t) - r['b']*sol2).rhs + elif not (e1/r['b']).has(t) and not (m1/r['b']).has(t): + sol1 = dsolve(diff(x(t),t,t) - (m1/r['b'])*diff(x(t),t) - (e1/r['b'])*x(t)).rhs + sol2 = dsolve(diff(y(t),t) - r['c']*sol1 - r['d']*y(t)).rhs + elif not (e2/r['c']).has(t) and not (m2/r['c']).has(t): + sol2 = dsolve(diff(y(t),t,t) - (m2/r['c'])*diff(y(t),t) - (e2/r['c'])*y(t)).rhs + sol1 = dsolve(diff(x(t),t) - r['a']*x(t) - r['b']*sol2).rhs + else: + x0 = Function('x0')(t) # x0 and y0 being particular solutions + y0 = Function('y0')(t) + F = exp(Integral(r['a'],t)) + P = exp(Integral(r['d'],t)) + sol1 = C1*x0 + C2*x0*Integral(r['b']*F*P/x0**2, t) + sol2 = C1*y0 + C2*(F*P/x0 + y0*Integral(r['b']*F*P/x0**2, t)) + return [Eq(x(t), sol1), Eq(y(t), sol2)] + + +def sysode_nonlinear_2eq_order1(match_): + func = match_['func'] + eq = match_['eq'] + fc = match_['func_coeff'] + t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] + if match_['type_of_equation'] == 'type5': + sol = _nonlinear_2eq_order1_type5(func, t, eq) + return sol + x = func[0].func + y = func[1].func + for i in range(2): + eqs = 0 + for terms in Add.make_args(eq[i]): + eqs += terms/fc[i,func[i],1] + eq[i] = eqs + if match_['type_of_equation'] == 'type1': + sol = _nonlinear_2eq_order1_type1(x, y, t, eq) + elif match_['type_of_equation'] == 'type2': + sol = _nonlinear_2eq_order1_type2(x, y, t, eq) + elif match_['type_of_equation'] == 'type3': + sol = _nonlinear_2eq_order1_type3(x, y, t, eq) + elif match_['type_of_equation'] == 'type4': + sol = _nonlinear_2eq_order1_type4(x, y, t, eq) + return sol + + +def _nonlinear_2eq_order1_type1(x, y, t, eq): + r""" + Equations: + + .. math:: x' = x^n F(x,y) + + .. math:: y' = g(y) F(x,y) + + Solution: + + .. math:: x = \varphi(y), \int \frac{1}{g(y) F(\varphi(y),y)} \,dy = t + C_2 + + where + + if `n \neq 1` + + .. math:: \varphi = [C_1 + (1-n) \int \frac{1}{g(y)} \,dy]^{\frac{1}{1-n}} + + if `n = 1` + + .. math:: \varphi = C_1 e^{\int \frac{1}{g(y)} \,dy} + + where `C_1` and `C_2` are arbitrary constants. + + """ + C1, C2 = get_numbered_constants(eq, num=2) + n = Wild('n', exclude=[x(t),y(t)]) + f = Wild('f') + u, v = symbols('u, v') + r = eq[0].match(diff(x(t),t) - x(t)**n*f) + g = ((diff(y(t),t) - eq[1])/r[f]).subs(y(t),v) + F = r[f].subs(x(t),u).subs(y(t),v) + n = r[n] + if n!=1: + phi = (C1 + (1-n)*Integral(1/g, v))**(1/(1-n)) + else: + phi = C1*exp(Integral(1/g, v)) + phi = phi.doit() + sol2 = solve(Integral(1/(g*F.subs(u,phi)), v).doit() - t - C2, v) + sol = [] + for sols in sol2: + sol.append(Eq(x(t),phi.subs(v, sols))) + sol.append(Eq(y(t), sols)) + return sol + +def _nonlinear_2eq_order1_type2(x, y, t, eq): + r""" + Equations: + + .. math:: x' = e^{\lambda x} F(x,y) + + .. math:: y' = g(y) F(x,y) + + Solution: + + .. math:: x = \varphi(y), \int \frac{1}{g(y) F(\varphi(y),y)} \,dy = t + C_2 + + where + + if `\lambda \neq 0` + + .. math:: \varphi = -\frac{1}{\lambda} log(C_1 - \lambda \int \frac{1}{g(y)} \,dy) + + if `\lambda = 0` + + .. math:: \varphi = C_1 + \int \frac{1}{g(y)} \,dy + + where `C_1` and `C_2` are arbitrary constants. + + """ + C1, C2 = get_numbered_constants(eq, num=2) + n = Wild('n', exclude=[x(t),y(t)]) + f = Wild('f') + u, v = symbols('u, v') + r = eq[0].match(diff(x(t),t) - exp(n*x(t))*f) + g = ((diff(y(t),t) - eq[1])/r[f]).subs(y(t),v) + F = r[f].subs(x(t),u).subs(y(t),v) + n = r[n] + if n: + phi = -1/n*log(C1 - n*Integral(1/g, v)) + else: + phi = C1 + Integral(1/g, v) + phi = phi.doit() + sol2 = solve(Integral(1/(g*F.subs(u,phi)), v).doit() - t - C2, v) + sol = [] + for sols in sol2: + sol.append(Eq(x(t),phi.subs(v, sols))) + sol.append(Eq(y(t), sols)) + return sol + +def _nonlinear_2eq_order1_type3(x, y, t, eq): + r""" + Autonomous system of general form + + .. math:: x' = F(x,y) + + .. math:: y' = G(x,y) + + Assuming `y = y(x, C_1)` where `C_1` is an arbitrary constant is the general + solution of the first-order equation + + .. math:: F(x,y) y'_x = G(x,y) + + Then the general solution of the original system of equations has the form + + .. math:: \int \frac{1}{F(x,y(x,C_1))} \,dx = t + C_1 + + """ + C1, C2, C3, C4 = get_numbered_constants(eq, num=4) + v = Function('v') + u = Symbol('u') + f = Wild('f') + g = Wild('g') + r1 = eq[0].match(diff(x(t),t) - f) + r2 = eq[1].match(diff(y(t),t) - g) + F = r1[f].subs(x(t), u).subs(y(t), v(u)) + G = r2[g].subs(x(t), u).subs(y(t), v(u)) + sol2r = dsolve(Eq(diff(v(u), u), G/F)) + if isinstance(sol2r, Equality): + sol2r = [sol2r] + for sol2s in sol2r: + sol1 = solve(Integral(1/F.subs(v(u), sol2s.rhs), u).doit() - t - C2, u) + sol = [] + for sols in sol1: + sol.append(Eq(x(t), sols)) + sol.append(Eq(y(t), (sol2s.rhs).subs(u, sols))) + return sol + +def _nonlinear_2eq_order1_type4(x, y, t, eq): + r""" + Equation: + + .. math:: x' = f_1(x) g_1(y) \phi(x,y,t) + + .. math:: y' = f_2(x) g_2(y) \phi(x,y,t) + + First integral: + + .. math:: \int \frac{f_2(x)}{f_1(x)} \,dx - \int \frac{g_1(y)}{g_2(y)} \,dy = C + + where `C` is an arbitrary constant. + + On solving the first integral for `x` (resp., `y` ) and on substituting the + resulting expression into either equation of the original solution, one + arrives at a first-order equation for determining `y` (resp., `x` ). + + """ + C1, C2 = get_numbered_constants(eq, num=2) + u, v = symbols('u, v') + U, V = symbols('U, V', cls=Function) + f = Wild('f') + g = Wild('g') + f1 = Wild('f1', exclude=[v,t]) + f2 = Wild('f2', exclude=[v,t]) + g1 = Wild('g1', exclude=[u,t]) + g2 = Wild('g2', exclude=[u,t]) + r1 = eq[0].match(diff(x(t),t) - f) + r2 = eq[1].match(diff(y(t),t) - g) + num, den = ( + (r1[f].subs(x(t),u).subs(y(t),v))/ + (r2[g].subs(x(t),u).subs(y(t),v))).as_numer_denom() + R1 = num.match(f1*g1) + R2 = den.match(f2*g2) + phi = (r1[f].subs(x(t),u).subs(y(t),v))/num + F1 = R1[f1]; F2 = R2[f2] + G1 = R1[g1]; G2 = R2[g2] + sol1r = solve(Integral(F2/F1, u).doit() - Integral(G1/G2,v).doit() - C1, u) + sol2r = solve(Integral(F2/F1, u).doit() - Integral(G1/G2,v).doit() - C1, v) + sol = [] + for sols in sol1r: + sol.append(Eq(y(t), dsolve(diff(V(t),t) - F2.subs(u,sols).subs(v,V(t))*G2.subs(v,V(t))*phi.subs(u,sols).subs(v,V(t))).rhs)) + for sols in sol2r: + sol.append(Eq(x(t), dsolve(diff(U(t),t) - F1.subs(u,U(t))*G1.subs(v,sols).subs(u,U(t))*phi.subs(v,sols).subs(u,U(t))).rhs)) + return set(sol) + +def _nonlinear_2eq_order1_type5(func, t, eq): + r""" + Clairaut system of ODEs + + .. math:: x = t x' + F(x',y') + + .. math:: y = t y' + G(x',y') + + The following are solutions of the system + + `(i)` straight lines: + + .. math:: x = C_1 t + F(C_1, C_2), y = C_2 t + G(C_1, C_2) + + where `C_1` and `C_2` are arbitrary constants; + + `(ii)` envelopes of the above lines; + + `(iii)` continuously differentiable lines made up from segments of the lines + `(i)` and `(ii)`. + + """ + C1, C2 = get_numbered_constants(eq, num=2) + f = Wild('f') + g = Wild('g') + def check_type(x, y): + r1 = eq[0].match(t*diff(x(t),t) - x(t) + f) + r2 = eq[1].match(t*diff(y(t),t) - y(t) + g) + if not (r1 and r2): + r1 = eq[0].match(diff(x(t),t) - x(t)/t + f/t) + r2 = eq[1].match(diff(y(t),t) - y(t)/t + g/t) + if not (r1 and r2): + r1 = (-eq[0]).match(t*diff(x(t),t) - x(t) + f) + r2 = (-eq[1]).match(t*diff(y(t),t) - y(t) + g) + if not (r1 and r2): + r1 = (-eq[0]).match(diff(x(t),t) - x(t)/t + f/t) + r2 = (-eq[1]).match(diff(y(t),t) - y(t)/t + g/t) + return [r1, r2] + for func_ in func: + if isinstance(func_, list): + x = func[0][0].func + y = func[0][1].func + [r1, r2] = check_type(x, y) + if not (r1 and r2): + [r1, r2] = check_type(y, x) + x, y = y, x + x1 = diff(x(t),t); y1 = diff(y(t),t) + return {Eq(x(t), C1*t + r1[f].subs(x1,C1).subs(y1,C2)), Eq(y(t), C2*t + r2[g].subs(x1,C1).subs(y1,C2))} + +def sysode_nonlinear_3eq_order1(match_): + x = match_['func'][0].func + y = match_['func'][1].func + z = match_['func'][2].func + eq = match_['eq'] + t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] + if match_['type_of_equation'] == 'type1': + sol = _nonlinear_3eq_order1_type1(x, y, z, t, eq) + if match_['type_of_equation'] == 'type2': + sol = _nonlinear_3eq_order1_type2(x, y, z, t, eq) + if match_['type_of_equation'] == 'type3': + sol = _nonlinear_3eq_order1_type3(x, y, z, t, eq) + if match_['type_of_equation'] == 'type4': + sol = _nonlinear_3eq_order1_type4(x, y, z, t, eq) + if match_['type_of_equation'] == 'type5': + sol = _nonlinear_3eq_order1_type5(x, y, z, t, eq) + return sol + +def _nonlinear_3eq_order1_type1(x, y, z, t, eq): + r""" + Equations: + + .. math:: a x' = (b - c) y z, \enspace b y' = (c - a) z x, \enspace c z' = (a - b) x y + + First Integrals: + + .. math:: a x^{2} + b y^{2} + c z^{2} = C_1 + + .. math:: a^{2} x^{2} + b^{2} y^{2} + c^{2} z^{2} = C_2 + + where `C_1` and `C_2` are arbitrary constants. On solving the integrals for `y` and + `z` and on substituting the resulting expressions into the first equation of the + system, we arrives at a separable first-order equation on `x`. Similarly doing that + for other two equations, we will arrive at first order equation on `y` and `z` too. + + References + ========== + -https://eqworld.ipmnet.ru/en/solutions/sysode/sode0401.pdf + + """ + C1, C2 = get_numbered_constants(eq, num=2) + u, v, w = symbols('u, v, w') + p = Wild('p', exclude=[x(t), y(t), z(t), t]) + q = Wild('q', exclude=[x(t), y(t), z(t), t]) + s = Wild('s', exclude=[x(t), y(t), z(t), t]) + r = (diff(x(t),t) - eq[0]).match(p*y(t)*z(t)) + r.update((diff(y(t),t) - eq[1]).match(q*z(t)*x(t))) + r.update((diff(z(t),t) - eq[2]).match(s*x(t)*y(t))) + n1, d1 = r[p].as_numer_denom() + n2, d2 = r[q].as_numer_denom() + n3, d3 = r[s].as_numer_denom() + val = solve([n1*u-d1*v+d1*w, d2*u+n2*v-d2*w, d3*u-d3*v-n3*w],[u,v]) + vals = [val[v], val[u]] + c = lcm(vals[0].as_numer_denom()[1], vals[1].as_numer_denom()[1]) + b = vals[0].subs(w, c) + a = vals[1].subs(w, c) + y_x = sqrt(((c*C1-C2) - a*(c-a)*x(t)**2)/(b*(c-b))) + z_x = sqrt(((b*C1-C2) - a*(b-a)*x(t)**2)/(c*(b-c))) + z_y = sqrt(((a*C1-C2) - b*(a-b)*y(t)**2)/(c*(a-c))) + x_y = sqrt(((c*C1-C2) - b*(c-b)*y(t)**2)/(a*(c-a))) + x_z = sqrt(((b*C1-C2) - c*(b-c)*z(t)**2)/(a*(b-a))) + y_z = sqrt(((a*C1-C2) - c*(a-c)*z(t)**2)/(b*(a-b))) + sol1 = dsolve(a*diff(x(t),t) - (b-c)*y_x*z_x) + sol2 = dsolve(b*diff(y(t),t) - (c-a)*z_y*x_y) + sol3 = dsolve(c*diff(z(t),t) - (a-b)*x_z*y_z) + return [sol1, sol2, sol3] + + +def _nonlinear_3eq_order1_type2(x, y, z, t, eq): + r""" + Equations: + + .. math:: a x' = (b - c) y z f(x, y, z, t) + + .. math:: b y' = (c - a) z x f(x, y, z, t) + + .. math:: c z' = (a - b) x y f(x, y, z, t) + + First Integrals: + + .. math:: a x^{2} + b y^{2} + c z^{2} = C_1 + + .. math:: a^{2} x^{2} + b^{2} y^{2} + c^{2} z^{2} = C_2 + + where `C_1` and `C_2` are arbitrary constants. On solving the integrals for `y` and + `z` and on substituting the resulting expressions into the first equation of the + system, we arrives at a first-order differential equations on `x`. Similarly doing + that for other two equations we will arrive at first order equation on `y` and `z`. + + References + ========== + -https://eqworld.ipmnet.ru/en/solutions/sysode/sode0402.pdf + + """ + C1, C2 = get_numbered_constants(eq, num=2) + u, v, w = symbols('u, v, w') + p = Wild('p', exclude=[x(t), y(t), z(t), t]) + q = Wild('q', exclude=[x(t), y(t), z(t), t]) + s = Wild('s', exclude=[x(t), y(t), z(t), t]) + f = Wild('f') + r1 = (diff(x(t),t) - eq[0]).match(y(t)*z(t)*f) + r = collect_const(r1[f]).match(p*f) + r.update(((diff(y(t),t) - eq[1])/r[f]).match(q*z(t)*x(t))) + r.update(((diff(z(t),t) - eq[2])/r[f]).match(s*x(t)*y(t))) + n1, d1 = r[p].as_numer_denom() + n2, d2 = r[q].as_numer_denom() + n3, d3 = r[s].as_numer_denom() + val = solve([n1*u-d1*v+d1*w, d2*u+n2*v-d2*w, -d3*u+d3*v+n3*w],[u,v]) + vals = [val[v], val[u]] + c = lcm(vals[0].as_numer_denom()[1], vals[1].as_numer_denom()[1]) + a = vals[0].subs(w, c) + b = vals[1].subs(w, c) + y_x = sqrt(((c*C1-C2) - a*(c-a)*x(t)**2)/(b*(c-b))) + z_x = sqrt(((b*C1-C2) - a*(b-a)*x(t)**2)/(c*(b-c))) + z_y = sqrt(((a*C1-C2) - b*(a-b)*y(t)**2)/(c*(a-c))) + x_y = sqrt(((c*C1-C2) - b*(c-b)*y(t)**2)/(a*(c-a))) + x_z = sqrt(((b*C1-C2) - c*(b-c)*z(t)**2)/(a*(b-a))) + y_z = sqrt(((a*C1-C2) - c*(a-c)*z(t)**2)/(b*(a-b))) + sol1 = dsolve(a*diff(x(t),t) - (b-c)*y_x*z_x*r[f]) + sol2 = dsolve(b*diff(y(t),t) - (c-a)*z_y*x_y*r[f]) + sol3 = dsolve(c*diff(z(t),t) - (a-b)*x_z*y_z*r[f]) + return [sol1, sol2, sol3] + +def _nonlinear_3eq_order1_type3(x, y, z, t, eq): + r""" + Equations: + + .. math:: x' = c F_2 - b F_3, \enspace y' = a F_3 - c F_1, \enspace z' = b F_1 - a F_2 + + where `F_n = F_n(x, y, z, t)`. + + 1. First Integral: + + .. math:: a x + b y + c z = C_1, + + where C is an arbitrary constant. + + 2. If we assume function `F_n` to be independent of `t`,i.e, `F_n` = `F_n (x, y, z)` + Then, on eliminating `t` and `z` from the first two equation of the system, one + arrives at the first-order equation + + .. math:: \frac{dy}{dx} = \frac{a F_3 (x, y, z) - c F_1 (x, y, z)}{c F_2 (x, y, z) - + b F_3 (x, y, z)} + + where `z = \frac{1}{c} (C_1 - a x - b y)` + + References + ========== + -https://eqworld.ipmnet.ru/en/solutions/sysode/sode0404.pdf + + """ + C1 = get_numbered_constants(eq, num=1) + u, v, w = symbols('u, v, w') + fu, fv, fw = symbols('u, v, w', cls=Function) + p = Wild('p', exclude=[x(t), y(t), z(t), t]) + q = Wild('q', exclude=[x(t), y(t), z(t), t]) + s = Wild('s', exclude=[x(t), y(t), z(t), t]) + F1, F2, F3 = symbols('F1, F2, F3', cls=Wild) + r1 = (diff(x(t), t) - eq[0]).match(F2-F3) + r = collect_const(r1[F2]).match(s*F2) + r.update(collect_const(r1[F3]).match(q*F3)) + if eq[1].has(r[F2]) and not eq[1].has(r[F3]): + r[F2], r[F3] = r[F3], r[F2] + r[s], r[q] = -r[q], -r[s] + r.update((diff(y(t), t) - eq[1]).match(p*r[F3] - r[s]*F1)) + a = r[p]; b = r[q]; c = r[s] + F1 = r[F1].subs(x(t), u).subs(y(t),v).subs(z(t), w) + F2 = r[F2].subs(x(t), u).subs(y(t),v).subs(z(t), w) + F3 = r[F3].subs(x(t), u).subs(y(t),v).subs(z(t), w) + z_xy = (C1-a*u-b*v)/c + y_zx = (C1-a*u-c*w)/b + x_yz = (C1-b*v-c*w)/a + y_x = dsolve(diff(fv(u),u) - ((a*F3-c*F1)/(c*F2-b*F3)).subs(w,z_xy).subs(v,fv(u))).rhs + z_x = dsolve(diff(fw(u),u) - ((b*F1-a*F2)/(c*F2-b*F3)).subs(v,y_zx).subs(w,fw(u))).rhs + z_y = dsolve(diff(fw(v),v) - ((b*F1-a*F2)/(a*F3-c*F1)).subs(u,x_yz).subs(w,fw(v))).rhs + x_y = dsolve(diff(fu(v),v) - ((c*F2-b*F3)/(a*F3-c*F1)).subs(w,z_xy).subs(u,fu(v))).rhs + y_z = dsolve(diff(fv(w),w) - ((a*F3-c*F1)/(b*F1-a*F2)).subs(u,x_yz).subs(v,fv(w))).rhs + x_z = dsolve(diff(fu(w),w) - ((c*F2-b*F3)/(b*F1-a*F2)).subs(v,y_zx).subs(u,fu(w))).rhs + sol1 = dsolve(diff(fu(t),t) - (c*F2 - b*F3).subs(v,y_x).subs(w,z_x).subs(u,fu(t))).rhs + sol2 = dsolve(diff(fv(t),t) - (a*F3 - c*F1).subs(u,x_y).subs(w,z_y).subs(v,fv(t))).rhs + sol3 = dsolve(diff(fw(t),t) - (b*F1 - a*F2).subs(u,x_z).subs(v,y_z).subs(w,fw(t))).rhs + return [sol1, sol2, sol3] + +def _nonlinear_3eq_order1_type4(x, y, z, t, eq): + r""" + Equations: + + .. math:: x' = c z F_2 - b y F_3, \enspace y' = a x F_3 - c z F_1, \enspace z' = b y F_1 - a x F_2 + + where `F_n = F_n (x, y, z, t)` + + 1. First integral: + + .. math:: a x^{2} + b y^{2} + c z^{2} = C_1 + + where `C` is an arbitrary constant. + + 2. Assuming the function `F_n` is independent of `t`: `F_n = F_n (x, y, z)`. Then on + eliminating `t` and `z` from the first two equations of the system, one arrives at + the first-order equation + + .. math:: \frac{dy}{dx} = \frac{a x F_3 (x, y, z) - c z F_1 (x, y, z)} + {c z F_2 (x, y, z) - b y F_3 (x, y, z)} + + where `z = \pm \sqrt{\frac{1}{c} (C_1 - a x^{2} - b y^{2})}` + + References + ========== + -https://eqworld.ipmnet.ru/en/solutions/sysode/sode0405.pdf + + """ + C1 = get_numbered_constants(eq, num=1) + u, v, w = symbols('u, v, w') + p = Wild('p', exclude=[x(t), y(t), z(t), t]) + q = Wild('q', exclude=[x(t), y(t), z(t), t]) + s = Wild('s', exclude=[x(t), y(t), z(t), t]) + F1, F2, F3 = symbols('F1, F2, F3', cls=Wild) + r1 = eq[0].match(diff(x(t),t) - z(t)*F2 + y(t)*F3) + r = collect_const(r1[F2]).match(s*F2) + r.update(collect_const(r1[F3]).match(q*F3)) + if eq[1].has(r[F2]) and not eq[1].has(r[F3]): + r[F2], r[F3] = r[F3], r[F2] + r[s], r[q] = -r[q], -r[s] + r.update((diff(y(t),t) - eq[1]).match(p*x(t)*r[F3] - r[s]*z(t)*F1)) + a = r[p]; b = r[q]; c = r[s] + F1 = r[F1].subs(x(t),u).subs(y(t),v).subs(z(t),w) + F2 = r[F2].subs(x(t),u).subs(y(t),v).subs(z(t),w) + F3 = r[F3].subs(x(t),u).subs(y(t),v).subs(z(t),w) + x_yz = sqrt((C1 - b*v**2 - c*w**2)/a) + y_zx = sqrt((C1 - c*w**2 - a*u**2)/b) + z_xy = sqrt((C1 - a*u**2 - b*v**2)/c) + y_x = dsolve(diff(v(u),u) - ((a*u*F3-c*w*F1)/(c*w*F2-b*v*F3)).subs(w,z_xy).subs(v,v(u))).rhs + z_x = dsolve(diff(w(u),u) - ((b*v*F1-a*u*F2)/(c*w*F2-b*v*F3)).subs(v,y_zx).subs(w,w(u))).rhs + z_y = dsolve(diff(w(v),v) - ((b*v*F1-a*u*F2)/(a*u*F3-c*w*F1)).subs(u,x_yz).subs(w,w(v))).rhs + x_y = dsolve(diff(u(v),v) - ((c*w*F2-b*v*F3)/(a*u*F3-c*w*F1)).subs(w,z_xy).subs(u,u(v))).rhs + y_z = dsolve(diff(v(w),w) - ((a*u*F3-c*w*F1)/(b*v*F1-a*u*F2)).subs(u,x_yz).subs(v,v(w))).rhs + x_z = dsolve(diff(u(w),w) - ((c*w*F2-b*v*F3)/(b*v*F1-a*u*F2)).subs(v,y_zx).subs(u,u(w))).rhs + sol1 = dsolve(diff(u(t),t) - (c*w*F2 - b*v*F3).subs(v,y_x).subs(w,z_x).subs(u,u(t))).rhs + sol2 = dsolve(diff(v(t),t) - (a*u*F3 - c*w*F1).subs(u,x_y).subs(w,z_y).subs(v,v(t))).rhs + sol3 = dsolve(diff(w(t),t) - (b*v*F1 - a*u*F2).subs(u,x_z).subs(v,y_z).subs(w,w(t))).rhs + return [sol1, sol2, sol3] + +def _nonlinear_3eq_order1_type5(x, y, z, t, eq): + r""" + .. math:: x' = x (c F_2 - b F_3), \enspace y' = y (a F_3 - c F_1), \enspace z' = z (b F_1 - a F_2) + + where `F_n = F_n (x, y, z, t)` and are arbitrary functions. + + First Integral: + + .. math:: \left|x\right|^{a} \left|y\right|^{b} \left|z\right|^{c} = C_1 + + where `C` is an arbitrary constant. If the function `F_n` is independent of `t`, + then, by eliminating `t` and `z` from the first two equations of the system, one + arrives at a first-order equation. + + References + ========== + -https://eqworld.ipmnet.ru/en/solutions/sysode/sode0406.pdf + + """ + C1 = get_numbered_constants(eq, num=1) + u, v, w = symbols('u, v, w') + fu, fv, fw = symbols('u, v, w', cls=Function) + p = Wild('p', exclude=[x(t), y(t), z(t), t]) + q = Wild('q', exclude=[x(t), y(t), z(t), t]) + s = Wild('s', exclude=[x(t), y(t), z(t), t]) + F1, F2, F3 = symbols('F1, F2, F3', cls=Wild) + r1 = eq[0].match(diff(x(t), t) - x(t)*F2 + x(t)*F3) + r = collect_const(r1[F2]).match(s*F2) + r.update(collect_const(r1[F3]).match(q*F3)) + if eq[1].has(r[F2]) and not eq[1].has(r[F3]): + r[F2], r[F3] = r[F3], r[F2] + r[s], r[q] = -r[q], -r[s] + r.update((diff(y(t), t) - eq[1]).match(y(t)*(p*r[F3] - r[s]*F1))) + a = r[p]; b = r[q]; c = r[s] + F1 = r[F1].subs(x(t), u).subs(y(t), v).subs(z(t), w) + F2 = r[F2].subs(x(t), u).subs(y(t), v).subs(z(t), w) + F3 = r[F3].subs(x(t), u).subs(y(t), v).subs(z(t), w) + x_yz = (C1*v**-b*w**-c)**-a + y_zx = (C1*w**-c*u**-a)**-b + z_xy = (C1*u**-a*v**-b)**-c + y_x = dsolve(diff(fv(u), u) - ((v*(a*F3 - c*F1))/(u*(c*F2 - b*F3))).subs(w, z_xy).subs(v, fv(u))).rhs + z_x = dsolve(diff(fw(u), u) - ((w*(b*F1 - a*F2))/(u*(c*F2 - b*F3))).subs(v, y_zx).subs(w, fw(u))).rhs + z_y = dsolve(diff(fw(v), v) - ((w*(b*F1 - a*F2))/(v*(a*F3 - c*F1))).subs(u, x_yz).subs(w, fw(v))).rhs + x_y = dsolve(diff(fu(v), v) - ((u*(c*F2 - b*F3))/(v*(a*F3 - c*F1))).subs(w, z_xy).subs(u, fu(v))).rhs + y_z = dsolve(diff(fv(w), w) - ((v*(a*F3 - c*F1))/(w*(b*F1 - a*F2))).subs(u, x_yz).subs(v, fv(w))).rhs + x_z = dsolve(diff(fu(w), w) - ((u*(c*F2 - b*F3))/(w*(b*F1 - a*F2))).subs(v, y_zx).subs(u, fu(w))).rhs + sol1 = dsolve(diff(fu(t), t) - (u*(c*F2 - b*F3)).subs(v, y_x).subs(w, z_x).subs(u, fu(t))).rhs + sol2 = dsolve(diff(fv(t), t) - (v*(a*F3 - c*F1)).subs(u, x_y).subs(w, z_y).subs(v, fv(t))).rhs + sol3 = dsolve(diff(fw(t), t) - (w*(b*F1 - a*F2)).subs(u, x_z).subs(v, y_z).subs(w, fw(t))).rhs + return [sol1, sol2, sol3] + + +#This import is written at the bottom to avoid circular imports. +from .single import SingleODEProblem, SingleODESolver, solver_map diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/riccati.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/riccati.py new file mode 100644 index 0000000000000000000000000000000000000000..2ef66ed0896d39bee8fba1b74a0c93734742fc1f --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/riccati.py @@ -0,0 +1,893 @@ +r""" +This module contains :py:meth:`~sympy.solvers.ode.riccati.solve_riccati`, +a function which gives all rational particular solutions to first order +Riccati ODEs. A general first order Riccati ODE is given by - + +.. math:: y' = b_0(x) + b_1(x)w + b_2(x)w^2 + +where `b_0, b_1` and `b_2` can be arbitrary rational functions of `x` +with `b_2 \ne 0`. When `b_2 = 0`, the equation is not a Riccati ODE +anymore and becomes a Linear ODE. Similarly, when `b_0 = 0`, the equation +is a Bernoulli ODE. The algorithm presented below can find rational +solution(s) to all ODEs with `b_2 \ne 0` that have a rational solution, +or prove that no rational solution exists for the equation. + +Background +========== + +A Riccati equation can be transformed to its normal form + +.. math:: y' + y^2 = a(x) + +using the transformation + +.. math:: y = -b_2(x) - \frac{b'_2(x)}{2 b_2(x)} - \frac{b_1(x)}{2} + +where `a(x)` is given by + +.. math:: a(x) = \frac{1}{4}\left(\frac{b_2'}{b_2} + b_1\right)^2 - \frac{1}{2}\left(\frac{b_2'}{b_2} + b_1\right)' - b_0 b_2 + +Thus, we can develop an algorithm to solve for the Riccati equation +in its normal form, which would in turn give us the solution for +the original Riccati equation. + +Algorithm +========= + +The algorithm implemented here is presented in the Ph.D thesis +"Rational and Algebraic Solutions of First-Order Algebraic ODEs" +by N. Thieu Vo. The entire thesis can be found here - +https://www3.risc.jku.at/publications/download/risc_5387/PhDThesisThieu.pdf + +We have only implemented the Rational Riccati solver (Algorithm 11, +Pg 78-82 in Thesis). Before we proceed towards the implementation +of the algorithm, a few definitions to understand are - + +1. Valuation of a Rational Function at `\infty`: + The valuation of a rational function `p(x)` at `\infty` is equal + to the difference between the degree of the denominator and the + numerator of `p(x)`. + + NOTE: A general definition of valuation of a rational function + at any value of `x` can be found in Pg 63 of the thesis, but + is not of any interest for this algorithm. + +2. Zeros and Poles of a Rational Function: + Let `a(x) = \frac{S(x)}{T(x)}, T \ne 0` be a rational function + of `x`. Then - + + a. The Zeros of `a(x)` are the roots of `S(x)`. + b. The Poles of `a(x)` are the roots of `T(x)`. However, `\infty` + can also be a pole of a(x). We say that `a(x)` has a pole at + `\infty` if `a(\frac{1}{x})` has a pole at 0. + +Every pole is associated with an order that is equal to the multiplicity +of its appearance as a root of `T(x)`. A pole is called a simple pole if +it has an order 1. Similarly, a pole is called a multiple pole if it has +an order `\ge` 2. + +Necessary Conditions +==================== + +For a Riccati equation in its normal form, + +.. math:: y' + y^2 = a(x) + +we can define + +a. A pole is called a movable pole if it is a pole of `y(x)` and is not +a pole of `a(x)`. +b. Similarly, a pole is called a non-movable pole if it is a pole of both +`y(x)` and `a(x)`. + +Then, the algorithm states that a rational solution exists only if - + +a. Every pole of `a(x)` must be either a simple pole or a multiple pole +of even order. +b. The valuation of `a(x)` at `\infty` must be even or be `\ge` 2. + +This algorithm finds all possible rational solutions for the Riccati ODE. +If no rational solutions are found, it means that no rational solutions +exist. + +The algorithm works for Riccati ODEs where the coefficients are rational +functions in the independent variable `x` with rational number coefficients +i.e. in `Q(x)`. The coefficients in the rational function cannot be floats, +irrational numbers, symbols or any other kind of expression. The reasons +for this are - + +1. When using symbols, different symbols could take the same value and this +would affect the multiplicity of poles if symbols are present here. + +2. An integer degree bound is required to calculate a polynomial solution +to an auxiliary differential equation, which in turn gives the particular +solution for the original ODE. If symbols/floats/irrational numbers are +present, we cannot determine if the expression for the degree bound is an +integer or not. + +Solution +======== + +With these definitions, we can state a general form for the solution of +the equation. `y(x)` must have the form - + +.. math:: y(x) = \sum_{i=1}^{n} \sum_{j=1}^{r_i} \frac{c_{ij}}{(x - x_i)^j} + \sum_{i=1}^{m} \frac{1}{x - \chi_i} + \sum_{i=0}^{N} d_i x^i + +where `x_1, x_2, \dots, x_n` are non-movable poles of `a(x)`, +`\chi_1, \chi_2, \dots, \chi_m` are movable poles of `a(x)`, and the values +of `N, n, r_1, r_2, \dots, r_n` can be determined from `a(x)`. The +coefficient vectors `(d_0, d_1, \dots, d_N)` and `(c_{i1}, c_{i2}, \dots, c_{i r_i})` +can be determined from `a(x)`. We will have 2 choices each of these vectors +and part of the procedure is figuring out which of the 2 should be used +to get the solution correctly. + +Implementation +============== + +In this implementation, we use ``Poly`` to represent a rational function +rather than using ``Expr`` since ``Poly`` is much faster. Since we cannot +represent rational functions directly using ``Poly``, we instead represent +a rational function with 2 ``Poly`` objects - one for its numerator and +the other for its denominator. + +The code is written to match the steps given in the thesis (Pg 82) + +Step 0 : Match the equation - +Find `b_0, b_1` and `b_2`. If `b_2 = 0` or no such functions exist, raise +an error + +Step 1 : Transform the equation to its normal form as explained in the +theory section. + +Step 2 : Initialize an empty set of solutions, ``sol``. + +Step 3 : If `a(x) = 0`, append `\frac{1}/{(x - C1)}` to ``sol``. + +Step 4 : If `a(x)` is a rational non-zero number, append `\pm \sqrt{a}` +to ``sol``. + +Step 5 : Find the poles and their multiplicities of `a(x)`. Let +the number of poles be `n`. Also find the valuation of `a(x)` at +`\infty` using ``val_at_inf``. + +NOTE: Although the algorithm considers `\infty` as a pole, it is +not mentioned if it a part of the set of finite poles. `\infty` +is NOT a part of the set of finite poles. If a pole exists at +`\infty`, we use its multiplicity to find the laurent series of +`a(x)` about `\infty`. + +Step 6 : Find `n` c-vectors (one for each pole) and 1 d-vector using +``construct_c`` and ``construct_d``. Now, determine all the ``2**(n + 1)`` +combinations of choosing between 2 choices for each of the `n` c-vectors +and 1 d-vector. + +NOTE: The equation for `d_{-1}` in Case 4 (Pg 80) has a printinig +mistake. The term `- d_N` must be replaced with `-N d_N`. The same +has been explained in the code as well. + +For each of these above combinations, do + +Step 8 : Compute `m` in ``compute_m_ybar``. `m` is the degree bound of +the polynomial solution we must find for the auxiliary equation. + +Step 9 : In ``compute_m_ybar``, compute ybar as well where ``ybar`` is +one part of y(x) - + +.. math:: \overline{y}(x) = \sum_{i=1}^{n} \sum_{j=1}^{r_i} \frac{c_{ij}}{(x - x_i)^j} + \sum_{i=0}^{N} d_i x^i + +Step 10 : If `m` is a non-negative integer - + +Step 11: Find a polynomial solution of degree `m` for the auxiliary equation. + +There are 2 cases possible - + + a. `m` is a non-negative integer: We can solve for the coefficients + in `p(x)` using Undetermined Coefficients. + + b. `m` is not a non-negative integer: In this case, we cannot find + a polynomial solution to the auxiliary equation, and hence, we ignore + this value of `m`. + +Step 12 : For each `p(x)` that exists, append `ybar + \frac{p'(x)}{p(x)}` +to ``sol``. + +Step 13 : For each solution in ``sol``, apply an inverse transformation, +so that the solutions of the original equation are found using the +solutions of the equation in its normal form. +""" + + +from itertools import product +from sympy.core import S +from sympy.core.add import Add +from sympy.core.numbers import oo, Float +from sympy.core.function import count_ops +from sympy.core.relational import Eq +from sympy.core.symbol import symbols, Symbol, Dummy +from sympy.functions import sqrt, exp +from sympy.functions.elementary.complexes import sign +from sympy.integrals.integrals import Integral +from sympy.polys.domains import ZZ +from sympy.polys.polytools import Poly +from sympy.polys.polyroots import roots +from sympy.solvers.solveset import linsolve + + +def riccati_normal(w, x, b1, b2): + """ + Given a solution `w(x)` to the equation + + .. math:: w'(x) = b_0(x) + b_1(x)*w(x) + b_2(x)*w(x)^2 + + and rational function coefficients `b_1(x)` and + `b_2(x)`, this function transforms the solution to + give a solution `y(x)` for its corresponding normal + Riccati ODE + + .. math:: y'(x) + y(x)^2 = a(x) + + using the transformation + + .. math:: y(x) = -b_2(x)*w(x) - b'_2(x)/(2*b_2(x)) - b_1(x)/2 + """ + return -b2*w - b2.diff(x)/(2*b2) - b1/2 + + +def riccati_inverse_normal(y, x, b1, b2, bp=None): + """ + Inverse transforming the solution to the normal + Riccati ODE to get the solution to the Riccati ODE. + """ + # bp is the expression which is independent of the solution + # and hence, it need not be computed again + if bp is None: + bp = -b2.diff(x)/(2*b2**2) - b1/(2*b2) + # w(x) = -y(x)/b2(x) - b2'(x)/(2*b2(x)^2) - b1(x)/(2*b2(x)) + return -y/b2 + bp + + +def riccati_reduced(eq, f, x): + """ + Convert a Riccati ODE into its corresponding + normal Riccati ODE. + """ + match, funcs = match_riccati(eq, f, x) + # If equation is not a Riccati ODE, exit + if not match: + return False + # Using the rational functions, find the expression for a(x) + b0, b1, b2 = funcs + a = -b0*b2 + b1**2/4 - b1.diff(x)/2 + 3*b2.diff(x)**2/(4*b2**2) + b1*b2.diff(x)/(2*b2) - \ + b2.diff(x, 2)/(2*b2) + # Normal form of Riccati ODE is f'(x) + f(x)^2 = a(x) + return f(x).diff(x) + f(x)**2 - a + +def linsolve_dict(eq, syms): + """ + Get the output of linsolve as a dict + """ + # Convert tuple type return value of linsolve + # to a dictionary for ease of use + sol = linsolve(eq, syms) + if not sol: + return {} + return dict(zip(syms, list(sol)[0])) + + +def match_riccati(eq, f, x): + """ + A function that matches and returns the coefficients + if an equation is a Riccati ODE + + Parameters + ========== + + eq: Equation to be matched + f: Dependent variable + x: Independent variable + + Returns + ======= + + match: True if equation is a Riccati ODE, False otherwise + funcs: [b0, b1, b2] if match is True, [] otherwise. Here, + b0, b1 and b2 are rational functions which match the equation. + """ + # Group terms based on f(x) + if isinstance(eq, Eq): + eq = eq.lhs - eq.rhs + eq = eq.expand().collect(f(x)) + cf = eq.coeff(f(x).diff(x)) + + # There must be an f(x).diff(x) term. + # eq must be an Add object since we are using the expanded + # equation and it must have atleast 2 terms (b2 != 0) + if cf != 0 and isinstance(eq, Add): + + # Divide all coefficients by the coefficient of f(x).diff(x) + # and add the terms again to get the same equation + eq = Add(*((x/cf).cancel() for x in eq.args)).collect(f(x)) + + # Match the equation with the pattern + b1 = -eq.coeff(f(x)) + b2 = -eq.coeff(f(x)**2) + b0 = (f(x).diff(x) - b1*f(x) - b2*f(x)**2 - eq).expand() + funcs = [b0, b1, b2] + + # Check if coefficients are not symbols and floats + if any(len(x.atoms(Symbol)) > 1 or len(x.atoms(Float)) for x in funcs): + return False, [] + + # If b_0(x) contains f(x), it is not a Riccati ODE + if len(b0.atoms(f)) or not all((b2 != 0, b0.is_rational_function(x), + b1.is_rational_function(x), b2.is_rational_function(x))): + return False, [] + return True, funcs + return False, [] + + +def val_at_inf(num, den, x): + # Valuation of a rational function at oo = deg(denom) - deg(numer) + return den.degree(x) - num.degree(x) + + +def check_necessary_conds(val_inf, muls): + """ + The necessary conditions for a rational solution + to exist are as follows - + + i) Every pole of a(x) must be either a simple pole + or a multiple pole of even order. + + ii) The valuation of a(x) at infinity must be even + or be greater than or equal to 2. + + Here, a simple pole is a pole with multiplicity 1 + and a multiple pole is a pole with multiplicity + greater than 1. + """ + return (val_inf >= 2 or (val_inf <= 0 and val_inf%2 == 0)) and \ + all(mul == 1 or (mul%2 == 0 and mul >= 2) for mul in muls) + + +def inverse_transform_poly(num, den, x): + """ + A function to make the substitution + x -> 1/x in a rational function that + is represented using Poly objects for + numerator and denominator. + """ + # Declare for reuse + one = Poly(1, x) + xpoly = Poly(x, x) + + # Check if degree of numerator is same as denominator + pwr = val_at_inf(num, den, x) + if pwr >= 0: + # Denominator has greater degree. Substituting x with + # 1/x would make the extra power go to the numerator + if num.expr != 0: + num = num.transform(one, xpoly) * x**pwr + den = den.transform(one, xpoly) + else: + # Numerator has greater degree. Substituting x with + # 1/x would make the extra power go to the denominator + num = num.transform(one, xpoly) + den = den.transform(one, xpoly) * x**(-pwr) + return num.cancel(den, include=True) + + +def limit_at_inf(num, den, x): + """ + Find the limit of a rational function + at oo + """ + # pwr = degree(num) - degree(den) + pwr = -val_at_inf(num, den, x) + # Numerator has a greater degree than denominator + # Limit at infinity would depend on the sign of the + # leading coefficients of numerator and denominator + if pwr > 0: + return oo*sign(num.LC()/den.LC()) + # Degree of numerator is equal to that of denominator + # Limit at infinity is just the ratio of leading coeffs + elif pwr == 0: + return num.LC()/den.LC() + # Degree of numerator is less than that of denominator + # Limit at infinity is just 0 + else: + return 0 + + +def construct_c_case_1(num, den, x, pole): + # Find the coefficient of 1/(x - pole)**2 in the + # Laurent series expansion of a(x) about pole. + num1, den1 = (num*Poly((x - pole)**2, x, extension=True)).cancel(den, include=True) + r = (num1.subs(x, pole))/(den1.subs(x, pole)) + + # If multiplicity is 2, the coefficient to be added + # in the c-vector is c = (1 +- sqrt(1 + 4*r))/2 + if r != -S(1)/4: + return [[(1 + sqrt(1 + 4*r))/2], [(1 - sqrt(1 + 4*r))/2]] + return [[S.Half]] + + +def construct_c_case_2(num, den, x, pole, mul): + # Generate the coefficients using the recurrence + # relation mentioned in (5.14) in the thesis (Pg 80) + + # r_i = mul/2 + ri = mul//2 + + # Find the Laurent series coefficients about the pole + ser = rational_laurent_series(num, den, x, pole, mul, 6) + + # Start with an empty memo to store the coefficients + # This is for the plus case + cplus = [0 for i in range(ri)] + + # Base Case + cplus[ri-1] = sqrt(ser[2*ri]) + + # Iterate backwards to find all coefficients + s = ri - 1 + sm = 0 + for s in range(ri-1, 0, -1): + sm = 0 + for j in range(s+1, ri): + sm += cplus[j-1]*cplus[ri+s-j-1] + if s!= 1: + cplus[s-1] = (ser[ri+s] - sm)/(2*cplus[ri-1]) + + # Memo for the minus case + cminus = [-x for x in cplus] + + # Find the 0th coefficient in the recurrence + cplus[0] = (ser[ri+s] - sm - ri*cplus[ri-1])/(2*cplus[ri-1]) + cminus[0] = (ser[ri+s] - sm - ri*cminus[ri-1])/(2*cminus[ri-1]) + + # Add both the plus and minus cases' coefficients + if cplus != cminus: + return [cplus, cminus] + return cplus + + +def construct_c_case_3(): + # If multiplicity is 1, the coefficient to be added + # in the c-vector is 1 (no choice) + return [[1]] + + +def construct_c(num, den, x, poles, muls): + """ + Helper function to calculate the coefficients + in the c-vector for each pole. + """ + c = [] + for pole, mul in zip(poles, muls): + c.append([]) + + # Case 3 + if mul == 1: + # Add the coefficients from Case 3 + c[-1].extend(construct_c_case_3()) + + # Case 1 + elif mul == 2: + # Add the coefficients from Case 1 + c[-1].extend(construct_c_case_1(num, den, x, pole)) + + # Case 2 + else: + # Add the coefficients from Case 2 + c[-1].extend(construct_c_case_2(num, den, x, pole, mul)) + + return c + + +def construct_d_case_4(ser, N): + # Initialize an empty vector + dplus = [0 for i in range(N+2)] + # d_N = sqrt(a_{2*N}) + dplus[N] = sqrt(ser[2*N]) + + # Use the recurrence relations to find + # the value of d_s + for s in range(N-1, -2, -1): + sm = 0 + for j in range(s+1, N): + sm += dplus[j]*dplus[N+s-j] + if s != -1: + dplus[s] = (ser[N+s] - sm)/(2*dplus[N]) + + # Coefficients for the case of d_N = -sqrt(a_{2*N}) + dminus = [-x for x in dplus] + + # The third equation in Eq 5.15 of the thesis is WRONG! + # d_N must be replaced with N*d_N in that equation. + dplus[-1] = (ser[N+s] - N*dplus[N] - sm)/(2*dplus[N]) + dminus[-1] = (ser[N+s] - N*dminus[N] - sm)/(2*dminus[N]) + + if dplus != dminus: + return [dplus, dminus] + return dplus + + +def construct_d_case_5(ser): + # List to store coefficients for plus case + dplus = [0, 0] + + # d_0 = sqrt(a_0) + dplus[0] = sqrt(ser[0]) + + # d_(-1) = a_(-1)/(2*d_0) + dplus[-1] = ser[-1]/(2*dplus[0]) + + # Coefficients for the minus case are just the negative + # of the coefficients for the positive case. + dminus = [-x for x in dplus] + + if dplus != dminus: + return [dplus, dminus] + return dplus + + +def construct_d_case_6(num, den, x): + # s_oo = lim x->0 1/x**2 * a(1/x) which is equivalent to + # s_oo = lim x->oo x**2 * a(x) + s_inf = limit_at_inf(Poly(x**2, x)*num, den, x) + + # d_(-1) = (1 +- sqrt(1 + 4*s_oo))/2 + if s_inf != -S(1)/4: + return [[(1 + sqrt(1 + 4*s_inf))/2], [(1 - sqrt(1 + 4*s_inf))/2]] + return [[S.Half]] + + +def construct_d(num, den, x, val_inf): + """ + Helper function to calculate the coefficients + in the d-vector based on the valuation of the + function at oo. + """ + N = -val_inf//2 + # Multiplicity of oo as a pole + mul = -val_inf if val_inf < 0 else 0 + ser = rational_laurent_series(num, den, x, oo, mul, 1) + + # Case 4 + if val_inf < 0: + d = construct_d_case_4(ser, N) + + # Case 5 + elif val_inf == 0: + d = construct_d_case_5(ser) + + # Case 6 + else: + d = construct_d_case_6(num, den, x) + + return d + + +def rational_laurent_series(num, den, x, r, m, n): + r""" + The function computes the Laurent series coefficients + of a rational function. + + Parameters + ========== + + num: A Poly object that is the numerator of `f(x)`. + den: A Poly object that is the denominator of `f(x)`. + x: The variable of expansion of the series. + r: The point of expansion of the series. + m: Multiplicity of r if r is a pole of `f(x)`. Should + be zero otherwise. + n: Order of the term upto which the series is expanded. + + Returns + ======= + + series: A dictionary that has power of the term as key + and coefficient of that term as value. + + Below is a basic outline of how the Laurent series of a + rational function `f(x)` about `x_0` is being calculated - + + 1. Substitute `x + x_0` in place of `x`. If `x_0` + is a pole of `f(x)`, multiply the expression by `x^m` + where `m` is the multiplicity of `x_0`. Denote the + the resulting expression as g(x). We do this substitution + so that we can now find the Laurent series of g(x) about + `x = 0`. + + 2. We can then assume that the Laurent series of `g(x)` + takes the following form - + + .. math:: g(x) = \frac{num(x)}{den(x)} = \sum_{m = 0}^{\infty} a_m x^m + + where `a_m` denotes the Laurent series coefficients. + + 3. Multiply the denominator to the RHS of the equation + and form a recurrence relation for the coefficients `a_m`. + """ + one = Poly(1, x, extension=True) + + if r == oo: + # Series at x = oo is equal to first transforming + # the function from x -> 1/x and finding the + # series at x = 0 + num, den = inverse_transform_poly(num, den, x) + r = S(0) + + if r: + # For an expansion about a non-zero point, a + # transformation from x -> x + r must be made + num = num.transform(Poly(x + r, x, extension=True), one) + den = den.transform(Poly(x + r, x, extension=True), one) + + # Remove the pole from the denominator if the series + # expansion is about one of the poles + num, den = (num*x**m).cancel(den, include=True) + + # Equate coefficients for the first terms (base case) + maxdegree = 1 + max(num.degree(), den.degree()) + syms = symbols(f'a:{maxdegree}', cls=Dummy) + diff = num - den * Poly(syms[::-1], x) + coeff_diffs = diff.all_coeffs()[::-1][:maxdegree] + (coeffs, ) = linsolve(coeff_diffs, syms) + + # Use the recursion relation for the rest + recursion = den.all_coeffs()[::-1] + div, rec_rhs = recursion[0], recursion[1:] + series = list(coeffs) + while len(series) < n: + next_coeff = Add(*(c*series[-1-n] for n, c in enumerate(rec_rhs))) / div + series.append(-next_coeff) + series = {m - i: val for i, val in enumerate(series)} + return series + +def compute_m_ybar(x, poles, choice, N): + """ + Helper function to calculate - + + 1. m - The degree bound for the polynomial + solution that must be found for the auxiliary + differential equation. + + 2. ybar - Part of the solution which can be + computed using the poles, c and d vectors. + """ + ybar = 0 + m = Poly(choice[-1][-1], x, extension=True) + + # Calculate the first (nested) summation for ybar + # as given in Step 9 of the Thesis (Pg 82) + dybar = [] + for i, polei in enumerate(poles): + for j, cij in enumerate(choice[i]): + dybar.append(cij/(x - polei)**(j + 1)) + m -=Poly(choice[i][0], x, extension=True) # can't accumulate Poly and use with Add + ybar += Add(*dybar) + + # Calculate the second summation for ybar + for i in range(N+1): + ybar += choice[-1][i]*x**i + return (m.expr, ybar) + + +def solve_aux_eq(numa, dena, numy, deny, x, m): + """ + Helper function to find a polynomial solution + of degree m for the auxiliary differential + equation. + """ + # Assume that the solution is of the type + # p(x) = C_0 + C_1*x + ... + C_{m-1}*x**(m-1) + x**m + psyms = symbols(f'C0:{m}', cls=Dummy) + K = ZZ[psyms] + psol = Poly(K.gens, x, domain=K) + Poly(x**m, x, domain=K) + + # Eq (5.16) in Thesis - Pg 81 + auxeq = (dena*(numy.diff(x)*deny - numy*deny.diff(x) + numy**2) - numa*deny**2)*psol + if m >= 1: + px = psol.diff(x) + auxeq += px*(2*numy*deny*dena) + if m >= 2: + auxeq += px.diff(x)*(deny**2*dena) + if m != 0: + # m is a non-zero integer. Find the constant terms using undetermined coefficients + return psol, linsolve_dict(auxeq.all_coeffs(), psyms), True + else: + # m == 0 . Check if 1 (x**0) is a solution to the auxiliary equation + return S.One, auxeq, auxeq == 0 + + +def remove_redundant_sols(sol1, sol2, x): + """ + Helper function to remove redundant + solutions to the differential equation. + """ + # If y1 and y2 are redundant solutions, there is + # some value of the arbitrary constant for which + # they will be equal + + syms1 = sol1.atoms(Symbol, Dummy) + syms2 = sol2.atoms(Symbol, Dummy) + num1, den1 = [Poly(e, x, extension=True) for e in sol1.together().as_numer_denom()] + num2, den2 = [Poly(e, x, extension=True) for e in sol2.together().as_numer_denom()] + # Cross multiply + e = num1*den2 - den1*num2 + # Check if there are any constants + syms = list(e.atoms(Symbol, Dummy)) + if len(syms): + # Find values of constants for which solutions are equal + redn = linsolve(e.all_coeffs(), syms) + if len(redn): + # Return the general solution over a particular solution + if len(syms1) > len(syms2): + return sol2 + # If both have constants, return the lesser complex solution + elif len(syms1) == len(syms2): + return sol1 if count_ops(syms1) >= count_ops(syms2) else sol2 + else: + return sol1 + + +def get_gen_sol_from_part_sol(part_sols, a, x): + """" + Helper function which computes the general + solution for a Riccati ODE from its particular + solutions. + + There are 3 cases to find the general solution + from the particular solutions for a Riccati ODE + depending on the number of particular solution(s) + we have - 1, 2 or 3. + + For more information, see Section 6 of + "Methods of Solution of the Riccati Differential Equation" + by D. R. Haaheim and F. M. Stein + """ + + # If no particular solutions are found, a general + # solution cannot be found + if len(part_sols) == 0: + return [] + + # In case of a single particular solution, the general + # solution can be found by using the substitution + # y = y1 + 1/z and solving a Bernoulli ODE to find z. + elif len(part_sols) == 1: + y1 = part_sols[0] + i = exp(Integral(2*y1, x)) + z = i * Integral(a/i, x) + z = z.doit() + if a == 0 or z == 0: + return y1 + return y1 + 1/z + + # In case of 2 particular solutions, the general solution + # can be found by solving a separable equation. This is + # the most common case, i.e. most Riccati ODEs have 2 + # rational particular solutions. + elif len(part_sols) == 2: + y1, y2 = part_sols + # One of them already has a constant + if len(y1.atoms(Dummy)) + len(y2.atoms(Dummy)) > 0: + u = exp(Integral(y2 - y1, x)).doit() + # Introduce a constant + else: + C1 = Dummy('C1') + u = C1*exp(Integral(y2 - y1, x)).doit() + if u == 1: + return y2 + return (y2*u - y1)/(u - 1) + + # In case of 3 particular solutions, a closed form + # of the general solution can be obtained directly + else: + y1, y2, y3 = part_sols[:3] + C1 = Dummy('C1') + return (C1 + 1)*y2*(y1 - y3)/(C1*y1 + y2 - (C1 + 1)*y3) + + +def solve_riccati(fx, x, b0, b1, b2, gensol=False): + """ + The main function that gives particular/general + solutions to Riccati ODEs that have atleast 1 + rational particular solution. + """ + # Step 1 : Convert to Normal Form + a = -b0*b2 + b1**2/4 - b1.diff(x)/2 + 3*b2.diff(x)**2/(4*b2**2) + b1*b2.diff(x)/(2*b2) - \ + b2.diff(x, 2)/(2*b2) + a_t = a.together() + num, den = [Poly(e, x, extension=True) for e in a_t.as_numer_denom()] + num, den = num.cancel(den, include=True) + + # Step 2 + presol = [] + + # Step 3 : a(x) is 0 + if num == 0: + presol.append(1/(x + Dummy('C1'))) + + # Step 4 : a(x) is a non-zero constant + elif x not in num.free_symbols.union(den.free_symbols): + presol.extend([sqrt(a), -sqrt(a)]) + + # Step 5 : Find poles and valuation at infinity + poles = roots(den, x) + poles, muls = list(poles.keys()), list(poles.values()) + val_inf = val_at_inf(num, den, x) + + if len(poles): + # Check necessary conditions (outlined in the module docstring) + if not check_necessary_conds(val_inf, muls): + raise ValueError("Rational Solution doesn't exist") + + # Step 6 + # Construct c-vectors for each singular point + c = construct_c(num, den, x, poles, muls) + + # Construct d vectors for each singular point + d = construct_d(num, den, x, val_inf) + + # Step 7 : Iterate over all possible combinations and return solutions + # For each possible combination, generate an array of 0's and 1's + # where 0 means pick 1st choice and 1 means pick the second choice. + + # NOTE: We could exit from the loop if we find 3 particular solutions, + # but it is not implemented here as - + # a. Finding 3 particular solutions is very rare. Most of the time, + # only 2 particular solutions are found. + # b. In case we exit after finding 3 particular solutions, it might + # happen that 1 or 2 of them are redundant solutions. So, instead of + # spending some more time in computing the particular solutions, + # we will end up computing the general solution from a single + # particular solution which is usually slower than computing the + # general solution from 2 or 3 particular solutions. + c.append(d) + choices = product(*c) + for choice in choices: + m, ybar = compute_m_ybar(x, poles, choice, -val_inf//2) + numy, deny = [Poly(e, x, extension=True) for e in ybar.together().as_numer_denom()] + # Step 10 : Check if a valid solution exists. If yes, also check + # if m is a non-negative integer + if m.is_nonnegative == True and m.is_integer == True: + + # Step 11 : Find polynomial solutions of degree m for the auxiliary equation + psol, coeffs, exists = solve_aux_eq(num, den, numy, deny, x, m) + + # Step 12 : If valid polynomial solution exists, append solution. + if exists: + # m == 0 case + if psol == 1 and coeffs == 0: + # p(x) = 1, so p'(x)/p(x) term need not be added + presol.append(ybar) + # m is a positive integer and there are valid coefficients + elif len(coeffs): + # Substitute the valid coefficients to get p(x) + psol = psol.xreplace(coeffs) + # y(x) = ybar(x) + p'(x)/p(x) + presol.append(ybar + psol.diff(x)/psol) + + # Remove redundant solutions from the list of existing solutions + remove = set() + for i in range(len(presol)): + for j in range(i+1, len(presol)): + rem = remove_redundant_sols(presol[i], presol[j], x) + if rem is not None: + remove.add(rem) + sols = [x for x in presol if x not in remove] + + # Step 15 : Inverse transform the solutions of the equation in normal form + bp = -b2.diff(x)/(2*b2**2) - b1/(2*b2) + + # If general solution is required, compute it from the particular solutions + if gensol: + sols = [get_gen_sol_from_part_sol(sols, a, x)] + + # Inverse transform the particular solutions + presol = [Eq(fx, riccati_inverse_normal(y, x, b1, b2, bp).cancel(extension=True)) for y in sols] + return presol diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/single.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/single.py new file mode 100644 index 0000000000000000000000000000000000000000..c4829acf41293c2f6f20af3e9c45d37457802102 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/single.py @@ -0,0 +1,2977 @@ +# +# This is the module for ODE solver classes for single ODEs. +# + +from __future__ import annotations +from typing import ClassVar, Iterator + +from .riccati import match_riccati, solve_riccati +from sympy.core import Add, S, Pow, Rational +from sympy.core.cache import cached_property +from sympy.core.exprtools import factor_terms +from sympy.core.expr import Expr +from sympy.core.function import AppliedUndef, Derivative, diff, Function, expand, Subs, _mexpand +from sympy.core.numbers import zoo +from sympy.core.relational import Equality, Eq +from sympy.core.symbol import Symbol, Dummy, Wild +from sympy.core.mul import Mul +from sympy.functions import exp, tan, log, sqrt, besselj, bessely, cbrt, airyai, airybi +from sympy.integrals import Integral +from sympy.polys import Poly +from sympy.polys.polytools import cancel, factor, degree +from sympy.simplify import collect, simplify, separatevars, logcombine, posify # type: ignore +from sympy.simplify.radsimp import fraction +from sympy.utilities import numbered_symbols +from sympy.solvers.solvers import solve +from sympy.solvers.deutils import ode_order, _preprocess +from sympy.polys.matrices.linsolve import _lin_eq2dict +from sympy.polys.solvers import PolyNonlinearError +from .hypergeometric import equivalence_hypergeometric, match_2nd_2F1_hypergeometric, \ + get_sol_2F1_hypergeometric, match_2nd_hypergeometric +from .nonhomogeneous import _get_euler_characteristic_eq_sols, _get_const_characteristic_eq_sols, \ + _solve_undetermined_coefficients, _solve_variation_of_parameters, _test_term, _undetermined_coefficients_match, \ + _get_simplified_sol +from .lie_group import _ode_lie_group + + +class ODEMatchError(NotImplementedError): + """Raised if a SingleODESolver is asked to solve an ODE it does not match""" + pass + + +class SingleODEProblem: + """Represents an ordinary differential equation (ODE) + + This class is used internally in the by dsolve and related + functions/classes so that properties of an ODE can be computed + efficiently. + + Examples + ======== + + This class is used internally by dsolve. To instantiate an instance + directly first define an ODE problem: + + >>> from sympy import Function, Symbol + >>> x = Symbol('x') + >>> f = Function('f') + >>> eq = f(x).diff(x, 2) + + Now you can create a SingleODEProblem instance and query its properties: + + >>> from sympy.solvers.ode.single import SingleODEProblem + >>> problem = SingleODEProblem(f(x).diff(x), f(x), x) + >>> problem.eq + Derivative(f(x), x) + >>> problem.func + f(x) + >>> problem.sym + x + """ + + # Instance attributes: + eq: Expr + func: AppliedUndef + sym: Symbol + _order: int + _eq_expanded: Expr + _eq_preprocessed: Expr + _eq_high_order_free = None + + def __init__(self, eq, func, sym, prep=True, **kwargs): + assert isinstance(eq, Expr) + assert isinstance(func, AppliedUndef) + assert isinstance(sym, Symbol) + assert isinstance(prep, bool) + self.eq = eq + self.func = func + self.sym = sym + self.prep = prep + self.params = kwargs + + @cached_property + def order(self) -> int: + return ode_order(self.eq, self.func) + + @cached_property + def eq_preprocessed(self) -> Expr: + return self._get_eq_preprocessed() + + @cached_property + def eq_high_order_free(self) -> Expr: + a = Wild('a', exclude=[self.func]) + c1 = Wild('c1', exclude=[self.sym]) + # Precondition to try remove f(x) from highest order derivative + reduced_eq = None + if self.eq.is_Add: + deriv_coef = self.eq.coeff(self.func.diff(self.sym, self.order)) + if deriv_coef not in (1, 0): + r = deriv_coef.match(a*self.func**c1) + if r and r[c1]: + den = self.func**r[c1] + reduced_eq = Add(*[arg/den for arg in self.eq.args]) + if reduced_eq is None: + reduced_eq = expand(self.eq) + return reduced_eq + + @cached_property + def eq_expanded(self) -> Expr: + return expand(self.eq_preprocessed) + + def _get_eq_preprocessed(self) -> Expr: + if self.prep: + process_eq, process_func = _preprocess(self.eq, self.func) + if process_func != self.func: + raise ValueError + else: + process_eq = self.eq + return process_eq + + def get_numbered_constants(self, num=1, start=1, prefix='C') -> list[Symbol]: + """ + Returns a list of constants that do not occur + in eq already. + """ + ncs = self.iter_numbered_constants(start, prefix) + Cs = [next(ncs) for i in range(num)] + return Cs + + def iter_numbered_constants(self, start=1, prefix='C') -> Iterator[Symbol]: + """ + Returns an iterator of constants that do not occur + in eq already. + """ + atom_set = self.eq.free_symbols + func_set = self.eq.atoms(Function) + if func_set: + atom_set |= {Symbol(str(f.func)) for f in func_set} + return numbered_symbols(start=start, prefix=prefix, exclude=atom_set) + + @cached_property + def is_autonomous(self): + u = Dummy('u') + x = self.sym + syms = self.eq.subs(self.func, u).free_symbols + return x not in syms + + def get_linear_coefficients(self, eq, func, order): + r""" + Matches a differential equation to the linear form: + + .. 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. + + Examples + ======== + + >>> from sympy import Function, cos, sin + >>> from sympy.abc import x + >>> from sympy.solvers.ode.single import SingleODEProblem + >>> f = Function('f') + >>> eq = f(x).diff(x, 3) + 2*f(x).diff(x) + \ + ... x*f(x).diff(x, 2) + cos(x)*f(x).diff(x) + x - f(x) - \ + ... sin(x) + >>> obj = SingleODEProblem(eq, f(x), x) + >>> obj.get_linear_coefficients(eq, f(x), 3) + {-1: x - sin(x), 0: -1, 1: cos(x) + 2, 2: x, 3: 1} + >>> eq = f(x).diff(x, 3) + 2*f(x).diff(x) + \ + ... x*f(x).diff(x, 2) + cos(x)*f(x).diff(x) + x - f(x) - \ + ... sin(f(x)) + >>> obj = SingleODEProblem(eq, f(x), x) + >>> obj.get_linear_coefficients(eq, f(x), 3) == None + True + + """ + f = func.func + x = func.args[0] + symset = {Derivative(f(x), x, i) for i in range(order+1)} + try: + rhs, lhs_terms = _lin_eq2dict(eq, symset) + except PolyNonlinearError: + return None + + if rhs.has(func) or any(c.has(func) for c in lhs_terms.values()): + return None + terms = {i: lhs_terms.get(f(x).diff(x, i), S.Zero) for i in range(order+1)} + terms[-1] = rhs + return terms + + # TODO: Add methods that can be used by many ODE solvers: + # order + # is_linear() + # get_linear_coefficients() + # eq_prepared (the ODE in prepared form) + + +class SingleODESolver: + """ + Base class for Single ODE solvers. + + Subclasses should implement the _matches and _get_general_solution + methods. This class is not intended to be instantiated directly but its + subclasses are as part of dsolve. + + Examples + ======== + + You can use a subclass of SingleODEProblem to solve a particular type of + ODE. We first define a particular ODE problem: + + >>> from sympy import Function, Symbol + >>> x = Symbol('x') + >>> f = Function('f') + >>> eq = f(x).diff(x, 2) + + Now we solve this problem using the NthAlgebraic solver which is a + subclass of SingleODESolver: + + >>> from sympy.solvers.ode.single import NthAlgebraic, SingleODEProblem + >>> problem = SingleODEProblem(eq, f(x), x) + >>> solver = NthAlgebraic(problem) + >>> solver.get_general_solution() + [Eq(f(x), _C*x + _C)] + + The normal way to solve an ODE is to use dsolve (which would use + NthAlgebraic and other solvers internally). When using dsolve a number of + other things are done such as evaluating integrals, simplifying the + solution and renumbering the constants: + + >>> from sympy import dsolve + >>> dsolve(eq, hint='nth_algebraic') + Eq(f(x), C1 + C2*x) + """ + + # Subclasses should store the hint name (the argument to dsolve) in this + # attribute + hint: ClassVar[str] + + # Subclasses should define this to indicate if they support an _Integral + # hint. + has_integral: ClassVar[bool] + + # The ODE to be solved + ode_problem: SingleODEProblem + + # Cache whether or not the equation has matched the method + _matched: bool | None = None + + # Subclasses should store in this attribute the list of order(s) of ODE + # that subclass can solve or leave it to None if not specific to any order + order: list | None = None + + def __init__(self, ode_problem): + self.ode_problem = ode_problem + + def matches(self) -> bool: + if self.order is not None and self.ode_problem.order not in self.order: + self._matched = False + return self._matched + + if self._matched is None: + self._matched = self._matches() + return self._matched + + def get_general_solution(self, *, simplify: bool = True) -> list[Equality]: + if not self.matches(): + msg = "%s solver cannot solve:\n%s" + raise ODEMatchError(msg % (self.hint, self.ode_problem.eq)) + return self._get_general_solution(simplify_flag=simplify) + + def _matches(self) -> bool: + msg = "Subclasses of SingleODESolver should implement matches." + raise NotImplementedError(msg) + + def _get_general_solution(self, *, simplify_flag: bool = True) -> list[Equality]: + msg = "Subclasses of SingleODESolver should implement get_general_solution." + raise NotImplementedError(msg) + + +class SinglePatternODESolver(SingleODESolver): + '''Superclass for ODE solvers based on pattern matching''' + + def wilds(self): + prob = self.ode_problem + f = prob.func.func + x = prob.sym + order = prob.order + return self._wilds(f, x, order) + + def wilds_match(self): + match = self._wilds_match + return [match.get(w, S.Zero) for w in self.wilds()] + + def _matches(self): + eq = self.ode_problem.eq_expanded + f = self.ode_problem.func.func + x = self.ode_problem.sym + order = self.ode_problem.order + df = f(x).diff(x, order) + + if order not in [1, 2]: + return False + + pattern = self._equation(f(x), x, order) + + if not pattern.coeff(df).has(Wild): + eq = expand(eq / eq.coeff(df)) + eq = eq.collect([f(x).diff(x), f(x)], func = cancel) + + self._wilds_match = match = eq.match(pattern) + if match is not None: + return self._verify(f(x)) + return False + + def _verify(self, fx) -> bool: + return True + + def _wilds(self, f, x, order): + msg = "Subclasses of SingleODESolver should implement _wilds" + raise NotImplementedError(msg) + + def _equation(self, fx, x, order): + msg = "Subclasses of SingleODESolver should implement _equation" + raise NotImplementedError(msg) + + +class NthAlgebraic(SingleODESolver): + r""" + Solves an `n`\th order ordinary differential equation using algebra and + integrals. + + There is no general form for the kind of equation that this can solve. The + the equation is solved algebraically treating differentiation as an + invertible algebraic function. + + Examples + ======== + + >>> from sympy import Function, dsolve, Eq + >>> from sympy.abc import x + >>> f = Function('f') + >>> eq = Eq(f(x) * (f(x).diff(x)**2 - 1), 0) + >>> dsolve(eq, f(x), hint='nth_algebraic') + [Eq(f(x), 0), Eq(f(x), C1 - x), Eq(f(x), C1 + x)] + + Note that this solver can return algebraic solutions that do not have any + integration constants (f(x) = 0 in the above example). + """ + + hint = 'nth_algebraic' + has_integral = True # nth_algebraic_Integral hint + + def _matches(self): + r""" + Matches any differential equation that nth_algebraic can solve. Uses + `sympy.solve` but teaches it how to integrate derivatives. + + This involves calling `sympy.solve` and does most of the work of finding a + solution (apart from evaluating the integrals). + """ + eq = self.ode_problem.eq + func = self.ode_problem.func + var = self.ode_problem.sym + + # Derivative that solve can handle: + diffx = self._get_diffx(var) + + # Replace derivatives wrt the independent variable with diffx + def replace(eq, var): + def expand_diffx(*args): + differand, diffs = args[0], args[1:] + toreplace = differand + for v, n in diffs: + for _ in range(n): + if v == var: + toreplace = diffx(toreplace) + else: + toreplace = Derivative(toreplace, v) + return toreplace + return eq.replace(Derivative, expand_diffx) + + # Restore derivatives in solution afterwards + def unreplace(eq, var): + return eq.replace(diffx, lambda e: Derivative(e, var)) + + subs_eqn = replace(eq, var) + try: + # turn off simplification to protect Integrals that have + # _t instead of fx in them and would otherwise factor + # as t_*Integral(1, x) + solns = solve(subs_eqn, func, simplify=False) + except NotImplementedError: + solns = [] + + solns = [simplify(unreplace(soln, var)) for soln in solns] + solns = [Equality(func, soln) for soln in solns] + + self.solutions = solns + return len(solns) != 0 + + def _get_general_solution(self, *, simplify_flag: bool = True): + return self.solutions + + # This needs to produce an invertible function but the inverse depends + # which variable we are integrating with respect to. Since the class can + # be stored in cached results we need to ensure that we always get the + # same class back for each particular integration variable so we store these + # classes in a global dict: + _diffx_stored: dict[Symbol, type[Function]] = {} + + @staticmethod + def _get_diffx(var): + diffcls = NthAlgebraic._diffx_stored.get(var, None) + + if diffcls is None: + # A class that behaves like Derivative wrt var but is "invertible". + class diffx(Function): + def inverse(self): + # don't use integrate here because fx has been replaced by _t + # in the equation; integrals will not be correct while solve + # is at work. + return lambda expr: Integral(expr, var) + Dummy('C') + + diffcls = NthAlgebraic._diffx_stored.setdefault(var, diffx) + + return diffcls + + +class FirstExact(SinglePatternODESolver): + r""" + Solves 1st order exact ordinary differential equations. + + A 1st order differential equation is called exact if it is the total + differential of a function. That is, the differential equation + + .. 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') + >>> P, Q, F= map(Function, ['P', 'Q', 'F']) + >>> pprint(Eq(Eq(F(x, y), Integral(P(t, y), (t, x0, x)) + + ... Integral(Q(x0, t), (t, y0, y))), C1)) + x y + / / + | | + F(x, y) = | P(t, y) dt + | Q(x0, t) dt = C1 + | | + / / + x0 y0 + + 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 + solving for. + + Examples + ======== + + >>> from sympy import Function, dsolve, cos, sin + >>> from sympy.abc import x + >>> f = Function('f') + >>> dsolve(cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x), + ... f(x), hint='1st_exact') + Eq(x*cos(f(x)) + f(x)**3/3, C1) + + References + ========== + + - https://en.wikipedia.org/wiki/Exact_differential_equation + - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", + Dover 1963, pp. 73 + + # indirect doctest + + """ + hint = "1st_exact" + has_integral = True + order = [1] + + def _wilds(self, f, x, order): + P = Wild('P', exclude=[f(x).diff(x)]) + Q = Wild('Q', exclude=[f(x).diff(x)]) + return P, Q + + def _equation(self, fx, x, order): + P, Q = self.wilds() + return P + Q*fx.diff(x) + + def _verify(self, fx) -> bool: + P, Q = self.wilds() + x = self.ode_problem.sym + y = Dummy('y') + + m, n = self.wilds_match() + + m = m.subs(fx, y) + n = n.subs(fx, y) + numerator = cancel(m.diff(y) - n.diff(x)) + + if numerator.is_zero: + # Is exact + return True + else: + # The following few conditions try to convert a non-exact + # differential equation into an exact one. + # References: + # 1. Differential equations with applications + # and historical notes - George E. Simmons + # 2. https://math.okstate.edu/people/binegar/2233-S99/2233-l12.pdf + + factor_n = cancel(numerator/n) + factor_m = cancel(-numerator/m) + if y not in factor_n.free_symbols: + # If (dP/dy - dQ/dx) / Q = f(x) + # then exp(integral(f(x))*equation becomes exact + factor = factor_n + integration_variable = x + elif x not in factor_m.free_symbols: + # If (dP/dy - dQ/dx) / -P = f(y) + # then exp(integral(f(y))*equation becomes exact + factor = factor_m + integration_variable = y + else: + # Couldn't convert to exact + return False + + factor = exp(Integral(factor, integration_variable)) + m *= factor + n *= factor + self._wilds_match[P] = m.subs(y, fx) + self._wilds_match[Q] = n.subs(y, fx) + return True + + def _get_general_solution(self, *, simplify_flag: bool = True): + m, n = self.wilds_match() + fx = self.ode_problem.func + x = self.ode_problem.sym + (C1,) = self.ode_problem.get_numbered_constants(num=1) + y = Dummy('y') + + m = m.subs(fx, y) + n = n.subs(fx, y) + + gen_sol = Eq(Subs(Integral(m, x) + + Integral(n - Integral(m, x).diff(y), y), y, fx), C1) + return [gen_sol] + + +class FirstLinear(SinglePatternODESolver): + r""" + Solves 1st order linear differential equations. + + 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 + >>> f, P, Q = map(Function, ['f', 'P', 'Q']) + >>> genform = Eq(f(x).diff(x) + P(x)*f(x), Q(x)) + >>> pprint(genform) + d + P(x)*f(x) + --(f(x)) = Q(x) + dx + >>> pprint(dsolve(genform, f(x), hint='1st_linear_Integral')) + / / \ + | | | + | | / | / + | | | | | + | | | P(x) dx | - | P(x) dx + | | | | | + | | / | / + f(x) = |C1 + | Q(x)*e dx|*e + | | | + \ / / + + + Examples + ======== + + >>> f = Function('f') + >>> pprint(dsolve(Eq(x*diff(f(x), x) - f(x), x**2*sin(x)), + ... f(x), '1st_linear')) + f(x) = x*(C1 - cos(x)) + + References + ========== + + - https://en.wikipedia.org/wiki/Linear_differential_equation#First-order_equation_with_variable_coefficients + - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", + Dover 1963, pp. 92 + + # indirect doctest + + """ + hint = '1st_linear' + has_integral = True + order = [1] + + def _wilds(self, f, x, order): + P = Wild('P', exclude=[f(x)]) + Q = Wild('Q', exclude=[f(x), f(x).diff(x)]) + return P, Q + + def _equation(self, fx, x, order): + P, Q = self.wilds() + return fx.diff(x) + P*fx - Q + + def _get_general_solution(self, *, simplify_flag: bool = True): + P, Q = self.wilds_match() + fx = self.ode_problem.func + x = self.ode_problem.sym + (C1,) = self.ode_problem.get_numbered_constants(num=1) + gensol = Eq(fx, ((C1 + Integral(Q*exp(Integral(P, x)), x)) + * exp(-Integral(P, x)))) + return [gensol] + + +class AlmostLinear(SinglePatternODESolver): + r""" + Solves an almost-linear differential equation. + + The general form of an almost linear differential equation is + + .. math:: a(x) g'(f(x)) f'(x) + b(x) g(f(x)) + c(x) + + Here `f(x)` is the function to be solved for (the dependent variable). + The substitution `g(f(x)) = u(x)` leads to a linear differential equation + for `u(x)` of the form `a(x) u' + b(x) u + c(x) = 0`. This can be solved + for `u(x)` by the `first_linear` hint and then `f(x)` is found by solving + `g(f(x)) = u(x)`. + + See Also + ======== + :obj:`sympy.solvers.ode.single.FirstLinear` + + Examples + ======== + + >>> from sympy import dsolve, Function, pprint, sin, cos + >>> 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') + Eq(f(x), (C1 - Ei(x))*exp(-x)) + >>> pprint(dsolve(eq, f(x), hint='almost_linear')) + -x + f(x) = (C1 - Ei(x))*e + >>> example = cos(f(x))*f(x).diff(x) + sin(f(x)) + 1 + >>> pprint(example) + d + sin(f(x)) + cos(f(x))*--(f(x)) + 1 + dx + >>> pprint(dsolve(example, f(x), hint='almost_linear')) + / -x \ / -x \ + [f(x) = pi - asin\C1*e - 1/, f(x) = asin\C1*e - 1/] + + + References + ========== + + - Joel Moses, "Symbolic Integration - The Stormy Decade", Communications + of the ACM, Volume 14, Number 8, August 1971, pp. 558 + """ + hint = "almost_linear" + has_integral = True + order = [1] + + def _wilds(self, f, x, order): + P = Wild('P', exclude=[f(x).diff(x)]) + Q = Wild('Q', exclude=[f(x).diff(x)]) + return P, Q + + def _equation(self, fx, x, order): + P, Q = self.wilds() + return P*fx.diff(x) + Q + + def _verify(self, fx): + a, b = self.wilds_match() + c, b = b.as_independent(fx) if b.is_Add else (S.Zero, b) + # a, b and c are the function a(x), b(x) and c(x) respectively. + # c(x) is obtained by separating out b as terms with and without fx i.e, l(y) + # The following conditions checks if the given equation is an almost-linear differential equation using the fact that + # a(x)*(l(y))' / l(y)' is independent of l(y) + + if b.diff(fx) != 0 and not simplify(b.diff(fx)/a).has(fx): + self.ly = factor_terms(b).as_independent(fx, as_Add=False)[1] # Gives the term containing fx i.e., l(y) + self.ax = a / self.ly.diff(fx) + self.cx = -c # cx is taken as -c(x) to simplify expression in the solution integral + self.bx = factor_terms(b) / self.ly + return True + + return False + + def _get_general_solution(self, *, simplify_flag: bool = True): + x = self.ode_problem.sym + (C1,) = self.ode_problem.get_numbered_constants(num=1) + gensol = Eq(self.ly, ((C1 + Integral((self.cx/self.ax)*exp(Integral(self.bx/self.ax, x)), x)) + * exp(-Integral(self.bx/self.ax, x)))) + + return [gensol] + + +class Bernoulli(SinglePatternODESolver): + r""" + Solves Bernoulli differential equations. + + 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 + :obj:`~sympy.solvers.ode.single.FirstLinear`). The general solution is:: + + >>> from sympy import Function, dsolve, Eq, pprint + >>> from sympy.abc import x, n + >>> f, P, Q = map(Function, ['f', 'P', 'Q']) + >>> genform = Eq(f(x).diff(x) + P(x)*f(x), Q(x)*f(x)**n) + >>> pprint(genform) + d n + P(x)*f(x) + --(f(x)) = Q(x)*f (x) + dx + >>> pprint(dsolve(genform, f(x), hint='Bernoulli_Integral'), num_columns=110) + -1 + ----- + n - 1 + // / / \ \ + || | | | | + || | / | / | / | + || | | | | | | | + || | -(n - 1)* | P(x) dx | -(n - 1)* | P(x) dx | (n - 1)* | P(x) dx| + || | | | | | | | + || | / | / | / | + f(x) = ||C1 - n* | Q(x)*e dx + | Q(x)*e dx|*e | + || | | | | + \\ / / / / + + + Note that the equation is separable when `n = 1` (see the docstring of + :obj:`~sympy.solvers.ode.single.Separable`). + + >>> pprint(dsolve(Eq(f(x).diff(x) + P(x)*f(x), Q(x)*f(x)), f(x), + ... hint='separable_Integral')) + f(x) + / + | / + | 1 | + | - dy = C1 + | (-P(x) + Q(x)) dx + | y | + | / + / + + + Examples + ======== + + >>> from sympy import Function, dsolve, Eq, pprint, log + >>> from sympy.abc import x + >>> f = Function('f') + + >>> pprint(dsolve(Eq(x*f(x).diff(x) + f(x), log(x)*f(x)**2), + ... f(x), hint='Bernoulli')) + 1 + f(x) = ----------------- + C1*x + log(x) + 1 + + References + ========== + + - https://en.wikipedia.org/wiki/Bernoulli_differential_equation + + - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", + Dover 1963, pp. 95 + + # indirect doctest + + """ + hint = "Bernoulli" + has_integral = True + order = [1] + + def _wilds(self, f, x, order): + P = Wild('P', exclude=[f(x)]) + Q = Wild('Q', exclude=[f(x)]) + n = Wild('n', exclude=[x, f(x), f(x).diff(x)]) + return P, Q, n + + def _equation(self, fx, x, order): + P, Q, n = self.wilds() + return fx.diff(x) + P*fx - Q*fx**n + + def _get_general_solution(self, *, simplify_flag: bool = True): + P, Q, n = self.wilds_match() + fx = self.ode_problem.func + x = self.ode_problem.sym + (C1,) = self.ode_problem.get_numbered_constants(num=1) + if n==1: + gensol = Eq(log(fx), ( + C1 + Integral((-P + Q), x) + )) + else: + gensol = Eq(fx**(1-n), ( + (C1 - (n - 1) * Integral(Q*exp(-n*Integral(P, x)) + * exp(Integral(P, x)), x) + ) * exp(-(1 - n)*Integral(P, x))) + ) + return [gensol] + + +class Factorable(SingleODESolver): + r""" + Solves equations having a solvable factor. + + This function is used to solve the equation having factors. Factors may be of type algebraic or ode. It + will try to solve each factor independently. Factors will be solved by calling dsolve. We will return the + list of solutions. + + Examples + ======== + + >>> from sympy import Function, dsolve, pprint + >>> from sympy.abc import x + >>> f = Function('f') + >>> eq = (f(x)**2-4)*(f(x).diff(x)+f(x)) + >>> pprint(dsolve(eq, f(x))) + -x + [f(x) = 2, f(x) = -2, f(x) = C1*e ] + + + """ + hint = "factorable" + has_integral = False + + def _matches(self): + eq_orig = self.ode_problem.eq + f = self.ode_problem.func.func + x = self.ode_problem.sym + df = f(x).diff(x) + self.eqs = [] + eq = eq_orig.collect(f(x), func = cancel) + eq = fraction(factor(eq))[0] + factors = Mul.make_args(factor(eq)) + roots = [fac.as_base_exp() for fac in factors if len(fac.args)!=0] + if len(roots)>1 or roots[0][1]>1: + for base, expo in roots: + if base.has(f(x)): + self.eqs.append(base) + if len(self.eqs)>0: + return True + roots = solve(eq, df) + if len(roots)>0: + self.eqs = [(df - root) for root in roots] + # Avoid infinite recursion + matches = self.eqs != [eq_orig] + return matches + for i in factors: + if i.has(f(x)): + self.eqs.append(i) + return len(self.eqs)>0 and len(factors)>1 + + def _get_general_solution(self, *, simplify_flag: bool = True): + func = self.ode_problem.func.func + x = self.ode_problem.sym + eqns = self.eqs + sols = [] + for eq in eqns: + try: + sol = dsolve(eq, func(x)) + except NotImplementedError: + continue + else: + if isinstance(sol, list): + sols.extend(sol) + else: + sols.append(sol) + + if sols == []: + raise NotImplementedError("The given ODE " + str(eq) + " cannot be solved by" + + " the factorable group method") + return sols + + +class RiccatiSpecial(SinglePatternODESolver): + r""" + 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, a, b, c, d + >>> from sympy import dsolve, checkodesol, pprint, Function + >>> f = Function('f') + >>> y = f(x) + >>> genform = a*y.diff(x) - (b*y**2 + c*y/x + d/x**2) + >>> sol = dsolve(genform, y, hint="Riccati_special_minus2") + >>> 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) = ------------------------------------------------------------------------ + 2*b*x + + >>> checkodesol(genform, sol, order=1)[0] + True + + References + ========== + + - https://www.maplesoft.com/support/help/Maple/view.aspx?path=odeadvisor/Riccati + - https://eqworld.ipmnet.ru/en/solutions/ode/ode0106.pdf - + https://eqworld.ipmnet.ru/en/solutions/ode/ode0123.pdf + """ + hint = "Riccati_special_minus2" + has_integral = False + order = [1] + + def _wilds(self, f, x, order): + a = Wild('a', exclude=[x, f(x), f(x).diff(x), 0]) + b = Wild('b', exclude=[x, f(x), f(x).diff(x), 0]) + c = Wild('c', exclude=[x, f(x), f(x).diff(x)]) + d = Wild('d', exclude=[x, f(x), f(x).diff(x)]) + return a, b, c, d + + def _equation(self, fx, x, order): + a, b, c, d = self.wilds() + return a*fx.diff(x) + b*fx**2 + c*fx/x + d/x**2 + + def _get_general_solution(self, *, simplify_flag: bool = True): + a, b, c, d = self.wilds_match() + fx = self.ode_problem.func + x = self.ode_problem.sym + (C1,) = self.ode_problem.get_numbered_constants(num=1) + mu = sqrt(4*d*b - (a - c)**2) + + gensol = Eq(fx, (a - c - mu*tan(mu/(2*a)*log(x) + C1))/(2*b*x)) + return [gensol] + + +class RationalRiccati(SinglePatternODESolver): + r""" + Gives general solutions to the first order Riccati differential + equations that have atleast one rational particular solution. + + .. math :: y' = b_0(x) + b_1(x) y + b_2(x) y^2 + + where `b_0`, `b_1` and `b_2` are rational functions of `x` + with `b_2 \ne 0` (`b_2 = 0` would make it a Bernoulli equation). + + Examples + ======== + + >>> from sympy import Symbol, Function, dsolve, checkodesol + >>> f = Function('f') + >>> x = Symbol('x') + + >>> eq = -x**4*f(x)**2 + x**3*f(x).diff(x) + x**2*f(x) + 20 + >>> sol = dsolve(eq, hint="1st_rational_riccati") + >>> sol + Eq(f(x), (4*C1 - 5*x**9 - 4)/(x**2*(C1 + x**9 - 1))) + >>> checkodesol(eq, sol) + (True, 0) + + References + ========== + + - Riccati ODE: https://en.wikipedia.org/wiki/Riccati_equation + - N. Thieu Vo - Rational and Algebraic Solutions of First-Order Algebraic ODEs: + Algorithm 11, pp. 78 - https://www3.risc.jku.at/publications/download/risc_5387/PhDThesisThieu.pdf + """ + has_integral = False + hint = "1st_rational_riccati" + order = [1] + + def _wilds(self, f, x, order): + b0 = Wild('b0', exclude=[f(x), f(x).diff(x)]) + b1 = Wild('b1', exclude=[f(x), f(x).diff(x)]) + b2 = Wild('b2', exclude=[f(x), f(x).diff(x)]) + return (b0, b1, b2) + + def _equation(self, fx, x, order): + b0, b1, b2 = self.wilds() + return fx.diff(x) - b0 - b1*fx - b2*fx**2 + + def _matches(self): + eq = self.ode_problem.eq_expanded + f = self.ode_problem.func.func + x = self.ode_problem.sym + order = self.ode_problem.order + + if order != 1: + return False + + match, funcs = match_riccati(eq, f, x) + if not match: + return False + _b0, _b1, _b2 = funcs + b0, b1, b2 = self.wilds() + self._wilds_match = match = {b0: _b0, b1: _b1, b2: _b2} + return True + + def _get_general_solution(self, *, simplify_flag: bool = True): + # Match the equation + b0, b1, b2 = self.wilds_match() + fx = self.ode_problem.func + x = self.ode_problem.sym + return solve_riccati(fx, x, b0, b1, b2, gensol=True) + + +class SecondNonlinearAutonomousConserved(SinglePatternODESolver): + r""" + Gives solution for the autonomous second order nonlinear + differential equation of the form + + .. math :: f''(x) = g(f(x)) + + The solution for this differential equation can be computed + by multiplying by `f'(x)` and integrating on both sides, + converting it into a first order differential equation. + + Examples + ======== + + >>> from sympy import Function, symbols, dsolve + >>> f, g = symbols('f g', cls=Function) + >>> x = symbols('x') + + >>> eq = f(x).diff(x, 2) - g(f(x)) + >>> dsolve(eq, simplify=False) + [Eq(Integral(1/sqrt(C1 + 2*Integral(g(_u), _u)), (_u, f(x))), C2 + x), + Eq(Integral(1/sqrt(C1 + 2*Integral(g(_u), _u)), (_u, f(x))), C2 - x)] + + >>> from sympy import exp, log + >>> eq = f(x).diff(x, 2) - exp(f(x)) + log(f(x)) + >>> dsolve(eq, simplify=False) + [Eq(Integral(1/sqrt(-2*_u*log(_u) + 2*_u + C1 + 2*exp(_u)), (_u, f(x))), C2 + x), + Eq(Integral(1/sqrt(-2*_u*log(_u) + 2*_u + C1 + 2*exp(_u)), (_u, f(x))), C2 - x)] + + References + ========== + + - https://eqworld.ipmnet.ru/en/solutions/ode/ode0301.pdf + """ + hint = "2nd_nonlinear_autonomous_conserved" + has_integral = True + order = [2] + + def _wilds(self, f, x, order): + fy = Wild('fy', exclude=[0, f(x).diff(x), f(x).diff(x, 2)]) + return (fy, ) + + def _equation(self, fx, x, order): + fy = self.wilds()[0] + return fx.diff(x, 2) + fy + + def _verify(self, fx): + return self.ode_problem.is_autonomous + + def _get_general_solution(self, *, simplify_flag: bool = True): + g = self.wilds_match()[0] + fx = self.ode_problem.func + x = self.ode_problem.sym + u = Dummy('u') + g = g.subs(fx, u) + C1, C2 = self.ode_problem.get_numbered_constants(num=2) + inside = -2*Integral(g, u) + C1 + lhs = Integral(1/sqrt(inside), (u, fx)) + return [Eq(lhs, C2 + x), Eq(lhs, C2 - x)] + + +class Liouville(SinglePatternODESolver): + r""" + Solves 2nd order Liouville differential equations. + + The general form of a Liouville ODE 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 + >>> f, g, h = map(Function, ['f', 'g', 'h']) + >>> 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 + >>> pprint(dsolve(genform, f(x), hint='Liouville_Integral')) + f(x) + / / + | | + | / | / + | | | | + | - | h(x) dx | | g(y) dy + | | | | + | / | / + C1 + C2* | e dx + | e dy = 0 + | | + / / + + Examples + ======== + + >>> from sympy import Function, dsolve, Eq, pprint + >>> from sympy.abc import x + >>> f = Function('f') + >>> pprint(dsolve(diff(f(x), x, x) + diff(f(x), x)**2/f(x) + + ... diff(f(x), x)/x, f(x), hint='Liouville')) + ________________ ________________ + [f(x) = -\/ C1 + C2*log(x) , f(x) = \/ C1 + C2*log(x) ] + + References + ========== + + - Goldstein and Braun, "Advanced Methods for the Solution of Differential + Equations", pp. 98 + - https://www.maplesoft.com/support/help/Maple/view.aspx?path=odeadvisor/Liouville + + # indirect doctest + + """ + hint = "Liouville" + has_integral = True + order = [2] + + def _wilds(self, f, x, order): + d = Wild('d', exclude=[f(x).diff(x), f(x).diff(x, 2)]) + e = Wild('e', exclude=[f(x).diff(x)]) + k = Wild('k', exclude=[f(x).diff(x)]) + return d, e, k + + def _equation(self, fx, x, order): + # 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 + d, e, k = self.wilds() + return d*fx.diff(x, 2) + e*fx.diff(x)**2 + k*fx.diff(x) + + def _verify(self, fx): + d, e, k = self.wilds_match() + self.y = Dummy('y') + x = self.ode_problem.sym + self.g = simplify(e/d).subs(fx, self.y) + self.h = simplify(k/d).subs(fx, self.y) + if self.y in self.h.free_symbols or x in self.g.free_symbols: + return False + return True + + def _get_general_solution(self, *, simplify_flag: bool = True): + d, e, k = self.wilds_match() + fx = self.ode_problem.func + x = self.ode_problem.sym + C1, C2 = self.ode_problem.get_numbered_constants(num=2) + int = Integral(exp(Integral(self.g, self.y)), (self.y, None, fx)) + gen_sol = Eq(int + C1*Integral(exp(-Integral(self.h, x)), x) + C2, 0) + + return [gen_sol] + + +class Separable(SinglePatternODESolver): + r""" + Solves separable 1st order differential equations. + + 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.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.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 + >>> a, b, c, d, f = map(Function, ['a', 'b', 'c', 'd', 'f']) + >>> genform = Eq(a(x)*b(f(x))*f(x).diff(x), c(x)*d(f(x))) + >>> pprint(genform) + d + a(x)*b(f(x))*--(f(x)) = c(x)*d(f(x)) + dx + >>> pprint(dsolve(genform, f(x), hint='separable_Integral')) + f(x) + / / + | | + | b(y) | c(x) + | ---- dy = C1 + | ---- dx + | d(y) | a(x) + | | + / / + + Examples + ======== + + >>> from sympy import Function, dsolve, Eq + >>> from sympy.abc import x + >>> f = Function('f') + >>> pprint(dsolve(Eq(f(x)*f(x).diff(x) + x, 3*x*f(x)**2), f(x), + ... hint='separable', simplify=False)) + / 2 \ 2 + log\3*f (x) - 1/ x + ---------------- = C1 + -- + 6 2 + + References + ========== + + - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", + Dover 1963, pp. 52 + + # indirect doctest + + """ + hint = "separable" + has_integral = True + order = [1] + + def _wilds(self, f, x, order): + d = Wild('d', exclude=[f(x).diff(x), f(x).diff(x, 2)]) + e = Wild('e', exclude=[f(x).diff(x)]) + return d, e + + def _equation(self, fx, x, order): + d, e = self.wilds() + return d + e*fx.diff(x) + + def _verify(self, fx): + d, e = self.wilds_match() + self.y = Dummy('y') + x = self.ode_problem.sym + d = separatevars(d.subs(fx, self.y)) + e = separatevars(e.subs(fx, self.y)) + # m1[coeff]*m1[x]*m1[y] + m2[coeff]*m2[x]*m2[y]*y' + self.m1 = separatevars(d, dict=True, symbols=(x, self.y)) + self.m2 = separatevars(e, dict=True, symbols=(x, self.y)) + return bool(self.m1 and self.m2) + + def _get_match_object(self): + fx = self.ode_problem.func + x = self.ode_problem.sym + return self.m1, self.m2, x, fx + + def _get_general_solution(self, *, simplify_flag: bool = True): + m1, m2, x, fx = self._get_match_object() + (C1,) = self.ode_problem.get_numbered_constants(num=1) + int = Integral(m2['coeff']*m2[self.y]/m1[self.y], + (self.y, None, fx)) + gen_sol = Eq(int, Integral(-m1['coeff']*m1[x]/ + m2[x], x) + C1) + return [gen_sol] + + +class SeparableReduced(Separable): + 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, pprint + >>> from sympy.abc import x, n + >>> f, g = 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 + ======== + :obj:`sympy.solvers.ode.single.Separable` + + Examples + ======== + + >>> from sympy import dsolve, Function, pprint + >>> 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') + [Eq(f(x), (1 - sqrt(C1*x**2 + 1))/x), Eq(f(x), (sqrt(C1*x**2 + 1) + 1)/x)] + >>> pprint(dsolve(eq, hint='separable_reduced')) + ___________ ___________ + / 2 / 2 + 1 - \/ C1*x + 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 + """ + hint = "separable_reduced" + has_integral = True + order = [1] + + def _degree(self, expr, x): + # Made this function to calculate the degree of + # x in an expression. If expr will be of form + # x**p*y, (wheare p can be variables/rationals) then it + # will return p. + for val in expr: + if val.has(x): + if isinstance(val, Pow) and val.as_base_exp()[0] == x: + return (val.as_base_exp()[1]) + elif val == x: + return (val.as_base_exp()[1]) + else: + return self._degree(val.args, x) + return 0 + + def _powers(self, expr): + # this function will return all the different relative power of x w.r.t f(x). + # expr = x**p * f(x)**q then it will return {p/q}. + pows = set() + fx = self.ode_problem.func + x = self.ode_problem.sym + self.y = Dummy('y') + if isinstance(expr, Add): + exprs = expr.atoms(Add) + elif isinstance(expr, Mul): + exprs = expr.atoms(Mul) + elif isinstance(expr, Pow): + exprs = expr.atoms(Pow) + else: + exprs = {expr} + + for arg in exprs: + if arg.has(x): + _, u = arg.as_independent(x, fx) + pow = self._degree((u.subs(fx, self.y), ), x)/self._degree((u.subs(fx, self.y), ), self.y) + pows.add(pow) + return pows + + def _verify(self, fx): + num, den = self.wilds_match() + x = self.ode_problem.sym + factor = simplify(x/fx*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) + num, dem = factor.as_numer_denom() + num = expand(num) + dem = expand(dem) + pows = self._powers(num) + pows.update(self._powers(dem)) + pows = list(pows) + if(len(pows)==1) and pows[0]!=zoo: + self.t = Dummy('t') + self.r2 = {'t': self.t} + num = num.subs(x**pows[0]*fx, self.t) + dem = dem.subs(x**pows[0]*fx, self.t) + test = num/dem + free = test.free_symbols + if len(free) == 1 and free.pop() == self.t: + self.r2.update({'power' : pows[0], 'u' : test}) + return True + return False + return False + + def _get_match_object(self): + fx = self.ode_problem.func + x = self.ode_problem.sym + u = self.r2['u'].subs(self.r2['t'], self.y) + ycoeff = 1/(self.y*(self.r2['power'] - u)) + m1 = {self.y: 1, x: -1/x, 'coeff': 1} + m2 = {self.y: ycoeff, x: 1, 'coeff': 1} + return m1, m2, x, x**self.r2['power']*fx + + +class HomogeneousCoeffSubsDepDivIndep(SinglePatternODESolver): + r""" + Solves a 1st order differential equation with homogeneous coefficients + using the substitution `u_1 = \frac{\text{}}{\text{}}`. + + This is a differential equation + + .. 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 + >>> f, g, h = map(Function, ['f', 'g', 'h']) + >>> genform = g(f(x)/x) + h(f(x)/x)*f(x).diff(x) + >>> pprint(genform) + /f(x)\ /f(x)\ d + g|----| + h|----|*--(f(x)) + \ x / \ x / dx + >>> pprint(dsolve(genform, f(x), + ... hint='1st_homogeneous_coeff_subs_dep_div_indep_Integral')) + f(x) + ---- + x + / + | + | -h(u1) + log(x) = C1 + | ---------------- d(u1) + | u1*h(u1) + g(u1) + | + / + + Where `u_1 h(u_1) + g(u_1) \ne 0` and `x \ne 0`. + + See also the docstrings of + :obj:`~sympy.solvers.ode.single.HomogeneousCoeffBest` and + :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsIndepDivDep`. + + Examples + ======== + + >>> from sympy import Function, 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_dep_div_indep', simplify=False)) + / 3 \ + |3*f(x) f (x)| + log|------ + -----| + | x 3 | + \ x / + log(x) = log(C1) - ------------------- + 3 + + References + ========== + + - https://en.wikipedia.org/wiki/Homogeneous_differential_equation + - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", + Dover 1963, pp. 59 + + # indirect doctest + + """ + hint = "1st_homogeneous_coeff_subs_dep_div_indep" + has_integral = True + order = [1] + + def _wilds(self, f, x, order): + d = Wild('d', exclude=[f(x).diff(x), f(x).diff(x, 2)]) + e = Wild('e', exclude=[f(x).diff(x)]) + return d, e + + def _equation(self, fx, x, order): + d, e = self.wilds() + return d + e*fx.diff(x) + + def _verify(self, fx): + self.d, self.e = self.wilds_match() + self.y = Dummy('y') + x = self.ode_problem.sym + self.d = separatevars(self.d.subs(fx, self.y)) + self.e = separatevars(self.e.subs(fx, self.y)) + ordera = homogeneous_order(self.d, x, self.y) + orderb = homogeneous_order(self.e, x, self.y) + if ordera == orderb and ordera is not None: + self.u = Dummy('u') + if simplify((self.d + self.u*self.e).subs({x: 1, self.y: self.u})) != 0: + return True + return False + return False + + def _get_match_object(self): + fx = self.ode_problem.func + x = self.ode_problem.sym + self.u1 = Dummy('u1') + xarg = 0 + yarg = 0 + return [self.d, self.e, fx, x, self.u, self.u1, self.y, xarg, yarg] + + def _get_general_solution(self, *, simplify_flag: bool = True): + d, e, fx, x, u, u1, y, xarg, yarg = self._get_match_object() + (C1,) = self.ode_problem.get_numbered_constants(num=1) + int = Integral( + (-e/(d + u1*e)).subs({x: 1, y: u1}), + (u1, None, fx/x)) + sol = logcombine(Eq(log(x), int + log(C1)), force=True) + gen_sol = sol.subs(fx, u).subs(((u, u - yarg), (x, x - xarg), (u, fx))) + return [gen_sol] + + +class HomogeneousCoeffSubsIndepDivDep(SinglePatternODESolver): + r""" + Solves a 1st order differential equation with homogeneous coefficients + using the substitution `u_2 = \frac{\text{}}{\text{}}`. + + This is a differential equation + + .. 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 + >>> f, g, h = map(Function, ['f', 'g', 'h']) + >>> genform = g(x/f(x)) + h(x/f(x))*f(x).diff(x) + >>> pprint(genform) + / x \ / x \ d + g|----| + h|----|*--(f(x)) + \f(x)/ \f(x)/ dx + >>> pprint(dsolve(genform, f(x), + ... hint='1st_homogeneous_coeff_subs_indep_div_dep_Integral')) + x + ---- + f(x) + / + | + | -g(u1) + | ---------------- d(u1) + | u1*g(u1) + h(u1) + | + / + + f(x) = C1*e + + Where `u_1 g(u_1) + h(u_1) \ne 0` and `f(x) \ne 0`. + + See also the docstrings of + :obj:`~sympy.solvers.ode.single.HomogeneousCoeffBest` and + :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsDepDivIndep`. + + Examples + ======== + + >>> 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', + ... simplify=False)) + / 2 \ + |3*x | + log|----- + 1| + | 2 | + \f (x) / + log(f(x)) = log(C1) - -------------- + 3 + + References + ========== + + - https://en.wikipedia.org/wiki/Homogeneous_differential_equation + - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", + Dover 1963, pp. 59 + + # indirect doctest + + """ + hint = "1st_homogeneous_coeff_subs_indep_div_dep" + has_integral = True + order = [1] + + def _wilds(self, f, x, order): + d = Wild('d', exclude=[f(x).diff(x), f(x).diff(x, 2)]) + e = Wild('e', exclude=[f(x).diff(x)]) + return d, e + + def _equation(self, fx, x, order): + d, e = self.wilds() + return d + e*fx.diff(x) + + def _verify(self, fx): + self.d, self.e = self.wilds_match() + self.y = Dummy('y') + x = self.ode_problem.sym + self.d = separatevars(self.d.subs(fx, self.y)) + self.e = separatevars(self.e.subs(fx, self.y)) + ordera = homogeneous_order(self.d, x, self.y) + orderb = homogeneous_order(self.e, x, self.y) + if ordera == orderb and ordera is not None: + self.u = Dummy('u') + if simplify((self.e + self.u*self.d).subs({x: self.u, self.y: 1})) != 0: + return True + return False + return False + + def _get_match_object(self): + fx = self.ode_problem.func + x = self.ode_problem.sym + self.u1 = Dummy('u1') + xarg = 0 + yarg = 0 + return [self.d, self.e, fx, x, self.u, self.u1, self.y, xarg, yarg] + + def _get_general_solution(self, *, simplify_flag: bool = True): + d, e, fx, x, u, u1, y, xarg, yarg = self._get_match_object() + (C1,) = self.ode_problem.get_numbered_constants(num=1) + int = Integral(simplify((-d/(e + u1*d)).subs({x: u1, y: 1})), (u1, None, x/fx)) # type: ignore + sol = logcombine(Eq(log(fx), int + log(C1)), force=True) + gen_sol = sol.subs(fx, u).subs(((u, u - yarg), (x, x - xarg), (u, fx))) + return [gen_sol] + + +class HomogeneousCoeffBest(HomogeneousCoeffSubsIndepDivDep, HomogeneousCoeffSubsDepDivIndep): + 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``. + + This is as determined by :py:meth:`~sympy.solvers.ode.ode.ode_sol_simplicity`. + + See the + :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsIndepDivDep` + and + :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsDepDivIndep` + docstrings for more information on these hints. Note that there is no + ``ode_1st_homogeneous_coeff_best_Integral`` hint. + + Examples + ======== + + >>> from sympy import Function, dsolve, pprint + >>> 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_best', simplify=False)) + / 2 \ + |3*x | + log|----- + 1| + | 2 | + \f (x) / + log(f(x)) = log(C1) - -------------- + 3 + + References + ========== + + - https://en.wikipedia.org/wiki/Homogeneous_differential_equation + - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", + Dover 1963, pp. 59 + + # indirect doctest + + """ + hint = "1st_homogeneous_coeff_best" + has_integral = False + order = [1] + + def _verify(self, fx): + return HomogeneousCoeffSubsIndepDivDep._verify(self, fx) and \ + HomogeneousCoeffSubsDepDivIndep._verify(self, fx) + + def _get_general_solution(self, *, simplify_flag: bool = True): + # There are two substitutions that solve the equation, u1=y/x and u2=x/y + # # They produce different integrals, so try them both and see which + # # one is easier + sol1 = HomogeneousCoeffSubsIndepDivDep._get_general_solution(self) + sol2 = HomogeneousCoeffSubsDepDivIndep._get_general_solution(self) + fx = self.ode_problem.func + if simplify_flag: + sol1 = odesimp(self.ode_problem.eq, *sol1, fx, "1st_homogeneous_coeff_subs_indep_div_dep") + sol2 = odesimp(self.ode_problem.eq, *sol2, fx, "1st_homogeneous_coeff_subs_dep_div_indep") + # XXX: not simplify should be not simplify_flag. mypy correctly complains + return min([sol1, sol2], key=lambda x: ode_sol_simplicity(x, fx, trysolving=not simplify)) # type: ignore + + +class LinearCoefficients(HomogeneousCoeffBest): + 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 + ======== + :obj:`sympy.solvers.ode.single.HomogeneousCoeffBest` + :obj:`sympy.solvers.ode.single.HomogeneousCoeffSubsIndepDivDep` + :obj:`sympy.solvers.ode.single.HomogeneousCoeffSubsDepDivIndep` + + Examples + ======== + + >>> from sympy import dsolve, Function, pprint + >>> 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') + [Eq(f(x), -x - sqrt(C1 + 7*x**2) - 1), Eq(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 + """ + hint = "linear_coefficients" + has_integral = True + order = [1] + + def _wilds(self, f, x, order): + d = Wild('d', exclude=[f(x).diff(x), f(x).diff(x, 2)]) + e = Wild('e', exclude=[f(x).diff(x)]) + return d, e + + def _equation(self, fx, x, order): + d, e = self.wilds() + return d + e*fx.diff(x) + + def _verify(self, fx): + self.d, self.e = self.wilds_match() + a, b = self.wilds() + F = self.d/self.e + x = self.ode_problem.sym + params = self._linear_coeff_match(F, fx) + if params: + self.xarg, self.yarg = params + u = Dummy('u') + t = Dummy('t') + self.y = Dummy('y') + # Dummy substitution for df and f(x). + dummy_eq = self.ode_problem.eq.subs(((fx.diff(x), t), (fx, u))) + reps = ((x, x + self.xarg), (u, u + self.yarg), (t, fx.diff(x)), (u, fx)) + dummy_eq = simplify(dummy_eq.subs(reps)) + # get the re-cast values for e and d + r2 = collect(expand(dummy_eq), [fx.diff(x), fx]).match(a*fx.diff(x) + b) + if r2: + self.d, self.e = r2[b], r2[a] + orderd = homogeneous_order(self.d, x, fx) + ordere = homogeneous_order(self.e, x, fx) + if orderd == ordere and orderd is not None: + self.d = self.d.subs(fx, self.y) + self.e = self.e.subs(fx, self.y) + return True + return False + return False + + def _linear_coeff_match(self, 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, sin + >>> from sympy.abc import x + >>> from sympy.solvers.ode.single import LinearCoefficients + >>> f = Function('f') + >>> eq = (-25*f(x) - 8*x + 62)/(4*f(x) + 11*x - 11) + >>> obj = LinearCoefficients(eq) + >>> obj._linear_coeff_match(eq, f(x)) + (1/9, 22/9) + >>> eq = sin((-5*f(x) - 8*x + 6)/(4*f(x) + x - 1)) + >>> obj = LinearCoefficients(eq) + >>> obj._linear_coeff_match(eq, f(x)) + (19/27, 2/27) + >>> eq = sin(f(x)/x) + >>> obj = LinearCoefficients(eq) + >>> obj._linear_coeff_match(eq, 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 + len(fi.args) == 1 and not fi.args[0].is_Function] or {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 _get_match_object(self): + fx = self.ode_problem.func + x = self.ode_problem.sym + self.u1 = Dummy('u1') + u = Dummy('u') + return [self.d, self.e, fx, x, u, self.u1, self.y, self.xarg, self.yarg] + + +class NthOrderReducible(SingleODESolver): + r""" + Solves ODEs that only involve derivatives of the dependent variable using + a substitution of the form `f^n(x) = g(x)`. + + For example any second order ODE of the form `f''(x) = h(f'(x), x)` can be + transformed into a pair of 1st order ODEs `g'(x) = h(g(x), x)` and + `f'(x) = g(x)`. Usually the 1st order ODE for `g` is easier to solve. If + that gives an explicit solution for `g` then `f` is found simply by + integration. + + + Examples + ======== + + >>> from sympy import Function, dsolve, Eq + >>> from sympy.abc import x + >>> f = Function('f') + >>> eq = Eq(x*f(x).diff(x)**2 + f(x).diff(x, 2), 0) + >>> dsolve(eq, f(x), hint='nth_order_reducible') + ... # doctest: +NORMALIZE_WHITESPACE + Eq(f(x), C1 - sqrt(-1/C2)*log(-C2*sqrt(-1/C2) + x) + sqrt(-1/C2)*log(C2*sqrt(-1/C2) + x)) + + """ + hint = "nth_order_reducible" + has_integral = False + + def _matches(self): + # Any ODE that can be solved with a substitution and + # repeated integration e.g.: + # `d^2/dx^2(y) + x*d/dx(y) = constant + #f'(x) must be finite for this to work + eq = self.ode_problem.eq_preprocessed + func = self.ode_problem.func + x = self.ode_problem.sym + r""" + Matches any differential equation that can be rewritten with a smaller + order. Only derivatives of ``func`` alone, wrt a single variable, + are considered, and only in them should ``func`` appear. + """ + # ODE only handles functions of 1 variable so this affirms that state + assert len(func.args) == 1 + vc = [d.variable_count[0] for d in eq.atoms(Derivative) + if d.expr == func and len(d.variable_count) == 1] + ords = [c for v, c in vc if v == x] + if len(ords) < 2: + return False + self.smallest = min(ords) + # make sure func does not appear outside of derivatives + D = Dummy() + if eq.subs(func.diff(x, self.smallest), D).has(func): + return False + return True + + def _get_general_solution(self, *, simplify_flag: bool = True): + eq = self.ode_problem.eq + f = self.ode_problem.func.func + x = self.ode_problem.sym + n = self.smallest + # get a unique function name for g + names = [a.name for a in eq.atoms(AppliedUndef)] + while True: + name = Dummy().name + if name not in names: + g = Function(name) + break + w = f(x).diff(x, n) + geq = eq.subs(w, g(x)) + gsol = dsolve(geq, g(x)) + + if not isinstance(gsol, list): + gsol = [gsol] + + # Might be multiple solutions to the reduced ODE: + fsol = [] + for gsoli in gsol: + fsoli = dsolve(gsoli.subs(g(x), w), f(x)) # or do integration n times + fsol.append(fsoli) + + return fsol + + +class SecondHypergeometric(SingleODESolver): + r""" + Solves 2nd order linear differential equations. + + It computes special function solutions which can be expressed using the + 2F1, 1F1 or 0F1 hypergeometric functions. + + .. math:: y'' + A(x) y' + B(x) y = 0\text{,} + + where `A` and `B` are rational functions. + + These kinds of differential equations have solution of non-Liouvillian form. + + Given linear ODE can be obtained from 2F1 given by + + .. math:: (x^2 - x) y'' + ((a + b + 1) x - c) y' + b a y = 0\text{,} + + where {a, b, c} are arbitrary constants. + + Notes + ===== + + The algorithm should find any solution of the form + + .. math:: y = P(x) _pF_q(..; ..;\frac{\alpha x^k + \beta}{\gamma x^k + \delta})\text{,} + + where pFq is any of 2F1, 1F1 or 0F1 and `P` is an "arbitrary function". + Currently only the 2F1 case is implemented in SymPy but the other cases are + described in the paper and could be implemented in future (contributions + welcome!). + + + Examples + ======== + + >>> from sympy import Function, dsolve, pprint + >>> from sympy.abc import x + >>> f = Function('f') + >>> eq = (x*x - x)*f(x).diff(x,2) + (5*x - 1)*f(x).diff(x) + 4*f(x) + >>> pprint(dsolve(eq, f(x), '2nd_hypergeometric')) + _ + / / 4 \\ |_ /-1, -1 | \ + |C1 + C2*|log(x) + -----||* | | | x| + \ \ x + 1// 2 1 \ 1 | / + f(x) = -------------------------------------------- + 3 + (x - 1) + + + References + ========== + + - "Non-Liouvillian solutions for second order linear ODEs" by L. Chan, E.S. Cheb-Terrab + + """ + hint = "2nd_hypergeometric" + has_integral = True + + def _matches(self): + eq = self.ode_problem.eq_preprocessed + func = self.ode_problem.func + r = match_2nd_hypergeometric(eq, func) + self.match_object = None + if r: + A, B = r + d = equivalence_hypergeometric(A, B, func) + if d: + if d['type'] == "2F1": + self.match_object = match_2nd_2F1_hypergeometric(d['I0'], d['k'], d['sing_point'], func) + if self.match_object is not None: + self.match_object.update({'A':A, 'B':B}) + # We can extend it for 1F1 and 0F1 type also. + return self.match_object is not None + + def _get_general_solution(self, *, simplify_flag: bool = True): + eq = self.ode_problem.eq + func = self.ode_problem.func + if self.match_object['type'] == "2F1": + sol = get_sol_2F1_hypergeometric(eq, func, self.match_object) + if sol is None: + raise NotImplementedError("The given ODE " + str(eq) + " cannot be solved by" + + " the hypergeometric method") + + return [sol] + + +class NthLinearConstantCoeffHomogeneous(SingleODESolver): + r""" + Solves an `n`\th order linear homogeneous differential equation with + constant coefficients. + + 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} + \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 + :py:class:`~sympy.polys.rootoftools.ComplexRootOf` instance will be return + instead. + + >>> from sympy import Function, dsolve + >>> from sympy.abc import x + >>> f = Function('f') + >>> dsolve(f(x).diff(x, 5) + 10*f(x).diff(x) - 2*f(x), f(x), + ... hint='nth_linear_constant_coeff_homogeneous') + ... # doctest: +NORMALIZE_WHITESPACE + Eq(f(x), C5*exp(x*CRootOf(_x**5 + 10*_x - 2, 0)) + + (C1*sin(x*im(CRootOf(_x**5 + 10*_x - 2, 1))) + + C2*cos(x*im(CRootOf(_x**5 + 10*_x - 2, 1))))*exp(x*re(CRootOf(_x**5 + 10*_x - 2, 1))) + + (C3*sin(x*im(CRootOf(_x**5 + 10*_x - 2, 3))) + + C4*cos(x*im(CRootOf(_x**5 + 10*_x - 2, 3))))*exp(x*re(CRootOf(_x**5 + 10*_x - 2, 3)))) + + Note that because this method does not involve integration, there is no + ``nth_linear_constant_coeff_homogeneous_Integral`` hint. + + Examples + ======== + + >>> from sympy import Function, dsolve, pprint + >>> from sympy.abc import x + >>> f = Function('f') + >>> pprint(dsolve(f(x).diff(x, 4) + 2*f(x).diff(x, 3) - + ... 2*f(x).diff(x, 2) - 6*f(x).diff(x) + 5*f(x), f(x), + ... hint='nth_linear_constant_coeff_homogeneous')) + x -2*x + f(x) = (C1 + C2*x)*e + (C3*sin(x) + C4*cos(x))*e + + References + ========== + + - https://en.wikipedia.org/wiki/Linear_differential_equation section: + Nonhomogeneous_equation_with_constant_coefficients + - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", + Dover 1963, pp. 211 + + # indirect doctest + + """ + hint = "nth_linear_constant_coeff_homogeneous" + has_integral = False + + def _matches(self): + eq = self.ode_problem.eq_high_order_free + func = self.ode_problem.func + order = self.ode_problem.order + x = self.ode_problem.sym + self.r = self.ode_problem.get_linear_coefficients(eq, func, order) + if order and self.r and not any(self.r[i].has(x) for i in self.r if i >= 0): + if not self.r[-1]: + return True + else: + return False + return False + + def _get_general_solution(self, *, simplify_flag: bool = True): + fx = self.ode_problem.func + order = self.ode_problem.order + roots, collectterms = _get_const_characteristic_eq_sols(self.r, fx, order) + # A generator of constants + constants = self.ode_problem.get_numbered_constants(num=len(roots)) + gsol_rhs = Add(*[i*j for (i, j) in zip(constants, roots)]) + gsol = Eq(fx, gsol_rhs) + if simplify_flag: + gsol = _get_simplified_sol([gsol], fx, collectterms) + + return [gsol] + + +class NthLinearConstantCoeffVariationOfParameters(SingleODESolver): + r""" + 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 + + .. 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 does not use integration, making it faster and more + reliable. + + Warning, using simplify=False with + '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 + ======== + + >>> from sympy import Function, dsolve, pprint, exp, log + >>> from sympy.abc import x + >>> f = Function('f') + >>> pprint(dsolve(f(x).diff(x, 3) - 3*f(x).diff(x, 2) + + ... 3*f(x).diff(x) - f(x) - exp(x)*log(x), f(x), + ... hint='nth_linear_constant_coeff_variation_of_parameters')) + / / / x*log(x) 11*x\\\ x + f(x) = |C1 + x*|C2 + x*|C3 + -------- - ----|||*e + \ \ \ 6 36 /// + + References + ========== + + - https://en.wikipedia.org/wiki/Variation_of_parameters + - https://planetmath.org/VariationOfParameters + - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", + Dover 1963, pp. 233 + + # indirect doctest + + """ + hint = "nth_linear_constant_coeff_variation_of_parameters" + has_integral = True + + def _matches(self): + eq = self.ode_problem.eq_high_order_free + func = self.ode_problem.func + order = self.ode_problem.order + x = self.ode_problem.sym + self.r = self.ode_problem.get_linear_coefficients(eq, func, order) + + if order and self.r and not any(self.r[i].has(x) for i in self.r if i >= 0): + if self.r[-1]: + return True + else: + return False + return False + + def _get_general_solution(self, *, simplify_flag: bool = True): + eq = self.ode_problem.eq_high_order_free + f = self.ode_problem.func.func + x = self.ode_problem.sym + order = self.ode_problem.order + roots, collectterms = _get_const_characteristic_eq_sols(self.r, f(x), order) + # A generator of constants + constants = self.ode_problem.get_numbered_constants(num=len(roots)) + homogen_sol_rhs = Add(*[i*j for (i, j) in zip(constants, roots)]) + homogen_sol = Eq(f(x), homogen_sol_rhs) + homogen_sol = _solve_variation_of_parameters(eq, f(x), roots, homogen_sol, order, self.r, simplify_flag) + if simplify_flag: + homogen_sol = _get_simplified_sol([homogen_sol], f(x), collectterms) + return [homogen_sol] + + +class NthLinearConstantCoeffUndeterminedCoefficients(SingleODESolver): + r""" + 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 + + .. 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 + ======== + + >>> from sympy import Function, dsolve, pprint, exp, cos + >>> from sympy.abc import x + >>> f = Function('f') + >>> pprint(dsolve(f(x).diff(x, 2) + 2*f(x).diff(x) + f(x) - + ... 4*exp(-x)*x**2 + cos(2*x), f(x), + ... hint='nth_linear_constant_coeff_undetermined_coefficients')) + / / 3\\ + | | x || -x 4*sin(2*x) 3*cos(2*x) + f(x) = |C1 + x*|C2 + --||*e - ---------- + ---------- + \ \ 3 // 25 25 + + References + ========== + + - https://en.wikipedia.org/wiki/Method_of_undetermined_coefficients + - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", + Dover 1963, pp. 221 + + # indirect doctest + + """ + hint = "nth_linear_constant_coeff_undetermined_coefficients" + has_integral = False + + def _matches(self): + eq = self.ode_problem.eq_high_order_free + func = self.ode_problem.func + order = self.ode_problem.order + x = self.ode_problem.sym + self.r = self.ode_problem.get_linear_coefficients(eq, func, order) + does_match = False + if order and self.r and not any(self.r[i].has(x) for i in self.r if i >= 0): + if self.r[-1]: + eq_homogeneous = Add(eq, -self.r[-1]) + undetcoeff = _undetermined_coefficients_match(self.r[-1], x, func, eq_homogeneous) + if undetcoeff['test']: + self.trialset = undetcoeff['trialset'] + does_match = True + return does_match + + def _get_general_solution(self, *, simplify_flag: bool = True): + eq = self.ode_problem.eq + f = self.ode_problem.func.func + x = self.ode_problem.sym + order = self.ode_problem.order + roots, collectterms = _get_const_characteristic_eq_sols(self.r, f(x), order) + # A generator of constants + constants = self.ode_problem.get_numbered_constants(num=len(roots)) + homogen_sol_rhs = Add(*[i*j for (i, j) in zip(constants, roots)]) + homogen_sol = Eq(f(x), homogen_sol_rhs) + self.r.update({'list': roots, 'sol': homogen_sol, 'simpliy_flag': simplify_flag}) + gsol = _solve_undetermined_coefficients(eq, f(x), order, self.r, self.trialset) + if simplify_flag: + gsol = _get_simplified_sol([gsol], f(x), collectterms) + return [gsol] + + +class NthLinearEulerEqHomogeneous(SingleODESolver): + r""" + 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 Euler's formula. The general + solution is the sum of the terms found. If SymPy cannot find exact roots + to the characteristic equation, a + :py:obj:`~.ComplexRootOf` instance will be returned + instead. + + >>> from sympy import Function, dsolve + >>> 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 + Eq(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 + ========== + + - https://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 + + """ + hint = "nth_linear_euler_eq_homogeneous" + has_integral = False + + def _matches(self): + eq = self.ode_problem.eq_preprocessed + f = self.ode_problem.func.func + order = self.ode_problem.order + x = self.ode_problem.sym + match = self.ode_problem.get_linear_coefficients(eq, f(x), order) + self.r = None + does_match = False + + if order and match: + coeff = match[order] + factor = x**order / coeff + self.r = {i: factor*match[i] for i in match} + if self.r and all(_test_term(self.r[i], f(x), i) for i in + self.r if i >= 0): + if not self.r[-1]: + does_match = True + return does_match + + def _get_general_solution(self, *, simplify_flag: bool = True): + fx = self.ode_problem.func + eq = self.ode_problem.eq + homogen_sol = _get_euler_characteristic_eq_sols(eq, fx, self.r)[0] + return [homogen_sol] + + +class NthLinearEulerEqNonhomogeneousVariationOfParameters(SingleODESolver): + r""" + Solves an `n`\th order linear non homogeneous Cauchy-Euler equidimensional + ordinary differential equation using variation of parameters. + + This is an equation with form `g(x) = a_0 f(x) + a_1 x f'(x) + a_2 x^2 f''(x) + \cdots`. + + This method works by assuming that the particular solution takes the form + + .. math:: \sum_{x=1}^{n} c_i(x) y_i(x) {a_n} {x^n} \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 multiplying eq given below with `a_n x^{n}` + + .. 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, \frac{x^{- n}}{a_n} g{\left(x \right)}]`. + + This method is general enough to solve any `n`\th order inhomogeneous + linear differential equation, 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 does not use integration, making it faster and more + reliable. + + Warning, using simplify=False with + '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 + ======== + + >>> from sympy import Function, dsolve, Derivative + >>> from sympy.abc import x + >>> f = Function('f') + >>> eq = x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x) - x**4 + >>> dsolve(eq, f(x), + ... hint='nth_linear_euler_eq_nonhomogeneous_variation_of_parameters').expand() + Eq(f(x), C1*x + C2*x**2 + x**4/6) + + """ + hint = "nth_linear_euler_eq_nonhomogeneous_variation_of_parameters" + has_integral = True + + def _matches(self): + eq = self.ode_problem.eq_preprocessed + f = self.ode_problem.func.func + order = self.ode_problem.order + x = self.ode_problem.sym + match = self.ode_problem.get_linear_coefficients(eq, f(x), order) + self.r = None + does_match = False + + if order and match: + coeff = match[order] + factor = x**order / coeff + self.r = {i: factor*match[i] for i in match} + if self.r and all(_test_term(self.r[i], f(x), i) for i in + self.r if i >= 0): + if self.r[-1]: + does_match = True + + return does_match + + def _get_general_solution(self, *, simplify_flag: bool = True): + eq = self.ode_problem.eq + f = self.ode_problem.func.func + x = self.ode_problem.sym + order = self.ode_problem.order + homogen_sol, roots = _get_euler_characteristic_eq_sols(eq, f(x), self.r) + self.r[-1] = self.r[-1]/self.r[order] + sol = _solve_variation_of_parameters(eq, f(x), roots, homogen_sol, order, self.r, simplify_flag) + + return [Eq(f(x), homogen_sol.rhs + (sol.rhs - homogen_sol.rhs)*self.r[order])] + + +class NthLinearEulerEqNonhomogeneousUndeterminedCoefficients(SingleODESolver): + r""" + Solves an `n`\th order linear non homogeneous Cauchy-Euler equidimensional + ordinary differential equation using undetermined coefficients. + + This is an equation with form `g(x) = 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 `x = exp(t)`, and deriving a characteristic equation + of form `g(exp(t)) = b_0 f(t) + b_1 f'(t) + b_2 f''(t) \cdots` which can + be then solved by nth_linear_constant_coeff_undetermined_coefficients if + g(exp(t)) has 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. + + After replacement of x by exp(t), 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 + ======== + + >>> from sympy import dsolve, Function, Derivative, log + >>> from sympy.abc import x + >>> f = Function('f') + >>> eq = x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x) - log(x) + >>> dsolve(eq, f(x), + ... hint='nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients').expand() + Eq(f(x), C1*x + C2*x**2 + log(x)/2 + 3/4) + + """ + hint = "nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients" + has_integral = False + + def _matches(self): + eq = self.ode_problem.eq_high_order_free + f = self.ode_problem.func.func + order = self.ode_problem.order + x = self.ode_problem.sym + match = self.ode_problem.get_linear_coefficients(eq, f(x), order) + self.r = None + does_match = False + + if order and match: + coeff = match[order] + factor = x**order / coeff + self.r = {i: factor*match[i] for i in match} + if self.r and all(_test_term(self.r[i], f(x), i) for i in + self.r if i >= 0): + if self.r[-1]: + e, re = posify(self.r[-1].subs(x, exp(x))) + undetcoeff = _undetermined_coefficients_match(e.subs(re), x) + if undetcoeff['test']: + does_match = True + return does_match + + def _get_general_solution(self, *, simplify_flag: bool = True): + f = self.ode_problem.func.func + x = self.ode_problem.sym + chareq, eq, symbol = S.Zero, S.Zero, Dummy('x') + for i in self.r.keys(): + if i >= 0: + chareq += (self.r[i]*diff(x**symbol, x, i)*x**-symbol).expand() + + for i in range(1, degree(Poly(chareq, symbol))+1): + eq += chareq.coeff(symbol**i)*diff(f(x), x, i) + + if chareq.as_coeff_add(symbol)[0]: + eq += chareq.as_coeff_add(symbol)[0]*f(x) + e, re = posify(self.r[-1].subs(x, exp(x))) + eq += e.subs(re) + + self.const_undet_instance = NthLinearConstantCoeffUndeterminedCoefficients(SingleODEProblem(eq, f(x), x)) + sol = self.const_undet_instance.get_general_solution(simplify = simplify_flag)[0] + sol = sol.subs(x, log(x)) # type: ignore + sol = sol.subs(f(log(x)), f(x)).expand() # type: ignore + + return [sol] + + +class SecondLinearBessel(SingleODESolver): + r""" + Gives solution of the Bessel differential equation + + .. math :: x^2 \frac{d^2y}{dx^2} + x \frac{dy}{dx} y(x) + (x^2-n^2) y(x) + + if `n` is integer then the solution is of the form ``Eq(f(x), C0 besselj(n,x) + + C1 bessely(n,x))`` as both the solutions are linearly independent else if + `n` is a fraction then the solution is of the form ``Eq(f(x), C0 besselj(n,x) + + C1 besselj(-n,x))`` which can also transform into ``Eq(f(x), C0 besselj(n,x) + + C1 bessely(n,x))``. + + Examples + ======== + + >>> from sympy.abc import x + >>> from sympy import Symbol + >>> v = Symbol('v', positive=True) + >>> from sympy import dsolve, Function + >>> f = Function('f') + >>> y = f(x) + >>> genform = x**2*y.diff(x, 2) + x*y.diff(x) + (x**2 - v**2)*y + >>> dsolve(genform) + Eq(f(x), C1*besselj(v, x) + C2*bessely(v, x)) + + References + ========== + + https://math24.net/bessel-differential-equation.html + + """ + hint = "2nd_linear_bessel" + has_integral = False + + def _matches(self): + eq = self.ode_problem.eq_high_order_free + f = self.ode_problem.func + order = self.ode_problem.order + x = self.ode_problem.sym + df = f.diff(x) + a = Wild('a', exclude=[f,df]) + b = Wild('b', exclude=[x, f,df]) + a4 = Wild('a4', exclude=[x,f,df]) + b4 = Wild('b4', exclude=[x,f,df]) + c4 = Wild('c4', exclude=[x,f,df]) + d4 = Wild('d4', exclude=[x,f,df]) + a3 = Wild('a3', exclude=[f, df, f.diff(x, 2)]) + b3 = Wild('b3', exclude=[f, df, f.diff(x, 2)]) + c3 = Wild('c3', exclude=[f, df, f.diff(x, 2)]) + deq = a3*(f.diff(x, 2)) + b3*df + c3*f + r = collect(eq, + [f.diff(x, 2), df, f]).match(deq) + if order == 2 and r: + if not all(r[key].is_polynomial() for key in r): + n, d = eq.as_numer_denom() + eq = expand(n) + r = collect(eq, + [f.diff(x, 2), df, f]).match(deq) + + if r and r[a3] != 0: + # leading coeff of f(x).diff(x, 2) + coeff = factor(r[a3]).match(a4*(x-b)**b4) + + if coeff: + # if coeff[b4] = 0 means constant coefficient + if coeff[b4] == 0: + return False + point = coeff[b] + else: + return False + + if point: + r[a3] = simplify(r[a3].subs(x, x+point)) + r[b3] = simplify(r[b3].subs(x, x+point)) + r[c3] = simplify(r[c3].subs(x, x+point)) + + # making a3 in the form of x**2 + r[a3] = cancel(r[a3]/(coeff[a4]*(x)**(-2+coeff[b4]))) + r[b3] = cancel(r[b3]/(coeff[a4]*(x)**(-2+coeff[b4]))) + r[c3] = cancel(r[c3]/(coeff[a4]*(x)**(-2+coeff[b4]))) + # checking if b3 is of form c*(x-b) + coeff1 = factor(r[b3]).match(a4*(x)) + if coeff1 is None: + return False + # c3 maybe of very complex form so I am simply checking (a - b) form + # if yes later I will match with the standard form of bessel in a and b + # a, b are wild variable defined above. + _coeff2 = expand(r[c3]).match(a - b) + if _coeff2 is None: + return False + # matching with standard form for c3 + coeff2 = factor(_coeff2[a]).match(c4**2*(x)**(2*a4)) + if coeff2 is None: + return False + + if _coeff2[b] == 0: + coeff2[d4] = 0 + else: + coeff2[d4] = factor(_coeff2[b]).match(d4**2)[d4] + + self.rn = {'n':coeff2[d4], 'a4':coeff2[c4], 'd4':coeff2[a4]} + self.rn['c4'] = coeff1[a4] + self.rn['b4'] = point + return True + return False + + def _get_general_solution(self, *, simplify_flag: bool = True): + f = self.ode_problem.func.func + x = self.ode_problem.sym + n = self.rn['n'] + a4 = self.rn['a4'] + c4 = self.rn['c4'] + d4 = self.rn['d4'] + b4 = self.rn['b4'] + n = sqrt(n**2 + Rational(1, 4)*(c4 - 1)**2) + (C1, C2) = self.ode_problem.get_numbered_constants(num=2) + return [Eq(f(x), ((x**(Rational(1-c4,2)))*(C1*besselj(n/d4,a4*x**d4/d4) + + C2*bessely(n/d4,a4*x**d4/d4))).subs(x, x-b4))] + + +class SecondLinearAiry(SingleODESolver): + r""" + Gives solution of the Airy differential equation + + .. math :: \frac{d^2y}{dx^2} + (a + b x) y(x) = 0 + + in terms of Airy special functions airyai and airybi. + + Examples + ======== + + >>> from sympy import dsolve, Function + >>> from sympy.abc import x + >>> f = Function("f") + >>> eq = f(x).diff(x, 2) - x*f(x) + >>> dsolve(eq) + Eq(f(x), C1*airyai(x) + C2*airybi(x)) + """ + hint = "2nd_linear_airy" + has_integral = False + + def _matches(self): + eq = self.ode_problem.eq_high_order_free + f = self.ode_problem.func + order = self.ode_problem.order + x = self.ode_problem.sym + df = f.diff(x) + a4 = Wild('a4', exclude=[x,f,df]) + b4 = Wild('b4', exclude=[x,f,df]) + match = self.ode_problem.get_linear_coefficients(eq, f, order) + does_match = False + if order == 2 and match and match[2] != 0: + if match[1].is_zero: + self.rn = cancel(match[0]/match[2]).match(a4+b4*x) + if self.rn and self.rn[b4] != 0: + self.rn = {'b':self.rn[a4],'m':self.rn[b4]} + does_match = True + return does_match + + def _get_general_solution(self, *, simplify_flag: bool = True): + f = self.ode_problem.func.func + x = self.ode_problem.sym + (C1, C2) = self.ode_problem.get_numbered_constants(num=2) + b = self.rn['b'] + m = self.rn['m'] + if m.is_positive: + arg = - b/cbrt(m)**2 - cbrt(m)*x + elif m.is_negative: + arg = - b/cbrt(-m)**2 + cbrt(-m)*x + else: + arg = - b/cbrt(-m)**2 + cbrt(-m)*x + + return [Eq(f(x), C1*airyai(arg) + C2*airybi(arg))] + + +class LieGroup(SingleODESolver): + r""" + This hint implements the Lie group method of solving first order differential + equations. The aim is to convert the given differential equation from the + given coordinate system into another coordinate system where it becomes + invariant under the one-parameter Lie group of translations. The converted + ODE can be easily solved by quadrature. It makes use of the + :py:meth:`sympy.solvers.ode.infinitesimals` function which returns the + infinitesimals of the transformation. + + The coordinates `r` and `s` can be found by solving the following Partial + Differential Equations. + + .. math :: \xi\frac{\partial r}{\partial x} + \eta\frac{\partial r}{\partial y} + = 0 + + .. math :: \xi\frac{\partial s}{\partial x} + \eta\frac{\partial s}{\partial y} + = 1 + + The differential equation becomes separable in the new coordinate system + + .. math :: \frac{ds}{dr} = \frac{\frac{\partial s}{\partial x} + + h(x, y)\frac{\partial s}{\partial y}}{ + \frac{\partial r}{\partial x} + h(x, y)\frac{\partial r}{\partial y}} + + After finding the solution by integration, it is then converted back to the original + coordinate system by substituting `r` and `s` in terms of `x` and `y` again. + + Examples + ======== + + >>> from sympy import Function, dsolve, exp, pprint + >>> from sympy.abc import x + >>> f = Function('f') + >>> pprint(dsolve(f(x).diff(x) + 2*x*f(x) - x*exp(-x**2), f(x), + ... hint='lie_group')) + / 2\ 2 + | x | -x + f(x) = |C1 + --|*e + \ 2 / + + + References + ========== + + - Solving differential equations by Symmetry Groups, + John Starrett, pp. 1 - pp. 14 + + """ + hint = "lie_group" + has_integral = False + + def _has_additional_params(self): + return 'xi' in self.ode_problem.params and 'eta' in self.ode_problem.params + + def _matches(self): + eq = self.ode_problem.eq + f = self.ode_problem.func.func + order = self.ode_problem.order + x = self.ode_problem.sym + df = f(x).diff(x) + y = Dummy('y') + d = Wild('d', exclude=[df, f(x).diff(x, 2)]) + e = Wild('e', exclude=[df]) + does_match = False + if self._has_additional_params() and order == 1: + xi = self.ode_problem.params['xi'] + eta = self.ode_problem.params['eta'] + self.r3 = {'xi': xi, 'eta': eta} + 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) + self.r3.update(r) + does_match = True + return does_match + + def _get_general_solution(self, *, simplify_flag: bool = True): + eq = self.ode_problem.eq + x = self.ode_problem.sym + func = self.ode_problem.func + order = self.ode_problem.order + df = func.diff(x) + + try: + eqsol = solve(eq, df) + except NotImplementedError: + eqsol = [] + + desols = [] + for s in eqsol: + sol = _ode_lie_group(s, func, order, match=self.r3) + if sol: + desols.extend(sol) + + if desols == []: + raise NotImplementedError("The given ODE " + str(eq) + " cannot be solved by" + + " the lie group method") + return desols + + +solver_map = { + 'factorable': Factorable, + 'nth_linear_constant_coeff_homogeneous': NthLinearConstantCoeffHomogeneous, + 'nth_linear_euler_eq_homogeneous': NthLinearEulerEqHomogeneous, + 'nth_linear_constant_coeff_undetermined_coefficients': NthLinearConstantCoeffUndeterminedCoefficients, + 'nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients': NthLinearEulerEqNonhomogeneousUndeterminedCoefficients, + 'separable': Separable, + '1st_exact': FirstExact, + '1st_linear': FirstLinear, + 'Bernoulli': Bernoulli, + 'Riccati_special_minus2': RiccatiSpecial, + '1st_rational_riccati': RationalRiccati, + '1st_homogeneous_coeff_best': HomogeneousCoeffBest, + '1st_homogeneous_coeff_subs_indep_div_dep': HomogeneousCoeffSubsIndepDivDep, + '1st_homogeneous_coeff_subs_dep_div_indep': HomogeneousCoeffSubsDepDivIndep, + 'almost_linear': AlmostLinear, + 'linear_coefficients': LinearCoefficients, + 'separable_reduced': SeparableReduced, + 'nth_linear_constant_coeff_variation_of_parameters': NthLinearConstantCoeffVariationOfParameters, + 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters': NthLinearEulerEqNonhomogeneousVariationOfParameters, + 'Liouville': Liouville, + '2nd_linear_airy': SecondLinearAiry, + '2nd_linear_bessel': SecondLinearBessel, + '2nd_hypergeometric': SecondHypergeometric, + 'nth_order_reducible': NthOrderReducible, + '2nd_nonlinear_autonomous_conserved': SecondNonlinearAutonomousConserved, + 'nth_algebraic': NthAlgebraic, + 'lie_group': LieGroup, + } + +# Avoid circular import: +from .ode import dsolve, ode_sol_simplicity, odesimp, homogeneous_order diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/subscheck.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/subscheck.py new file mode 100644 index 0000000000000000000000000000000000000000..6ac7fba7d364bf599e928ccf591b5bef096576d0 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/subscheck.py @@ -0,0 +1,392 @@ +from sympy.core import S, Pow +from sympy.core.function import (Derivative, AppliedUndef, diff) +from sympy.core.relational import Equality, Eq +from sympy.core.symbol import Dummy +from sympy.core.sympify import sympify + +from sympy.logic.boolalg import BooleanAtom +from sympy.functions import exp +from sympy.series import Order +from sympy.simplify.simplify import simplify, posify, besselsimp +from sympy.simplify.trigsimp import trigsimp +from sympy.simplify.sqrtdenest import sqrtdenest +from sympy.solvers import solve +from sympy.solvers.deutils import _preprocess, ode_order +from sympy.utilities.iterables import iterable, is_sequence + + +def sub_func_doit(eq, func, new): + r""" + When replacing the func with something else, we usually want the + derivative evaluated, so this function helps in making that happen. + + Examples + ======== + + >>> from sympy import Derivative, symbols, Function + >>> from sympy.solvers.ode.subscheck import sub_func_doit + >>> x, z = symbols('x, z') + >>> y = Function('y') + + >>> sub_func_doit(3*Derivative(y(x), x) - 1, y(x), x) + 2 + + >>> sub_func_doit(x*Derivative(y(x), x) - y(x)**2 + y(x), y(x), + ... 1/(x*(z + 1/x))) + x*(-1/(x**2*(z + 1/x)) + 1/(x**3*(z + 1/x)**2)) + 1/(x*(z + 1/x)) + ...- 1/(x**2*(z + 1/x)**2) + """ + reps= {func: new} + for d in eq.atoms(Derivative): + if d.expr == func: + reps[d] = new.diff(*d.variable_count) + else: + reps[d] = d.xreplace({func: new}).doit(deep=False) + return eq.xreplace(reps) + + +def checkodesol(ode, sol, func=None, order='auto', solve_for_func=True): + r""" + Substitutes ``sol`` into ``ode`` and checks that the result is ``0``. + + This works when ``func`` is one function, like `f(x)` or a list of + functions like `[f(x), g(x)]` when `ode` is a system of ODEs. ``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``. Sometimes this function will + return ``False`` even when an expression is identically equal to ``0``. + This happens when :py:meth:`~sympy.simplify.simplify.simplify` does not + reduce the expression to ``0``. If an expression returned by this + function vanishes identically, then ``sol`` really is a solution to + the ``ode``. + + If this function seems to hang, it is probably because of a hard + simplification. + + To use this function to test, test the first item of the tuple. + + Examples + ======== + + >>> from sympy import (Eq, Function, checkodesol, symbols, + ... Derivative, exp) + >>> x, C1, C2 = symbols('x,C1,C2') + >>> f, g = symbols('f g', cls=Function) + >>> checkodesol(f(x).diff(x), Eq(f(x), C1)) + (True, 0) + >>> assert checkodesol(f(x).diff(x), C1)[0] + >>> assert not checkodesol(f(x).diff(x), x)[0] + >>> checkodesol(f(x).diff(x, 2), x**2) + (False, 2) + + >>> eqs = [Eq(Derivative(f(x), x), f(x)), Eq(Derivative(g(x), x), g(x))] + >>> sol = [Eq(f(x), C1*exp(x)), Eq(g(x), C2*exp(x))] + >>> checkodesol(eqs, sol) + (True, [0, 0]) + + """ + if iterable(ode): + return checksysodesol(ode, sol, func=func) + + if not isinstance(ode, Equality): + ode = Eq(ode, 0) + if func is None: + try: + _, func = _preprocess(ode.lhs) + except ValueError: + funcs = [s.atoms(AppliedUndef) for s in ( + sol if is_sequence(sol, set) else [sol])] + funcs = set().union(*funcs) + if len(funcs) != 1: + raise ValueError( + 'must pass func arg to checkodesol for this case.') + func = funcs.pop() + if not isinstance(func, AppliedUndef) or len(func.args) != 1: + raise ValueError( + "func must be a function of one variable, not %s" % func) + if is_sequence(sol, set): + return type(sol)([checkodesol(ode, i, order=order, solve_for_func=solve_for_func) for i in sol]) + + if not isinstance(sol, Equality): + sol = Eq(func, sol) + elif sol.rhs == func: + sol = sol.reversed + + if order == 'auto': + order = ode_order(ode, func) + solved = sol.lhs == func and not sol.rhs.has(func) + if solve_for_func and not solved: + rhs = solve(sol, func) + if rhs: + eqs = [Eq(func, t) for t in rhs] + if len(rhs) == 1: + eqs = eqs[0] + return checkodesol(ode, eqs, order=order, + solve_for_func=False) + + x = func.args[0] + + # Handle series solutions here + if sol.has(Order): + assert sol.lhs == func + Oterm = sol.rhs.getO() + solrhs = sol.rhs.removeO() + + Oexpr = Oterm.expr + assert isinstance(Oexpr, Pow) + sorder = Oexpr.exp + assert Oterm == Order(x**sorder) + + odesubs = (ode.lhs-ode.rhs).subs(func, solrhs).doit().expand() + + neworder = Order(x**(sorder - order)) + odesubs = odesubs + neworder + assert odesubs.getO() == neworder + residual = odesubs.removeO() + + return (residual == 0, residual) + + s = True + testnum = 0 + while s: + if testnum == 0: + # 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: + s = sub_func_doit(ode_diff, func, sol.rhs) + s = besselsimp(s) + else: + testnum += 1 + continue + ss = simplify(s.rewrite(exp)) + 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(force=True) + else: + s = 0 + testnum += 1 + elif testnum == 1: + # 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)) - + trigsimp(ode.lhs) + trigsimp(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. + # 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 + # (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} + elif sol.rhs == func and not sol.lhs.has(func): + 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 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)) + if not sdf: + raise NotImplementedError + except NotImplementedError: + testnum += 1 + break + else: + diffsols[i] = sdf[0] + else: + # This is what the solution says df/dx should be. + diffsols[i] = diffsols[i - 1].diff(x) + + # Make sure the above didn't fail. + if testnum > 2: + continue + else: + # 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: + # We can only substitute f(x) if the solution was + # solved for f(x). + 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 = simplify(ode_or_bool) + + if isinstance(ode_or_bool, (bool, BooleanAtom)): + if ode_or_bool: + lhs = rhs = S.Zero + else: + lhs = ode_or_bool.lhs + rhs = ode_or_bool.rhs + # 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) + + " is a solution to " + str(ode) + ".") + else: + return (False, s) + + +def checksysodesol(eqs, sols, func=None): + r""" + Substitutes corresponding ``sols`` for each functions into each ``eqs`` and + checks that the result of substitutions for each equation is ``0``. The + equations and solutions passed can be any iterable. + + This only works when each ``sols`` have one function only, like `x(t)` or `y(t)`. + For each function, ``sols`` can have a single solution or a list of solutions. + 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. + + When a sequence of equations is passed, the same sequence is used to return + the result for each equation with each function substituted with corresponding + solutions. + + It tries the following method to find zero equivalence for each equation: + + Substitute the solutions for functions, like `x(t)` and `y(t)` into the + original equations containing those functions. + This function returns a tuple. The first item in the tuple is ``True`` if + the substitution results for each equation is ``0``, and ``False`` otherwise. + The second item in the tuple is what the substitution results in. Each element + of the ``list`` should always be ``0`` corresponding to each equation if the + first item is ``True``. Note that sometimes this function may return ``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 each function + vanishes identically, then ``sols`` really is a solution to ``eqs``. + + If this function seems to hang, it is probably because of a difficult simplification. + + Examples + ======== + + >>> from sympy import Eq, diff, symbols, sin, cos, exp, sqrt, S, Function + >>> from sympy.solvers.ode.subscheck import checksysodesol + >>> C1, C2 = symbols('C1:3') + >>> t = symbols('t') + >>> x, y = symbols('x, y', cls=Function) + >>> eq = (Eq(diff(x(t),t), x(t) + y(t) + 17), Eq(diff(y(t),t), -2*x(t) + y(t) + 12)) + >>> sol = [Eq(x(t), (C1*sin(sqrt(2)*t) + C2*cos(sqrt(2)*t))*exp(t) - S(5)/3), + ... Eq(y(t), (sqrt(2)*C1*cos(sqrt(2)*t) - sqrt(2)*C2*sin(sqrt(2)*t))*exp(t) - S(46)/3)] + >>> checksysodesol(eq, sol) + (True, [0, 0]) + >>> eq = (Eq(diff(x(t),t),x(t)*y(t)**4), Eq(diff(y(t),t),y(t)**3)) + >>> sol = [Eq(x(t), C1*exp(-1/(4*(C2 + t)))), Eq(y(t), -sqrt(2)*sqrt(-1/(C2 + t))/2), + ... Eq(x(t), C1*exp(-1/(4*(C2 + t)))), Eq(y(t), sqrt(2)*sqrt(-1/(C2 + t))/2)] + >>> checksysodesol(eq, sol) + (True, [0, 0]) + + """ + def _sympify(eq): + return list(map(sympify, eq if iterable(eq) else [eq])) + eqs = _sympify(eqs) + for i in range(len(eqs)): + if isinstance(eqs[i], Equality): + eqs[i] = eqs[i].lhs - eqs[i].rhs + if func is None: + funcs = [] + for eq in eqs: + derivs = eq.atoms(Derivative) + func = set().union(*[d.atoms(AppliedUndef) for d in derivs]) + funcs.extend(func) + funcs = list(set(funcs)) + if not all(isinstance(func, AppliedUndef) and len(func.args) == 1 for func in funcs)\ + and len({func.args for func in funcs})!=1: + raise ValueError("func must be a function of one variable, not %s" % func) + for sol in sols: + if len(sol.atoms(AppliedUndef)) != 1: + raise ValueError("solutions should have one function only") + if len(funcs) != len({sol.lhs for sol in sols}): + raise ValueError("number of solutions provided does not match the number of equations") + dictsol = {} + for sol in sols: + func = list(sol.atoms(AppliedUndef))[0] + if sol.rhs == func: + sol = sol.reversed + solved = sol.lhs == func and not sol.rhs.has(func) + if not solved: + rhs = solve(sol, func) + if not rhs: + raise NotImplementedError + else: + rhs = sol.rhs + dictsol[func] = rhs + checkeq = [] + for eq in eqs: + for func in funcs: + eq = sub_func_doit(eq, func, dictsol[func]) + ss = simplify(eq) + if ss != 0: + eq = ss.expand(force=True) + if eq != 0: + eq = sqrtdenest(eq).simplify() + else: + eq = 0 + checkeq.append(eq) + if len(set(checkeq)) == 1 and list(set(checkeq))[0] == 0: + return (True, checkeq) + else: + return (False, checkeq) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/systems.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/systems.py new file mode 100644 index 0000000000000000000000000000000000000000..2d2c9b57a969c7fb5c67c06ce952fa398e22a48d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/systems.py @@ -0,0 +1,2135 @@ +from sympy.core import Add, Mul, S +from sympy.core.containers import Tuple +from sympy.core.exprtools import factor_terms +from sympy.core.numbers import I +from sympy.core.relational import Eq, Equality +from sympy.core.sorting import default_sort_key, ordered +from sympy.core.symbol import Dummy, Symbol +from sympy.core.function import (expand_mul, expand, Derivative, + AppliedUndef, Function, Subs) +from sympy.functions import (exp, im, cos, sin, re, Piecewise, + piecewise_fold, sqrt, log) +from sympy.functions.combinatorial.factorials import factorial +from sympy.matrices import zeros, Matrix, NonSquareMatrixError, MatrixBase, eye +from sympy.polys import Poly, together +from sympy.simplify import collect, radsimp, signsimp # type: ignore +from sympy.simplify.powsimp import powdenest, powsimp +from sympy.simplify.ratsimp import ratsimp +from sympy.simplify.simplify import simplify +from sympy.sets.sets import FiniteSet +from sympy.solvers.deutils import ode_order +from sympy.solvers.solveset import NonlinearError, solveset +from sympy.utilities.iterables import (connected_components, iterable, + strongly_connected_components) +from sympy.utilities.misc import filldedent +from sympy.integrals.integrals import Integral, integrate + + +def _get_func_order(eqs, funcs): + return {func: max(ode_order(eq, func) for eq in eqs) for func in funcs} + + +class ODEOrderError(ValueError): + """Raised by linear_ode_to_matrix if the system has the wrong order""" + pass + + +class ODENonlinearError(NonlinearError): + """Raised by linear_ode_to_matrix if the system is nonlinear""" + pass + + +def _simpsol(soleq): + lhs = soleq.lhs + sol = soleq.rhs + sol = powsimp(sol) + gens = list(sol.atoms(exp)) + p = Poly(sol, *gens, expand=False) + gens = [factor_terms(g) for g in gens] + if not gens: + gens = p.gens + syms = [Symbol('C1'), Symbol('C2')] + terms = [] + for coeff, monom in zip(p.coeffs(), p.monoms()): + coeff = piecewise_fold(coeff) + if isinstance(coeff, Piecewise): + coeff = Piecewise(*((ratsimp(coef).collect(syms), cond) for coef, cond in coeff.args)) + else: + coeff = ratsimp(coeff).collect(syms) + monom = Mul(*(g ** i for g, i in zip(gens, monom))) + terms.append(coeff * monom) + return Eq(lhs, Add(*terms)) + + +def _solsimp(e, t): + no_t, has_t = powsimp(expand_mul(e)).as_independent(t) + + no_t = ratsimp(no_t) + has_t = has_t.replace(exp, lambda a: exp(factor_terms(a))) + + return no_t + has_t + + +def simpsol(sol, wrt1, wrt2, doit=True): + """Simplify solutions from dsolve_system.""" + + # The parameter sol is the solution as returned by dsolve (list of Eq). + # + # The parameters wrt1 and wrt2 are lists of symbols to be collected for + # with those in wrt1 being collected for first. This allows for collecting + # on any factors involving the independent variable before collecting on + # the integration constants or vice versa using e.g.: + # + # sol = simpsol(sol, [t], [C1, C2]) # t first, constants after + # sol = simpsol(sol, [C1, C2], [t]) # constants first, t after + # + # If doit=True (default) then simpsol will begin by evaluating any + # unevaluated integrals. Since many integrals will appear multiple times + # in the solutions this is done intelligently by computing each integral + # only once. + # + # The strategy is to first perform simple cancellation with factor_terms + # and then multiply out all brackets with expand_mul. This gives an Add + # with many terms. + # + # We split each term into two multiplicative factors dep and coeff where + # all factors that involve wrt1 are in dep and any constant factors are in + # coeff e.g. + # sqrt(2)*C1*exp(t) -> ( exp(t), sqrt(2)*C1 ) + # + # The dep factors are simplified using powsimp to combine expanded + # exponential factors e.g. + # exp(a*t)*exp(b*t) -> exp(t*(a+b)) + # + # We then collect coefficients for all terms having the same (simplified) + # dep. The coefficients are then simplified using together and ratsimp and + # lastly by recursively applying the same transformation to the + # coefficients to collect on wrt2. + # + # Finally the result is recombined into an Add and signsimp is used to + # normalise any minus signs. + + def simprhs(rhs, rep, wrt1, wrt2): + """Simplify the rhs of an ODE solution""" + if rep: + rhs = rhs.subs(rep) + rhs = factor_terms(rhs) + rhs = simp_coeff_dep(rhs, wrt1, wrt2) + rhs = signsimp(rhs) + return rhs + + def simp_coeff_dep(expr, wrt1, wrt2=None): + """Split rhs into terms, split terms into dep and coeff and collect on dep""" + add_dep_terms = lambda e: e.is_Add and e.has(*wrt1) + expandable = lambda e: e.is_Mul and any(map(add_dep_terms, e.args)) + expand_func = lambda e: expand_mul(e, deep=False) + expand_mul_mod = lambda e: e.replace(expandable, expand_func) + terms = Add.make_args(expand_mul_mod(expr)) + dc = {} + for term in terms: + coeff, dep = term.as_independent(*wrt1, as_Add=False) + # Collect together the coefficients for terms that have the same + # dependence on wrt1 (after dep is normalised using simpdep). + dep = simpdep(dep, wrt1) + + # See if the dependence on t cancels out... + if dep is not S.One: + dep2 = factor_terms(dep) + if not dep2.has(*wrt1): + coeff *= dep2 + dep = S.One + + if dep not in dc: + dc[dep] = coeff + else: + dc[dep] += coeff + # Apply the method recursively to the coefficients but this time + # collecting on wrt2 rather than wrt2. + termpairs = ((simpcoeff(c, wrt2), d) for d, c in dc.items()) + if wrt2 is not None: + termpairs = ((simp_coeff_dep(c, wrt2), d) for c, d in termpairs) + return Add(*(c * d for c, d in termpairs)) + + def simpdep(term, wrt1): + """Normalise factors involving t with powsimp and recombine exp""" + def canonicalise(a): + # Using factor_terms here isn't quite right because it leads to things + # like exp(t*(1+t)) that we don't want. We do want to cancel factors + # and pull out a common denominator but ideally the numerator would be + # expressed as a standard form polynomial in t so we expand_mul + # and collect afterwards. + a = factor_terms(a) + num, den = a.as_numer_denom() + num = expand_mul(num) + num = collect(num, wrt1) + return num / den + + term = powsimp(term) + rep = {e: exp(canonicalise(e.args[0])) for e in term.atoms(exp)} + term = term.subs(rep) + return term + + def simpcoeff(coeff, wrt2): + """Bring to a common fraction and cancel with ratsimp""" + coeff = together(coeff) + if coeff.is_polynomial(): + # Calling ratsimp can be expensive. The main reason is to simplify + # sums of terms with irrational denominators so we limit ourselves + # to the case where the expression is polynomial in any symbols. + # Maybe there's a better approach... + coeff = ratsimp(radsimp(coeff)) + # collect on secondary variables first and any remaining symbols after + if wrt2 is not None: + syms = list(wrt2) + list(ordered(coeff.free_symbols - set(wrt2))) + else: + syms = list(ordered(coeff.free_symbols)) + coeff = collect(coeff, syms) + coeff = together(coeff) + return coeff + + # There are often repeated integrals. Collect unique integrals and + # evaluate each once and then substitute into the final result to replace + # all occurrences in each of the solution equations. + if doit: + integrals = set().union(*(s.atoms(Integral) for s in sol)) + rep = {i: factor_terms(i).doit() for i in integrals} + else: + rep = {} + + sol = [Eq(s.lhs, simprhs(s.rhs, rep, wrt1, wrt2)) for s in sol] + return sol + + +def linodesolve_type(A, t, b=None): + r""" + Helper function that determines the type of the system of ODEs for solving with :obj:`sympy.solvers.ode.systems.linodesolve()` + + Explanation + =========== + + This function takes in the coefficient matrix and/or the non-homogeneous term + and returns the type of the equation that can be solved by :obj:`sympy.solvers.ode.systems.linodesolve()`. + + If the system is constant coefficient homogeneous, then "type1" is returned + + If the system is constant coefficient non-homogeneous, then "type2" is returned + + If the system is non-constant coefficient homogeneous, then "type3" is returned + + If the system is non-constant coefficient non-homogeneous, then "type4" is returned + + If the system has a non-constant coefficient matrix which can be factorized into constant + coefficient matrix, then "type5" or "type6" is returned for when the system is homogeneous or + non-homogeneous respectively. + + Note that, if the system of ODEs is of "type3" or "type4", then along with the type, + the commutative antiderivative of the coefficient matrix is also returned. + + If the system cannot be solved by :obj:`sympy.solvers.ode.systems.linodesolve()`, then + NotImplementedError is raised. + + Parameters + ========== + + A : Matrix + Coefficient matrix of the system of ODEs + b : Matrix or None + Non-homogeneous term of the system. The default value is None. + If this argument is None, then the system is assumed to be homogeneous. + + Examples + ======== + + >>> from sympy import symbols, Matrix + >>> from sympy.solvers.ode.systems import linodesolve_type + >>> t = symbols("t") + >>> A = Matrix([[1, 1], [2, 3]]) + >>> b = Matrix([t, 1]) + + >>> linodesolve_type(A, t) + {'antiderivative': None, 'type_of_equation': 'type1'} + + >>> linodesolve_type(A, t, b=b) + {'antiderivative': None, 'type_of_equation': 'type2'} + + >>> A_t = Matrix([[1, t], [-t, 1]]) + + >>> linodesolve_type(A_t, t) + {'antiderivative': Matrix([ + [ t, t**2/2], + [-t**2/2, t]]), 'type_of_equation': 'type3'} + + >>> linodesolve_type(A_t, t, b=b) + {'antiderivative': Matrix([ + [ t, t**2/2], + [-t**2/2, t]]), 'type_of_equation': 'type4'} + + >>> A_non_commutative = Matrix([[1, t], [t, -1]]) + >>> linodesolve_type(A_non_commutative, t) + Traceback (most recent call last): + ... + NotImplementedError: + The system does not have a commutative antiderivative, it cannot be + solved by linodesolve. + + Returns + ======= + + Dict + + Raises + ====== + + NotImplementedError + When the coefficient matrix does not have a commutative antiderivative + + See Also + ======== + + linodesolve: Function for which linodesolve_type gets the information + + """ + + match = {} + is_non_constant = not _matrix_is_constant(A, t) + is_non_homogeneous = not (b is None or b.is_zero_matrix) + type = "type{}".format(int("{}{}".format(int(is_non_constant), int(is_non_homogeneous)), 2) + 1) + + B = None + match.update({"type_of_equation": type, "antiderivative": B}) + + if is_non_constant: + B, is_commuting = _is_commutative_anti_derivative(A, t) + if not is_commuting: + raise NotImplementedError(filldedent(''' + The system does not have a commutative antiderivative, it cannot be solved + by linodesolve. + ''')) + + match['antiderivative'] = B + match.update(_first_order_type5_6_subs(A, t, b=b)) + + return match + + +def _first_order_type5_6_subs(A, t, b=None): + match = {} + + factor_terms = _factor_matrix(A, t) + is_homogeneous = b is None or b.is_zero_matrix + + if factor_terms is not None: + t_ = Symbol("{}_".format(t)) + F_t = integrate(factor_terms[0], t) + inverse = solveset(Eq(t_, F_t), t) + + # Note: A simple way to check if a function is invertible + # or not. + if isinstance(inverse, FiniteSet) and not inverse.has(Piecewise)\ + and len(inverse) == 1: + + A = factor_terms[1] + if not is_homogeneous: + b = b / factor_terms[0] + b = b.subs(t, list(inverse)[0]) + type = "type{}".format(5 + (not is_homogeneous)) + match.update({'func_coeff': A, 'tau': F_t, + 't_': t_, 'type_of_equation': type, 'rhs': b}) + + return match + + +def linear_ode_to_matrix(eqs, funcs, t, order): + r""" + Convert a linear system of ODEs to matrix form + + Explanation + =========== + + Express a system of linear ordinary differential equations as a single + matrix differential equation [1]. For example the system $x' = x + y + 1$ + and $y' = x - y$ can be represented as + + .. math:: A_1 X' = A_0 X + b + + where $A_1$ and $A_0$ are $2 \times 2$ matrices and $b$, $X$ and $X'$ are + $2 \times 1$ matrices with $X = [x, y]^T$. + + Higher-order systems are represented with additional matrices e.g. a + second-order system would look like + + .. math:: A_2 X'' = A_1 X' + A_0 X + b + + Examples + ======== + + >>> from sympy import Function, Symbol, Matrix, Eq + >>> from sympy.solvers.ode.systems import linear_ode_to_matrix + >>> t = Symbol('t') + >>> x = Function('x') + >>> y = Function('y') + + We can create a system of linear ODEs like + + >>> eqs = [ + ... Eq(x(t).diff(t), x(t) + y(t) + 1), + ... Eq(y(t).diff(t), x(t) - y(t)), + ... ] + >>> funcs = [x(t), y(t)] + >>> order = 1 # 1st order system + + Now ``linear_ode_to_matrix`` can represent this as a matrix + differential equation. + + >>> (A1, A0), b = linear_ode_to_matrix(eqs, funcs, t, order) + >>> A1 + Matrix([ + [1, 0], + [0, 1]]) + >>> A0 + Matrix([ + [1, 1], + [1, -1]]) + >>> b + Matrix([ + [1], + [0]]) + + The original equations can be recovered from these matrices: + + >>> eqs_mat = Matrix([eq.lhs - eq.rhs for eq in eqs]) + >>> X = Matrix(funcs) + >>> A1 * X.diff(t) - A0 * X - b == eqs_mat + True + + If the system of equations has a maximum order greater than the + order of the system specified, a ODEOrderError exception is raised. + + >>> eqs = [Eq(x(t).diff(t, 2), x(t).diff(t) + x(t)), Eq(y(t).diff(t), y(t) + x(t))] + >>> linear_ode_to_matrix(eqs, funcs, t, 1) + Traceback (most recent call last): + ... + ODEOrderError: Cannot represent system in 1-order form + + If the system of equations is nonlinear, then ODENonlinearError is + raised. + + >>> eqs = [Eq(x(t).diff(t), x(t) + y(t)), Eq(y(t).diff(t), y(t)**2 + x(t))] + >>> linear_ode_to_matrix(eqs, funcs, t, 1) + Traceback (most recent call last): + ... + ODENonlinearError: The system of ODEs is nonlinear. + + Parameters + ========== + + eqs : list of SymPy expressions or equalities + The equations as expressions (assumed equal to zero). + funcs : list of applied functions + The dependent variables of the system of ODEs. + t : symbol + The independent variable. + order : int + The order of the system of ODEs. + + Returns + ======= + + The tuple ``(As, b)`` where ``As`` is a tuple of matrices and ``b`` is the + the matrix representing the rhs of the matrix equation. + + Raises + ====== + + ODEOrderError + When the system of ODEs have an order greater than what was specified + ODENonlinearError + When the system of ODEs is nonlinear + + See Also + ======== + + linear_eq_to_matrix: for systems of linear algebraic equations. + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Matrix_differential_equation + + """ + from sympy.solvers.solveset import linear_eq_to_matrix + + if any(ode_order(eq, func) > order for eq in eqs for func in funcs): + msg = "Cannot represent system in {}-order form" + raise ODEOrderError(msg.format(order)) + + As = [] + + for o in range(order, -1, -1): + # Work from the highest derivative down + syms = [func.diff(t, o) for func in funcs] + + # Ai is the matrix for X(t).diff(t, o) + # eqs is minus the remainder of the equations. + try: + Ai, b = linear_eq_to_matrix(eqs, syms) + except NonlinearError: + raise ODENonlinearError("The system of ODEs is nonlinear.") + + Ai = Ai.applyfunc(expand_mul) + + As.append(Ai if o == order else -Ai) + + if o: + eqs = [-eq for eq in b] + else: + rhs = b + + return As, rhs + + +def matrix_exp(A, t): + r""" + Matrix exponential $\exp(A*t)$ for the matrix ``A`` and scalar ``t``. + + Explanation + =========== + + This functions returns the $\exp(A*t)$ by doing a simple + matrix multiplication: + + .. math:: \exp(A*t) = P * expJ * P^{-1} + + where $expJ$ is $\exp(J*t)$. $J$ is the Jordan normal + form of $A$ and $P$ is matrix such that: + + .. math:: A = P * J * P^{-1} + + The matrix exponential $\exp(A*t)$ appears in the solution of linear + differential equations. For example if $x$ is a vector and $A$ is a matrix + then the initial value problem + + .. math:: \frac{dx(t)}{dt} = A \times x(t), x(0) = x0 + + has the unique solution + + .. math:: x(t) = \exp(A t) x0 + + Examples + ======== + + >>> from sympy import Symbol, Matrix, pprint + >>> from sympy.solvers.ode.systems import matrix_exp + >>> t = Symbol('t') + + We will consider a 2x2 matrix for comupting the exponential + + >>> A = Matrix([[2, -5], [2, -4]]) + >>> pprint(A) + [2 -5] + [ ] + [2 -4] + + Now, exp(A*t) is given as follows: + + >>> pprint(matrix_exp(A, t)) + [ -t -t -t ] + [3*e *sin(t) + e *cos(t) -5*e *sin(t) ] + [ ] + [ -t -t -t ] + [ 2*e *sin(t) - 3*e *sin(t) + e *cos(t)] + + Parameters + ========== + + A : Matrix + The matrix $A$ in the expression $\exp(A*t)$ + t : Symbol + The independent variable + + See Also + ======== + + matrix_exp_jordan_form: For exponential of Jordan normal form + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Jordan_normal_form + .. [2] https://en.wikipedia.org/wiki/Matrix_exponential + + """ + P, expJ = matrix_exp_jordan_form(A, t) + return P * expJ * P.inv() + + +def matrix_exp_jordan_form(A, t): + r""" + Matrix exponential $\exp(A*t)$ for the matrix *A* and scalar *t*. + + Explanation + =========== + + Returns the Jordan form of the $\exp(A*t)$ along with the matrix $P$ such that: + + .. math:: + \exp(A*t) = P * expJ * P^{-1} + + Examples + ======== + + >>> from sympy import Matrix, Symbol + >>> from sympy.solvers.ode.systems import matrix_exp, matrix_exp_jordan_form + >>> t = Symbol('t') + + We will consider a 2x2 defective matrix. This shows that our method + works even for defective matrices. + + >>> A = Matrix([[1, 1], [0, 1]]) + + It can be observed that this function gives us the Jordan normal form + and the required invertible matrix P. + + >>> P, expJ = matrix_exp_jordan_form(A, t) + + Here, it is shown that P and expJ returned by this function is correct + as they satisfy the formula: P * expJ * P_inverse = exp(A*t). + + >>> P * expJ * P.inv() == matrix_exp(A, t) + True + + Parameters + ========== + + A : Matrix + The matrix $A$ in the expression $\exp(A*t)$ + t : Symbol + The independent variable + + References + ========== + + .. [1] https://en.wikipedia.org/wiki/Defective_matrix + .. [2] https://en.wikipedia.org/wiki/Jordan_matrix + .. [3] https://en.wikipedia.org/wiki/Jordan_normal_form + + """ + + N, M = A.shape + if N != M: + raise ValueError('Needed square matrix but got shape (%s, %s)' % (N, M)) + elif A.has(t): + raise ValueError('Matrix A should not depend on t') + + def jordan_chains(A): + '''Chains from Jordan normal form analogous to M.eigenvects(). + Returns a dict with eignevalues as keys like: + {e1: [[v111,v112,...], [v121, v122,...]], e2:...} + where vijk is the kth vector in the jth chain for eigenvalue i. + ''' + P, blocks = A.jordan_cells() + basis = [P[:,i] for i in range(P.shape[1])] + n = 0 + chains = {} + for b in blocks: + eigval = b[0, 0] + size = b.shape[0] + if eigval not in chains: + chains[eigval] = [] + chains[eigval].append(basis[n:n+size]) + n += size + return chains + + eigenchains = jordan_chains(A) + + # Needed for consistency across Python versions + eigenchains_iter = sorted(eigenchains.items(), key=default_sort_key) + isreal = not A.has(I) + + blocks = [] + vectors = [] + seen_conjugate = set() + for e, chains in eigenchains_iter: + for chain in chains: + n = len(chain) + if isreal and e != e.conjugate() and e.conjugate() in eigenchains: + if e in seen_conjugate: + continue + seen_conjugate.add(e.conjugate()) + exprt = exp(re(e) * t) + imrt = im(e) * t + imblock = Matrix([[cos(imrt), sin(imrt)], + [-sin(imrt), cos(imrt)]]) + expJblock2 = Matrix(n, n, lambda i,j: + imblock * t**(j-i) / factorial(j-i) if j >= i + else zeros(2, 2)) + expJblock = Matrix(2*n, 2*n, lambda i,j: expJblock2[i//2,j//2][i%2,j%2]) + + blocks.append(exprt * expJblock) + for i in range(n): + vectors.append(re(chain[i])) + vectors.append(im(chain[i])) + else: + vectors.extend(chain) + fun = lambda i,j: t**(j-i)/factorial(j-i) if j >= i else 0 + expJblock = Matrix(n, n, fun) + blocks.append(exp(e * t) * expJblock) + + expJ = Matrix.diag(*blocks) + P = Matrix(N, N, lambda i,j: vectors[j][i]) + + return P, expJ + + +# Note: To add a docstring example with tau +def linodesolve(A, t, b=None, B=None, type="auto", doit=False, + tau=None): + r""" + System of n equations linear first-order differential equations + + Explanation + =========== + + This solver solves the system of ODEs of the following form: + + .. math:: + X'(t) = A(t) X(t) + b(t) + + Here, $A(t)$ is the coefficient matrix, $X(t)$ is the vector of n independent variables, + $b(t)$ is the non-homogeneous term and $X'(t)$ is the derivative of $X(t)$ + + Depending on the properties of $A(t)$ and $b(t)$, this solver evaluates the solution + differently. + + When $A(t)$ is constant coefficient matrix and $b(t)$ is zero vector i.e. system is homogeneous, + the system is "type1". The solution is: + + .. math:: + X(t) = \exp(A t) C + + Here, $C$ is a vector of constants and $A$ is the constant coefficient matrix. + + When $A(t)$ is constant coefficient matrix and $b(t)$ is non-zero i.e. system is non-homogeneous, + the system is "type2". The solution is: + + .. math:: + X(t) = e^{A t} ( \int e^{- A t} b \,dt + C) + + When $A(t)$ is coefficient matrix such that its commutative with its antiderivative $B(t)$ and + $b(t)$ is a zero vector i.e. system is homogeneous, the system is "type3". The solution is: + + .. math:: + X(t) = \exp(B(t)) C + + When $A(t)$ is commutative with its antiderivative $B(t)$ and $b(t)$ is non-zero i.e. system is + non-homogeneous, the system is "type4". The solution is: + + .. math:: + X(t) = e^{B(t)} ( \int e^{-B(t)} b(t) \,dt + C) + + When $A(t)$ is a coefficient matrix such that it can be factorized into a scalar and a constant + coefficient matrix: + + .. math:: + A(t) = f(t) * A + + Where $f(t)$ is a scalar expression in the independent variable $t$ and $A$ is a constant matrix, + then we can do the following substitutions: + + .. math:: + tau = \int f(t) dt, X(t) = Y(tau), b(t) = b(f^{-1}(tau)) + + Here, the substitution for the non-homogeneous term is done only when its non-zero. + Using these substitutions, our original system becomes: + + .. math:: + Y'(tau) = A * Y(tau) + b(tau)/f(tau) + + The above system can be easily solved using the solution for "type1" or "type2" depending + on the homogeneity of the system. After we get the solution for $Y(tau)$, we substitute the + solution for $tau$ as $t$ to get back $X(t)$ + + .. math:: + X(t) = Y(tau) + + Systems of "type5" and "type6" have a commutative antiderivative but we use this solution + because its faster to compute. + + The final solution is the general solution for all the four equations since a constant coefficient + matrix is always commutative with its antidervative. + + An additional feature of this function is, if someone wants to substitute for value of the independent + variable, they can pass the substitution `tau` and the solution will have the independent variable + substituted with the passed expression(`tau`). + + Parameters + ========== + + A : Matrix + Coefficient matrix of the system of linear first order ODEs. + t : Symbol + Independent variable in the system of ODEs. + b : Matrix or None + Non-homogeneous term in the system of ODEs. If None is passed, + a homogeneous system of ODEs is assumed. + B : Matrix or None + Antiderivative of the coefficient matrix. If the antiderivative + is not passed and the solution requires the term, then the solver + would compute it internally. + type : String + Type of the system of ODEs passed. Depending on the type, the + solution is evaluated. The type values allowed and the corresponding + system it solves are: "type1" for constant coefficient homogeneous + "type2" for constant coefficient non-homogeneous, "type3" for non-constant + coefficient homogeneous, "type4" for non-constant coefficient non-homogeneous, + "type5" and "type6" for non-constant coefficient homogeneous and non-homogeneous + systems respectively where the coefficient matrix can be factorized to a constant + coefficient matrix. + The default value is "auto" which will let the solver decide the correct type of + the system passed. + doit : Boolean + Evaluate the solution if True, default value is False + tau: Expression + Used to substitute for the value of `t` after we get the solution of the system. + + Examples + ======== + + To solve the system of ODEs using this function directly, several things must be + done in the right order. Wrong inputs to the function will lead to incorrect results. + + >>> from sympy import symbols, Function, Eq + >>> from sympy.solvers.ode.systems import canonical_odes, linear_ode_to_matrix, linodesolve, linodesolve_type + >>> from sympy.solvers.ode.subscheck import checkodesol + >>> f, g = symbols("f, g", cls=Function) + >>> x, a = symbols("x, a") + >>> funcs = [f(x), g(x)] + >>> eqs = [Eq(f(x).diff(x) - f(x), a*g(x) + 1), Eq(g(x).diff(x) + g(x), a*f(x))] + + Here, it is important to note that before we derive the coefficient matrix, it is + important to get the system of ODEs into the desired form. For that we will use + :obj:`sympy.solvers.ode.systems.canonical_odes()`. + + >>> eqs = canonical_odes(eqs, funcs, x) + >>> eqs + [[Eq(Derivative(f(x), x), a*g(x) + f(x) + 1), Eq(Derivative(g(x), x), a*f(x) - g(x))]] + + Now, we will use :obj:`sympy.solvers.ode.systems.linear_ode_to_matrix()` to get the coefficient matrix and the + non-homogeneous term if it is there. + + >>> eqs = eqs[0] + >>> (A1, A0), b = linear_ode_to_matrix(eqs, funcs, x, 1) + >>> A = A0 + + We have the coefficient matrices and the non-homogeneous term ready. Now, we can use + :obj:`sympy.solvers.ode.systems.linodesolve_type()` to get the information for the system of ODEs + to finally pass it to the solver. + + >>> system_info = linodesolve_type(A, x, b=b) + >>> sol_vector = linodesolve(A, x, b=b, B=system_info['antiderivative'], type=system_info['type_of_equation']) + + Now, we can prove if the solution is correct or not by using :obj:`sympy.solvers.ode.checkodesol()` + + >>> sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)] + >>> checkodesol(eqs, sol) + (True, [0, 0]) + + We can also use the doit method to evaluate the solutions passed by the function. + + >>> sol_vector_evaluated = linodesolve(A, x, b=b, type="type2", doit=True) + + Now, we will look at a system of ODEs which is non-constant. + + >>> eqs = [Eq(f(x).diff(x), f(x) + x*g(x)), Eq(g(x).diff(x), -x*f(x) + g(x))] + + The system defined above is already in the desired form, so we do not have to convert it. + + >>> (A1, A0), b = linear_ode_to_matrix(eqs, funcs, x, 1) + >>> A = A0 + + A user can also pass the commutative antiderivative required for type3 and type4 system of ODEs. + Passing an incorrect one will lead to incorrect results. If the coefficient matrix is not commutative + with its antiderivative, then :obj:`sympy.solvers.ode.systems.linodesolve_type()` raises a NotImplementedError. + If it does have a commutative antiderivative, then the function just returns the information about the system. + + >>> system_info = linodesolve_type(A, x, b=b) + + Now, we can pass the antiderivative as an argument to get the solution. If the system information is not + passed, then the solver will compute the required arguments internally. + + >>> sol_vector = linodesolve(A, x, b=b) + + Once again, we can verify the solution obtained. + + >>> sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)] + >>> checkodesol(eqs, sol) + (True, [0, 0]) + + Returns + ======= + + List + + Raises + ====== + + ValueError + This error is raised when the coefficient matrix, non-homogeneous term + or the antiderivative, if passed, are not a matrix or + do not have correct dimensions + NonSquareMatrixError + When the coefficient matrix or its antiderivative, if passed is not a + square matrix + NotImplementedError + If the coefficient matrix does not have a commutative antiderivative + + See Also + ======== + + linear_ode_to_matrix: Coefficient matrix computation function + canonical_odes: System of ODEs representation change + linodesolve_type: Getting information about systems of ODEs to pass in this solver + + """ + + if not isinstance(A, MatrixBase): + raise ValueError(filldedent('''\ + The coefficients of the system of ODEs should be of type Matrix + ''')) + + if not A.is_square: + raise NonSquareMatrixError(filldedent('''\ + The coefficient matrix must be a square + ''')) + + if b is not None: + if not isinstance(b, MatrixBase): + raise ValueError(filldedent('''\ + The non-homogeneous terms of the system of ODEs should be of type Matrix + ''')) + + if A.rows != b.rows: + raise ValueError(filldedent('''\ + The system of ODEs should have the same number of non-homogeneous terms and the number of + equations + ''')) + + if B is not None: + if not isinstance(B, MatrixBase): + raise ValueError(filldedent('''\ + The antiderivative of coefficients of the system of ODEs should be of type Matrix + ''')) + + if not B.is_square: + raise NonSquareMatrixError(filldedent('''\ + The antiderivative of the coefficient matrix must be a square + ''')) + + if A.rows != B.rows: + raise ValueError(filldedent('''\ + The coefficient matrix and its antiderivative should have same dimensions + ''')) + + if not any(type == "type{}".format(i) for i in range(1, 7)) and not type == "auto": + raise ValueError(filldedent('''\ + The input type should be a valid one + ''')) + + n = A.rows + + # constants = numbered_symbols(prefix='C', cls=Dummy, start=const_idx+1) + Cvect = Matrix([Dummy() for _ in range(n)]) + + if b is None and any(type == typ for typ in ["type2", "type4", "type6"]): + b = zeros(n, 1) + + is_transformed = tau is not None + passed_type = type + + if type == "auto": + system_info = linodesolve_type(A, t, b=b) + type = system_info["type_of_equation"] + B = system_info["antiderivative"] + + if type in ("type5", "type6"): + is_transformed = True + if passed_type != "auto": + if tau is None: + system_info = _first_order_type5_6_subs(A, t, b=b) + if not system_info: + raise ValueError(filldedent(''' + The system passed isn't {}. + '''.format(type))) + + tau = system_info['tau'] + t = system_info['t_'] + A = system_info['A'] + b = system_info['b'] + + intx_wrtt = lambda x: Integral(x, t) if x else 0 + if type in ("type1", "type2", "type5", "type6"): + P, J = matrix_exp_jordan_form(A, t) + P = simplify(P) + + if type in ("type1", "type5"): + sol_vector = P * (J * Cvect) + else: + Jinv = J.subs(t, -t) + sol_vector = P * J * ((Jinv * P.inv() * b).applyfunc(intx_wrtt) + Cvect) + else: + if B is None: + B, _ = _is_commutative_anti_derivative(A, t) + + if type == "type3": + sol_vector = B.exp() * Cvect + else: + sol_vector = B.exp() * (((-B).exp() * b).applyfunc(intx_wrtt) + Cvect) + + if is_transformed: + sol_vector = sol_vector.subs(t, tau) + + gens = sol_vector.atoms(exp) + + if type != "type1": + sol_vector = [expand_mul(s) for s in sol_vector] + + sol_vector = [collect(s, ordered(gens), exact=True) for s in sol_vector] + + if doit: + sol_vector = [s.doit() for s in sol_vector] + + return sol_vector + + +def _matrix_is_constant(M, t): + """Checks if the matrix M is independent of t or not.""" + return all(coef.as_independent(t, as_Add=True)[1] == 0 for coef in M) + + +def canonical_odes(eqs, funcs, t): + r""" + Function that solves for highest order derivatives in a system + + Explanation + =========== + + This function inputs a system of ODEs and based on the system, + the dependent variables and their highest order, returns the system + in the following form: + + .. math:: + X'(t) = A(t) X(t) + b(t) + + Here, $X(t)$ is the vector of dependent variables of lower order, $A(t)$ is + the coefficient matrix, $b(t)$ is the non-homogeneous term and $X'(t)$ is the + vector of dependent variables in their respective highest order. We use the term + canonical form to imply the system of ODEs which is of the above form. + + If the system passed has a non-linear term with multiple solutions, then a list of + systems is returned in its canonical form. + + Parameters + ========== + + eqs : List + List of the ODEs + funcs : List + List of dependent variables + t : Symbol + Independent variable + + Examples + ======== + + >>> from sympy import symbols, Function, Eq, Derivative + >>> from sympy.solvers.ode.systems import canonical_odes + >>> f, g = symbols("f g", cls=Function) + >>> x, y = symbols("x y") + >>> funcs = [f(x), g(x)] + >>> eqs = [Eq(f(x).diff(x) - 7*f(x), 12*g(x)), Eq(g(x).diff(x) + g(x), 20*f(x))] + + >>> canonical_eqs = canonical_odes(eqs, funcs, x) + >>> canonical_eqs + [[Eq(Derivative(f(x), x), 7*f(x) + 12*g(x)), Eq(Derivative(g(x), x), 20*f(x) - g(x))]] + + >>> system = [Eq(Derivative(f(x), x)**2 - 2*Derivative(f(x), x) + 1, 4), Eq(-y*f(x) + Derivative(g(x), x), 0)] + + >>> canonical_system = canonical_odes(system, funcs, x) + >>> canonical_system + [[Eq(Derivative(f(x), x), -1), Eq(Derivative(g(x), x), y*f(x))], [Eq(Derivative(f(x), x), 3), Eq(Derivative(g(x), x), y*f(x))]] + + Returns + ======= + + List + + """ + from sympy.solvers.solvers import solve + + order = _get_func_order(eqs, funcs) + + canon_eqs = solve(eqs, *[func.diff(t, order[func]) for func in funcs], dict=True) + + systems = [] + for eq in canon_eqs: + system = [Eq(func.diff(t, order[func]), eq[func.diff(t, order[func])]) for func in funcs] + systems.append(system) + + return systems + + +def _is_commutative_anti_derivative(A, t): + r""" + Helper function for determining if the Matrix passed is commutative with its antiderivative + + Explanation + =========== + + This function checks if the Matrix $A$ passed is commutative with its antiderivative with respect + to the independent variable $t$. + + .. math:: + B(t) = \int A(t) dt + + The function outputs two values, first one being the antiderivative $B(t)$, second one being a + boolean value, if True, then the matrix $A(t)$ passed is commutative with $B(t)$, else the matrix + passed isn't commutative with $B(t)$. + + Parameters + ========== + + A : Matrix + The matrix which has to be checked + t : Symbol + Independent variable + + Examples + ======== + + >>> from sympy import symbols, Matrix + >>> from sympy.solvers.ode.systems import _is_commutative_anti_derivative + >>> t = symbols("t") + >>> A = Matrix([[1, t], [-t, 1]]) + + >>> B, is_commuting = _is_commutative_anti_derivative(A, t) + >>> is_commuting + True + + Returns + ======= + + Matrix, Boolean + + """ + B = integrate(A, t) + is_commuting = (B*A - A*B).applyfunc(expand).applyfunc(factor_terms).is_zero_matrix + + is_commuting = False if is_commuting is None else is_commuting + + return B, is_commuting + + +def _factor_matrix(A, t): + term = None + for element in A: + temp_term = element.as_independent(t)[1] + if temp_term.has(t): + term = temp_term + break + + if term is not None: + A_factored = (A/term).applyfunc(ratsimp) + can_factor = _matrix_is_constant(A_factored, t) + term = (term, A_factored) if can_factor else None + + return term + + +def _is_second_order_type2(A, t): + term = _factor_matrix(A, t) + is_type2 = False + + if term is not None: + term = 1/term[0] + is_type2 = term.is_polynomial() + + if is_type2: + poly = Poly(term.expand(), t) + monoms = poly.monoms() + + if monoms[0][0] in (2, 4): + cs = _get_poly_coeffs(poly, 4) + a, b, c, d, e = cs + + a1 = powdenest(sqrt(a), force=True) + c1 = powdenest(sqrt(e), force=True) + b1 = powdenest(sqrt(c - 2*a1*c1), force=True) + + is_type2 = (b == 2*a1*b1) and (d == 2*b1*c1) + term = a1*t**2 + b1*t + c1 + + else: + is_type2 = False + + return is_type2, term + + +def _get_poly_coeffs(poly, order): + cs = [0 for _ in range(order+1)] + for c, m in zip(poly.coeffs(), poly.monoms()): + cs[-1-m[0]] = c + return cs + + +def _match_second_order_type(A1, A0, t, b=None): + r""" + Works only for second order system in its canonical form. + + Type 0: Constant coefficient matrix, can be simply solved by + introducing dummy variables. + Type 1: When the substitution: $U = t*X' - X$ works for reducing + the second order system to first order system. + Type 2: When the system is of the form: $poly * X'' = A*X$ where + $poly$ is square of a quadratic polynomial with respect to + *t* and $A$ is a constant coefficient matrix. + + """ + match = {"type_of_equation": "type0"} + n = A1.shape[0] + + if _matrix_is_constant(A1, t) and _matrix_is_constant(A0, t): + return match + + if (A1 + A0*t).applyfunc(expand_mul).is_zero_matrix: + match.update({"type_of_equation": "type1", "A1": A1}) + + elif A1.is_zero_matrix and (b is None or b.is_zero_matrix): + is_type2, term = _is_second_order_type2(A0, t) + if is_type2: + a, b, c = _get_poly_coeffs(Poly(term, t), 2) + A = (A0*(term**2).expand()).applyfunc(ratsimp) + (b**2/4 - a*c)*eye(n, n) + tau = integrate(1/term, t) + t_ = Symbol("{}_".format(t)) + match.update({"type_of_equation": "type2", "A0": A, + "g(t)": sqrt(term), "tau": tau, "is_transformed": True, + "t_": t_}) + + return match + + +def _second_order_subs_type1(A, b, funcs, t): + r""" + For a linear, second order system of ODEs, a particular substitution. + + A system of the below form can be reduced to a linear first order system of + ODEs: + .. math:: + X'' = A(t) * (t*X' - X) + b(t) + + By substituting: + .. math:: U = t*X' - X + + To get the system: + .. math:: U' = t*(A(t)*U + b(t)) + + Where $U$ is the vector of dependent variables, $X$ is the vector of dependent + variables in `funcs` and $X'$ is the first order derivative of $X$ with respect to + $t$. It may or may not reduce the system into linear first order system of ODEs. + + Then a check is made to determine if the system passed can be reduced or not, if + this substitution works, then the system is reduced and its solved for the new + substitution. After we get the solution for $U$: + + .. math:: U = a(t) + + We substitute and return the reduced system: + + .. math:: + a(t) = t*X' - X + + Parameters + ========== + + A: Matrix + Coefficient matrix($A(t)*t$) of the second order system of this form. + b: Matrix + Non-homogeneous term($b(t)$) of the system of ODEs. + funcs: List + List of dependent variables + t: Symbol + Independent variable of the system of ODEs. + + Returns + ======= + + List + + """ + + U = Matrix([t*func.diff(t) - func for func in funcs]) + + sol = linodesolve(A, t, t*b) + reduced_eqs = [Eq(u, s) for s, u in zip(sol, U)] + reduced_eqs = canonical_odes(reduced_eqs, funcs, t)[0] + + return reduced_eqs + + +def _second_order_subs_type2(A, funcs, t_): + r""" + Returns a second order system based on the coefficient matrix passed. + + Explanation + =========== + + This function returns a system of second order ODE of the following form: + + .. math:: + X'' = A * X + + Here, $X$ is the vector of dependent variables, but a bit modified, $A$ is the + coefficient matrix passed. + + Along with returning the second order system, this function also returns the new + dependent variables with the new independent variable `t_` passed. + + Parameters + ========== + + A: Matrix + Coefficient matrix of the system + funcs: List + List of old dependent variables + t_: Symbol + New independent variable + + Returns + ======= + + List, List + + """ + func_names = [func.func.__name__ for func in funcs] + new_funcs = [Function(Dummy("{}_".format(name)))(t_) for name in func_names] + rhss = A * Matrix(new_funcs) + new_eqs = [Eq(func.diff(t_, 2), rhs) for func, rhs in zip(new_funcs, rhss)] + + return new_eqs, new_funcs + + +def _is_euler_system(As, t): + return all(_matrix_is_constant((A*t**i).applyfunc(ratsimp), t) for i, A in enumerate(As)) + + +def _classify_linear_system(eqs, funcs, t, is_canon=False): + r""" + Returns a dictionary with details of the eqs if the system passed is linear + and can be classified by this function else returns None + + Explanation + =========== + + This function takes the eqs, converts it into a form Ax = b where x is a vector of terms + containing dependent variables and their derivatives till their maximum order. If it is + possible to convert eqs into Ax = b, then all the equations in eqs are linear otherwise + they are non-linear. + + To check if the equations are constant coefficient, we need to check if all the terms in + A obtained above are constant or not. + + To check if the equations are homogeneous or not, we need to check if b is a zero matrix + or not. + + Parameters + ========== + + eqs: List + List of ODEs + funcs: List + List of dependent variables + t: Symbol + Independent variable of the equations in eqs + is_canon: Boolean + If True, then this function will not try to get the + system in canonical form. Default value is False + + Returns + ======= + + match = { + 'no_of_equation': len(eqs), + 'eq': eqs, + 'func': funcs, + 'order': order, + 'is_linear': is_linear, + 'is_constant': is_constant, + 'is_homogeneous': is_homogeneous, + } + + Dict or list of Dicts or None + Dict with values for keys: + 1. no_of_equation: Number of equations + 2. eq: The set of equations + 3. func: List of dependent variables + 4. order: A dictionary that gives the order of the + dependent variable in eqs + 5. is_linear: Boolean value indicating if the set of + equations are linear or not. + 6. is_constant: Boolean value indicating if the set of + equations have constant coefficients or not. + 7. is_homogeneous: Boolean value indicating if the set of + equations are homogeneous or not. + 8. commutative_antiderivative: Antiderivative of the coefficient + matrix if the coefficient matrix is non-constant + and commutative with its antiderivative. This key + may or may not exist. + 9. is_general: Boolean value indicating if the system of ODEs is + solvable using one of the general case solvers or not. + 10. rhs: rhs of the non-homogeneous system of ODEs in Matrix form. This + key may or may not exist. + 11. is_higher_order: True if the system passed has an order greater than 1. + This key may or may not exist. + 12. is_second_order: True if the system passed is a second order ODE. This + key may or may not exist. + This Dict is the answer returned if the eqs are linear and constant + coefficient. Otherwise, None is returned. + + """ + + # Error for i == 0 can be added but isn't for now + + # Check for len(funcs) == len(eqs) + if len(funcs) != len(eqs): + raise ValueError("Number of functions given is not equal to the number of equations %s" % funcs) + + # ValueError when functions have more than one arguments + for func in funcs: + if len(func.args) != 1: + raise ValueError("dsolve() and classify_sysode() work with " + "functions of one variable only, not %s" % func) + + # Getting the func_dict and order using the helper + # function + order = _get_func_order(eqs, funcs) + system_order = max(order[func] for func in funcs) + is_higher_order = system_order > 1 + is_second_order = system_order == 2 and all(order[func] == 2 for func in funcs) + + # Not adding the check if the len(func.args) for + # every func in funcs is 1 + + # Linearity check + try: + + canon_eqs = canonical_odes(eqs, funcs, t) if not is_canon else [eqs] + if len(canon_eqs) == 1: + As, b = linear_ode_to_matrix(canon_eqs[0], funcs, t, system_order) + else: + + match = { + 'is_implicit': True, + 'canon_eqs': canon_eqs + } + + return match + + # When the system of ODEs is non-linear, an ODENonlinearError is raised. + # This function catches the error and None is returned. + except ODENonlinearError: + return None + + is_linear = True + + # Homogeneous check + is_homogeneous = True if b.is_zero_matrix else False + + # Is general key is used to identify if the system of ODEs can be solved by + # one of the general case solvers or not. + match = { + 'no_of_equation': len(eqs), + 'eq': eqs, + 'func': funcs, + 'order': order, + 'is_linear': is_linear, + 'is_homogeneous': is_homogeneous, + 'is_general': True + } + + if not is_homogeneous: + match['rhs'] = b + + is_constant = all(_matrix_is_constant(A_, t) for A_ in As) + + # The match['is_linear'] check will be added in the future when this + # function becomes ready to deal with non-linear systems of ODEs + + if not is_higher_order: + A = As[1] + match['func_coeff'] = A + + # Constant coefficient check + is_constant = _matrix_is_constant(A, t) + match['is_constant'] = is_constant + + try: + system_info = linodesolve_type(A, t, b=b) + except NotImplementedError: + return None + + match.update(system_info) + antiderivative = match.pop("antiderivative") + + if not is_constant: + match['commutative_antiderivative'] = antiderivative + + return match + else: + match['type_of_equation'] = "type0" + + if is_second_order: + A1, A0 = As[1:] + + match_second_order = _match_second_order_type(A1, A0, t) + match.update(match_second_order) + + match['is_second_order'] = True + + # If system is constant, then no need to check if its in euler + # form or not. It will be easier and faster to directly proceed + # to solve it. + if match['type_of_equation'] == "type0" and not is_constant: + is_euler = _is_euler_system(As, t) + if is_euler: + t_ = Symbol('{}_'.format(t)) + match.update({'is_transformed': True, 'type_of_equation': 'type1', + 't_': t_}) + else: + is_jordan = lambda M: M == Matrix.jordan_block(M.shape[0], M[0, 0]) + terms = _factor_matrix(As[-1], t) + if all(A.is_zero_matrix for A in As[1:-1]) and terms is not None and not is_jordan(terms[1]): + P, J = terms[1].jordan_form() + match.update({'type_of_equation': 'type2', 'J': J, + 'f(t)': terms[0], 'P': P, 'is_transformed': True}) + + if match['type_of_equation'] != 'type0' and is_second_order: + match.pop('is_second_order', None) + + match['is_higher_order'] = is_higher_order + + return match + +def _preprocess_eqs(eqs): + processed_eqs = [] + for eq in eqs: + processed_eqs.append(eq if isinstance(eq, Equality) else Eq(eq, 0)) + + return processed_eqs + + +def _eqs2dict(eqs, funcs): + eqsorig = {} + eqsmap = {} + funcset = set(funcs) + for eq in eqs: + f1, = eq.lhs.atoms(AppliedUndef) + f2s = (eq.rhs.atoms(AppliedUndef) - {f1}) & funcset + eqsmap[f1] = f2s + eqsorig[f1] = eq + return eqsmap, eqsorig + + +def _dict2graph(d): + nodes = list(d) + edges = [(f1, f2) for f1, f2s in d.items() for f2 in f2s] + G = (nodes, edges) + return G + + +def _is_type1(scc, t): + eqs, funcs = scc + + try: + (A1, A0), b = linear_ode_to_matrix(eqs, funcs, t, 1) + except (ODENonlinearError, ODEOrderError): + return False + + if _matrix_is_constant(A0, t) and b.is_zero_matrix: + return True + + return False + + +def _combine_type1_subsystems(subsystem, funcs, t): + indices = [i for i, sys in enumerate(zip(subsystem, funcs)) if _is_type1(sys, t)] + remove = set() + for ip, i in enumerate(indices): + for j in indices[ip+1:]: + if any(eq2.has(funcs[i]) for eq2 in subsystem[j]): + subsystem[j] = subsystem[i] + subsystem[j] + remove.add(i) + subsystem = [sys for i, sys in enumerate(subsystem) if i not in remove] + return subsystem + + +def _component_division(eqs, funcs, t): + + # Assuming that each eq in eqs is in canonical form, + # that is, [f(x).diff(x) = .., g(x).diff(x) = .., etc] + # and that the system passed is in its first order + eqsmap, eqsorig = _eqs2dict(eqs, funcs) + + subsystems = [] + for cc in connected_components(_dict2graph(eqsmap)): + eqsmap_c = {f: eqsmap[f] for f in cc} + sccs = strongly_connected_components(_dict2graph(eqsmap_c)) + subsystem = [[eqsorig[f] for f in scc] for scc in sccs] + subsystem = _combine_type1_subsystems(subsystem, sccs, t) + subsystems.append(subsystem) + + return subsystems + + +# Returns: List of equations +def _linear_ode_solver(match): + t = match['t'] + funcs = match['func'] + + rhs = match.get('rhs', None) + tau = match.get('tau', None) + t = match['t_'] if 't_' in match else t + A = match['func_coeff'] + + # Note: To make B None when the matrix has constant + # coefficient + B = match.get('commutative_antiderivative', None) + type = match['type_of_equation'] + + sol_vector = linodesolve(A, t, b=rhs, B=B, + type=type, tau=tau) + + sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)] + + return sol + + +def _select_equations(eqs, funcs, key=lambda x: x): + eq_dict = {e.lhs: e.rhs for e in eqs} + return [Eq(f, eq_dict[key(f)]) for f in funcs] + + +def _higher_order_ode_solver(match): + eqs = match["eq"] + funcs = match["func"] + t = match["t"] + sysorder = match['order'] + type = match.get('type_of_equation', "type0") + + is_second_order = match.get('is_second_order', False) + is_transformed = match.get('is_transformed', False) + is_euler = is_transformed and type == "type1" + is_higher_order_type2 = is_transformed and type == "type2" and 'P' in match + + if is_second_order: + new_eqs, new_funcs = _second_order_to_first_order(eqs, funcs, t, + A1=match.get("A1", None), A0=match.get("A0", None), + b=match.get("rhs", None), type=type, + t_=match.get("t_", None)) + else: + new_eqs, new_funcs = _higher_order_to_first_order(eqs, sysorder, t, funcs=funcs, + type=type, J=match.get('J', None), + f_t=match.get('f(t)', None), + P=match.get('P', None), b=match.get('rhs', None)) + + if is_transformed: + t = match.get('t_', t) + + if not is_higher_order_type2: + new_eqs = _select_equations(new_eqs, [f.diff(t) for f in new_funcs]) + + sol = None + + # NotImplementedError may be raised when the system may be actually + # solvable if it can be just divided into sub-systems + try: + if not is_higher_order_type2: + sol = _strong_component_solver(new_eqs, new_funcs, t) + except NotImplementedError: + sol = None + + # Dividing the system only when it becomes essential + if sol is None: + try: + sol = _component_solver(new_eqs, new_funcs, t) + except NotImplementedError: + sol = None + + if sol is None: + return sol + + is_second_order_type2 = is_second_order and type == "type2" + + underscores = '__' if is_transformed else '_' + + sol = _select_equations(sol, funcs, + key=lambda x: Function(Dummy('{}{}0'.format(x.func.__name__, underscores)))(t)) + + if match.get("is_transformed", False): + if is_second_order_type2: + g_t = match["g(t)"] + tau = match["tau"] + sol = [Eq(s.lhs, s.rhs.subs(t, tau) * g_t) for s in sol] + elif is_euler: + t = match['t'] + tau = match['t_'] + sol = [s.subs(tau, log(t)) for s in sol] + elif is_higher_order_type2: + P = match['P'] + sol_vector = P * Matrix([s.rhs for s in sol]) + sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)] + + return sol + + +# Returns: List of equations or None +# If None is returned by this solver, then the system +# of ODEs cannot be solved directly by dsolve_system. +def _strong_component_solver(eqs, funcs, t): + from sympy.solvers.ode.ode import dsolve, constant_renumber + + match = _classify_linear_system(eqs, funcs, t, is_canon=True) + sol = None + + # Assuming that we can't get an implicit system + # since we are already canonical equations from + # dsolve_system + if match: + match['t'] = t + + if match.get('is_higher_order', False): + sol = _higher_order_ode_solver(match) + + elif match.get('is_linear', False): + sol = _linear_ode_solver(match) + + # Note: For now, only linear systems are handled by this function + # hence, the match condition is added. This can be removed later. + if sol is None and len(eqs) == 1: + sol = dsolve(eqs[0], func=funcs[0]) + variables = Tuple(eqs[0]).free_symbols + new_constants = [Dummy() for _ in range(ode_order(eqs[0], funcs[0]))] + sol = constant_renumber(sol, variables=variables, newconstants=new_constants) + sol = [sol] + + # To add non-linear case here in future + + return sol + + +def _get_funcs_from_canon(eqs): + return [eq.lhs.args[0] for eq in eqs] + + +# Returns: List of Equations(a solution) +def _weak_component_solver(wcc, t): + + # We will divide the systems into sccs + # only when the wcc cannot be solved as + # a whole + eqs = [] + for scc in wcc: + eqs += scc + funcs = _get_funcs_from_canon(eqs) + + sol = _strong_component_solver(eqs, funcs, t) + if sol: + return sol + + sol = [] + + for scc in wcc: + eqs = scc + funcs = _get_funcs_from_canon(eqs) + + # Substituting solutions for the dependent + # variables solved in previous SCC, if any solved. + comp_eqs = [eq.subs({s.lhs: s.rhs for s in sol}) for eq in eqs] + scc_sol = _strong_component_solver(comp_eqs, funcs, t) + + if scc_sol is None: + raise NotImplementedError(filldedent(''' + The system of ODEs passed cannot be solved by dsolve_system. + ''')) + + # scc_sol: List of equations + # scc_sol is a solution + sol += scc_sol + + return sol + + +# Returns: List of Equations(a solution) +def _component_solver(eqs, funcs, t): + components = _component_division(eqs, funcs, t) + sol = [] + + for wcc in components: + + # wcc_sol: List of Equations + sol += _weak_component_solver(wcc, t) + + # sol: List of Equations + return sol + + +def _second_order_to_first_order(eqs, funcs, t, type="auto", A1=None, + A0=None, b=None, t_=None): + r""" + Expects the system to be in second order and in canonical form + + Explanation + =========== + + Reduces a second order system into a first order one depending on the type of second + order system. + 1. "type0": If this is passed, then the system will be reduced to first order by + introducing dummy variables. + 2. "type1": If this is passed, then a particular substitution will be used to reduce the + the system into first order. + 3. "type2": If this is passed, then the system will be transformed with new dependent + variables and independent variables. This transformation is a part of solving + the corresponding system of ODEs. + + `A1` and `A0` are the coefficient matrices from the system and it is assumed that the + second order system has the form given below: + + .. math:: + A2 * X'' = A1 * X' + A0 * X + b + + Here, $A2$ is the coefficient matrix for the vector $X''$ and $b$ is the non-homogeneous + term. + + Default value for `b` is None but if `A1` and `A0` are passed and `b` is not passed, then the + system will be assumed homogeneous. + + """ + is_a1 = A1 is None + is_a0 = A0 is None + + if (type == "type1" and is_a1) or (type == "type2" and is_a0)\ + or (type == "auto" and (is_a1 or is_a0)): + (A2, A1, A0), b = linear_ode_to_matrix(eqs, funcs, t, 2) + + if not A2.is_Identity: + raise ValueError(filldedent(''' + The system must be in its canonical form. + ''')) + + if type == "auto": + match = _match_second_order_type(A1, A0, t) + type = match["type_of_equation"] + A1 = match.get("A1", None) + A0 = match.get("A0", None) + + sys_order = dict.fromkeys(funcs, 2) + + if type == "type1": + if b is None: + b = zeros(len(eqs)) + eqs = _second_order_subs_type1(A1, b, funcs, t) + sys_order = dict.fromkeys(funcs, 1) + + if type == "type2": + if t_ is None: + t_ = Symbol("{}_".format(t)) + t = t_ + eqs, funcs = _second_order_subs_type2(A0, funcs, t_) + sys_order = dict.fromkeys(funcs, 2) + + return _higher_order_to_first_order(eqs, sys_order, t, funcs=funcs) + + +def _higher_order_type2_to_sub_systems(J, f_t, funcs, t, max_order, b=None, P=None): + + # Note: To add a test for this ValueError + if J is None or f_t is None or not _matrix_is_constant(J, t): + raise ValueError(filldedent(''' + Correctly input for args 'A' and 'f_t' for Linear, Higher Order, + Type 2 + ''')) + + if P is None and b is not None and not b.is_zero_matrix: + raise ValueError(filldedent(''' + Provide the keyword 'P' for matrix P in A = P * J * P-1. + ''')) + + new_funcs = Matrix([Function(Dummy('{}__0'.format(f.func.__name__)))(t) for f in funcs]) + new_eqs = new_funcs.diff(t, max_order) - f_t * J * new_funcs + + if b is not None and not b.is_zero_matrix: + new_eqs -= P.inv() * b + + new_eqs = canonical_odes(new_eqs, new_funcs, t)[0] + + return new_eqs, new_funcs + + +def _higher_order_to_first_order(eqs, sys_order, t, funcs=None, type="type0", **kwargs): + if funcs is None: + funcs = sys_order.keys() + + # Standard Cauchy Euler system + if type == "type1": + t_ = Symbol('{}_'.format(t)) + new_funcs = [Function(Dummy('{}_'.format(f.func.__name__)))(t_) for f in funcs] + max_order = max(sys_order[func] for func in funcs) + subs_dict = dict(zip(funcs, new_funcs)) + subs_dict[t] = exp(t_) + + free_function = Function(Dummy()) + + def _get_coeffs_from_subs_expression(expr): + if isinstance(expr, Subs): + free_symbol = expr.args[1][0] + term = expr.args[0] + return {ode_order(term, free_symbol): 1} + + if isinstance(expr, Mul): + coeff = expr.args[0] + order = list(_get_coeffs_from_subs_expression(expr.args[1]).keys())[0] + return {order: coeff} + + if isinstance(expr, Add): + coeffs = {} + for arg in expr.args: + + if isinstance(arg, Mul): + coeffs.update(_get_coeffs_from_subs_expression(arg)) + + else: + order = list(_get_coeffs_from_subs_expression(arg).keys())[0] + coeffs[order] = 1 + + return coeffs + + for o in range(1, max_order + 1): + expr = free_function(log(t_)).diff(t_, o)*t_**o + coeff_dict = _get_coeffs_from_subs_expression(expr) + coeffs = [coeff_dict[order] if order in coeff_dict else 0 for order in range(o + 1)] + expr_to_subs = sum(free_function(t_).diff(t_, i) * c for i, c in + enumerate(coeffs)) / t**o + subs_dict.update({f.diff(t, o): expr_to_subs.subs(free_function(t_), nf) + for f, nf in zip(funcs, new_funcs)}) + + new_eqs = [eq.subs(subs_dict) for eq in eqs] + new_sys_order = {nf: sys_order[f] for f, nf in zip(funcs, new_funcs)} + + new_eqs = canonical_odes(new_eqs, new_funcs, t_)[0] + + return _higher_order_to_first_order(new_eqs, new_sys_order, t_, funcs=new_funcs) + + # Systems of the form: X(n)(t) = f(t)*A*X + b + # where X(n)(t) is the nth derivative of the vector of dependent variables + # with respect to the independent variable and A is a constant matrix. + if type == "type2": + J = kwargs.get('J', None) + f_t = kwargs.get('f_t', None) + b = kwargs.get('b', None) + P = kwargs.get('P', None) + max_order = max(sys_order[func] for func in funcs) + + return _higher_order_type2_to_sub_systems(J, f_t, funcs, t, max_order, P=P, b=b) + + # Note: To be changed to this after doit option is disabled for default cases + # new_sysorder = _get_func_order(new_eqs, new_funcs) + # + # return _higher_order_to_first_order(new_eqs, new_sysorder, t, funcs=new_funcs) + + new_funcs = [] + + for prev_func in funcs: + func_name = prev_func.func.__name__ + func = Function(Dummy('{}_0'.format(func_name)))(t) + new_funcs.append(func) + subs_dict = {prev_func: func} + new_eqs = [] + + for i in range(1, sys_order[prev_func]): + new_func = Function(Dummy('{}_{}'.format(func_name, i)))(t) + subs_dict[prev_func.diff(t, i)] = new_func + new_funcs.append(new_func) + + prev_f = subs_dict[prev_func.diff(t, i-1)] + new_eq = Eq(prev_f.diff(t), new_func) + new_eqs.append(new_eq) + + eqs = [eq.subs(subs_dict) for eq in eqs] + new_eqs + + return eqs, new_funcs + + +def dsolve_system(eqs, funcs=None, t=None, ics=None, doit=False, simplify=True): + r""" + Solves any(supported) system of Ordinary Differential Equations + + Explanation + =========== + + This function takes a system of ODEs as an input, determines if the + it is solvable by this function, and returns the solution if found any. + + This function can handle: + 1. Linear, First Order, Constant coefficient homogeneous system of ODEs + 2. Linear, First Order, Constant coefficient non-homogeneous system of ODEs + 3. Linear, First Order, non-constant coefficient homogeneous system of ODEs + 4. Linear, First Order, non-constant coefficient non-homogeneous system of ODEs + 5. Any implicit system which can be divided into system of ODEs which is of the above 4 forms + 6. Any higher order linear system of ODEs that can be reduced to one of the 5 forms of systems described above. + + The types of systems described above are not limited by the number of equations, i.e. this + function can solve the above types irrespective of the number of equations in the system passed. + But, the bigger the system, the more time it will take to solve the system. + + This function returns a list of solutions. Each solution is a list of equations where LHS is + the dependent variable and RHS is an expression in terms of the independent variable. + + Among the non constant coefficient types, not all the systems are solvable by this function. Only + those which have either a coefficient matrix with a commutative antiderivative or those systems which + may be divided further so that the divided systems may have coefficient matrix with commutative antiderivative. + + Parameters + ========== + + eqs : List + system of ODEs to be solved + funcs : List or None + List of dependent variables that make up the system of ODEs + t : Symbol or None + Independent variable in the system of ODEs + ics : Dict or None + Set of initial boundary/conditions for the system of ODEs + doit : Boolean + Evaluate the solutions if True. Default value is True. Can be + set to false if the integral evaluation takes too much time and/or + is not required. + simplify: Boolean + Simplify the solutions for the systems. Default value is True. + Can be set to false if simplification takes too much time and/or + is not required. + + Examples + ======== + + >>> from sympy import symbols, Eq, Function + >>> from sympy.solvers.ode.systems import dsolve_system + >>> f, g = symbols("f g", cls=Function) + >>> x = symbols("x") + + >>> eqs = [Eq(f(x).diff(x), g(x)), Eq(g(x).diff(x), f(x))] + >>> dsolve_system(eqs) + [[Eq(f(x), -C1*exp(-x) + C2*exp(x)), Eq(g(x), C1*exp(-x) + C2*exp(x))]] + + You can also pass the initial conditions for the system of ODEs: + + >>> dsolve_system(eqs, ics={f(0): 1, g(0): 0}) + [[Eq(f(x), exp(x)/2 + exp(-x)/2), Eq(g(x), exp(x)/2 - exp(-x)/2)]] + + Optionally, you can pass the dependent variables and the independent + variable for which the system is to be solved: + + >>> funcs = [f(x), g(x)] + >>> dsolve_system(eqs, funcs=funcs, t=x) + [[Eq(f(x), -C1*exp(-x) + C2*exp(x)), Eq(g(x), C1*exp(-x) + C2*exp(x))]] + + Lets look at an implicit system of ODEs: + + >>> eqs = [Eq(f(x).diff(x)**2, g(x)**2), Eq(g(x).diff(x), g(x))] + >>> dsolve_system(eqs) + [[Eq(f(x), C1 - C2*exp(x)), Eq(g(x), C2*exp(x))], [Eq(f(x), C1 + C2*exp(x)), Eq(g(x), C2*exp(x))]] + + Returns + ======= + + List of List of Equations + + Raises + ====== + + NotImplementedError + When the system of ODEs is not solvable by this function. + ValueError + When the parameters passed are not in the required form. + + """ + from sympy.solvers.ode.ode import solve_ics, _extract_funcs, constant_renumber + + if not iterable(eqs): + raise ValueError(filldedent(''' + List of equations should be passed. The input is not valid. + ''')) + + eqs = _preprocess_eqs(eqs) + + if funcs is not None and not isinstance(funcs, list): + raise ValueError(filldedent(''' + Input to the funcs should be a list of functions. + ''')) + + if funcs is None: + funcs = _extract_funcs(eqs) + + if any(len(func.args) != 1 for func in funcs): + raise ValueError(filldedent(''' + dsolve_system can solve a system of ODEs with only one independent + variable. + ''')) + + if len(eqs) != len(funcs): + raise ValueError(filldedent(''' + Number of equations and number of functions do not match + ''')) + + if t is not None and not isinstance(t, Symbol): + raise ValueError(filldedent(''' + The independent variable must be of type Symbol + ''')) + + if t is None: + t = list(list(eqs[0].atoms(Derivative))[0].atoms(Symbol))[0] + + sols = [] + canon_eqs = canonical_odes(eqs, funcs, t) + + for canon_eq in canon_eqs: + try: + sol = _strong_component_solver(canon_eq, funcs, t) + except NotImplementedError: + sol = None + + if sol is None: + sol = _component_solver(canon_eq, funcs, t) + + sols.append(sol) + + if sols: + final_sols = [] + variables = Tuple(*eqs).free_symbols + + for sol in sols: + + sol = _select_equations(sol, funcs) + sol = constant_renumber(sol, variables=variables) + + if ics: + constants = Tuple(*sol).free_symbols - variables + solved_constants = solve_ics(sol, funcs, constants, ics) + sol = [s.subs(solved_constants) for s in sol] + + if simplify: + constants = Tuple(*sol).free_symbols - variables + sol = simpsol(sol, [t], constants, doit=doit) + + final_sols.append(sol) + + sols = final_sols + + return sols diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35c8aa90f2b43b958b710f16e69862fa23d4ff87 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/test_lie_group.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/test_lie_group.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1e8ec11d486fc7f4b7fe43e6b53a8dc911e70b3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/test_lie_group.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/test_riccati.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/test_riccati.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b97d3a253c9c6ad3035ff71d4e2e68113ca6ac45 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/test_riccati.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/test_subscheck.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/test_subscheck.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3267d0d541c9ace5ca12ea3039d8b4217076646e Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/__pycache__/test_subscheck.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_lie_group.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_lie_group.py new file mode 100644 index 0000000000000000000000000000000000000000..153d30ff563773819e49c989f447c1ec7962169b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_lie_group.py @@ -0,0 +1,152 @@ +from sympy.core.function import Function +from sympy.core.numbers import Rational +from sympy.core.relational import Eq +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (atan, sin, tan) + +from sympy.solvers.ode import (classify_ode, checkinfsol, dsolve, infinitesimals) + +from sympy.solvers.ode.subscheck import checkodesol + +from sympy.testing.pytest import XFAIL + + +C1 = Symbol('C1') +x, y = symbols("x y") +f = Function('f') +xi = Function('xi') +eta = Function('eta') + + +def test_heuristic1(): + a, b, c, a4, a3, a2, a1, a0 = symbols("a b c a4 a3 a2 a1 a0") + 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)**Rational(-1, 2) + eq5 = x**2*df - f(x) + x**2*exp(x - (1/x)) + eqlist = [eq, eq1, eq2, eq3, eq4, eq5] + + i = infinitesimals(eq, hint='abaco1_simple') + 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)}] + i1 = infinitesimals(eq1, hint='abaco1_simple') + assert i1 == [{eta(x, f(x)): exp(-a*x), xi(x, f(x)): 0}] + i2 = infinitesimals(eq2, hint='abaco1_simple') + assert i2 == [{eta(x, f(x)): exp(-x**2), xi(x, f(x)): 0}] + i3 = infinitesimals(eq3, hint='abaco1_simple') + 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, hint='abaco1_simple') + assert i4 == [{eta(x, f(x)): 1, xi(x, f(x)): 0}, + {eta(x, f(x)): 0, + xi(x, f(x)): sqrt(a0 + a1*x + a2*x**2 + a3*x**3 + a4*x**4)}] + i5 = infinitesimals(eq5, hint='abaco1_simple') + 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 (zip(eqlist, ilist)): + check = checkinfsol(eq, i) + assert check[0] + + # This ODE can be solved by the Lie Group method, when there are + # better assumptions + eq6 = df - (f(x)/x)*(x*log(x**2/f(x)) + 2) + i = infinitesimals(eq6, hint='abaco1_product') + assert i == [{eta(x, f(x)): f(x)*exp(-x), xi(x, f(x)): 0}] + assert checkinfsol(eq6, i)[0] + + eq7 = x*(f(x).diff(x)) + 1 - f(x)**2 + i = infinitesimals(eq7, hint='chi') + assert checkinfsol(eq7, i)[0] + + +def test_heuristic3(): + a, b = symbols("a b") + df = f(x).diff(x) + + eq = x**2*df + x*f(x) + f(x)**2 + x**2 + i = infinitesimals(eq, hint='bivariate') + 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, hint='bivariate') + assert checkinfsol(eq, i)[0] + + +def test_heuristic_function_sum(): + eq = f(x).diff(x) - (3*(1 + x**2/f(x)**2)*atan(f(x)/x) + (1 - 2*f(x))/x + + (1 - 3*f(x))*(x/f(x)**2)) + i = infinitesimals(eq, hint='function_sum') + assert i == [{eta(x, f(x)): f(x)**(-2) + x**(-2), xi(x, f(x)): 0}] + assert checkinfsol(eq, i)[0] + + +def test_heuristic_abaco2_similar(): + a, b = symbols("a b") + F = Function('F') + eq = f(x).diff(x) - F(a*x + b*f(x)) + i = infinitesimals(eq, hint='abaco2_similar') + assert i == [{eta(x, f(x)): -a/b, xi(x, f(x)): 1}] + assert checkinfsol(eq, i)[0] + + eq = f(x).diff(x) - (f(x)**2 / (sin(f(x) - x) - x**2 + 2*x*f(x))) + i = infinitesimals(eq, hint='abaco2_similar') + assert i == [{eta(x, f(x)): f(x)**2, xi(x, f(x)): f(x)**2}] + assert checkinfsol(eq, i)[0] + + +def test_heuristic_abaco2_unique_unknown(): + + a, b = symbols("a b") + F = Function('F') + eq = f(x).diff(x) - x**(a - 1)*(f(x)**(1 - b))*F(x**a/a + f(x)**b/b) + i = infinitesimals(eq, hint='abaco2_unique_unknown') + assert i == [{eta(x, f(x)): -f(x)*f(x)**(-b), xi(x, f(x)): x*x**(-a)}] + assert checkinfsol(eq, i)[0] + + eq = f(x).diff(x) + tan(F(x**2 + f(x)**2) + atan(x/f(x))) + i = infinitesimals(eq, hint='abaco2_unique_unknown') + assert i == [{eta(x, f(x)): x, xi(x, f(x)): -f(x)}] + assert checkinfsol(eq, i)[0] + + eq = (x*f(x).diff(x) + f(x) + 2*x)**2 -4*x*f(x) -4*x**2 -4*a + i = infinitesimals(eq, hint='abaco2_unique_unknown') + assert checkinfsol(eq, i)[0] + + +def test_heuristic_linear(): + a, b, m, n = symbols("a b m n") + + eq = x**(n*(m + 1) - m)*(f(x).diff(x)) - a*f(x)**n -b*x**(n*(m + 1)) + i = infinitesimals(eq, hint='linear') + assert checkinfsol(eq, i)[0] + + +@XFAIL +def test_kamke(): + a, b, alpha, c = symbols("a b alpha c") + eq = x**2*(a*f(x)**2+(f(x).diff(x))) + b*x**alpha + c + i = infinitesimals(eq, hint='sum_function') # XFAIL + assert checkinfsol(eq, i)[0] + + +def test_user_infinitesimals(): + x = Symbol("x") # assuming x is real generates an error + eq = x*(f(x).diff(x)) + 1 - f(x)**2 + sol = Eq(f(x), (C1 + x**2)/(C1 - x**2)) + infinitesimals = {'xi':sqrt(f(x) - 1)/sqrt(f(x) + 1), 'eta':0} + assert dsolve(eq, hint='lie_group', **infinitesimals) == sol + assert checkodesol(eq, sol) == (True, 0) + + +@XFAIL +def test_lie_group_issue15219(): + eqn = exp(f(x).diff(x)-f(x)) + assert 'lie_group' not in classify_ode(eqn, f(x)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_ode.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_ode.py new file mode 100644 index 0000000000000000000000000000000000000000..65e0fa62d52445a4669f3cdc5ef278dbf9c88ea4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_ode.py @@ -0,0 +1,1105 @@ +from sympy.core.function import (Derivative, Function, Subs, diff) +from sympy.core.numbers import (E, I, Rational, pi) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.complexes import (im, re) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.hyperbolic import acosh +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (atan2, cos, sin, tan) +from sympy.integrals.integrals import Integral +from sympy.polys.polytools import Poly +from sympy.series.order import O +from sympy.simplify.radsimp import collect + +from sympy.solvers.ode import (classify_ode, + homogeneous_order, dsolve) + +from sympy.solvers.ode.subscheck import checkodesol +from sympy.solvers.ode.ode import (classify_sysode, + constant_renumber, constantsimp, get_numbered_constants, solve_ics) + +from sympy.solvers.ode.nonhomogeneous import _undetermined_coefficients_match +from sympy.solvers.ode.single import LinearCoefficients +from sympy.solvers.deutils import ode_order +from sympy.testing.pytest import XFAIL, raises, slow, SKIP +from sympy.utilities.misc import filldedent + + +C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 = symbols('C0:11') +u, x, y, z = symbols('u,x:z', real=True) +f = Function('f') +g = Function('g') +h = Function('h') + +# Note: Examples which were specifically testing Single ODE solver are moved to test_single.py +# and all the system of ode examples are moved to test_systems.py +# Note: the tests below may fail (but still be correct) if ODE solver, +# the integral engine, solve(), or even simplify() changes. Also, in +# differently formatted solutions, the arbitrary constants might not be +# equal. Using specific hints in tests can help to avoid this. + +# Tests of order higher than 1 should run the solutions through +# constant_renumber because it will normalize it (constant_renumber causes +# dsolve() to return different results on different machines) + + +def test_get_numbered_constants(): + with raises(ValueError): + get_numbered_constants(None) + + +def test_dsolve_all_hint(): + eq = f(x).diff(x) + output = dsolve(eq, hint='all') + + # Match the Dummy variables: + sol1 = output['separable_Integral'] + _y = sol1.lhs.args[1][0] + sol1 = output['1st_homogeneous_coeff_subs_dep_div_indep_Integral'] + _u1 = sol1.rhs.args[1].args[1][0] + + expected = {'Bernoulli_Integral': Eq(f(x), C1 + Integral(0, x)), + '1st_homogeneous_coeff_best': Eq(f(x), C1), + 'Bernoulli': Eq(f(x), C1), + 'nth_algebraic': Eq(f(x), C1), + 'nth_linear_euler_eq_homogeneous': Eq(f(x), C1), + 'nth_linear_constant_coeff_homogeneous': Eq(f(x), C1), + 'separable': Eq(f(x), C1), + '1st_homogeneous_coeff_subs_indep_div_dep': Eq(f(x), C1), + 'nth_algebraic_Integral': Eq(f(x), C1), + '1st_linear': Eq(f(x), C1), + '1st_linear_Integral': Eq(f(x), C1 + Integral(0, x)), + '1st_exact': Eq(f(x), C1), + '1st_exact_Integral': Eq(Subs(Integral(0, x) + Integral(1, _y), _y, f(x)), C1), + 'lie_group': Eq(f(x), C1), + '1st_homogeneous_coeff_subs_dep_div_indep': Eq(f(x), C1), + '1st_homogeneous_coeff_subs_dep_div_indep_Integral': Eq(log(x), C1 + Integral(-1/_u1, (_u1, f(x)/x))), + '1st_power_series': Eq(f(x), C1), + 'separable_Integral': Eq(Integral(1, (_y, f(x))), C1 + Integral(0, x)), + '1st_homogeneous_coeff_subs_indep_div_dep_Integral': Eq(f(x), C1), + 'best': Eq(f(x), C1), + 'best_hint': 'nth_algebraic', + 'default': 'nth_algebraic', + 'order': 1} + assert output == expected + + assert dsolve(eq, hint='best') == Eq(f(x), C1) + + +def test_dsolve_ics(): + # Maybe this should just use one of the solutions instead of raising... + with raises(NotImplementedError): + dsolve(f(x).diff(x) - sqrt(f(x)), ics={f(1):1}) + + +@slow +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', 'Bernoulli', 'Bernoulli_Integral', + 'almost_linear', 'almost_linear_Integral', 'best', 'best_hint', + 'default', 'factorable', 'lie_group', + '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', + 'Bernoulli_Integral', 'almost_linear_Integral', 'best', 'best_hint', 'default', + 'factorable', '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) + assert dsolve(eq, hint='best') == Eq(f(x), C1/x) + assert a['default'] == 'factorable' + assert a['best_hint'] == 'factorable' + assert not a['1st_exact'].has(Integral) + assert not a['separable'].has(Integral) + assert not a['1st_homogeneous_coeff_best'].has(Integral) + assert not a['1st_homogeneous_coeff_subs_dep_div_indep'].has(Integral) + assert not a['1st_homogeneous_coeff_subs_indep_div_dep'].has(Integral) + assert not a['1st_linear'].has(Integral) + assert a['1st_linear_Integral'].has(Integral) + assert a['1st_exact_Integral'].has(Integral) + assert a['1st_homogeneous_coeff_subs_dep_div_indep_Integral'].has(Integral) + assert a['1st_homogeneous_coeff_subs_indep_div_dep_Integral'].has(Integral) + assert a['separable_Integral'].has(Integral) + assert sorted(b.keys()) == keys + assert b['order'] == ode_order(eq, f(x)) + assert b['best'] == Eq(f(x), C1/x) + assert dsolve(eq, hint='best', simplify=False) == Eq(f(x), C1/x) + assert b['default'] == 'factorable' + assert b['best_hint'] == 'factorable' + assert a['separable'] != b['separable'] + assert a['1st_homogeneous_coeff_subs_dep_div_indep'] != \ + b['1st_homogeneous_coeff_subs_dep_div_indep'] + assert a['1st_homogeneous_coeff_subs_indep_div_dep'] != \ + b['1st_homogeneous_coeff_subs_indep_div_dep'] + assert not b['1st_exact'].has(Integral) + assert not b['separable'].has(Integral) + assert not b['1st_homogeneous_coeff_best'].has(Integral) + assert not b['1st_homogeneous_coeff_subs_dep_div_indep'].has(Integral) + assert not b['1st_homogeneous_coeff_subs_indep_div_dep'].has(Integral) + assert not b['1st_linear'].has(Integral) + assert b['1st_linear_Integral'].has(Integral) + assert b['1st_exact_Integral'].has(Integral) + assert b['1st_homogeneous_coeff_subs_dep_div_indep_Integral'].has(Integral) + assert b['1st_homogeneous_coeff_subs_indep_div_dep_Integral'].has(Integral) + assert b['separable_Integral'].has(Integral) + assert sorted(c.keys()) == Integral_keys + raises(ValueError, lambda: dsolve(eq, hint='notarealhint')) + raises(ValueError, lambda: dsolve(eq, hint='Liouville')) + assert dsolve(f(x).diff(x) - 1/f(x)**2, hint='all')['best'] == \ + dsolve(f(x).diff(x) - 1/f(x)**2, hint='best') + assert dsolve(f(x) + f(x).diff(x) + sin(x).diff(x) + 1, f(x), + 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_algebraic', + 'nth_linear_constant_coeff_homogeneous', + 'nth_linear_euler_eq_homogeneous', + 'Liouville', + '2nd_power_series_ordinary', + 'nth_algebraic_Integral', + 'Liouville_Integral', + ) + assert classify_ode(f(x), f(x)) == ('nth_algebraic', 'nth_algebraic_Integral') + assert classify_ode(Eq(f(x).diff(x), 0), f(x)) == ( + 'nth_algebraic', + 'separable', + '1st_exact', + '1st_linear', + 'Bernoulli', + '1st_homogeneous_coeff_best', + '1st_homogeneous_coeff_subs_indep_div_dep', + '1st_homogeneous_coeff_subs_dep_div_indep', + '1st_power_series', 'lie_group', + 'nth_linear_constant_coeff_homogeneous', + 'nth_linear_euler_eq_homogeneous', + 'nth_algebraic_Integral', + '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') + assert classify_ode(f(x).diff(x)**2, f(x)) == ('factorable', + 'nth_algebraic', + 'separable', + '1st_exact', + '1st_linear', + 'Bernoulli', + '1st_homogeneous_coeff_best', + '1st_homogeneous_coeff_subs_indep_div_dep', + '1st_homogeneous_coeff_subs_dep_div_indep', + '1st_power_series', + 'lie_group', + 'nth_linear_euler_eq_homogeneous', + 'nth_algebraic_Integral', + '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') + # issue 4749: f(x) should be cleared from highest derivative before classifying + 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 == ('1st_exact', + '1st_linear', + 'Bernoulli', + 'almost_linear', + '1st_power_series', "lie_group", + 'nth_linear_constant_coeff_undetermined_coefficients', + 'nth_linear_constant_coeff_variation_of_parameters', + '1st_exact_Integral', + '1st_linear_Integral', + 'Bernoulli_Integral', + 'almost_linear_Integral', + 'nth_linear_constant_coeff_variation_of_parameters_Integral') + assert b == ('factorable', + '1st_linear', + 'Bernoulli', + '1st_power_series', + 'lie_group', + 'nth_linear_constant_coeff_undetermined_coefficients', + 'nth_linear_constant_coeff_variation_of_parameters', + '1st_linear_Integral', + 'Bernoulli_Integral', + 'nth_linear_constant_coeff_variation_of_parameters_Integral') + assert c == ('factorable', + '1st_linear', + 'Bernoulli', + '1st_power_series', + 'lie_group', + 'nth_linear_constant_coeff_undetermined_coefficients', + 'nth_linear_constant_coeff_variation_of_parameters', + '1st_linear_Integral', + 'Bernoulli_Integral', + 'nth_linear_constant_coeff_variation_of_parameters_Integral') + + assert classify_ode( + 2*x*f(x)*f(x).diff(x) + (1 + x)*f(x)**2 - exp(x), f(x) + ) == ('factorable', '1st_exact', 'Bernoulli', 'almost_linear', 'lie_group', + '1st_exact_Integral', '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))) + # issue 5176 + 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)) == \ + ('factorable', 'separable', '1st_exact', '1st_linear', 'Bernoulli', + '1st_power_series', 'lie_group', 'separable_Integral', '1st_exact_Integral', + '1st_linear_Integral', 'Bernoulli_Integral') + # preprocessing + ans = ('factorable', 'nth_algebraic', 'separable', '1st_exact', '1st_linear', 'Bernoulli', + '1st_homogeneous_coeff_best', + '1st_homogeneous_coeff_subs_indep_div_dep', + '1st_homogeneous_coeff_subs_dep_div_indep', + '1st_power_series', 'lie_group', + 'nth_linear_constant_coeff_undetermined_coefficients', + 'nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients', + 'nth_linear_constant_coeff_variation_of_parameters', + 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters', + 'nth_algebraic_Integral', + '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', + 'nth_linear_euler_eq_nonhomogeneous_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 + + assert classify_ode(Eq(2*x**3*f(x).diff(x), 0), f(x)) == \ + ('factorable', 'nth_algebraic', 'separable', '1st_exact', + '1st_linear', 'Bernoulli', '1st_power_series', + 'lie_group', 'nth_linear_euler_eq_homogeneous', + 'nth_algebraic_Integral', 'separable_Integral', '1st_exact_Integral', + '1st_linear_Integral', 'Bernoulli_Integral') + + + assert classify_ode(Eq(2*f(x)**3*f(x).diff(x), 0), f(x)) == \ + ('factorable', 'nth_algebraic', 'separable', '1st_exact', '1st_linear', + 'Bernoulli', '1st_power_series', 'lie_group', 'nth_algebraic_Integral', + 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', + 'Bernoulli_Integral') + # test issue 13864 + assert classify_ode(Eq(diff(f(x), x) - f(x)**x, 0), f(x)) == \ + ('1st_power_series', 'lie_group') + assert isinstance(classify_ode(Eq(f(x), 5), f(x), dict=True), dict) + + #This is for new behavior of classify_ode when called internally with default, It should + # return the first hint which matches therefore, 'ordered_hints' key will not be there. + assert sorted(classify_ode(Eq(f(x).diff(x), 0), f(x), dict=True).keys()) == \ + ['default', 'nth_linear_constant_coeff_homogeneous', 'order'] + a = classify_ode(2*x*f(x)*f(x).diff(x) + (1 + x)*f(x)**2 - exp(x), f(x), dict=True, hint='Bernoulli') + assert sorted(a.keys()) == ['Bernoulli', 'Bernoulli_Integral', 'default', 'order', 'ordered_hints'] + + # test issue 22155 + a = classify_ode(f(x).diff(x) - exp(f(x) - x), f(x)) + assert a == ('separable', + '1st_exact', '1st_power_series', + 'lie_group', 'separable_Integral', + '1st_exact_Integral') + + +def test_classify_ode_ics(): + # Dummy + eq = f(x).diff(x, x) - f(x) + + # Not f(0) or f'(0) + ics = {x: 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + + ############################ + # f(0) type (AppliedUndef) # + ############################ + + + # Wrong function + ics = {g(0): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Contains x + ics = {f(x): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Too many args + ics = {f(0, 0): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # point contains x + ics = {f(0): f(x)} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Does not raise + ics = {f(0): f(0)} + classify_ode(eq, f(x), ics=ics) + + # Does not raise + ics = {f(0): 1} + classify_ode(eq, f(x), ics=ics) + + + ##################### + # f'(0) type (Subs) # + ##################### + + # Wrong function + ics = {g(x).diff(x).subs(x, 0): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Contains x + ics = {f(y).diff(y).subs(y, x): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Wrong variable + ics = {f(y).diff(y).subs(y, 0): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Too many args + ics = {f(x, y).diff(x).subs(x, 0): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Derivative wrt wrong vars + ics = {Derivative(f(x), x, y).subs(x, 0): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # point contains x + ics = {f(x).diff(x).subs(x, 0): f(x)} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Does not raise + ics = {f(x).diff(x).subs(x, 0): f(x).diff(x).subs(x, 0)} + classify_ode(eq, f(x), ics=ics) + + # Does not raise + ics = {f(x).diff(x).subs(x, 0): 1} + classify_ode(eq, f(x), ics=ics) + + ########################### + # f'(y) type (Derivative) # + ########################### + + # Wrong function + ics = {g(x).diff(x).subs(x, y): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Contains x + ics = {f(y).diff(y).subs(y, x): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Too many args + ics = {f(x, y).diff(x).subs(x, y): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Derivative wrt wrong vars + ics = {Derivative(f(x), x, z).subs(x, y): 1} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # point contains x + ics = {f(x).diff(x).subs(x, y): f(x)} + raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) + + # Does not raise + ics = {f(x).diff(x).subs(x, 0): f(0)} + classify_ode(eq, f(x), ics=ics) + + # Does not raise + ics = {f(x).diff(x).subs(x, y): 1} + classify_ode(eq, f(x), ics=ics) + +def test_classify_sysode(): + # Here x is assumed to be x(t) and y as y(t) for simplicity. + # Similarly diff(x,t) and diff(y,y) is assumed to be x1 and y1 respectively. + k, l, m, n = symbols('k, l, m, n', Integer=True) + k1, k2, k3, l1, l2, l3, m1, m2, m3 = symbols('k1, k2, k3, l1, l2, l3, m1, m2, m3', Integer=True) + P, Q, R, p, q, r = symbols('P, Q, R, p, q, r', cls=Function) + P1, P2, P3, Q1, Q2, R1, R2 = symbols('P1, P2, P3, Q1, Q2, R1, R2', cls=Function) + x, y, z = symbols('x, y, z', cls=Function) + t = symbols('t') + x1 = diff(x(t),t) + y1 = diff(y(t),t) + + eq6 = (Eq(x1, exp(k*x(t))*P(x(t),y(t))), Eq(y1,r(y(t))*P(x(t),y(t)))) + sol6 = {'no_of_equation': 2, 'func_coeff': {(0, x(t), 0): 0, (1, x(t), 1): 0, (0, x(t), 1): 1, (1, y(t), 0): 0, \ + (1, x(t), 0): 0, (0, y(t), 1): 0, (0, y(t), 0): 0, (1, y(t), 1): 1}, 'type_of_equation': 'type2', 'func': \ + [x(t), y(t)], 'is_linear': False, 'eq': [-P(x(t), y(t))*exp(k*x(t)) + Derivative(x(t), t), -P(x(t), \ + y(t))*r(y(t)) + Derivative(y(t), t)], 'order': {y(t): 1, x(t): 1}} + assert classify_sysode(eq6) == sol6 + + eq7 = (Eq(x1, x(t)**2+y(t)/x(t)), Eq(y1, x(t)/y(t))) + sol7 = {'no_of_equation': 2, 'func_coeff': {(0, x(t), 0): 0, (1, x(t), 1): 0, (0, x(t), 1): 1, (1, y(t), 0): 0, \ + (1, x(t), 0): -1/y(t), (0, y(t), 1): 0, (0, y(t), 0): -1/x(t), (1, y(t), 1): 1}, 'type_of_equation': 'type3', \ + 'func': [x(t), y(t)], 'is_linear': False, 'eq': [-x(t)**2 + Derivative(x(t), t) - y(t)/x(t), -x(t)/y(t) + \ + Derivative(y(t), t)], 'order': {y(t): 1, x(t): 1}} + assert classify_sysode(eq7) == sol7 + + eq8 = (Eq(x1, P1(x(t))*Q1(y(t))*R(x(t),y(t),t)), Eq(y1, P1(x(t))*Q1(y(t))*R(x(t),y(t),t))) + sol8 = {'func': [x(t), y(t)], 'is_linear': False, 'type_of_equation': 'type4', 'eq': \ + [-P1(x(t))*Q1(y(t))*R(x(t), y(t), t) + Derivative(x(t), t), -P1(x(t))*Q1(y(t))*R(x(t), y(t), t) + \ + Derivative(y(t), t)], 'func_coeff': {(0, y(t), 1): 0, (1, y(t), 1): 1, (1, x(t), 1): 0, (0, y(t), 0): 0, \ + (1, x(t), 0): 0, (0, x(t), 0): 0, (1, y(t), 0): 0, (0, x(t), 1): 1}, 'order': {y(t): 1, x(t): 1}, 'no_of_equation': 2} + assert classify_sysode(eq8) == sol8 + + eq11 = (Eq(x1,x(t)*y(t)**3), Eq(y1,y(t)**5)) + sol11 = {'no_of_equation': 2, 'func_coeff': {(0, x(t), 0): -y(t)**3, (1, x(t), 1): 0, (0, x(t), 1): 1, \ + (1, y(t), 0): 0, (1, x(t), 0): 0, (0, y(t), 1): 0, (0, y(t), 0): 0, (1, y(t), 1): 1}, 'type_of_equation': \ + 'type1', 'func': [x(t), y(t)], 'is_linear': False, 'eq': [-x(t)*y(t)**3 + Derivative(x(t), t), \ + -y(t)**5 + Derivative(y(t), t)], 'order': {y(t): 1, x(t): 1}} + assert classify_sysode(eq11) == sol11 + + eq13 = (Eq(x1,x(t)*y(t)*sin(t)**2), Eq(y1,y(t)**2*sin(t)**2)) + sol13 = {'no_of_equation': 2, 'func_coeff': {(0, x(t), 0): -y(t)*sin(t)**2, (1, x(t), 1): 0, (0, x(t), 1): 1, \ + (1, y(t), 0): 0, (1, x(t), 0): 0, (0, y(t), 1): 0, (0, y(t), 0): -x(t)*sin(t)**2, (1, y(t), 1): 1}, \ + 'type_of_equation': 'type4', 'func': [x(t), y(t)], 'is_linear': False, 'eq': [-x(t)*y(t)*sin(t)**2 + \ + Derivative(x(t), t), -y(t)**2*sin(t)**2 + Derivative(y(t), t)], 'order': {y(t): 1, x(t): 1}} + assert classify_sysode(eq13) == sol13 + + +def test_solve_ics(): + # Basic tests that things work from dsolve. + assert dsolve(f(x).diff(x) - 1/f(x), f(x), ics={f(1): 2}) == \ + Eq(f(x), sqrt(2 * x + 2)) + assert dsolve(f(x).diff(x) - f(x), f(x), ics={f(0): 1}) == Eq(f(x), exp(x)) + assert dsolve(f(x).diff(x) - f(x), f(x), ics={f(x).diff(x).subs(x, 0): 1}) == Eq(f(x), exp(x)) + assert dsolve(f(x).diff(x, x) + f(x), f(x), ics={f(0): 1, + f(x).diff(x).subs(x, 0): 1}) == Eq(f(x), sin(x) + cos(x)) + assert dsolve([f(x).diff(x) - f(x) + g(x), g(x).diff(x) - g(x) - f(x)], + [f(x), g(x)], ics={f(0): 1, g(0): 0}) == [Eq(f(x), exp(x)*cos(x)), Eq(g(x), exp(x)*sin(x))] + + # Test cases where dsolve returns two solutions. + eq = (x**2*f(x)**2 - x).diff(x) + assert dsolve(eq, f(x), ics={f(1): 0}) == [Eq(f(x), + -sqrt(x - 1)/x), Eq(f(x), sqrt(x - 1)/x)] + assert dsolve(eq, f(x), ics={f(x).diff(x).subs(x, 1): 0}) == [Eq(f(x), + -sqrt(x - S.Half)/x), Eq(f(x), sqrt(x - S.Half)/x)] + + eq = cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x) + assert dsolve(eq, f(x), + ics={f(0):1}, hint='1st_exact', simplify=False) == Eq(x*cos(f(x)) + f(x)**3/3, Rational(1, 3)) + assert dsolve(eq, f(x), + ics={f(0):1}, hint='1st_exact', simplify=True) == Eq(x*cos(f(x)) + f(x)**3/3, Rational(1, 3)) + + assert solve_ics([Eq(f(x), C1*exp(x))], [f(x)], [C1], {f(0): 1}) == {C1: 1} + assert solve_ics([Eq(f(x), C1*sin(x) + C2*cos(x))], [f(x)], [C1, C2], + {f(0): 1, f(pi/2): 1}) == {C1: 1, C2: 1} + + assert solve_ics([Eq(f(x), C1*sin(x) + C2*cos(x))], [f(x)], [C1, C2], + {f(0): 1, f(x).diff(x).subs(x, 0): 1}) == {C1: 1, C2: 1} + + assert solve_ics([Eq(f(x), C1*sin(x) + C2*cos(x))], [f(x)], [C1, C2], {f(0): 1}) == \ + {C2: 1} + + # Some more complicated tests Refer to PR #16098 + + assert set(dsolve(f(x).diff(x)*(f(x).diff(x, 2)-x), ics={f(0):0, f(x).diff(x).subs(x, 1):0})) == \ + {Eq(f(x), 0), Eq(f(x), x ** 3 / 6 - x / 2)} + assert set(dsolve(f(x).diff(x)*(f(x).diff(x, 2)-x), ics={f(0):0})) == \ + {Eq(f(x), 0), Eq(f(x), C2*x + x**3/6)} + + K, r, f0 = symbols('K r f0') + sol = Eq(f(x), K*f0*exp(r*x)/((-K + f0)*(f0*exp(r*x)/(-K + f0) - 1))) + assert (dsolve(Eq(f(x).diff(x), r * f(x) * (1 - f(x) / K)), f(x), ics={f(0): f0})) == sol + + + #Order dependent issues Refer to PR #16098 + assert set(dsolve(f(x).diff(x)*(f(x).diff(x, 2)-x), ics={f(x).diff(x).subs(x,0):0, f(0):0})) == \ + {Eq(f(x), 0), Eq(f(x), x ** 3 / 6)} + assert set(dsolve(f(x).diff(x)*(f(x).diff(x, 2)-x), ics={f(0):0, f(x).diff(x).subs(x,0):0})) == \ + {Eq(f(x), 0), Eq(f(x), x ** 3 / 6)} + + # XXX: Ought to be ValueError + raises(ValueError, lambda: solve_ics([Eq(f(x), C1*sin(x) + C2*cos(x))], [f(x)], [C1, C2], {f(0): 1, f(pi): 1})) + + # Degenerate case. f'(0) is identically 0. + raises(ValueError, lambda: solve_ics([Eq(f(x), sqrt(C1 - x**2))], [f(x)], [C1], {f(x).diff(x).subs(x, 0): 0})) + + EI, q, L = symbols('EI q L') + + # eq = Eq(EI*diff(f(x), x, 4), q) + sols = [Eq(f(x), C1 + C2*x + C3*x**2 + C4*x**3 + q*x**4/(24*EI))] + funcs = [f(x)] + constants = [C1, C2, C3, C4] + # Test both cases, Derivative (the default from f(x).diff(x).subs(x, L)), + # and Subs + ics1 = {f(0): 0, + f(x).diff(x).subs(x, 0): 0, + f(L).diff(L, 2): 0, + f(L).diff(L, 3): 0} + ics2 = {f(0): 0, + f(x).diff(x).subs(x, 0): 0, + Subs(f(x).diff(x, 2), x, L): 0, + Subs(f(x).diff(x, 3), x, L): 0} + + solved_constants1 = solve_ics(sols, funcs, constants, ics1) + solved_constants2 = solve_ics(sols, funcs, constants, ics2) + assert solved_constants1 == solved_constants2 == { + C1: 0, + C2: 0, + C3: L**2*q/(4*EI), + C4: -L*q/(6*EI)} + + # Allow the ics to refer to f + ics = {f(0): f(0)} + assert dsolve(f(x).diff(x) - f(x), f(x), ics=ics) == Eq(f(x), f(0)*exp(x)) + + ics = {f(x).diff(x).subs(x, 0): f(x).diff(x).subs(x, 0), f(0): f(0)} + assert dsolve(f(x).diff(x, x) + f(x), f(x), ics=ics) == \ + Eq(f(x), f(0)*cos(x) + f(x).diff(x).subs(x, 0)*sin(x)) + +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(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 + # issue 5835: 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(f(x), x, x), g(x)) == 0 + 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( + x*sin(Derivative(x*Derivative(f(x), x)**2, x, x)), f(x)) == 3 + + +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) 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(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)) 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) 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) 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) is None + raises(ValueError, lambda: homogeneous_order(x*y)) + + +@XFAIL +def test_noncircularized_real_imaginary_parts(): + # If this passes, lines numbered 3878-3882 (at the time of this commit) + # of sympy/solvers/ode.py for nth_linear_constant_coeff_homogeneous + # should be removed. + y = sqrt(1+x) + i, r = im(y), re(y) + assert not (i.has(atan2) and r.has(atan2)) + + +def test_collect_respecting_exponentials(): + # If this test passes, lines 1306-1311 (at the time of this commit) + # of sympy/solvers/ode.py should be removed. + sol = 1 + exp(x/2) + assert sol == collect( sol, exp(x/3)) + + +def test_undetermined_coefficients_match(): + assert _undetermined_coefficients_match(g(x), x) == {'test': False} + assert _undetermined_coefficients_match(sin(2*x + sqrt(5)), x) == \ + {'test': True, 'trialset': + {cos(2*x + sqrt(5)), sin(2*x + sqrt(5))}} + assert _undetermined_coefficients_match(sin(x)*cos(x), x) == \ + {'test': False} + s = {cos(x), x*cos(x), x**2*cos(x), x**2*sin(x), x*sin(x), sin(x)} + assert _undetermined_coefficients_match(sin(x)*(x**2 + x + 1), x) == \ + {'test': True, 'trialset': s} + assert _undetermined_coefficients_match( + 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': {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)}} + assert _undetermined_coefficients_match(1/sin(x), x) == {'test': False} + assert _undetermined_coefficients_match(log(x), x) == {'test': False} + assert _undetermined_coefficients_match(2**(x)*(x**2 + x + 1), x) == \ + {'test': True, 'trialset': {2**x, x*2**x, x**2*2**x}} + assert _undetermined_coefficients_match(x**y, x) == {'test': False} + assert _undetermined_coefficients_match(exp(x)*exp(2*x + 1), x) == \ + {'test': True, 'trialset': {exp(1 + 3*x)}} + assert _undetermined_coefficients_match(sin(x)*(x**2 + x + 1), x) == \ + {'test': True, 'trialset': {x*cos(x), x*sin(x), x**2*cos(x), + x**2*sin(x), cos(x), sin(x)}} + assert _undetermined_coefficients_match(sin(x)*(x + sin(x)), x) == \ + {'test': False} + assert _undetermined_coefficients_match(sin(x)*(x + sin(2*x)), x) == \ + {'test': False} + assert _undetermined_coefficients_match(sin(x)*tan(x), x) == \ + {'test': False} + assert _undetermined_coefficients_match( + x**2*sin(x)*exp(x) + x*sin(x) + x, x + ) == { + 'test': True, 'trialset': {x**2*cos(x)*exp(x), x, cos(x), S.One, + 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': {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': {2**x, x*2**x}} + assert _undetermined_coefficients_match(2**x*exp(2*x), x) == \ + {'test': True, 'trialset': {2**x*exp(2*x)}} + assert _undetermined_coefficients_match(exp(-x)/x, x) == \ + {'test': False} + # Below are from Ordinary Differential Equations, + # Tenenbaum and Pollard, pg. 231 + assert _undetermined_coefficients_match(S(4), x) == \ + {'test': True, 'trialset': {S.One}} + assert _undetermined_coefficients_match(12*exp(x), x) == \ + {'test': True, 'trialset': {exp(x)}} + assert _undetermined_coefficients_match(exp(I*x), x) == \ + {'test': True, 'trialset': {exp(I*x)}} + assert _undetermined_coefficients_match(sin(x), x) == \ + {'test': True, 'trialset': {cos(x), sin(x)}} + assert _undetermined_coefficients_match(cos(x), x) == \ + {'test': True, 'trialset': {cos(x), sin(x)}} + assert _undetermined_coefficients_match(8 + 6*exp(x) + 2*sin(x), x) == \ + {'test': True, 'trialset': {S.One, cos(x), sin(x), exp(x)}} + assert _undetermined_coefficients_match(x**2, x) == \ + {'test': True, 'trialset': {S.One, x, x**2}} + assert _undetermined_coefficients_match(9*x*exp(x) + exp(-x), x) == \ + {'test': True, 'trialset': {x*exp(x), exp(x), exp(-x)}} + assert _undetermined_coefficients_match(2*exp(2*x)*sin(x), x) == \ + {'test': True, 'trialset': {exp(2*x)*sin(x), cos(x)*exp(2*x)}} + assert _undetermined_coefficients_match(x - sin(x), x) == \ + {'test': True, 'trialset': {S.One, x, cos(x), sin(x)}} + assert _undetermined_coefficients_match(x**2 + 2*x, x) == \ + {'test': True, 'trialset': {S.One, x, x**2}} + assert _undetermined_coefficients_match(4*x*sin(x), x) == \ + {'test': True, 'trialset': {x*cos(x), x*sin(x), cos(x), sin(x)}} + assert _undetermined_coefficients_match(x*sin(2*x), x) == \ + {'test': True, 'trialset': + {x*cos(2*x), x*sin(2*x), cos(2*x), sin(2*x)}} + assert _undetermined_coefficients_match(x**2*exp(-x), x) == \ + {'test': True, 'trialset': {x*exp(-x), x**2*exp(-x), exp(-x)}} + assert _undetermined_coefficients_match(2*exp(-x) - x**2*exp(-x), x) == \ + {'test': True, 'trialset': {x*exp(-x), x**2*exp(-x), exp(-x)}} + assert _undetermined_coefficients_match(exp(-2*x) + x**2, x) == \ + {'test': True, 'trialset': {S.One, x, x**2, exp(-2*x)}} + assert _undetermined_coefficients_match(x*exp(-x), x) == \ + {'test': True, 'trialset': {x*exp(-x), exp(-x)}} + assert _undetermined_coefficients_match(x + exp(2*x), x) == \ + {'test': True, 'trialset': {S.One, x, exp(2*x)}} + assert _undetermined_coefficients_match(sin(x) + exp(-x), x) == \ + {'test': True, 'trialset': {cos(x), sin(x), exp(-x)}} + assert _undetermined_coefficients_match(exp(x), x) == \ + {'test': True, 'trialset': {exp(x)}} + # converted from sin(x)**2 + assert _undetermined_coefficients_match(S.Half - cos(2*x)/2, x) == \ + {'test': True, 'trialset': {S.One, cos(2*x), sin(2*x)}} + # converted from exp(2*x)*sin(x)**2 + assert _undetermined_coefficients_match( + exp(2*x)*(S.Half + cos(2*x)/2), x + ) == { + 'test': True, 'trialset': {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) == \ + {'test': True, 'trialset': {S.One, x, cos(x), sin(x)}} + # converted from sin(2*x)*sin(x) + assert _undetermined_coefficients_match(cos(x)/2 - cos(3*x)/2, x) == \ + {'test': True, 'trialset': {cos(x), cos(3*x), sin(x), sin(3*x)}} + assert _undetermined_coefficients_match(cos(x**2), x) == {'test': False} + assert _undetermined_coefficients_match(2**(x**2), x) == {'test': False} + + +def test_issue_4785_22462(): + 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)) == ('factorable', '1st_exact', '1st_linear', + 'Bernoulli', 'almost_linear', '1st_power_series', 'lie_group', + 'nth_linear_constant_coeff_undetermined_coefficients', + 'nth_linear_constant_coeff_variation_of_parameters', + '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral', + 'almost_linear_Integral', + 'nth_linear_constant_coeff_variation_of_parameters_Integral') + # issue 4864 + eq = (x**2 + f(x)**2)*f(x).diff(x) - 2*x*f(x) + assert classify_ode(eq, f(x)) == ('factorable', '1st_exact', + '1st_homogeneous_coeff_best', + '1st_homogeneous_coeff_subs_indep_div_dep', + '1st_homogeneous_coeff_subs_dep_div_indep', + '1st_power_series', + 'lie_group', '1st_exact_Integral', + '1st_homogeneous_coeff_subs_indep_div_dep_Integral', + '1st_homogeneous_coeff_subs_dep_div_indep_Integral') + + +def test_issue_4825(): + 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) == \ + {'order': 0, 'default': None, 'ordered_hints': ()} + # See also issue 3793, test Z13. + raises(ValueError, lambda: dsolve(f(x).diff(x), f(y))) + assert classify_ode(f(x).diff(x), f(y), dict=True) == \ + {'order': 0, 'default': None, 'ordered_hints': ()} + + +def test_constant_renumber_order_issue_5308(): + from sympy.utilities.iterables import variations + + assert constant_renumber(C1*x + C2*y) == \ + constant_renumber(C1*y + C2*x) == \ + 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)) == e + + +def test_constant_renumber(): + e1, e2, x, y = symbols("e1:3 x y") + exprs = [e2*x, e1*x + e2*y] + + assert constant_renumber(exprs[0]) == e2*x + assert constant_renumber(exprs[0], variables=[x]) == C1*x + assert constant_renumber(exprs[0], variables=[x], newconstants=[C2]) == C2*x + assert constant_renumber(exprs, variables=[x, y]) == [C1*x, C1*y + C2*x] + assert constant_renumber(exprs, variables=[x, y], newconstants=symbols("C3:5")) == [C3*x, C3*y + C4*x] + + +def test_issue_5770(): + k = Symbol("k", real=True) + t = Symbol('t') + w = Function('w') + sol = dsolve(w(t).diff(t, 6) - k**6*w(t), w(t)) + assert len([s for s in sol.free_symbols if s.name.startswith('C')]) == 6 + assert constantsimp((C1*cos(x) + C2*cos(x))*exp(x), {C1, C2}) == \ + C1*cos(x)*exp(x) + assert constantsimp(C1*cos(x) + C2*cos(x) + C3*sin(x), {C1, C2, C3}) == \ + C1*cos(x) + C3*sin(x) + assert constantsimp(exp(C1 + x), {C1}) == C1*exp(x) + assert constantsimp(x + C1 + y, {C1, y}) == C1 + x + assert constantsimp(x + C1 + Integral(x, (x, 1, 2)), {C1}) == C1 + x + + +def test_issue_5112_5430(): + assert homogeneous_order(-log(x) + acosh(x), x) is None + assert homogeneous_order(y - log(x), x, y) is None + + +def test_issue_5095(): + f = Function('f') + raises(ValueError, lambda: dsolve(f(x).diff(x)**2, f(x), 'fdsjf')) + + +def test_homogeneous_function(): + f = Function('f') + eq1 = tan(x + f(x)) + eq2 = sin((3*x)/(4*f(x))) + eq3 = cos(x*f(x)*Rational(3, 4)) + 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(): + 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()) + obj1 = LinearCoefficients(eq1) + eq2 = rat + obj2 = LinearCoefficients(eq2) + eq3 = log(sin(rat)) + obj3 = LinearCoefficients(eq3) + ans = (4, Rational(-13, 3)) + assert obj1._linear_coeff_match(eq1, f(x)) == ans + assert obj2._linear_coeff_match(eq2, f(x)) == ans + assert obj3._linear_coeff_match(eq3, f(x)) == ans + + # no c + eq4 = (3*x)/f(x) + obj4 = LinearCoefficients(eq4) + # not x and f(x) + eq5 = (3*x + 2)/x + obj5 = LinearCoefficients(eq5) + # denom will be zero + eq6 = (3*x + 2*f(x) + 1)/(3*x + 2*f(x) + 5) + obj6 = LinearCoefficients(eq6) + # not rational coefficient + eq7 = (3*x + 2*f(x) + sqrt(2))/(3*x + 2*f(x) + 5) + obj7 = LinearCoefficients(eq7) + assert obj4._linear_coeff_match(eq4, f(x)) is None + assert obj5._linear_coeff_match(eq5, f(x)) is None + assert obj6._linear_coeff_match(eq6, f(x)) is None + assert obj7._linear_coeff_match(eq7, f(x)) is None + + +def test_constantsimp_take_problem(): + c = exp(C1) + 2 + assert len(Poly(constantsimp(exp(C1) + c + c*x, [C1])).gens) == 2 + + +def test_series(): + C1 = Symbol("C1") + eq = f(x).diff(x) - f(x) + sol = Eq(f(x), C1 + C1*x + C1*x**2/2 + C1*x**3/6 + C1*x**4/24 + + C1*x**5/120 + O(x**6)) + assert dsolve(eq, hint='1st_power_series') == sol + assert checkodesol(eq, sol, order=1)[0] + + eq = f(x).diff(x) - x*f(x) + sol = Eq(f(x), C1*x**4/8 + C1*x**2/2 + C1 + O(x**6)) + assert dsolve(eq, hint='1st_power_series') == sol + assert checkodesol(eq, sol, order=1)[0] + + eq = f(x).diff(x) - sin(x*f(x)) + sol = Eq(f(x), (x - 2)**2*(1+ sin(4))*cos(4) + (x - 2)*sin(4) + 2 + O(x**3)) + assert dsolve(eq, hint='1st_power_series', ics={f(2): 2}, n=3) == sol + # FIXME: The solution here should be O((x-2)**3) so is incorrect + #assert checkodesol(eq, sol, order=1)[0] + + +@slow +def test_2nd_power_series_ordinary(): + C1, C2 = symbols("C1 C2") + + eq = f(x).diff(x, 2) - x*f(x) + assert classify_ode(eq) == ('2nd_linear_airy', '2nd_power_series_ordinary') + sol = Eq(f(x), C2*(x**3/6 + 1) + C1*x*(x**3/12 + 1) + O(x**6)) + assert dsolve(eq, hint='2nd_power_series_ordinary') == sol + assert checkodesol(eq, sol) == (True, 0) + + sol = Eq(f(x), C2*((x + 2)**4/6 + (x + 2)**3/6 - (x + 2)**2 + 1) + + C1*(x + (x + 2)**4/12 - (x + 2)**3/3 + S(2)) + + O(x**6)) + assert dsolve(eq, hint='2nd_power_series_ordinary', x0=-2) == sol + # FIXME: Solution should be O((x+2)**6) + # assert checkodesol(eq, sol) == (True, 0) + + sol = Eq(f(x), C2*x + C1 + O(x**2)) + assert dsolve(eq, hint='2nd_power_series_ordinary', n=2) == sol + assert checkodesol(eq, sol) == (True, 0) + + eq = (1 + x**2)*(f(x).diff(x, 2)) + 2*x*(f(x).diff(x)) -2*f(x) + assert classify_ode(eq) == ('factorable', '2nd_hypergeometric', '2nd_hypergeometric_Integral', + '2nd_power_series_ordinary') + + sol = Eq(f(x), C2*(-x**4/3 + x**2 + 1) + C1*x + O(x**6)) + assert dsolve(eq, hint='2nd_power_series_ordinary') == sol + assert checkodesol(eq, sol) == (True, 0) + + eq = f(x).diff(x, 2) + x*(f(x).diff(x)) + f(x) + assert classify_ode(eq) == ('factorable', '2nd_power_series_ordinary',) + sol = Eq(f(x), C2*(x**4/8 - x**2/2 + 1) + C1*x*(-x**2/3 + 1) + O(x**6)) + assert dsolve(eq) == sol + # FIXME: checkodesol fails for this solution... + # assert checkodesol(eq, sol) == (True, 0) + + eq = f(x).diff(x, 2) + f(x).diff(x) - x*f(x) + assert classify_ode(eq) == ('2nd_power_series_ordinary',) + sol = Eq(f(x), C2*(-x**4/24 + x**3/6 + 1) + + C1*x*(x**3/24 + x**2/6 - x/2 + 1) + O(x**6)) + assert dsolve(eq) == sol + # FIXME: checkodesol fails for this solution... + # assert checkodesol(eq, sol) == (True, 0) + + eq = f(x).diff(x, 2) + x*f(x) + assert classify_ode(eq) == ('2nd_linear_airy', '2nd_power_series_ordinary') + sol = Eq(f(x), C2*(x**6/180 - x**3/6 + 1) + C1*x*(-x**3/12 + 1) + O(x**7)) + assert dsolve(eq, hint='2nd_power_series_ordinary', n=7) == sol + assert checkodesol(eq, sol) == (True, 0) + + +def test_2nd_power_series_regular(): + C1, C2, a = symbols("C1 C2 a") + eq = x**2*(f(x).diff(x, 2)) - 3*x*(f(x).diff(x)) + (4*x + 4)*f(x) + sol = Eq(f(x), C1*x**2*(-16*x**3/9 + 4*x**2 - 4*x + 1) + O(x**6)) + assert dsolve(eq, hint='2nd_power_series_regular') == sol + assert checkodesol(eq, sol) == (True, 0) + + eq = 4*x**2*(f(x).diff(x, 2)) -8*x**2*(f(x).diff(x)) + (4*x**2 + + 1)*f(x) + sol = Eq(f(x), C1*sqrt(x)*(x**4/24 + x**3/6 + x**2/2 + x + 1) + O(x**6)) + assert dsolve(eq, hint='2nd_power_series_regular') == sol + assert checkodesol(eq, sol) == (True, 0) + + eq = x**2*(f(x).diff(x, 2)) - x**2*(f(x).diff(x)) + ( + x**2 - 2)*f(x) + sol = Eq(f(x), C1*(-x**6/720 - 3*x**5/80 - x**4/8 + x**2/2 + x/2 + 1)/x + + C2*x**2*(-x**3/60 + x**2/20 + x/2 + 1) + O(x**6)) + assert dsolve(eq) == sol + assert checkodesol(eq, sol) == (True, 0) + + eq = x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**2 - Rational(1, 4))*f(x) + sol = Eq(f(x), C1*(x**4/24 - x**2/2 + 1)/sqrt(x) + + C2*sqrt(x)*(x**4/120 - x**2/6 + 1) + O(x**6)) + assert dsolve(eq, hint='2nd_power_series_regular') == sol + assert checkodesol(eq, sol) == (True, 0) + + eq = x*f(x).diff(x, 2) + f(x).diff(x) - a*x*f(x) + sol = Eq(f(x), C1*(a**2*x**4/64 + a*x**2/4 + 1) + O(x**6)) + assert dsolve(eq, f(x), hint="2nd_power_series_regular") == sol + assert checkodesol(eq, sol) == (True, 0) + + eq = f(x).diff(x, 2) + ((1 - x)/x)*f(x).diff(x) + (a/x)*f(x) + sol = Eq(f(x), C1*(-a*x**5*(a - 4)*(a - 3)*(a - 2)*(a - 1)/14400 + \ + a*x**4*(a - 3)*(a - 2)*(a - 1)/576 - a*x**3*(a - 2)*(a - 1)/36 + \ + a*x**2*(a - 1)/4 - a*x + 1) + O(x**6)) + assert dsolve(eq, f(x), hint="2nd_power_series_regular") == sol + assert checkodesol(eq, sol) == (True, 0) + + +def test_issue_15056(): + t = Symbol('t') + C3 = Symbol('C3') + assert get_numbered_constants(Symbol('C1') * Function('C2')(t)) == C3 + + +def test_issue_15913(): + eq = -C1/x - 2*x*f(x) - f(x) + Derivative(f(x), x) + sol = C2*exp(x**2 + x) + exp(x**2 + x)*Integral(C1*exp(-x**2 - x)/x, x) + assert checkodesol(eq, sol) == (True, 0) + sol = C1 + C2*exp(-x*y) + eq = Derivative(y*f(x), x) + f(x).diff(x, 2) + assert checkodesol(eq, sol, f(x)) == (True, 0) + + +def test_issue_16146(): + raises(ValueError, lambda: dsolve([f(x).diff(x), g(x).diff(x)], [f(x), g(x), h(x)])) + raises(ValueError, lambda: dsolve([f(x).diff(x), g(x).diff(x)], [f(x)])) + + +def test_dsolve_remove_redundant_solutions(): + + eq = (f(x)-2)*f(x).diff(x) + sol = Eq(f(x), C1) + assert dsolve(eq) == sol + + eq = (f(x)-sin(x))*(f(x).diff(x, 2)) + sol = {Eq(f(x), C1 + C2*x), Eq(f(x), sin(x))} + assert set(dsolve(eq)) == sol + + eq = (f(x)**2-2*f(x)+1)*f(x).diff(x, 3) + sol = Eq(f(x), C1 + C2*x + C3*x**2) + assert dsolve(eq) == sol + + +def test_issue_13060(): + A, B = symbols("A B", cls=Function) + t = Symbol("t") + eq = [Eq(Derivative(A(t), t), A(t)*B(t)), Eq(Derivative(B(t), t), A(t)*B(t))] + sol = dsolve(eq) + assert checkodesol(eq, sol) == (True, [0, 0]) + + +def test_issue_22523(): + N, s = symbols('N s') + rho = Function('rho') + # intentionally use 4.0 to confirm issue with nfloat + # works here + eqn = 4.0*N*sqrt(N - 1)*rho(s) + (4*s**2*(N - 1) + (N - 2*s*(N - 1))**2 + )*Derivative(rho(s), (s, 2)) + match = classify_ode(eqn, dict=True, hint='all') + assert match['2nd_power_series_ordinary']['terms'] == 5 + C1, C2 = symbols('C1,C2') + sol = dsolve(eqn, hint='2nd_power_series_ordinary') + # there is no r(2.0) in this result + assert filldedent(sol) == filldedent(str(''' + Eq(rho(s), C2*(1 - 4.0*s**4*sqrt(N - 1.0)/N + 0.666666666666667*s**4/N + - 2.66666666666667*s**3*sqrt(N - 1.0)/N - 2.0*s**2*sqrt(N - 1.0)/N + + 9.33333333333333*s**4*sqrt(N - 1.0)/N**2 - 0.666666666666667*s**4/N**2 + + 2.66666666666667*s**3*sqrt(N - 1.0)/N**2 - + 5.33333333333333*s**4*sqrt(N - 1.0)/N**3) + C1*s*(1.0 - + 1.33333333333333*s**3*sqrt(N - 1.0)/N - 0.666666666666667*s**2*sqrt(N + - 1.0)/N + 1.33333333333333*s**3*sqrt(N - 1.0)/N**2) + O(s**6))''')) + + +def test_issue_22604(): + x1, x2 = symbols('x1, x2', cls = Function) + t, k1, k2, m1, m2 = symbols('t k1 k2 m1 m2', real = True) + k1, k2, m1, m2 = 1, 1, 1, 1 + eq1 = Eq(m1*diff(x1(t), t, 2) + k1*x1(t) - k2*(x2(t) - x1(t)), 0) + eq2 = Eq(m2*diff(x2(t), t, 2) + k2*(x2(t) - x1(t)), 0) + eqs = [eq1, eq2] + [x1sol, x2sol] = dsolve(eqs, [x1(t), x2(t)], ics = {x1(0):0, x1(t).diff().subs(t,0):0, \ + x2(0):1, x2(t).diff().subs(t,0):0}) + assert x1sol == Eq(x1(t), sqrt(3 - sqrt(5))*(sqrt(10) + 5*sqrt(2))*cos(sqrt(2)*t*sqrt(3 - sqrt(5))/2)/20 + \ + (-5*sqrt(2) + sqrt(10))*sqrt(sqrt(5) + 3)*cos(sqrt(2)*t*sqrt(sqrt(5) + 3)/2)/20) + assert x2sol == Eq(x2(t), (sqrt(5) + 5)*cos(sqrt(2)*t*sqrt(3 - sqrt(5))/2)/10 + (5 - sqrt(5))*cos(sqrt(2)*t*sqrt(sqrt(5) + 3)/2)/10) + + +def test_issue_22462(): + for de in [ + Eq(f(x).diff(x), -20*f(x)**2 - 500*f(x)/7200), + Eq(f(x).diff(x), -2*f(x)**2 - 5*f(x)/7)]: + assert 'Bernoulli' in classify_ode(de, f(x)) + + +def test_issue_23425(): + x = symbols('x') + y = Function('y') + eq = Eq(-E**x*y(x).diff().diff() + y(x).diff(), 0) + assert classify_ode(eq) == \ + ('Liouville', 'nth_order_reducible', \ + '2nd_power_series_ordinary', 'Liouville_Integral') + + +@SKIP("too slow for @slow") +def test_issue_25820(): + x = Symbol('x') + y = Function('y') + eq = y(x)**3*y(x).diff(x, 2) + 49 + assert dsolve(eq, y(x)) is not None # doesn't raise diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_riccati.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_riccati.py new file mode 100644 index 0000000000000000000000000000000000000000..548a1ee5b5e82d88f1b0aa319af09b8b9d1d9bfe --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_riccati.py @@ -0,0 +1,877 @@ +from sympy.core.random import randint +from sympy.core.function import Function +from sympy.core.mul import Mul +from sympy.core.numbers import (I, Rational, oo) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, symbols) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.hyperbolic import tanh +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin +from sympy.polys.polytools import Poly +from sympy.simplify.ratsimp import ratsimp +from sympy.solvers.ode.subscheck import checkodesol +from sympy.testing.pytest import slow +from sympy.solvers.ode.riccati import (riccati_normal, riccati_inverse_normal, + riccati_reduced, match_riccati, inverse_transform_poly, limit_at_inf, + check_necessary_conds, val_at_inf, construct_c_case_1, + construct_c_case_2, construct_c_case_3, construct_d_case_4, + construct_d_case_5, construct_d_case_6, rational_laurent_series, + solve_riccati) + +f = Function('f') +x = symbols('x') + +# These are the functions used to generate the tests +# SHOULD NOT BE USED DIRECTLY IN TESTS + +def rand_rational(maxint): + return Rational(randint(-maxint, maxint), randint(1, maxint)) + + +def rand_poly(x, degree, maxint): + return Poly([rand_rational(maxint) for _ in range(degree+1)], x) + + +def rand_rational_function(x, degree, maxint): + degnum = randint(1, degree) + degden = randint(1, degree) + num = rand_poly(x, degnum, maxint) + den = rand_poly(x, degden, maxint) + while den == Poly(0, x): + den = rand_poly(x, degden, maxint) + return num / den + + +def find_riccati_ode(ratfunc, x, yf): + y = ratfunc + yp = y.diff(x) + q1 = rand_rational_function(x, 1, 3) + q2 = rand_rational_function(x, 1, 3) + while q2 == 0: + q2 = rand_rational_function(x, 1, 3) + q0 = ratsimp(yp - q1*y - q2*y**2) + eq = Eq(yf.diff(), q0 + q1*yf + q2*yf**2) + sol = Eq(yf, y) + assert checkodesol(eq, sol) == (True, 0) + return eq, q0, q1, q2 + + +# Testing functions start + +def test_riccati_transformation(): + """ + This function tests the transformation of the + solution of a Riccati ODE to the solution of + its corresponding normal Riccati ODE. + + Each test case 4 values - + + 1. w - The solution to be transformed + 2. b1 - The coefficient of f(x) in the ODE. + 3. b2 - The coefficient of f(x)**2 in the ODE. + 4. y - The solution to the normal Riccati ODE. + """ + tests = [ + ( + x/(x - 1), + (x**2 + 7)/3*x, + x, + -x**2/(x - 1) - x*(x**2/3 + S(7)/3)/2 - 1/(2*x) + ), + ( + (2*x + 3)/(2*x + 2), + (3 - 3*x)/(x + 1), + 5*x, + -5*x*(2*x + 3)/(2*x + 2) - (3 - 3*x)/(Mul(2, x + 1, evaluate=False)) - 1/(2*x) + ), + ( + -1/(2*x**2 - 1), + 0, + (2 - x)/(4*x - 2), + (2 - x)/((4*x - 2)*(2*x**2 - 1)) - (4*x - 2)*(Mul(-4, 2 - x, evaluate=False)/(4*x - \ + 2)**2 - 1/(4*x - 2))/(Mul(2, 2 - x, evaluate=False)) + ), + ( + x, + (8*x - 12)/(12*x + 9), + x**3/(6*x - 9), + -x**4/(6*x - 9) - (8*x - 12)/(Mul(2, 12*x + 9, evaluate=False)) - (6*x - 9)*(-6*x**3/(6*x \ + - 9)**2 + 3*x**2/(6*x - 9))/(2*x**3) + )] + for w, b1, b2, y in tests: + assert y == riccati_normal(w, x, b1, b2) + assert w == riccati_inverse_normal(y, x, b1, b2).cancel() + + # Test bp parameter in riccati_inverse_normal + tests = [ + ( + (-2*x - 1)/(2*x**2 + 2*x - 2), + -2/x, + (-x - 1)/(4*x), + 8*x**2*(1/(4*x) + (-x - 1)/(4*x**2))/(-x - 1)**2 + 4/(-x - 1), + -2*x*(-1/(4*x) - (-x - 1)/(4*x**2))/(-x - 1) - (-2*x - 1)*(-x - 1)/(4*x*(2*x**2 + 2*x \ + - 2)) + 1/x + ), + ( + 3/(2*x**2), + -2/x, + (-x - 1)/(4*x), + 8*x**2*(1/(4*x) + (-x - 1)/(4*x**2))/(-x - 1)**2 + 4/(-x - 1), + -2*x*(-1/(4*x) - (-x - 1)/(4*x**2))/(-x - 1) + 1/x - Mul(3, -x - 1, evaluate=False)/(8*x**3) + )] + for w, b1, b2, bp, y in tests: + assert y == riccati_normal(w, x, b1, b2) + assert w == riccati_inverse_normal(y, x, b1, b2, bp).cancel() + + +def test_riccati_reduced(): + """ + This function tests the transformation of a + Riccati ODE to its normal Riccati ODE. + + Each test case 2 values - + + 1. eq - A Riccati ODE. + 2. normal_eq - The normal Riccati ODE of eq. + """ + tests = [ + ( + f(x).diff(x) - x**2 - x*f(x) - x*f(x)**2, + + f(x).diff(x) + f(x)**2 + x**3 - x**2/4 - 3/(4*x**2) + ), + ( + 6*x/(2*x + 9) + f(x).diff(x) - (x + 1)*f(x)**2/x, + + -3*x**2*(1/x + (-x - 1)/x**2)**2/(4*(-x - 1)**2) + Mul(6, \ + -x - 1, evaluate=False)/(2*x + 9) + f(x)**2 + f(x).diff(x) \ + - (-1 + (x + 1)/x)/(x*(-x - 1)) + ), + ( + f(x)**2 + f(x).diff(x) - (x - 1)*f(x)/(-x - S(1)/2), + + -(2*x - 2)**2/(4*(2*x + 1)**2) + (2*x - 2)/(2*x + 1)**2 + \ + f(x)**2 + f(x).diff(x) - 1/(2*x + 1) + ), + ( + f(x).diff(x) - f(x)**2/x, + + f(x)**2 + f(x).diff(x) + 1/(4*x**2) + ), + ( + -3*(-x**2 - x + 1)/(x**2 + 6*x + 1) + f(x).diff(x) + f(x)**2/x, + + f(x)**2 + f(x).diff(x) + (3*x**2/(x**2 + 6*x + 1) + 3*x/(x**2 \ + + 6*x + 1) - 3/(x**2 + 6*x + 1))/x + 1/(4*x**2) + ), + ( + 6*x/(2*x + 9) + f(x).diff(x) - (x + 1)*f(x)/x, + + False + ), + ( + f(x)*f(x).diff(x) - 1/x + f(x)/3 + f(x)**2/(x**2 - 2), + + False + )] + for eq, normal_eq in tests: + assert normal_eq == riccati_reduced(eq, f, x) + + +def test_match_riccati(): + """ + This function tests if an ODE is Riccati or not. + + Each test case has 5 values - + + 1. eq - The Riccati ODE. + 2. match - Boolean indicating if eq is a Riccati ODE. + 3. b0 - + 4. b1 - Coefficient of f(x) in eq. + 5. b2 - Coefficient of f(x)**2 in eq. + """ + tests = [ + # Test Rational Riccati ODEs + ( + f(x).diff(x) - (405*x**3 - 882*x**2 - 78*x + 92)/(243*x**4 \ + - 945*x**3 + 846*x**2 + 180*x - 72) - 2 - f(x)**2/(3*x + 1) \ + - (S(1)/3 - x)*f(x)/(S(1)/3 - 3*x/2), + + True, + + 45*x**3/(27*x**4 - 105*x**3 + 94*x**2 + 20*x - 8) - 98*x**2/ \ + (27*x**4 - 105*x**3 + 94*x**2 + 20*x - 8) - 26*x/(81*x**4 - \ + 315*x**3 + 282*x**2 + 60*x - 24) + 2 + 92/(243*x**4 - 945*x**3 \ + + 846*x**2 + 180*x - 72), + + Mul(-1, 2 - 6*x, evaluate=False)/(9*x - 2), + + 1/(3*x + 1) + ), + ( + f(x).diff(x) + 4*x/27 - (x/3 - 1)*f(x)**2 - (2*x/3 + \ + 1)*f(x)/(3*x + 2) - S(10)/27 - (265*x**2 + 423*x + 162) \ + /(324*x**3 + 216*x**2), + + True, + + -4*x/27 + S(10)/27 + 3/(6*x**3 + 4*x**2) + 47/(36*x**2 \ + + 24*x) + 265/(324*x + 216), + + Mul(-1, -2*x - 3, evaluate=False)/(9*x + 6), + + x/3 - 1 + ), + ( + f(x).diff(x) - (304*x**5 - 745*x**4 + 631*x**3 - 876*x**2 \ + + 198*x - 108)/(36*x**6 - 216*x**5 + 477*x**4 - 567*x**3 + \ + 360*x**2 - 108*x) - S(17)/9 - (x - S(3)/2)*f(x)/(x/2 - \ + S(3)/2) - (x/3 - 3)*f(x)**2/(3*x), + + True, + + 304*x**4/(36*x**5 - 216*x**4 + 477*x**3 - 567*x**2 + 360*x - \ + 108) - 745*x**3/(36*x**5 - 216*x**4 + 477*x**3 - 567*x**2 + \ + 360*x - 108) + 631*x**2/(36*x**5 - 216*x**4 + 477*x**3 - 567* \ + x**2 + 360*x - 108) - 292*x/(12*x**5 - 72*x**4 + 159*x**3 - \ + 189*x**2 + 120*x - 36) + S(17)/9 - 12/(4*x**6 - 24*x**5 + \ + 53*x**4 - 63*x**3 + 40*x**2 - 12*x) + 22/(4*x**5 - 24*x**4 \ + + 53*x**3 - 63*x**2 + 40*x - 12), + + Mul(-1, 3 - 2*x, evaluate=False)/(x - 3), + + Mul(-1, 9 - x, evaluate=False)/(9*x) + ), + # Test Non-Rational Riccati ODEs + ( + f(x).diff(x) - x**(S(3)/2)/(x**(S(1)/2) - 2) + x**2*f(x) + \ + x*f(x)**2/(x**(S(3)/4)), + False, 0, 0, 0 + ), + ( + f(x).diff(x) - sin(x**2) + exp(x)*f(x) + log(x)*f(x)**2, + False, 0, 0, 0 + ), + ( + f(x).diff(x) - tanh(x + sqrt(x)) + f(x) + x**4*f(x)**2, + False, 0, 0, 0 + ), + # Test Non-Riccati ODEs + ( + (1 - x**2)*f(x).diff(x, 2) - 2*x*f(x).diff(x) + 20*f(x), + False, 0, 0, 0 + ), + ( + f(x).diff(x) - x**2 + x**3*f(x) + (x**2/(x + 1))*f(x)**3, + False, 0, 0, 0 + ), + ( + f(x).diff(x)*f(x)**2 + (x**2 - 1)/(x**3 + 1)*f(x) + 1/(2*x \ + + 3) + f(x)**2, + False, 0, 0, 0 + )] + for eq, res, b0, b1, b2 in tests: + match, funcs = match_riccati(eq, f, x) + assert match == res + if res: + assert [b0, b1, b2] == funcs + + +def test_val_at_inf(): + """ + This function tests the valuation of rational + function at oo. + + Each test case has 3 values - + + 1. num - Numerator of rational function. + 2. den - Denominator of rational function. + 3. val_inf - Valuation of rational function at oo + """ + tests = [ + # degree(denom) > degree(numer) + ( + Poly(10*x**3 + 8*x**2 - 13*x + 6, x), + Poly(-13*x**10 - x**9 + 5*x**8 + 7*x**7 + 10*x**6 + 6*x**5 - 7*x**4 + 11*x**3 - 8*x**2 + 5*x + 13, x), + 7 + ), + ( + Poly(1, x), + Poly(-9*x**4 + 3*x**3 + 15*x**2 - 6*x - 14, x), + 4 + ), + # degree(denom) == degree(numer) + ( + Poly(-6*x**3 - 8*x**2 + 8*x - 6, x), + Poly(-5*x**3 + 12*x**2 - 6*x - 9, x), + 0 + ), + # degree(denom) < degree(numer) + ( + Poly(12*x**8 - 12*x**7 - 11*x**6 + 8*x**5 + 3*x**4 - x**3 + x**2 - 11*x, x), + Poly(-14*x**2 + x, x), + -6 + ), + ( + Poly(5*x**6 + 9*x**5 - 11*x**4 - 9*x**3 + x**2 - 4*x + 4, x), + Poly(15*x**4 + 3*x**3 - 8*x**2 + 15*x + 12, x), + -2 + )] + for num, den, val in tests: + assert val_at_inf(num, den, x) == val + + +def test_necessary_conds(): + """ + This function tests the necessary conditions for + a Riccati ODE to have a rational particular solution. + """ + # Valuation at Infinity is an odd negative integer + assert check_necessary_conds(-3, [1, 2, 4]) == False + # Valuation at Infinity is a positive integer lesser than 2 + assert check_necessary_conds(1, [1, 2, 4]) == False + # Multiplicity of a pole is an odd integer greater than 1 + assert check_necessary_conds(2, [3, 1, 6]) == False + # All values are correct + assert check_necessary_conds(-10, [1, 2, 8, 12]) == True + + +def test_inverse_transform_poly(): + """ + This function tests the substitution x -> 1/x + in rational functions represented using Poly. + """ + fns = [ + (15*x**3 - 8*x**2 - 2*x - 6)/(18*x + 6), + + (180*x**5 + 40*x**4 + 80*x**3 + 30*x**2 - 60*x - 80)/(180*x**3 - 150*x**2 + 75*x + 12), + + (-15*x**5 - 36*x**4 + 75*x**3 - 60*x**2 - 80*x - 60)/(80*x**4 + 60*x**3 + 60*x**2 + 60*x - 80), + + (60*x**7 + 24*x**6 - 15*x**5 - 20*x**4 + 30*x**2 + 100*x - 60)/(240*x**2 - 20*x - 30), + + (30*x**6 - 12*x**5 + 15*x**4 - 15*x**2 + 10*x + 60)/(3*x**10 - 45*x**9 + 15*x**5 + 15*x**4 - 5*x**3 \ + + 15*x**2 + 45*x - 15) + ] + for f in fns: + num, den = [Poly(e, x) for e in f.as_numer_denom()] + num, den = inverse_transform_poly(num, den, x) + assert f.subs(x, 1/x).cancel() == num/den + + +def test_limit_at_inf(): + """ + This function tests the limit at oo of a + rational function. + + Each test case has 3 values - + + 1. num - Numerator of rational function. + 2. den - Denominator of rational function. + 3. limit_at_inf - Limit of rational function at oo + """ + tests = [ + # deg(denom) > deg(numer) + ( + Poly(-12*x**2 + 20*x + 32, x), + Poly(32*x**3 + 72*x**2 + 3*x - 32, x), + 0 + ), + # deg(denom) < deg(numer) + ( + Poly(1260*x**4 - 1260*x**3 - 700*x**2 - 1260*x + 1400, x), + Poly(6300*x**3 - 1575*x**2 + 756*x - 540, x), + oo + ), + # deg(denom) < deg(numer), one of the leading coefficients is negative + ( + Poly(-735*x**8 - 1400*x**7 + 1680*x**6 - 315*x**5 - 600*x**4 + 840*x**3 - 525*x**2 \ + + 630*x + 3780, x), + Poly(1008*x**7 - 2940*x**6 - 84*x**5 + 2940*x**4 - 420*x**3 + 1512*x**2 + 105*x + 168, x), + -oo + ), + # deg(denom) == deg(numer) + ( + Poly(105*x**7 - 960*x**6 + 60*x**5 + 60*x**4 - 80*x**3 + 45*x**2 + 120*x + 15, x), + Poly(735*x**7 + 525*x**6 + 720*x**5 + 720*x**4 - 8400*x**3 - 2520*x**2 + 2800*x + 280, x), + S(1)/7 + ), + ( + Poly(288*x**4 - 450*x**3 + 280*x**2 - 900*x - 90, x), + Poly(607*x**4 + 840*x**3 - 1050*x**2 + 420*x + 420, x), + S(288)/607 + )] + for num, den, lim in tests: + assert limit_at_inf(num, den, x) == lim + + +def test_construct_c_case_1(): + """ + This function tests the Case 1 in the step + to calculate coefficients of c-vectors. + + Each test case has 4 values - + + 1. num - Numerator of the rational function a(x). + 2. den - Denominator of the rational function a(x). + 3. pole - Pole of a(x) for which c-vector is being + calculated. + 4. c - The c-vector for the pole. + """ + tests = [ + ( + Poly(-3*x**3 + 3*x**2 + 4*x - 5, x, extension=True), + Poly(4*x**8 + 16*x**7 + 9*x**5 + 12*x**4 + 6*x**3 + 12*x**2, x, extension=True), + S(0), + [[S(1)/2 + sqrt(6)*I/6], [S(1)/2 - sqrt(6)*I/6]] + ), + ( + Poly(1200*x**3 + 1440*x**2 + 816*x + 560, x, extension=True), + Poly(128*x**5 - 656*x**4 + 1264*x**3 - 1125*x**2 + 385*x + 49, x, extension=True), + S(7)/4, + [[S(1)/2 + sqrt(16367978)/634], [S(1)/2 - sqrt(16367978)/634]] + ), + ( + Poly(4*x + 2, x, extension=True), + Poly(18*x**4 + (2 - 18*sqrt(3))*x**3 + (14 - 11*sqrt(3))*x**2 + (4 - 6*sqrt(3))*x \ + + 8*sqrt(3) + 16, x, domain='QQ'), + (S(1) + sqrt(3))/2, + [[S(1)/2 + sqrt(Mul(4, 2*sqrt(3) + 4, evaluate=False)/(19*sqrt(3) + 44) + 1)/2], \ + [S(1)/2 - sqrt(Mul(4, 2*sqrt(3) + 4, evaluate=False)/(19*sqrt(3) + 44) + 1)/2]] + )] + for num, den, pole, c in tests: + assert construct_c_case_1(num, den, x, pole) == c + + +def test_construct_c_case_2(): + """ + This function tests the Case 2 in the step + to calculate coefficients of c-vectors. + + Each test case has 5 values - + + 1. num - Numerator of the rational function a(x). + 2. den - Denominator of the rational function a(x). + 3. pole - Pole of a(x) for which c-vector is being + calculated. + 4. mul - The multiplicity of the pole. + 5. c - The c-vector for the pole. + """ + tests = [ + # Testing poles with multiplicity 2 + ( + Poly(1, x, extension=True), + Poly((x - 1)**2*(x - 2), x, extension=True), + 1, 2, + [[-I*(-1 - I)/2], [I*(-1 + I)/2]] + ), + ( + Poly(3*x**5 - 12*x**4 - 7*x**3 + 1, x, extension=True), + Poly((3*x - 1)**2*(x + 2)**2, x, extension=True), + S(1)/3, 2, + [[-S(89)/98], [-S(9)/98]] + ), + # Testing poles with multiplicity 4 + ( + Poly(x**3 - x**2 + 4*x, x, extension=True), + Poly((x - 2)**4*(x + 5)**2, x, extension=True), + 2, 4, + [[7*sqrt(3)*(S(60)/343 - 4*sqrt(3)/7)/12, 2*sqrt(3)/7], \ + [-7*sqrt(3)*(S(60)/343 + 4*sqrt(3)/7)/12, -2*sqrt(3)/7]] + ), + ( + Poly(3*x**5 + x**4 + 3, x, extension=True), + Poly((4*x + 1)**4*(x + 2), x, extension=True), + -S(1)/4, 4, + [[128*sqrt(439)*(-sqrt(439)/128 - S(55)/14336)/439, sqrt(439)/256], \ + [-128*sqrt(439)*(sqrt(439)/128 - S(55)/14336)/439, -sqrt(439)/256]] + ), + # Testing poles with multiplicity 6 + ( + Poly(x**3 + 2, x, extension=True), + Poly((3*x - 1)**6*(x**2 + 1), x, extension=True), + S(1)/3, 6, + [[27*sqrt(66)*(-sqrt(66)/54 - S(131)/267300)/22, -2*sqrt(66)/1485, sqrt(66)/162], \ + [-27*sqrt(66)*(sqrt(66)/54 - S(131)/267300)/22, 2*sqrt(66)/1485, -sqrt(66)/162]] + ), + ( + Poly(x**2 + 12, x, extension=True), + Poly((x - sqrt(2))**6, x, extension=True), + sqrt(2), 6, + [[sqrt(14)*(S(6)/7 - 3*sqrt(14))/28, sqrt(7)/7, sqrt(14)], \ + [-sqrt(14)*(S(6)/7 + 3*sqrt(14))/28, -sqrt(7)/7, -sqrt(14)]] + )] + for num, den, pole, mul, c in tests: + assert construct_c_case_2(num, den, x, pole, mul) == c + + +def test_construct_c_case_3(): + """ + This function tests the Case 3 in the step + to calculate coefficients of c-vectors. + """ + assert construct_c_case_3() == [[1]] + + +def test_construct_d_case_4(): + """ + This function tests the Case 4 in the step + to calculate coefficients of the d-vector. + + Each test case has 4 values - + + 1. num - Numerator of the rational function a(x). + 2. den - Denominator of the rational function a(x). + 3. mul - Multiplicity of oo as a pole. + 4. d - The d-vector. + """ + tests = [ + # Tests with multiplicity at oo = 2 + ( + Poly(-x**5 - 2*x**4 + 4*x**3 + 2*x + 5, x, extension=True), + Poly(9*x**3 - 2*x**2 + 10*x - 2, x, extension=True), + 2, + [[10*I/27, I/3, -3*I*(S(158)/243 - I/3)/2], \ + [-10*I/27, -I/3, 3*I*(S(158)/243 + I/3)/2]] + ), + ( + Poly(-x**6 + 9*x**5 + 5*x**4 + 6*x**3 + 5*x**2 + 6*x + 7, x, extension=True), + Poly(x**4 + 3*x**3 + 12*x**2 - x + 7, x, extension=True), + 2, + [[-6*I, I, -I*(17 - I)/2], [6*I, -I, I*(17 + I)/2]] + ), + # Tests with multiplicity at oo = 4 + ( + Poly(-2*x**6 - x**5 - x**4 - 2*x**3 - x**2 - 3*x - 3, x, extension=True), + Poly(3*x**2 + 10*x + 7, x, extension=True), + 4, + [[269*sqrt(6)*I/288, -17*sqrt(6)*I/36, sqrt(6)*I/3, -sqrt(6)*I*(S(16969)/2592 \ + - 2*sqrt(6)*I/3)/4], [-269*sqrt(6)*I/288, 17*sqrt(6)*I/36, -sqrt(6)*I/3, \ + sqrt(6)*I*(S(16969)/2592 + 2*sqrt(6)*I/3)/4]] + ), + ( + Poly(-3*x**5 - 3*x**4 - 3*x**3 - x**2 - 1, x, extension=True), + Poly(12*x - 2, x, extension=True), + 4, + [[41*I/192, 7*I/24, I/2, -I*(-S(59)/6912 - I)], \ + [-41*I/192, -7*I/24, -I/2, I*(-S(59)/6912 + I)]] + ), + # Tests with multiplicity at oo = 4 + ( + Poly(-x**7 - x**5 - x**4 - x**2 - x, x, extension=True), + Poly(x + 2, x, extension=True), + 6, + [[-5*I/2, 2*I, -I, I, -I*(-9 - 3*I)/2], [5*I/2, -2*I, I, -I, I*(-9 + 3*I)/2]] + ), + ( + Poly(-x**7 - x**6 - 2*x**5 - 2*x**4 - x**3 - x**2 + 2*x - 2, x, extension=True), + Poly(2*x - 2, x, extension=True), + 6, + [[3*sqrt(2)*I/4, 3*sqrt(2)*I/4, sqrt(2)*I/2, sqrt(2)*I/2, -sqrt(2)*I*(-S(7)/8 - \ + 3*sqrt(2)*I/2)/2], [-3*sqrt(2)*I/4, -3*sqrt(2)*I/4, -sqrt(2)*I/2, -sqrt(2)*I/2, \ + sqrt(2)*I*(-S(7)/8 + 3*sqrt(2)*I/2)/2]] + )] + for num, den, mul, d in tests: + ser = rational_laurent_series(num, den, x, oo, mul, 1) + assert construct_d_case_4(ser, mul//2) == d + + +def test_construct_d_case_5(): + """ + This function tests the Case 5 in the step + to calculate coefficients of the d-vector. + + Each test case has 3 values - + + 1. num - Numerator of the rational function a(x). + 2. den - Denominator of the rational function a(x). + 3. d - The d-vector. + """ + tests = [ + ( + Poly(2*x**3 + x**2 + x - 2, x, extension=True), + Poly(9*x**3 + 5*x**2 + 2*x - 1, x, extension=True), + [[sqrt(2)/3, -sqrt(2)/108], [-sqrt(2)/3, sqrt(2)/108]] + ), + ( + Poly(3*x**5 + x**4 - x**3 + x**2 - 2*x - 2, x, domain='ZZ'), + Poly(9*x**5 + 7*x**4 + 3*x**3 + 2*x**2 + 5*x + 7, x, domain='ZZ'), + [[sqrt(3)/3, -2*sqrt(3)/27], [-sqrt(3)/3, 2*sqrt(3)/27]] + ), + ( + Poly(x**2 - x + 1, x, domain='ZZ'), + Poly(3*x**2 + 7*x + 3, x, domain='ZZ'), + [[sqrt(3)/3, -5*sqrt(3)/9], [-sqrt(3)/3, 5*sqrt(3)/9]] + )] + for num, den, d in tests: + # Multiplicity of oo is 0 + ser = rational_laurent_series(num, den, x, oo, 0, 1) + assert construct_d_case_5(ser) == d + + +def test_construct_d_case_6(): + """ + This function tests the Case 6 in the step + to calculate coefficients of the d-vector. + + Each test case has 3 values - + + 1. num - Numerator of the rational function a(x). + 2. den - Denominator of the rational function a(x). + 3. d - The d-vector. + """ + tests = [ + ( + Poly(-2*x**2 - 5, x, domain='ZZ'), + Poly(4*x**4 + 2*x**2 + 10*x + 2, x, domain='ZZ'), + [[S(1)/2 + I/2], [S(1)/2 - I/2]] + ), + ( + Poly(-2*x**3 - 4*x**2 - 2*x - 5, x, domain='ZZ'), + Poly(x**6 - x**5 + 2*x**4 - 4*x**3 - 5*x**2 - 5*x + 9, x, domain='ZZ'), + [[1], [0]] + ), + ( + Poly(-5*x**3 + x**2 + 11*x + 12, x, domain='ZZ'), + Poly(6*x**8 - 26*x**7 - 27*x**6 - 10*x**5 - 44*x**4 - 46*x**3 - 34*x**2 \ + - 27*x - 42, x, domain='ZZ'), + [[1], [0]] + )] + for num, den, d in tests: + assert construct_d_case_6(num, den, x) == d + + +def test_rational_laurent_series(): + """ + This function tests the computation of coefficients + of Laurent series of a rational function. + + Each test case has 5 values - + + 1. num - Numerator of the rational function. + 2. den - Denominator of the rational function. + 3. x0 - Point about which Laurent series is to + be calculated. + 4. mul - Multiplicity of x0 if x0 is a pole of + the rational function (0 otherwise). + 5. n - Number of terms upto which the series + is to be calculated. + """ + tests = [ + # Laurent series about simple pole (Multiplicity = 1) + ( + Poly(x**2 - 3*x + 9, x, extension=True), + Poly(x**2 - x, x, extension=True), + S(1), 1, 6, + {1: 7, 0: -8, -1: 9, -2: -9, -3: 9, -4: -9} + ), + # Laurent series about multiple pole (Multiplicity > 1) + ( + Poly(64*x**3 - 1728*x + 1216, x, extension=True), + Poly(64*x**4 - 80*x**3 - 831*x**2 + 1809*x - 972, x, extension=True), + S(9)/8, 2, 3, + {0: S(32177152)/46521675, 2: S(1019)/984, -1: S(11947565056)/28610830125, \ + 1: S(209149)/75645} + ), + ( + Poly(1, x, extension=True), + Poly(x**5 + (-4*sqrt(2) - 1)*x**4 + (4*sqrt(2) + 12)*x**3 + (-12 - 8*sqrt(2))*x**2 \ + + (4 + 8*sqrt(2))*x - 4, x, extension=True), + sqrt(2), 4, 6, + {4: 1 + sqrt(2), 3: -3 - 2*sqrt(2), 2: Mul(-1, -3 - 2*sqrt(2), evaluate=False)/(-1 \ + + sqrt(2)), 1: (-3 - 2*sqrt(2))/(-1 + sqrt(2))**2, 0: Mul(-1, -3 - 2*sqrt(2), evaluate=False \ + )/(-1 + sqrt(2))**3, -1: (-3 - 2*sqrt(2))/(-1 + sqrt(2))**4} + ), + # Laurent series about oo + ( + Poly(x**5 - 4*x**3 + 6*x**2 + 10*x - 13, x, extension=True), + Poly(x**2 - 5, x, extension=True), + oo, 3, 6, + {3: 1, 2: 0, 1: 1, 0: 6, -1: 15, -2: 17} + ), + # Laurent series at x0 where x0 is not a pole of the function + # Using multiplicity as 0 (as x0 will not be a pole) + ( + Poly(3*x**3 + 6*x**2 - 2*x + 5, x, extension=True), + Poly(9*x**4 - x**3 - 3*x**2 + 4*x + 4, x, extension=True), + S(2)/5, 0, 1, + {0: S(3345)/3304, -1: S(399325)/2729104, -2: S(3926413375)/4508479808, \ + -3: S(-5000852751875)/1862002160704, -4: S(-6683640101653125)/6152055138966016} + ), + ( + Poly(-7*x**2 + 2*x - 4, x, extension=True), + Poly(7*x**5 + 9*x**4 + 8*x**3 + 3*x**2 + 6*x + 9, x, extension=True), + oo, 0, 6, + {0: 0, -2: 0, -5: -S(71)/49, -1: 0, -3: -1, -4: S(11)/7} + )] + for num, den, x0, mul, n, ser in tests: + assert ser == rational_laurent_series(num, den, x, x0, mul, n) + + +def check_dummy_sol(eq, solse, dummy_sym): + """ + Helper function to check if actual solution + matches expected solution if actual solution + contains dummy symbols. + """ + if isinstance(eq, Eq): + eq = eq.lhs - eq.rhs + _, funcs = match_riccati(eq, f, x) + + sols = solve_riccati(f(x), x, *funcs) + C1 = Dummy('C1') + sols = [sol.subs(C1, dummy_sym) for sol in sols] + + assert all(x[0] for x in checkodesol(eq, sols)) + assert all(s1.dummy_eq(s2, dummy_sym) for s1, s2 in zip(sols, solse)) + + +def test_solve_riccati(): + """ + This function tests the computation of rational + particular solutions for a Riccati ODE. + + Each test case has 2 values - + + 1. eq - Riccati ODE to be solved. + 2. sol - Expected solution to the equation. + + Some examples have been taken from the paper - "Statistical Investigation of + First-Order Algebraic ODEs and their Rational General Solutions" by + Georg Grasegger, N. Thieu Vo, Franz Winkler + + https://www3.risc.jku.at/publications/download/risc_5197/RISCReport15-19.pdf + """ + C0 = Dummy('C0') + # Type: 1st Order Rational Riccati, dy/dx = a + b*y + c*y**2, + # a, b, c are rational functions of x + + tests = [ + # a(x) is a constant + ( + Eq(f(x).diff(x) + f(x)**2 - 2, 0), + [Eq(f(x), sqrt(2)), Eq(f(x), -sqrt(2))] + ), + # a(x) is a constant + ( + f(x)**2 + f(x).diff(x) + 4*f(x)/x + 2/x**2, + [Eq(f(x), (-2*C0 - x)/(C0*x + x**2))] + ), + # a(x) is a constant + ( + 2*x**2*f(x).diff(x) - x*(4*f(x) + f(x).diff(x) - 4) + (f(x) - 1)*f(x), + [Eq(f(x), (C0 + 2*x**2)/(C0 + x))] + ), + # Pole with multiplicity 1 + ( + Eq(f(x).diff(x), -f(x)**2 - 2/(x**3 - x**2)), + [Eq(f(x), 1/(x**2 - x))] + ), + # One pole of multiplicity 2 + ( + x**2 - (2*x + 1/x)*f(x) + f(x)**2 + f(x).diff(x), + [Eq(f(x), (C0*x + x**3 + 2*x)/(C0 + x**2)), Eq(f(x), x)] + ), + ( + x**4*f(x).diff(x) + x**2 - x*(2*f(x)**2 + f(x).diff(x)) + f(x), + [Eq(f(x), (C0*x**2 + x)/(C0 + x**2)), Eq(f(x), x**2)] + ), + # Multiple poles of multiplicity 2 + ( + -f(x)**2 + f(x).diff(x) + (15*x**2 - 20*x + 7)/((x - 1)**2*(2*x \ + - 1)**2), + [Eq(f(x), (9*C0*x - 6*C0 - 15*x**5 + 60*x**4 - 94*x**3 + 72*x**2 \ + - 30*x + 6)/(6*C0*x**2 - 9*C0*x + 3*C0 + 6*x**6 - 29*x**5 + \ + 57*x**4 - 58*x**3 + 30*x**2 - 6*x)), Eq(f(x), (3*x - 2)/(2*x**2 \ + - 3*x + 1))] + ), + # Regression: Poles with even multiplicity > 2 fixed + ( + f(x)**2 + f(x).diff(x) - (4*x**6 - 8*x**5 + 12*x**4 + 4*x**3 + \ + 7*x**2 - 20*x + 4)/(4*x**4), + [Eq(f(x), (2*x**5 - 2*x**4 - x**3 + 4*x**2 + 3*x - 2)/(2*x**4 \ + - 2*x**2))] + ), + # Regression: Poles with even multiplicity > 2 fixed + ( + Eq(f(x).diff(x), (-x**6 + 15*x**4 - 40*x**3 + 45*x**2 - 24*x + 4)/\ + (x**12 - 12*x**11 + 66*x**10 - 220*x**9 + 495*x**8 - 792*x**7 + 924*x**6 - \ + 792*x**5 + 495*x**4 - 220*x**3 + 66*x**2 - 12*x + 1) + f(x)**2 + f(x)), + [Eq(f(x), 1/(x**6 - 6*x**5 + 15*x**4 - 20*x**3 + 15*x**2 - 6*x + 1))] + ), + # More than 2 poles with multiplicity 2 + # Regression: Fixed mistake in necessary conditions + ( + Eq(f(x).diff(x), x*f(x) + 2*x + (3*x - 2)*f(x)**2/(4*x + 2) + \ + (8*x**2 - 7*x + 26)/(16*x**3 - 24*x**2 + 8) - S(3)/2), + [Eq(f(x), (1 - 4*x)/(2*x - 2))] + ), + # Regression: Fixed mistake in necessary conditions + ( + Eq(f(x).diff(x), (-12*x**2 - 48*x - 15)/(24*x**3 - 40*x**2 + 8*x + 8) \ + + 3*f(x)**2/(6*x + 2)), + [Eq(f(x), (2*x + 1)/(2*x - 2))] + ), + # Imaginary poles + ( + f(x).diff(x) + (3*x**2 + 1)*f(x)**2/x + (6*x**2 - x + 3)*f(x)/(x*(x \ + - 1)) + (3*x**2 - 2*x + 2)/(x*(x - 1)**2), + [Eq(f(x), (-C0 - x**3 + x**2 - 2*x)/(C0*x - C0 + x**4 - x**3 + x**2 \ + - x)), Eq(f(x), -1/(x - 1))], + ), + # Imaginary coefficients in equation + ( + f(x).diff(x) - 2*I*(f(x)**2 + 1)/x, + [Eq(f(x), (-I*C0 + I*x**4)/(C0 + x**4)), Eq(f(x), -I)] + ), + # Regression: linsolve returning empty solution + # Large value of m (> 10) + ( + Eq(f(x).diff(x), x*f(x)/(S(3)/2 - 2*x) + (x/2 - S(1)/3)*f(x)**2/\ + (2*x/3 - S(1)/2) - S(5)/4 + (281*x**2 - 1260*x + 756)/(16*x**3 - 12*x**2)), + [Eq(f(x), (9 - x)/x), Eq(f(x), (40*x**14 + 28*x**13 + 420*x**12 + 2940*x**11 + \ + 18480*x**10 + 103950*x**9 + 519750*x**8 + 2286900*x**7 + 8731800*x**6 + 28378350*\ + x**5 + 76403250*x**4 + 163721250*x**3 + 261954000*x**2 + 278326125*x + 147349125)/\ + ((24*x**14 + 140*x**13 + 840*x**12 + 4620*x**11 + 23100*x**10 + 103950*x**9 + \ + 415800*x**8 + 1455300*x**7 + 4365900*x**6 + 10914750*x**5 + 21829500*x**4 + 32744250\ + *x**3 + 32744250*x**2 + 16372125*x)))] + ), + # Regression: Fixed bug due to a typo in paper + ( + Eq(f(x).diff(x), 18*x**3 + 18*x**2 + (-x/2 - S(1)/2)*f(x)**2 + 6), + [Eq(f(x), 6*x)] + ), + # Regression: Fixed bug due to a typo in paper + ( + Eq(f(x).diff(x), -3*x**3/4 + 15*x/2 + (x/3 - S(4)/3)*f(x)**2 \ + + 9 + (1 - x)*f(x)/x + 3/x), + [Eq(f(x), -3*x/2 - 3)] + )] + for eq, sol in tests: + check_dummy_sol(eq, sol, C0) + + +@slow +def test_solve_riccati_slow(): + """ + This function tests the computation of rational + particular solutions for a Riccati ODE. + + Each test case has 2 values - + + 1. eq - Riccati ODE to be solved. + 2. sol - Expected solution to the equation. + """ + C0 = Dummy('C0') + tests = [ + # Very large values of m (989 and 991) + ( + Eq(f(x).diff(x), (1 - x)*f(x)/(x - 3) + (2 - 12*x)*f(x)**2/(2*x - 9) + \ + (54924*x**3 - 405264*x**2 + 1084347*x - 1087533)/(8*x**4 - 132*x**3 + 810*x**2 - \ + 2187*x + 2187) + 495), + [Eq(f(x), (18*x + 6)/(2*x - 9))] + )] + for eq, sol in tests: + check_dummy_sol(eq, sol, C0) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_single.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_single.py new file mode 100644 index 0000000000000000000000000000000000000000..45b38029e97b9e74236c45f2f3efb6aa87c26e5c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_single.py @@ -0,0 +1,2902 @@ +# +# The main tests for the code in single.py are currently located in +# sympy/solvers/tests/test_ode.py +# +r""" +This File contains test functions for the individual hints used for solving ODEs. + +Examples of each solver will be returned by _get_examples_ode_sol_name_of_solver. + +Examples should have a key 'XFAIL' which stores the list of hints if they are +expected to fail for that hint. + +Functions that are for internal use: + +1) _ode_solver_test(ode_examples) - It takes a dictionary of examples returned by + _get_examples method and tests them with their respective hints. + +2) _test_particular_example(our_hint, example_name) - It tests the ODE example corresponding + to the hint provided. + +3) _test_all_hints(runxfail=False) - It is used to test all the examples with all the hints + currently implemented. It calls _test_all_examples_for_one_hint() which outputs whether the + given hint functions properly if it classifies the ODE example. + If runxfail flag is set to True then it will only test the examples which are expected to fail. + + Everytime the ODE of a particular solver is added, _test_all_hints() is to be executed to find + the possible failures of different solver hints. + +4) _test_all_examples_for_one_hint(our_hint, all_examples) - It takes hint as argument and checks + this hint against all the ODE examples and gives output as the number of ODEs matched, number + of ODEs which were solved correctly, list of ODEs which gives incorrect solution and list of + ODEs which raises exception. + +""" +from sympy.core.function import (Derivative, diff) +from sympy.core.mul import Mul +from sympy.core.numbers import (E, I, Rational, pi) +from sympy.core.relational import (Eq, Ne) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, symbols) +from sympy.functions.elementary.complexes import (im, re) +from sympy.functions.elementary.exponential import (LambertW, exp, log) +from sympy.functions.elementary.hyperbolic import (asinh, cosh, sinh, tanh) +from sympy.functions.elementary.miscellaneous import (cbrt, sqrt) +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (acos, asin, atan, cos, sec, sin, tan) +from sympy.functions.special.error_functions import (Ei, erfi) +from sympy.functions.special.hyper import hyper +from sympy.integrals.integrals import (Integral, integrate) +from sympy.polys.rootoftools import rootof + +from sympy.core import Function, Symbol +from sympy.functions import airyai, airybi, besselj, bessely, lowergamma +from sympy.integrals.risch import NonElementaryIntegral +from sympy.solvers.ode import classify_ode, dsolve +from sympy.solvers.ode.ode import allhints, _remove_redundant_solutions +from sympy.solvers.ode.single import (FirstLinear, ODEMatchError, + SingleODEProblem, SingleODESolver, NthOrderReducible) + +from sympy.solvers.ode.subscheck import checkodesol + +from sympy.testing.pytest import raises, slow +import traceback + + +x = Symbol('x') +u = Symbol('u') +_u = Dummy('u') +y = Symbol('y') +f = Function('f') +g = Function('g') +C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 = symbols('C1:11') +a, b, c = symbols('a b c') + + +hint_message = """\ +Hint did not match the example {example}. + +The ODE is: +{eq}. + +The expected hint was +{our_hint}\ +""" + +expected_sol_message = """\ +Different solution found from dsolve for example {example}. + +The ODE is: +{eq} + +The expected solution was +{sol} + +What dsolve returned is: +{dsolve_sol}\ +""" + +checkodesol_msg = """\ +solution found is not correct for example {example}. + +The ODE is: +{eq}\ +""" + +dsol_incorrect_msg = """\ +solution returned by dsolve is incorrect when using {hint}. + +The ODE is: +{eq} + +The expected solution was +{sol} + +what dsolve returned is: +{dsolve_sol} + +You can test this with: + +eq = {eq} +sol = dsolve(eq, hint='{hint}') +print(sol) +print(checkodesol(eq, sol)) + +""" + +exception_msg = """\ +dsolve raised exception : {e} + +when using {hint} for the example {example} + +You can test this with: + +from sympy.solvers.ode.tests.test_single import _test_an_example + +_test_an_example('{hint}', example_name = '{example}') + +The ODE is: +{eq} + +\ +""" + +check_hint_msg = """\ +Tested hint was : {hint} + +Total of {matched} examples matched with this hint. + +Out of which {solve} gave correct results. + +Examples which gave incorrect results are {unsolve}. + +Examples which raised exceptions are {exceptions} +\ +""" + + +def _add_example_keys(func): + def inner(): + solver=func() + examples=[] + for example in solver['examples']: + temp={ + 'eq': solver['examples'][example]['eq'], + 'sol': solver['examples'][example]['sol'], + 'XFAIL': solver['examples'][example].get('XFAIL', []), + 'func': solver['examples'][example].get('func',solver['func']), + 'example_name': example, + 'slow': solver['examples'][example].get('slow', False), + 'simplify_flag':solver['examples'][example].get('simplify_flag',True), + 'checkodesol_XFAIL': solver['examples'][example].get('checkodesol_XFAIL', False), + 'dsolve_too_slow':solver['examples'][example].get('dsolve_too_slow',False), + 'checkodesol_too_slow':solver['examples'][example].get('checkodesol_too_slow',False), + 'hint': solver['hint'] + } + examples.append(temp) + return examples + return inner() + + +def _ode_solver_test(ode_examples, run_slow_test=False): + for example in ode_examples: + if ((not run_slow_test) and example['slow']) or (run_slow_test and (not example['slow'])): + continue + + result = _test_particular_example(example['hint'], example, solver_flag=True) + if result['xpass_msg'] != "": + print(result['xpass_msg']) + + +def _test_all_hints(runxfail=False): + all_hints = list(allhints)+["default"] + all_examples = _get_all_examples() + + for our_hint in all_hints: + if our_hint.endswith('_Integral') or 'series' in our_hint: + continue + _test_all_examples_for_one_hint(our_hint, all_examples, runxfail) + + +def _test_dummy_sol(expected_sol,dsolve_sol): + if type(dsolve_sol)==list: + return any(expected_sol.dummy_eq(sub_dsol) for sub_dsol in dsolve_sol) + else: + return expected_sol.dummy_eq(dsolve_sol) + + +def _test_an_example(our_hint, example_name): + all_examples = _get_all_examples() + for example in all_examples: + if example['example_name'] == example_name: + _test_particular_example(our_hint, example) + + +def _test_particular_example(our_hint, ode_example, solver_flag=False): + eq = ode_example['eq'] + expected_sol = ode_example['sol'] + example = ode_example['example_name'] + xfail = our_hint in ode_example['XFAIL'] + func = ode_example['func'] + result = {'msg': '', 'xpass_msg': ''} + simplify_flag=ode_example['simplify_flag'] + checkodesol_XFAIL = ode_example['checkodesol_XFAIL'] + dsolve_too_slow = ode_example['dsolve_too_slow'] + checkodesol_too_slow = ode_example['checkodesol_too_slow'] + xpass = True + if solver_flag: + if our_hint not in classify_ode(eq, func): + message = hint_message.format(example=example, eq=eq, our_hint=our_hint) + raise AssertionError(message) + + if our_hint in classify_ode(eq, func): + result['match_list'] = example + try: + if not (dsolve_too_slow): + dsolve_sol = dsolve(eq, func, simplify=simplify_flag,hint=our_hint) + else: + if len(expected_sol)==1: + dsolve_sol = expected_sol[0] + else: + dsolve_sol = expected_sol + + except Exception as e: + dsolve_sol = [] + result['exception_list'] = example + if not solver_flag: + traceback.print_exc() + result['msg'] = exception_msg.format(e=str(e), hint=our_hint, example=example, eq=eq) + if solver_flag and not xfail: + print(result['msg']) + raise + xpass = False + + if solver_flag and dsolve_sol!=[]: + expect_sol_check = False + if type(dsolve_sol)==list: + for sub_sol in expected_sol: + if sub_sol.has(Dummy): + expect_sol_check = not _test_dummy_sol(sub_sol, dsolve_sol) + else: + expect_sol_check = sub_sol not in dsolve_sol + if expect_sol_check: + break + else: + expect_sol_check = dsolve_sol not in expected_sol + for sub_sol in expected_sol: + if sub_sol.has(Dummy): + expect_sol_check = not _test_dummy_sol(sub_sol, dsolve_sol) + + if expect_sol_check: + message = expected_sol_message.format(example=example, eq=eq, sol=expected_sol, dsolve_sol=dsolve_sol) + raise AssertionError(message) + + expected_checkodesol = [(True, 0) for i in range(len(expected_sol))] + if len(expected_sol) == 1: + expected_checkodesol = (True, 0) + + if not checkodesol_too_slow: + if not checkodesol_XFAIL: + if checkodesol(eq, dsolve_sol, func, solve_for_func=False) != expected_checkodesol: + result['unsolve_list'] = example + xpass = False + message = dsol_incorrect_msg.format(hint=our_hint, eq=eq, sol=expected_sol,dsolve_sol=dsolve_sol) + if solver_flag: + message = checkodesol_msg.format(example=example, eq=eq) + raise AssertionError(message) + else: + result['msg'] = 'AssertionError: ' + message + + if xpass and xfail: + result['xpass_msg'] = example + "is now passing for the hint" + our_hint + return result + + +def _test_all_examples_for_one_hint(our_hint, all_examples=[], runxfail=None): + if all_examples == []: + all_examples = _get_all_examples() + match_list, unsolve_list, exception_list = [], [], [] + for ode_example in all_examples: + xfail = our_hint in ode_example['XFAIL'] + if runxfail and not xfail: + continue + if xfail: + continue + result = _test_particular_example(our_hint, ode_example) + match_list += result.get('match_list',[]) + unsolve_list += result.get('unsolve_list',[]) + exception_list += result.get('exception_list',[]) + if runxfail is not None: + msg = result['msg'] + if msg!='': + print(result['msg']) + # print(result.get('xpass_msg','')) + if runxfail is None: + match_count = len(match_list) + solved = len(match_list)-len(unsolve_list)-len(exception_list) + msg = check_hint_msg.format(hint=our_hint, matched=match_count, solve=solved, unsolve=unsolve_list, exceptions=exception_list) + print(msg) + + +def test_SingleODESolver(): + # Test that not implemented methods give NotImplementedError + # Subclasses should override these methods. + problem = SingleODEProblem(f(x).diff(x), f(x), x) + solver = SingleODESolver(problem) + raises(NotImplementedError, lambda: solver.matches()) + raises(NotImplementedError, lambda: solver.get_general_solution()) + raises(NotImplementedError, lambda: solver._matches()) + raises(NotImplementedError, lambda: solver._get_general_solution()) + + # This ODE can not be solved by the FirstLinear solver. Here we test that + # it does not match and the asking for a general solution gives + # ODEMatchError + + problem = SingleODEProblem(f(x).diff(x) + f(x)*f(x), f(x), x) + + solver = FirstLinear(problem) + raises(ODEMatchError, lambda: solver.get_general_solution()) + + solver = FirstLinear(problem) + assert solver.matches() is False + + #These are just test for order of ODE + + problem = SingleODEProblem(f(x).diff(x) + f(x), f(x), x) + assert problem.order == 1 + + problem = SingleODEProblem(f(x).diff(x,4) + f(x).diff(x,2) - f(x).diff(x,3), f(x), x) + assert problem.order == 4 + + problem = SingleODEProblem(f(x).diff(x, 3) + f(x).diff(x, 2) - f(x)**2, f(x), x) + assert problem.is_autonomous == True + + problem = SingleODEProblem(f(x).diff(x, 3) + x*f(x).diff(x, 2) - f(x)**2, f(x), x) + assert problem.is_autonomous == False + + +def test_linear_coefficients(): + _ode_solver_test(_get_examples_ode_sol_linear_coefficients) + + +@slow +def test_1st_homogeneous_coeff_ode(): + #These were marked as test_1st_homogeneous_coeff_corner_case + eq1 = f(x).diff(x) - f(x)/x + c1 = classify_ode(eq1, f(x)) + eq2 = x*f(x).diff(x) - f(x) + c2 = classify_ode(eq2, f(x)) + sdi = "1st_homogeneous_coeff_subs_dep_div_indep" + sid = "1st_homogeneous_coeff_subs_indep_div_dep" + assert sid not in c1 and sdi not in c1 + assert sid not in c2 and sdi not in c2 + _ode_solver_test(_get_examples_ode_sol_1st_homogeneous_coeff_subs_dep_div_indep) + _ode_solver_test(_get_examples_ode_sol_1st_homogeneous_coeff_best) + + +@slow +def test_slow_examples_1st_homogeneous_coeff_ode(): + _ode_solver_test(_get_examples_ode_sol_1st_homogeneous_coeff_subs_dep_div_indep, run_slow_test=True) + _ode_solver_test(_get_examples_ode_sol_1st_homogeneous_coeff_best, run_slow_test=True) + + +@slow +def test_nth_linear_constant_coeff_homogeneous(): + _ode_solver_test(_get_examples_ode_sol_nth_linear_constant_coeff_homogeneous) + + +@slow +def test_slow_examples_nth_linear_constant_coeff_homogeneous(): + _ode_solver_test(_get_examples_ode_sol_nth_linear_constant_coeff_homogeneous, run_slow_test=True) + + +def test_Airy_equation(): + _ode_solver_test(_get_examples_ode_sol_2nd_linear_airy) + + +@slow +def test_lie_group(): + _ode_solver_test(_get_examples_ode_sol_lie_group) + + +@slow +def test_separable_reduced(): + df = f(x).diff(x) + eq = (x / f(x))*df + tan(x**2*f(x) / (x**2*f(x) - 1)) + assert classify_ode(eq) == ('factorable', 'separable_reduced', 'lie_group', + 'separable_reduced_Integral') + _ode_solver_test(_get_examples_ode_sol_separable_reduced) + + +@slow +def test_slow_examples_separable_reduced(): + _ode_solver_test(_get_examples_ode_sol_separable_reduced, run_slow_test=True) + + +@slow +def test_2nd_2F1_hypergeometric(): + _ode_solver_test(_get_examples_ode_sol_2nd_2F1_hypergeometric) + + +def test_2nd_2F1_hypergeometric_integral(): + eq = x*(x-1)*f(x).diff(x, 2) + (-1+ S(7)/2*x)*f(x).diff(x) + f(x) + sol = Eq(f(x), (C1 + C2*Integral(exp(Integral((1 - x/2)/(x*(x - 1)), x))/(1 - + x/2)**2, x))*exp(Integral(1/(x - 1), x)/4)*exp(-Integral(7/(x - + 1), x)/4)*hyper((S(1)/2, -1), (1,), x)) + assert sol == dsolve(eq, hint='2nd_hypergeometric_Integral') + assert checkodesol(eq, sol) == (True, 0) + + +@slow +def test_2nd_nonlinear_autonomous_conserved(): + _ode_solver_test(_get_examples_ode_sol_2nd_nonlinear_autonomous_conserved) + + +def test_2nd_nonlinear_autonomous_conserved_integral(): + eq = f(x).diff(x, 2) + asin(f(x)) + actual = [Eq(Integral(1/sqrt(C1 - 2*Integral(asin(_u), _u)), (_u, f(x))), C2 + x), + Eq(Integral(1/sqrt(C1 - 2*Integral(asin(_u), _u)), (_u, f(x))), C2 - x)] + solved = dsolve(eq, hint='2nd_nonlinear_autonomous_conserved_Integral', simplify=False) + for a,s in zip(actual, solved): + assert a.dummy_eq(s) + # checkodesol unable to simplify solutions with f(x) in an integral equation + assert checkodesol(eq, [s.doit() for s in solved]) == [(True, 0), (True, 0)] + + +@slow +def test_2nd_linear_bessel_equation(): + _ode_solver_test(_get_examples_ode_sol_2nd_linear_bessel) + + +@slow +def test_nth_algebraic(): + eqn = f(x) + f(x)*f(x).diff(x) + solns = [Eq(f(x), exp(x)), + Eq(f(x), C1*exp(C2*x))] + solns_final = _remove_redundant_solutions(eqn, solns, 2, x) + assert solns_final == [Eq(f(x), C1*exp(C2*x))] + + _ode_solver_test(_get_examples_ode_sol_nth_algebraic) + + +@slow +def test_slow_examples_nth_linear_constant_coeff_var_of_parameters(): + _ode_solver_test(_get_examples_ode_sol_nth_linear_var_of_parameters, run_slow_test=True) + + +def test_nth_linear_constant_coeff_var_of_parameters(): + _ode_solver_test(_get_examples_ode_sol_nth_linear_var_of_parameters) + + +@slow +def test_nth_linear_constant_coeff_variation_of_parameters__integral(): + # solve_variation_of_parameters shouldn't attempt to simplify the + # Wronskian if simplify=False. If wronskian() ever gets good enough + # to simplify the result itself, this test might fail. + our_hint = 'nth_linear_constant_coeff_variation_of_parameters_Integral' + eq = f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - 2*x - exp(I*x) + sol_simp = dsolve(eq, f(x), hint=our_hint, simplify=True) + sol_nsimp = dsolve(eq, f(x), hint=our_hint, simplify=False) + assert sol_simp != sol_nsimp + assert checkodesol(eq, sol_simp, order=5, solve_for_func=False) == (True, 0) + assert checkodesol(eq, sol_simp, order=5, solve_for_func=False) == (True, 0) + + +@slow +def test_slow_examples_1st_exact(): + _ode_solver_test(_get_examples_ode_sol_1st_exact, run_slow_test=True) + + +@slow +def test_1st_exact(): + _ode_solver_test(_get_examples_ode_sol_1st_exact) + + +def test_1st_exact_integral(): + eq = cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x) + sol_1 = dsolve(eq, f(x), simplify=False, hint='1st_exact_Integral') + assert checkodesol(eq, sol_1, order=1, solve_for_func=False) + + +@slow +def test_slow_examples_nth_order_reducible(): + _ode_solver_test(_get_examples_ode_sol_nth_order_reducible, run_slow_test=True) + + +@slow +def test_slow_examples_nth_linear_constant_coeff_undetermined_coefficients(): + _ode_solver_test(_get_examples_ode_sol_nth_linear_undetermined_coefficients, run_slow_test=True) + + +@slow +def test_slow_examples_separable(): + _ode_solver_test(_get_examples_ode_sol_separable, run_slow_test=True) + + +@slow +def test_nth_linear_constant_coeff_undetermined_coefficients(): + #issue-https://github.com/sympy/sympy/issues/5787 + # This test case is to show the classification of imaginary constants under + # nth_linear_constant_coeff_undetermined_coefficients + eq = Eq(diff(f(x), x), I*f(x) + S.Half - I) + our_hint = 'nth_linear_constant_coeff_undetermined_coefficients' + assert our_hint in classify_ode(eq) + _ode_solver_test(_get_examples_ode_sol_nth_linear_undetermined_coefficients) + + +def test_nth_order_reducible(): + F = lambda eq: NthOrderReducible(SingleODEProblem(eq, f(x), x))._matches() + D = Derivative + assert F(D(y*f(x), x, y) + D(f(x), x)) == False + assert F(D(y*f(y), y, y) + D(f(y), y)) == False + assert F(f(x)*D(f(x), x) + D(f(x), x, 2))== False + assert F(D(x*f(y), y, 2) + D(u*y*f(x), x, 3)) == False # no simplification by design + assert F(D(f(y), y, 2) + D(f(y), y, 3) + D(f(x), x, 4)) == False + assert F(D(f(x), x, 2) + D(f(x), x, 3)) == True + _ode_solver_test(_get_examples_ode_sol_nth_order_reducible) + + +@slow +def test_separable(): + _ode_solver_test(_get_examples_ode_sol_separable) + + +@slow +def test_factorable(): + assert integrate(-asin(f(2*x)+pi), x) == -Integral(asin(pi + f(2*x)), x) + _ode_solver_test(_get_examples_ode_sol_factorable) + + +@slow +def test_slow_examples_factorable(): + _ode_solver_test(_get_examples_ode_sol_factorable, run_slow_test=True) + + +def test_Riccati_special_minus2(): + _ode_solver_test(_get_examples_ode_sol_riccati) + + +@slow +def test_1st_rational_riccati(): + _ode_solver_test(_get_examples_ode_sol_1st_rational_riccati) + + +def test_Bernoulli(): + _ode_solver_test(_get_examples_ode_sol_bernoulli) + + +def test_1st_linear(): + _ode_solver_test(_get_examples_ode_sol_1st_linear) + + +def test_almost_linear(): + _ode_solver_test(_get_examples_ode_sol_almost_linear) + + +@slow +def test_Liouville_ODE(): + hint = 'Liouville' + 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 + + _ode_solver_test(_get_examples_ode_sol_liouville) + + +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) + + _ode_solver_test(_get_examples_ode_sol_euler_homogeneous) + + +def test_nth_order_linear_euler_eq_nonhomogeneous_undetermined_coefficients(): + x, t = symbols('x t') + a, b, c, d = symbols('a b c d', integer=True) + our_hint = "nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients" + + eq = x**4*diff(f(x), x, 4) - 13*x**2*diff(f(x), x, 2) + 36*f(x) + x + assert our_hint in classify_ode(eq, f(x)) + + eq = a*x**2*diff(f(x), x, 2) + b*x*diff(f(x), x) + c*f(x) + d*log(x) + assert our_hint in classify_ode(eq, f(x)) + + _ode_solver_test(_get_examples_ode_sol_euler_undetermined_coeff) + + +@slow +def test_nth_order_linear_euler_eq_nonhomogeneous_variation_of_parameters(): + x, t = symbols('x, t') + a, b, c, d = symbols('a, b, c, d', integer=True) + our_hint = "nth_linear_euler_eq_nonhomogeneous_variation_of_parameters" + + eq = Eq(x**2*diff(f(x),x,2) - 8*x*diff(f(x),x) + 12*f(x), x**2) + assert our_hint in classify_ode(eq, f(x)) + + eq = Eq(a*x**3*diff(f(x),x,3) + b*x**2*diff(f(x),x,2) + c*x*diff(f(x),x) + d*f(x), x*log(x)) + assert our_hint in classify_ode(eq, f(x)) + + _ode_solver_test(_get_examples_ode_sol_euler_var_para) + + +@_add_example_keys +def _get_examples_ode_sol_euler_homogeneous(): + r1, r2, r3, r4, r5 = [rootof(x**5 - 14*x**4 + 71*x**3 - 154*x**2 + 120*x - 1, n) for n in range(5)] + return { + 'hint': "nth_linear_euler_eq_homogeneous", + 'func': f(x), + 'examples':{ + 'euler_hom_01': { + 'eq': Eq(-3*diff(f(x), x)*x + 2*x**2*diff(f(x), x, x), 0), + 'sol': [Eq(f(x), C1 + C2*x**Rational(5, 2))], + }, + + 'euler_hom_02': { + 'eq': Eq(3*f(x) - 5*diff(f(x), x)*x + 2*x**2*diff(f(x), x, x), 0), + 'sol': [Eq(f(x), C1*sqrt(x) + C2*x**3)] + }, + + 'euler_hom_03': { + 'eq': Eq(4*f(x) + 5*diff(f(x), x)*x + x**2*diff(f(x), x, x), 0), + 'sol': [Eq(f(x), (C1 + C2*log(x))/x**2)] + }, + + 'euler_hom_04': { + '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': [Eq(f(x), C1/x**2 + C2*x + C3*x**3)] + }, + + 'euler_hom_05': { + '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': [Eq(f(x), x**5*(C1 + C2*log(x) + C3*log(x)**2))] + }, + + 'euler_hom_06': { + 'eq': x**2*diff(f(x), x, 2) + x*diff(f(x), x) - 9*f(x), + 'sol': [Eq(f(x), C1*x**-3 + C2*x**3)] + }, + + 'euler_hom_07': { + 'eq': sin(x)*x**2*f(x).diff(x, 2) + sin(x)*x*f(x).diff(x) + sin(x)*f(x), + 'sol': [Eq(f(x), C1*sin(log(x)) + C2*cos(log(x)))], + 'XFAIL': ['2nd_power_series_regular','nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients'] + }, + + 'euler_hom_08': { + 'eq': x**6 * f(x).diff(x, 6) - x*f(x).diff(x) + f(x), + 'sol': [Eq(f(x), C1*x + C2*x**r1 + C3*x**r2 + C4*x**r3 + C5*x**r4 + C6*x**r5)], + 'checkodesol_XFAIL':True + }, + + #This example is from issue: https://github.com/sympy/sympy/issues/15237 #This example is from issue: + # https://github.com/sympy/sympy/issues/15237 + 'euler_hom_09': { + 'eq': Derivative(x*f(x), x, x, x), + 'sol': [Eq(f(x), C1 + C2/x + C3*x)], + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_euler_undetermined_coeff(): + return { + 'hint': "nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients", + 'func': f(x), + 'examples':{ + 'euler_undet_01': { + 'eq': Eq(x**2*diff(f(x), x, x) + x*diff(f(x), x), 1), + 'sol': [Eq(f(x), C1 + C2*log(x) + log(x)**2/2)] + }, + + 'euler_undet_02': { + 'eq': Eq(x**2*diff(f(x), x, x) - 2*x*diff(f(x), x) + 2*f(x), x**3), + 'sol': [Eq(f(x), x*(C1 + C2*x + Rational(1, 2)*x**2))] + }, + + 'euler_undet_03': { + 'eq': Eq(x**2*diff(f(x), x, x) - x*diff(f(x), x) - 3*f(x), log(x)/x), + 'sol': [Eq(f(x), (C1 + C2*x**4 - log(x)**2/8 - log(x)/16)/x)] + }, + + 'euler_undet_04': { + 'eq': Eq(x**2*diff(f(x), x, x) + 3*x*diff(f(x), x) - 8*f(x), log(x)**3 - log(x)), + 'sol': [Eq(f(x), C1/x**4 + C2*x**2 - Rational(1,8)*log(x)**3 - Rational(3,32)*log(x)**2 - Rational(1,64)*log(x) - Rational(7, 256))] + }, + + 'euler_undet_05': { + 'eq': Eq(x**3*diff(f(x), x, x, x) - 3*x**2*diff(f(x), x, x) + 6*x*diff(f(x), x) - 6*f(x), log(x)), + 'sol': [Eq(f(x), C1*x + C2*x**2 + C3*x**3 - Rational(1, 6)*log(x) - Rational(11, 36))] + }, + + #Below examples were added for the issue: https://github.com/sympy/sympy/issues/5096 + 'euler_undet_06': { + 'eq': 2*x**2*f(x).diff(x, 2) + f(x) + sqrt(2*x)*sin(log(2*x)/2), + 'sol': [Eq(f(x), sqrt(x)*(C1*sin(log(x)/2) + C2*cos(log(x)/2) + sqrt(2)*log(x)*cos(log(2*x)/2)/2))] + }, + + 'euler_undet_07': { + 'eq': 2*x**2*f(x).diff(x, 2) + f(x) + sin(log(2*x)/2), + 'sol': [Eq(f(x), C1*sqrt(x)*sin(log(x)/2) + C2*sqrt(x)*cos(log(x)/2) - 2*sin(log(2*x)/2)/5 - 4*cos(log(2*x)/2)/5)] + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_euler_var_para(): + return { + 'hint': "nth_linear_euler_eq_nonhomogeneous_variation_of_parameters", + 'func': f(x), + 'examples':{ + 'euler_var_01': { + 'eq': Eq(x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x), x**4), + 'sol': [Eq(f(x), x*(C1 + C2*x + x**3/6))] + }, + + 'euler_var_02': { + 'eq': Eq(3*x**2*diff(f(x), x, x) + 6*x*diff(f(x), x) - 6*f(x), x**3*exp(x)), + 'sol': [Eq(f(x), C1/x**2 + C2*x + x*exp(x)/3 - 4*exp(x)/3 + 8*exp(x)/(3*x) - 8*exp(x)/(3*x**2))] + }, + + 'euler_var_03': { + 'eq': Eq(x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x), x**4*exp(x)), + 'sol': [Eq(f(x), x*(C1 + C2*x + x*exp(x) - 2*exp(x)))] + }, + + 'euler_var_04': { + 'eq': x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x) - log(x), + 'sol': [Eq(f(x), C1*x + C2*x**2 + log(x)/2 + Rational(3, 4))] + }, + + 'euler_var_05': { + 'eq': -exp(x) + (x*Derivative(f(x), (x, 2)) + Derivative(f(x), x))/x, + 'sol': [Eq(f(x), C1 + C2*log(x) + exp(x) - Ei(x))] + }, + + 'euler_var_06': { + 'eq': x**2 * f(x).diff(x, 2) + x * f(x).diff(x) + 4 * f(x) - 1/x, + 'sol': [Eq(f(x), C1*sin(2*log(x)) + C2*cos(2*log(x)) + 1/(5*x))] + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_bernoulli(): + # Type: Bernoulli, f'(x) + p(x)*f(x) == q(x)*f(x)**n + return { + 'hint': "Bernoulli", + 'func': f(x), + 'examples':{ + 'bernoulli_01': { + 'eq': Eq(x*f(x).diff(x) + f(x) - f(x)**2, 0), + 'sol': [Eq(f(x), 1/(C1*x + 1))], + 'XFAIL': ['separable_reduced'] + }, + + 'bernoulli_02': { + 'eq': f(x).diff(x) - y*f(x), + 'sol': [Eq(f(x), C1*exp(x*y))] + }, + + 'bernoulli_03': { + 'eq': f(x)*f(x).diff(x) - 1, + 'sol': [Eq(f(x), -sqrt(C1 + 2*x)), Eq(f(x), sqrt(C1 + 2*x))] + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_riccati(): + # Type: Riccati special alpha = -2, a*dy/dx + b*y**2 + c*y/x +d/x**2 + return { + 'hint': "Riccati_special_minus2", + 'func': f(x), + 'examples':{ + 'riccati_01': { + 'eq': 2*f(x).diff(x) + f(x)**2 - f(x)/x + 3*x**(-2), + 'sol': [Eq(f(x), (-sqrt(3)*tan(C1 + sqrt(3)*log(x)/4) + 3)/(2*x))], + }, + }, + } + + +@_add_example_keys +def _get_examples_ode_sol_1st_rational_riccati(): + # Type: 1st Order Rational Riccati, dy/dx = a + b*y + c*y**2, + # a, b, c are rational functions of x + return { + 'hint': "1st_rational_riccati", + 'func': f(x), + 'examples':{ + # a(x) is a constant + "rational_riccati_01": { + "eq": Eq(f(x).diff(x) + f(x)**2 - 2, 0), + "sol": [Eq(f(x), sqrt(2)*(-C1 - exp(2*sqrt(2)*x))/(C1 - exp(2*sqrt(2)*x)))] + }, + # a(x) is a constant + "rational_riccati_02": { + "eq": f(x)**2 + Derivative(f(x), x) + 4*f(x)/x + 2/x**2, + "sol": [Eq(f(x), (-2*C1 - x)/(x*(C1 + x)))] + }, + # a(x) is a constant + "rational_riccati_03": { + "eq": 2*x**2*Derivative(f(x), x) - x*(4*f(x) + Derivative(f(x), x) - 4) + (f(x) - 1)*f(x), + "sol": [Eq(f(x), (C1 + 2*x**2)/(C1 + x))] + }, + # Constant coefficients + "rational_riccati_04": { + "eq": f(x).diff(x) - 6 - 5*f(x) - f(x)**2, + "sol": [Eq(f(x), (-2*C1 + 3*exp(x))/(C1 - exp(x)))] + }, + # One pole of multiplicity 2 + "rational_riccati_05": { + "eq": x**2 - (2*x + 1/x)*f(x) + f(x)**2 + Derivative(f(x), x), + "sol": [Eq(f(x), x*(C1 + x**2 + 1)/(C1 + x**2 - 1))] + }, + # One pole of multiplicity 2 + "rational_riccati_06": { + "eq": x**4*Derivative(f(x), x) + x**2 - x*(2*f(x)**2 + Derivative(f(x), x)) + f(x), + "sol": [Eq(f(x), x*(C1*x - x + 1)/(C1 + x**2 - 1))] + }, + # Multiple poles of multiplicity 2 + "rational_riccati_07": { + "eq": -f(x)**2 + Derivative(f(x), x) + (15*x**2 - 20*x + 7)/((x - 1)**2*(2*x \ + - 1)**2), + "sol": [Eq(f(x), (9*C1*x - 6*C1 - 15*x**5 + 60*x**4 - 94*x**3 + 72*x**2 - \ + 33*x + 8)/(6*C1*x**2 - 9*C1*x + 3*C1 + 6*x**6 - 29*x**5 + 57*x**4 - \ + 58*x**3 + 28*x**2 - 3*x - 1))] + }, + # Imaginary poles + "rational_riccati_08": { + "eq": Derivative(f(x), x) + (3*x**2 + 1)*f(x)**2/x + (6*x**2 - x + 3)*f(x)/(x*(x \ + - 1)) + (3*x**2 - 2*x + 2)/(x*(x - 1)**2), + "sol": [Eq(f(x), (-C1 - x**3 + x**2 - 2*x + 1)/(C1*x - C1 + x**4 - x**3 + x**2 - \ + 2*x + 1))], + }, + # Imaginary coefficients in equation + "rational_riccati_09": { + "eq": Derivative(f(x), x) - 2*I*(f(x)**2 + 1)/x, + "sol": [Eq(f(x), (-I*C1 + I*x**4 + I)/(C1 + x**4 - 1))] + }, + # Regression: linsolve returning empty solution + # Large value of m (> 10) + "rational_riccati_10": { + "eq": Eq(Derivative(f(x), x), x*f(x)/(S(3)/2 - 2*x) + (x/2 - S(1)/3)*f(x)**2/\ + (2*x/3 - S(1)/2) - S(5)/4 + (281*x**2 - 1260*x + 756)/(16*x**3 - 12*x**2)), + "sol": [Eq(f(x), (40*C1*x**14 + 28*C1*x**13 + 420*C1*x**12 + 2940*C1*x**11 + \ + 18480*C1*x**10 + 103950*C1*x**9 + 519750*C1*x**8 + 2286900*C1*x**7 + \ + 8731800*C1*x**6 + 28378350*C1*x**5 + 76403250*C1*x**4 + 163721250*C1*x**3 \ + + 261954000*C1*x**2 + 278326125*C1*x + 147349125*C1 + x*exp(2*x) - 9*exp(2*x) \ + )/(x*(24*C1*x**13 + 140*C1*x**12 + 840*C1*x**11 + 4620*C1*x**10 + 23100*C1*x**9 \ + + 103950*C1*x**8 + 415800*C1*x**7 + 1455300*C1*x**6 + 4365900*C1*x**5 + \ + 10914750*C1*x**4 + 21829500*C1*x**3 + 32744250*C1*x**2 + 32744250*C1*x + \ + 16372125*C1 - exp(2*x))))] + } + } + } + + + +@_add_example_keys +def _get_examples_ode_sol_1st_linear(): + # Type: first order linear form f'(x)+p(x)f(x)=q(x) + return { + 'hint': "1st_linear", + 'func': f(x), + 'examples':{ + 'linear_01': { + 'eq': Eq(f(x).diff(x) + x*f(x), x**2), + 'sol': [Eq(f(x), (C1 + x*exp(x**2/2)- sqrt(2)*sqrt(pi)*erfi(sqrt(2)*x/2)/2)*exp(-x**2/2))], + }, + }, + } + + +@_add_example_keys +def _get_examples_ode_sol_factorable(): + """ some hints are marked as xfail for examples because they missed additional algebraic solution + which could be found by Factorable hint. Fact_01 raise exception for + nth_linear_constant_coeff_undetermined_coefficients""" + + y = Dummy('y') + a0,a1,a2,a3,a4 = symbols('a0, a1, a2, a3, a4') + return { + 'hint': "factorable", + 'func': f(x), + 'examples':{ + 'fact_01': { + 'eq': f(x) + f(x)*f(x).diff(x), + 'sol': [Eq(f(x), 0), Eq(f(x), C1 - x)], + 'XFAIL': ['separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_homogeneous_coeff_best', + '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', + 'lie_group', 'nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients', + 'nth_linear_constant_coeff_variation_of_parameters', + 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters', + 'nth_linear_constant_coeff_undetermined_coefficients'] + }, + + 'fact_02': { + 'eq': f(x)*(f(x).diff(x)+f(x)*x+2), + 'sol': [Eq(f(x), (C1 - sqrt(2)*sqrt(pi)*erfi(sqrt(2)*x/2))*exp(-x**2/2)), Eq(f(x), 0)], + 'XFAIL': ['Bernoulli', '1st_linear', 'lie_group'] + }, + + 'fact_03': { + 'eq': (f(x).diff(x)+f(x)*x**2)*(f(x).diff(x, 2) + x*f(x)), + 'sol': [Eq(f(x), C1*airyai(-x) + C2*airybi(-x)),Eq(f(x), C1*exp(-x**3/3))] + }, + + 'fact_04': { + 'eq': (f(x).diff(x)+f(x)*x**2)*(f(x).diff(x, 2) + f(x)), + 'sol': [Eq(f(x), C1*exp(-x**3/3)), Eq(f(x), C1*sin(x) + C2*cos(x))] + }, + + 'fact_05': { + 'eq': (f(x).diff(x)**2-1)*(f(x).diff(x)**2-4), + 'sol': [Eq(f(x), C1 - x), Eq(f(x), C1 + x), Eq(f(x), C1 + 2*x), Eq(f(x), C1 - 2*x)] + }, + + 'fact_06': { + 'eq': (f(x).diff(x, 2)-exp(f(x)))*f(x).diff(x), + 'sol': [ + Eq(f(x), log(-C1/(cos(sqrt(-C1)*(C2 + x)) + 1))), + Eq(f(x), log(-C1/(cos(sqrt(-C1)*(C2 - x)) + 1))), + Eq(f(x), C1) + ], + 'slow': True, + }, + + 'fact_07': { + 'eq': (f(x).diff(x)**2-1)*(f(x)*f(x).diff(x)-1), + 'sol': [Eq(f(x), C1 - x), Eq(f(x), -sqrt(C1 + 2*x)),Eq(f(x), sqrt(C1 + 2*x)), Eq(f(x), C1 + x)] + }, + + 'fact_08': { + 'eq': Derivative(f(x), x)**4 - 2*Derivative(f(x), x)**2 + 1, + 'sol': [Eq(f(x), C1 - x), Eq(f(x), C1 + x)] + }, + + 'fact_09': { + 'eq': f(x)**2*Derivative(f(x), x)**6 - 2*f(x)**2*Derivative(f(x), + x)**4 + f(x)**2*Derivative(f(x), x)**2 - 2*f(x)*Derivative(f(x), + x)**5 + 4*f(x)*Derivative(f(x), x)**3 - 2*f(x)*Derivative(f(x), + x) + Derivative(f(x), x)**4 - 2*Derivative(f(x), x)**2 + 1, + 'sol': [ + Eq(f(x), C1 - x), Eq(f(x), -sqrt(C1 + 2*x)), + Eq(f(x), sqrt(C1 + 2*x)), Eq(f(x), C1 + x) + ] + }, + + 'fact_10': { + 'eq': x**4*f(x)**2 + 2*x**4*f(x)*Derivative(f(x), (x, 2)) + x**4*Derivative(f(x), + (x, 2))**2 + 2*x**3*f(x)*Derivative(f(x), x) + 2*x**3*Derivative(f(x), + x)*Derivative(f(x), (x, 2)) - 7*x**2*f(x)**2 - 7*x**2*f(x)*Derivative(f(x), + (x, 2)) + x**2*Derivative(f(x), x)**2 - 7*x*f(x)*Derivative(f(x), x) + 12*f(x)**2, + 'sol': [ + Eq(f(x), C1*besselj(2, x) + C2*bessely(2, x)), + Eq(f(x), C1*besselj(sqrt(3), x) + C2*bessely(sqrt(3), x)) + ], + 'slow': True, + }, + + 'fact_11': { + 'eq': (f(x).diff(x, 2)-exp(f(x)))*(f(x).diff(x, 2)+exp(f(x))), + 'sol': [ + Eq(f(x), log(C1/(cos(C1*sqrt(-1/C1)*(C2 + x)) - 1))), + Eq(f(x), log(C1/(cos(C1*sqrt(-1/C1)*(C2 - x)) - 1))), + Eq(f(x), log(C1/(1 - cos(C1*sqrt(-1/C1)*(C2 + x))))), + Eq(f(x), log(C1/(1 - cos(C1*sqrt(-1/C1)*(C2 - x))))) + ], + 'dsolve_too_slow': True, + }, + + #Below examples were added for the issue: https://github.com/sympy/sympy/issues/15889 + 'fact_12': { + 'eq': exp(f(x).diff(x))-f(x)**2, + 'sol': [Eq(NonElementaryIntegral(1/log(y**2), (y, f(x))), C1 + x)], + 'XFAIL': ['lie_group'] #It shows not implemented error for lie_group. + }, + + 'fact_13': { + 'eq': f(x).diff(x)**2 - f(x)**3, + 'sol': [Eq(f(x), 4/(C1**2 - 2*C1*x + x**2))], + 'XFAIL': ['lie_group'] #It shows not implemented error for lie_group. + }, + + 'fact_14': { + 'eq': f(x).diff(x)**2 - f(x), + 'sol': [Eq(f(x), C1**2/4 - C1*x/2 + x**2/4)] + }, + + 'fact_15': { + 'eq': f(x).diff(x)**2 - f(x)**2, + 'sol': [Eq(f(x), C1*exp(x)), Eq(f(x), C1*exp(-x))] + }, + + 'fact_16': { + 'eq': f(x).diff(x)**2 - f(x)**3, + 'sol': [Eq(f(x), 4/(C1**2 - 2*C1*x + x**2))], + }, + + # kamke ode 1.1 + 'fact_17': { + 'eq': f(x).diff(x)-(a4*x**4 + a3*x**3 + a2*x**2 + a1*x + a0)**(-1/2), + 'sol': [Eq(f(x), C1 + Integral(1/sqrt(a0 + a1*x + a2*x**2 + a3*x**3 + a4*x**4), x))], + 'slow': True + }, + + # This is from issue: https://github.com/sympy/sympy/issues/9446 + 'fact_18':{ + 'eq': Eq(f(2 * x), sin(Derivative(f(x)))), + 'sol': [Eq(f(x), C1 + Integral(pi - asin(f(2*x)), x)), Eq(f(x), C1 + Integral(asin(f(2*x)), x))], + 'checkodesol_XFAIL':True + }, + + # This is from issue: https://github.com/sympy/sympy/issues/7093 + 'fact_19': { + 'eq': Derivative(f(x), x)**2 - x**3, + 'sol': [Eq(f(x), C1 - 2*x**Rational(5,2)/5), Eq(f(x), C1 + 2*x**Rational(5,2)/5)], + }, + + 'fact_20': { + 'eq': x*f(x).diff(x, 2) - x*f(x), + 'sol': [Eq(f(x), C1*exp(-x) + C2*exp(x))], + }, + } + } + + + +@_add_example_keys +def _get_examples_ode_sol_almost_linear(): + from sympy.functions.special.error_functions import Ei + A = Symbol('A', positive=True) + f = Function('f') + d = f(x).diff(x) + + return { + 'hint': "almost_linear", + 'func': f(x), + 'examples':{ + 'almost_lin_01': { + 'eq': x**2*f(x)**2*d + f(x)**3 + 1, + 'sol': [Eq(f(x), (C1*exp(3/x) - 1)**Rational(1, 3)), + Eq(f(x), (-1 - sqrt(3)*I)*(C1*exp(3/x) - 1)**Rational(1, 3)/2), + Eq(f(x), (-1 + sqrt(3)*I)*(C1*exp(3/x) - 1)**Rational(1, 3)/2)], + + }, + + 'almost_lin_02': { + 'eq': x*f(x)*d + 2*x*f(x)**2 + 1, + 'sol': [Eq(f(x), -sqrt((C1 - 2*Ei(4*x))*exp(-4*x))), Eq(f(x), sqrt((C1 - 2*Ei(4*x))*exp(-4*x)))] + }, + + 'almost_lin_03': { + 'eq': x*d + x*f(x) + 1, + 'sol': [Eq(f(x), (C1 - Ei(x))*exp(-x))] + }, + + 'almost_lin_04': { + 'eq': x*exp(f(x))*d + exp(f(x)) + 3*x, + 'sol': [Eq(f(x), log(C1/x - x*Rational(3, 2)))], + }, + + 'almost_lin_05': { + 'eq': x + A*(x + diff(f(x), x) + f(x)) + diff(f(x), x) + f(x) + 2, + 'sol': [Eq(f(x), (C1 + Piecewise( + (x, Eq(A + 1, 0)), ((-A*x + A - x - 1)*exp(x)/(A + 1), True)))*exp(-x))], + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_liouville(): + n = Symbol('n') + _y = Dummy('y') + return { + 'hint': "Liouville", + 'func': f(x), + 'examples':{ + 'liouville_01': { + 'eq': diff(f(x), x)/x + diff(f(x), x, x)/2 - diff(f(x), x)**2/2, + 'sol': [Eq(f(x), log(x/(C1 + C2*x)))], + + }, + + 'liouville_02': { + 'eq': diff(x*exp(-f(x)), x, x), + 'sol': [Eq(f(x), log(x/(C1 + C2*x)))] + }, + + 'liouville_03': { + 'eq': ((diff(f(x), x)/x + diff(f(x), x, x)/2 - diff(f(x), x)**2/2)*exp(-f(x))/exp(f(x))).expand(), + 'sol': [Eq(f(x), log(x/(C1 + C2*x)))] + }, + + 'liouville_04': { + 'eq': diff(f(x), x, x) + 1/f(x)*(diff(f(x), x))**2 + 1/x*diff(f(x), x), + 'sol': [Eq(f(x), -sqrt(C1 + C2*log(x))), Eq(f(x), sqrt(C1 + C2*log(x)))], + }, + + 'liouville_05': { + 'eq': x*diff(f(x), x, x) + x/f(x)*diff(f(x), x)**2 + x*diff(f(x), x), + 'sol': [Eq(f(x), -sqrt(C1 + C2*exp(-x))), Eq(f(x), sqrt(C1 + C2*exp(-x)))], + }, + + 'liouville_06': { + 'eq': Eq((x*exp(f(x))).diff(x, x), 0), + 'sol': [Eq(f(x), log(C1 + C2/x))], + }, + + 'liouville_07': { + 'eq': (diff(f(x), x)/x + diff(f(x), x, x)/2 - diff(f(x), x)**2/2)*exp(-f(x))/exp(f(x)), + 'sol': [Eq(f(x), log(x/(C1 + C2*x)))], + }, + + 'liouville_08': { + 'eq': x**2*diff(f(x),x) + (n*f(x) + f(x)**2)*diff(f(x),x)**2 + diff(f(x), (x, 2)), + 'sol': [Eq(C1 + C2*lowergamma(Rational(1,3), x**3/3) + NonElementaryIntegral(exp(_y**3/3)*exp(_y**2*n/2), (_y, f(x))), 0)], + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_nth_algebraic(): + M, m, r, t = symbols('M m r t') + phi = Function('phi') + k = Symbol('k') + # This one needs a substitution f' = g. + # 'algeb_12': { + # 'eq': -exp(x) + (x*Derivative(f(x), (x, 2)) + Derivative(f(x), x))/x, + # 'sol': [Eq(f(x), C1 + C2*log(x) + exp(x) - Ei(x))], + # }, + return { + 'hint': "nth_algebraic", + 'func': f(x), + 'examples':{ + 'algeb_01': { + 'eq': f(x) * f(x).diff(x) * f(x).diff(x, x) * (f(x) - 1) * (f(x).diff(x) - x), + 'sol': [Eq(f(x), C1 + x**2/2), Eq(f(x), C1 + C2*x)] + }, + + 'algeb_02': { + 'eq': f(x) * f(x).diff(x) * f(x).diff(x, x) * (f(x) - 1), + 'sol': [Eq(f(x), C1 + C2*x)] + }, + + 'algeb_03': { + 'eq': f(x) * f(x).diff(x) * f(x).diff(x, x), + 'sol': [Eq(f(x), C1 + C2*x)] + }, + + 'algeb_04': { + 'eq': Eq(-M * phi(t).diff(t), + Rational(3, 2) * m * r**2 * phi(t).diff(t) * phi(t).diff(t,t)), + 'sol': [Eq(phi(t), C1), Eq(phi(t), C1 + C2*t - M*t**2/(3*m*r**2))], + 'func': phi(t) + }, + + 'algeb_05': { + 'eq': (1 - sin(f(x))) * f(x).diff(x), + 'sol': [Eq(f(x), C1)], + 'XFAIL': ['separable'] #It raised exception. + }, + + 'algeb_06': { + 'eq': (diff(f(x)) - x)*(diff(f(x)) + x), + 'sol': [Eq(f(x), C1 - x**2/2), Eq(f(x), C1 + x**2/2)] + }, + + 'algeb_07': { + 'eq': Eq(Derivative(f(x), x), Derivative(g(x), x)), + 'sol': [Eq(f(x), C1 + g(x))], + }, + + 'algeb_08': { + 'eq': f(x).diff(x) - C1, #this example is from issue 15999 + 'sol': [Eq(f(x), C1*x + C2)], + }, + + 'algeb_09': { + 'eq': f(x)*f(x).diff(x), + 'sol': [Eq(f(x), C1)], + }, + + 'algeb_10': { + 'eq': (diff(f(x)) - x)*(diff(f(x)) + x), + 'sol': [Eq(f(x), C1 - x**2/2), Eq(f(x), C1 + x**2/2)], + }, + + 'algeb_11': { + 'eq': f(x) + f(x)*f(x).diff(x), + 'sol': [Eq(f(x), 0), Eq(f(x), C1 - x)], + 'XFAIL': ['separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_homogeneous_coeff_best', + '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', + 'lie_group', 'nth_linear_constant_coeff_undetermined_coefficients', + 'nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients', + 'nth_linear_constant_coeff_variation_of_parameters', + 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters'] + #nth_linear_constant_coeff_undetermined_coefficients raises exception rest all of them misses a solution. + }, + + 'algeb_12': { + 'eq': Derivative(x*f(x), x, x, x), + 'sol': [Eq(f(x), (C1 + C2*x + C3*x**2) / x)], + 'XFAIL': ['nth_algebraic'] # It passes only when prep=False is set in dsolve. + }, + + 'algeb_13': { + 'eq': Eq(Derivative(x*Derivative(f(x), x), x)/x, exp(x)), + 'sol': [Eq(f(x), C1 + C2*log(x) + exp(x) - Ei(x))], + 'XFAIL': ['nth_algebraic'] # It passes only when prep=False is set in dsolve. + }, + + # These are simple tests from the old ode module example 14-18 + 'algeb_14': { + 'eq': Eq(f(x).diff(x), 0), + 'sol': [Eq(f(x), C1)], + }, + + 'algeb_15': { + 'eq': Eq(3*f(x).diff(x) - 5, 0), + 'sol': [Eq(f(x), C1 + x*Rational(5, 3))], + }, + + 'algeb_16': { + 'eq': Eq(3*f(x).diff(x), 5), + 'sol': [Eq(f(x), C1 + x*Rational(5, 3))], + }, + + # Type: 2nd order, constant coefficients (two complex roots) + 'algeb_17': { + 'eq': Eq(3*f(x).diff(x) - 1, 0), + 'sol': [Eq(f(x), C1 + x/3)], + }, + + 'algeb_18': { + 'eq': Eq(x*f(x).diff(x) - 1, 0), + 'sol': [Eq(f(x), C1 + log(x))], + }, + + # https://github.com/sympy/sympy/issues/6989 + 'algeb_19': { + 'eq': f(x).diff(x) - x*exp(-k*x), + 'sol': [Eq(f(x), C1 + Piecewise(((-k*x - 1)*exp(-k*x)/k**2, Ne(k**2, 0)),(x**2/2, True)))], + }, + + 'algeb_20': { + 'eq': -f(x).diff(x) + x*exp(-k*x), + 'sol': [Eq(f(x), C1 + Piecewise(((-k*x - 1)*exp(-k*x)/k**2, Ne(k**2, 0)),(x**2/2, True)))], + }, + + # https://github.com/sympy/sympy/issues/10867 + 'algeb_21': { + 'eq': Eq(g(x).diff(x).diff(x), (x-2)**2 + (x-3)**3), + 'sol': [Eq(g(x), C1 + C2*x + x**5/20 - 2*x**4/3 + 23*x**3/6 - 23*x**2/2)], + 'func': g(x), + }, + + # https://github.com/sympy/sympy/issues/13691 + 'algeb_22': { + 'eq': f(x).diff(x) - C1*g(x).diff(x), + 'sol': [Eq(f(x), C2 + C1*g(x))], + 'func': f(x), + }, + + # https://github.com/sympy/sympy/issues/4838 + 'algeb_23': { + 'eq': f(x).diff(x) - 3*C1 - 3*x**2, + 'sol': [Eq(f(x), C2 + 3*C1*x + x**3)], + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_nth_order_reducible(): + return { + 'hint': "nth_order_reducible", + 'func': f(x), + 'examples':{ + 'reducible_01': { + 'eq': Eq(x*Derivative(f(x), x)**2 + Derivative(f(x), x, 2), 0), + 'sol': [Eq(f(x),C1 - sqrt(-1/C2)*log(-C2*sqrt(-1/C2) + x) + + sqrt(-1/C2)*log(C2*sqrt(-1/C2) + x))], + 'slow': True, + }, + + 'reducible_02': { + 'eq': -exp(x) + (x*Derivative(f(x), (x, 2)) + Derivative(f(x), x))/x, + 'sol': [Eq(f(x), C1 + C2*log(x) + exp(x) - Ei(x))], + 'slow': True, + }, + + 'reducible_03': { + 'eq': Eq(sqrt(2) * f(x).diff(x,x,x) + f(x).diff(x), 0), + 'sol': [Eq(f(x), C1 + C2*sin(2**Rational(3, 4)*x/2) + C3*cos(2**Rational(3, 4)*x/2))], + 'slow': True, + }, + + 'reducible_04': { + 'eq': f(x).diff(x, 2) + 2*f(x).diff(x), + 'sol': [Eq(f(x), C1 + C2*exp(-2*x))], + }, + + 'reducible_05': { + 'eq': f(x).diff(x, 3) + f(x).diff(x, 2) - 6*f(x).diff(x), + 'sol': [Eq(f(x), C1 + C2*exp(-3*x) + C3*exp(2*x))], + 'slow': True, + }, + + 'reducible_06': { + 'eq': f(x).diff(x, 4) - f(x).diff(x, 3) - 4*f(x).diff(x, 2) + \ + 4*f(x).diff(x), + 'sol': [Eq(f(x), C1 + C2*exp(-2*x) + C3*exp(x) + C4*exp(2*x))], + 'slow': True, + }, + + 'reducible_07': { + 'eq': f(x).diff(x, 4) + 3*f(x).diff(x, 3), + 'sol': [Eq(f(x), C1 + C2*x + C3*x**2 + C4*exp(-3*x))], + 'slow': True, + }, + + 'reducible_08': { + 'eq': f(x).diff(x, 4) - 2*f(x).diff(x, 2), + 'sol': [Eq(f(x), C1 + C2*x + C3*exp(-sqrt(2)*x) + C4*exp(sqrt(2)*x))], + 'slow': True, + }, + + 'reducible_09': { + 'eq': f(x).diff(x, 4) + 4*f(x).diff(x, 2), + 'sol': [Eq(f(x), C1 + C2*x + C3*sin(2*x) + C4*cos(2*x))], + 'slow': True, + }, + + 'reducible_10': { + 'eq': f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x), + 'sol': [Eq(f(x), C1 + C2*x*sin(x) + C2*cos(x) - C3*x*cos(x) + C3*sin(x) + C4*sin(x) + C5*cos(x))], + 'slow': True, + }, + + 'reducible_11': { + 'eq': f(x).diff(x, 2) - f(x).diff(x)**3, + 'sol': [Eq(f(x), C1 - sqrt(2)*sqrt(-1/(C2 + x))*(C2 + x)), + Eq(f(x), C1 + sqrt(2)*sqrt(-1/(C2 + x))*(C2 + x))], + 'slow': True, + }, + + # Needs to be a way to know how to combine derivatives in the expression + 'reducible_12': { + 'eq': Derivative(x*f(x), x, x, x) + Derivative(f(x), x, x, x), + 'sol': [Eq(f(x), C1 + C3/Mul(2, (x**2 + 2*x + 1), evaluate=False) + + x*(C2 + C3/Mul(2, (x**2 + 2*x + 1), evaluate=False)))], # 2-arg Mul! + 'slow': True, + }, + } + } + + + +@_add_example_keys +def _get_examples_ode_sol_nth_linear_undetermined_coefficients(): + # examples 3-27 below are from Ordinary Differential Equations, + # Tenenbaum and Pollard, pg. 231 + g = exp(-x) + f2 = f(x).diff(x, 2) + c = 3*f(x).diff(x, 3) + 5*f2 + f(x).diff(x) - f(x) - x + t = symbols("t") + u = symbols("u",cls=Function) + R, L, C, E_0, alpha = symbols("R L C E_0 alpha",positive=True) + omega = Symbol('omega') + return { + 'hint': "nth_linear_constant_coeff_undetermined_coefficients", + 'func': f(x), + 'examples':{ + 'undet_01': { + 'eq': c - x*g, + 'sol': [Eq(f(x), C3*exp(x/3) - x + (C1 + x*(C2 - x**2/24 - 3*x/32))*exp(-x) - 1)], + 'slow': True, + }, + + 'undet_02': { + 'eq': c - g, + 'sol': [Eq(f(x), C3*exp(x/3) - x + (C1 + x*(C2 - x/8))*exp(-x) - 1)], + 'slow': True, + }, + + 'undet_03': { + 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - 4, + 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + 2)], + 'slow': True, + }, + + 'undet_04': { + 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - 12*exp(x), + 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + 2*exp(x))], + 'slow': True, + }, + + 'undet_05': { + 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - exp(I*x), + 'sol': [Eq(f(x), (S(3)/10 + I/10)*(C1*exp(-2*x) + C2*exp(-x) - I*exp(I*x)))], + 'slow': True, + }, + + 'undet_06': { + 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - sin(x), + 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + sin(x)/10 - 3*cos(x)/10)], + 'slow': True, + }, + + 'undet_07': { + 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - cos(x), + 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + 3*sin(x)/10 + cos(x)/10)], + 'slow': True, + }, + + 'undet_08': { + 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - (8 + 6*exp(x) + 2*sin(x)), + 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + exp(x) + sin(x)/5 - 3*cos(x)/5 + 4)], + 'slow': True, + }, + + 'undet_09': { + 'eq': f2 + f(x).diff(x) + f(x) - x**2, + 'sol': [Eq(f(x), -2*x + x**2 + (C1*sin(x*sqrt(3)/2) + C2*cos(x*sqrt(3)/2))*exp(-x/2))], + 'slow': True, + }, + + 'undet_10': { + 'eq': f2 - 2*f(x).diff(x) - 8*f(x) - 9*x*exp(x) - 10*exp(-x), + 'sol': [Eq(f(x), -x*exp(x) - 2*exp(-x) + C1*exp(-2*x) + C2*exp(4*x))], + 'slow': True, + }, + + 'undet_11': { + 'eq': f2 - 3*f(x).diff(x) - 2*exp(2*x)*sin(x), + 'sol': [Eq(f(x), C1 + C2*exp(3*x) - 3*exp(2*x)*sin(x)/5 - exp(2*x)*cos(x)/5)], + 'slow': True, + }, + + 'undet_12': { + 'eq': f(x).diff(x, 4) - 2*f2 + f(x) - x + sin(x), + 'sol': [Eq(f(x), x - sin(x)/4 + (C1 + C2*x)*exp(-x) + (C3 + C4*x)*exp(x))], + 'slow': True, + }, + + 'undet_13': { + 'eq': f2 + f(x).diff(x) - x**2 - 2*x, + 'sol': [Eq(f(x), C1 + x**3/3 + C2*exp(-x))], + 'slow': True, + }, + + 'undet_14': { + 'eq': f2 + f(x).diff(x) - x - sin(2*x), + 'sol': [Eq(f(x), C1 - x - sin(2*x)/5 - cos(2*x)/10 + x**2/2 + C2*exp(-x))], + 'slow': True, + }, + + 'undet_15': { + 'eq': f2 + f(x) - 4*x*sin(x), + 'sol': [Eq(f(x), (C1 - x**2)*cos(x) + (C2 + x)*sin(x))], + 'slow': True, + }, + + 'undet_16': { + 'eq': f2 + 4*f(x) - x*sin(2*x), + 'sol': [Eq(f(x), (C1 - x**2/8)*cos(2*x) + (C2 + x/16)*sin(2*x))], + 'slow': True, + }, + + 'undet_17': { + 'eq': f2 + 2*f(x).diff(x) + f(x) - x**2*exp(-x), + 'sol': [Eq(f(x), (C1 + x*(C2 + x**3/12))*exp(-x))], + 'slow': True, + }, + + 'undet_18': { + 'eq': f(x).diff(x, 3) + 3*f2 + 3*f(x).diff(x) + f(x) - 2*exp(-x) + \ + x**2*exp(-x), + 'sol': [Eq(f(x), (C1 + x*(C2 + x*(C3 - x**3/60 + x/3)))*exp(-x))], + 'slow': True, + }, + + 'undet_19': { + 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - exp(-2*x) - x**2, + 'sol': [Eq(f(x), C2*exp(-x) + x**2/2 - x*Rational(3,2) + (C1 - x)*exp(-2*x) + Rational(7,4))], + 'slow': True, + }, + + 'undet_20': { + 'eq': f2 - 3*f(x).diff(x) + 2*f(x) - x*exp(-x), + 'sol': [Eq(f(x), C1*exp(x) + C2*exp(2*x) + (6*x + 5)*exp(-x)/36)], + 'slow': True, + }, + + 'undet_21': { + 'eq': f2 + f(x).diff(x) - 6*f(x) - x - exp(2*x), + 'sol': [Eq(f(x), Rational(-1, 36) - x/6 + C2*exp(-3*x) + (C1 + x/5)*exp(2*x))], + 'slow': True, + }, + + 'undet_22': { + 'eq': f2 + f(x) - sin(x) - exp(-x), + 'sol': [Eq(f(x), C2*sin(x) + (C1 - x/2)*cos(x) + exp(-x)/2)], + 'slow': True, + }, + + 'undet_23': { + 'eq': f(x).diff(x, 3) - 3*f2 + 3*f(x).diff(x) - f(x) - exp(x), + 'sol': [Eq(f(x), (C1 + x*(C2 + x*(C3 + x/6)))*exp(x))], + 'slow': True, + }, + + 'undet_24': { + 'eq': f2 + f(x) - S.Half - cos(2*x)/2, + 'sol': [Eq(f(x), S.Half - cos(2*x)/6 + C1*sin(x) + C2*cos(x))], + 'slow': True, + }, + + 'undet_25': { + 'eq': f(x).diff(x, 3) - f(x).diff(x) - exp(2*x)*(S.Half - cos(2*x)/2), + 'sol': [Eq(f(x), C1 + C2*exp(-x) + C3*exp(x) + (-21*sin(2*x) + 27*cos(2*x) + 130)*exp(2*x)/1560)], + 'slow': True, + }, + + #Note: 'undet_26' is referred in 'undet_37' + 'undet_26': { + 'eq': (f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - 2*x - + sin(x) - cos(x)), + 'sol': [Eq(f(x), C1 + x**2 + (C2 + x*(C3 - x/8))*sin(x) + (C4 + x*(C5 + x/8))*cos(x))], + 'slow': True, + }, + + 'undet_27': { + 'eq': f2 + f(x) - cos(x)/2 + cos(3*x)/2, + 'sol': [Eq(f(x), cos(3*x)/16 + C2*cos(x) + (C1 + x/4)*sin(x))], + 'slow': True, + }, + + 'undet_28': { + 'eq': f(x).diff(x) - 1, + 'sol': [Eq(f(x), C1 + x)], + 'slow': True, + }, + + # https://github.com/sympy/sympy/issues/19358 + 'undet_29': { + 'eq': f2 + f(x).diff(x) + exp(x-C1), + 'sol': [Eq(f(x), C2 + C3*exp(-x) - exp(-C1 + x)/2)], + 'slow': True, + }, + + # https://github.com/sympy/sympy/issues/18408 + 'undet_30': { + 'eq': f(x).diff(x, 3) - f(x).diff(x) - sinh(x), + 'sol': [Eq(f(x), C1 + C2*exp(-x) + C3*exp(x) + x*sinh(x)/2)], + }, + + 'undet_31': { + 'eq': f(x).diff(x, 2) - 49*f(x) - sinh(3*x), + 'sol': [Eq(f(x), C1*exp(-7*x) + C2*exp(7*x) - sinh(3*x)/40)], + }, + + 'undet_32': { + 'eq': f(x).diff(x, 3) - f(x).diff(x) - sinh(x) - exp(x), + 'sol': [Eq(f(x), C1 + C3*exp(-x) + x*sinh(x)/2 + (C2 + x/2)*exp(x))], + }, + + # https://github.com/sympy/sympy/issues/5096 + 'undet_33': { + 'eq': f(x).diff(x, x) + f(x) - x*sin(x - 2), + 'sol': [Eq(f(x), C1*sin(x) + C2*cos(x) - x**2*cos(x - 2)/4 + x*sin(x - 2)/4)], + }, + + 'undet_34': { + 'eq': f(x).diff(x, 2) + f(x) - x**4*sin(x-1), + 'sol': [ Eq(f(x), C1*sin(x) + C2*cos(x) - x**5*cos(x - 1)/10 + x**4*sin(x - 1)/4 + x**3*cos(x - 1)/2 - 3*x**2*sin(x - 1)/4 - 3*x*cos(x - 1)/4)], + }, + + 'undet_35': { + 'eq': f(x).diff(x, 2) - f(x) - exp(x - 1), + 'sol': [Eq(f(x), C2*exp(-x) + (C1 + x*exp(-1)/2)*exp(x))], + }, + + 'undet_36': { + 'eq': f(x).diff(x, 2)+f(x)-(sin(x-2)+1), + 'sol': [Eq(f(x), C1*sin(x) + C2*cos(x) - x*cos(x - 2)/2 + 1)], + }, + + # Equivalent to example_name 'undet_26'. + # This previously failed because the algorithm for undetermined coefficients + # didn't know to multiply exp(I*x) by sufficient x because it is linearly + # dependent on sin(x) and cos(x). + 'undet_37': { + 'eq': f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - 2*x - exp(I*x), + 'sol': [Eq(f(x), C1 + x**2*(I*exp(I*x)/8 + 1) + (C2 + C3*x)*sin(x) + (C4 + C5*x)*cos(x))], + }, + + # https://github.com/sympy/sympy/issues/12623 + 'undet_38': { + 'eq': Eq( u(t).diff(t,t) + R /L*u(t).diff(t) + 1/(L*C)*u(t), alpha), + 'sol': [Eq(u(t), C*L*alpha + C2*exp(-t*(R + sqrt(C*R**2 - 4*L)/sqrt(C))/(2*L)) + + C1*exp(t*(-R + sqrt(C*R**2 - 4*L)/sqrt(C))/(2*L)))], + 'func': u(t) + }, + + 'undet_39': { + 'eq': Eq( L*C*u(t).diff(t,t) + R*C*u(t).diff(t) + u(t), E_0*exp(I*omega*t) ), + 'sol': [Eq(u(t), C2*exp(-t*(R + sqrt(C*R**2 - 4*L)/sqrt(C))/(2*L)) + + C1*exp(t*(-R + sqrt(C*R**2 - 4*L)/sqrt(C))/(2*L)) + - E_0*exp(I*omega*t)/(C*L*omega**2 - I*C*R*omega - 1))], + 'func': u(t), + }, + + # https://github.com/sympy/sympy/issues/6879 + 'undet_40': { + 'eq': Eq(Derivative(f(x), x, 2) - 2*Derivative(f(x), x) + f(x), sin(x)), + 'sol': [Eq(f(x), (C1 + C2*x)*exp(x) + cos(x)/2)], + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_separable(): + # test_separable1-5 are from Ordinary Differential Equations, Tenenbaum and + # Pollard, pg. 55 + t,a = symbols('a,t') + m = 96 + g = 9.8 + k = .2 + f1 = g * m + v = Function('v') + return { + 'hint': "separable", + 'func': f(x), + 'examples':{ + 'separable_01': { + 'eq': f(x).diff(x) - f(x), + 'sol': [Eq(f(x), C1*exp(x))], + }, + + 'separable_02': { + 'eq': x*f(x).diff(x) - f(x), + 'sol': [Eq(f(x), C1*x)], + }, + + 'separable_03': { + 'eq': f(x).diff(x) + sin(x), + 'sol': [Eq(f(x), C1 + cos(x))], + }, + + 'separable_04': { + 'eq': f(x)**2 + 1 - (x**2 + 1)*f(x).diff(x), + 'sol': [Eq(f(x), tan(C1 + atan(x)))], + }, + + 'separable_05': { + 'eq': f(x).diff(x)/tan(x) - f(x) - 2, + 'sol': [Eq(f(x), C1/cos(x) - 2)], + }, + + 'separable_06': { + 'eq': f(x).diff(x) * (1 - sin(f(x))) - 1, + 'sol': [Eq(-x + f(x) + cos(f(x)), C1)], + }, + + 'separable_07': { + 'eq': f(x)*x**2*f(x).diff(x) - f(x)**3 - 2*x**2*f(x).diff(x), + 'sol': [Eq(f(x), (-x - sqrt(x*(4*C1*x + x - 4)))/(C1*x - 1)/2), + Eq(f(x), (-x + sqrt(x*(4*C1*x + x - 4)))/(C1*x - 1)/2)], + 'slow': True, + }, + + 'separable_08': { + 'eq': f(x)**2 - 1 - (2*f(x) + x*f(x))*f(x).diff(x), + 'sol': [Eq(f(x), -sqrt(C1*x**2 + 4*C1*x + 4*C1 + 1)), + Eq(f(x), sqrt(C1*x**2 + 4*C1*x + 4*C1 + 1))], + 'slow': True, + }, + + 'separable_09': { + 'eq': x*log(x)*f(x).diff(x) + sqrt(1 + f(x)**2), + 'sol': [Eq(f(x), sinh(C1 - log(log(x))))], #One more solution is f(x)=I + 'slow': True, + 'checkodesol_XFAIL': True, + }, + + 'separable_10': { + 'eq': exp(x + 1)*tan(f(x)) + cos(f(x))*f(x).diff(x), + 'sol': [Eq(E*exp(x) + log(cos(f(x)) - 1)/2 - log(cos(f(x)) + 1)/2 + cos(f(x)), C1)], + 'slow': True, + }, + + 'separable_11': { + 'eq': (x*cos(f(x)) + x**2*sin(f(x))*f(x).diff(x) - a**2*sin(f(x))*f(x).diff(x)), + 'sol': [ + Eq(f(x), -acos(C1*sqrt(-a**2 + x**2)) + 2*pi), + Eq(f(x), acos(C1*sqrt(-a**2 + x**2))) + ], + 'slow': True, + }, + + 'separable_12': { + 'eq': f(x).diff(x) - f(x)*tan(x), + 'sol': [Eq(f(x), C1/cos(x))], + }, + + 'separable_13': { + 'eq': (x - 1)*cos(f(x))*f(x).diff(x) - 2*x*sin(f(x)), + 'sol': [ + Eq(f(x), pi - asin(C1*(x**2 - 2*x + 1)*exp(2*x))), + Eq(f(x), asin(C1*(x**2 - 2*x + 1)*exp(2*x))) + ], + }, + + 'separable_14': { + 'eq': f(x).diff(x) - f(x)*log(f(x))/tan(x), + 'sol': [Eq(f(x), exp(C1*sin(x)))], + }, + + 'separable_15': { + 'eq': x*f(x).diff(x) + (1 + f(x)**2)*atan(f(x)), + 'sol': [Eq(f(x), tan(C1/x))], #Two more solutions are f(x)=0 and f(x)=I + 'slow': True, + 'checkodesol_XFAIL': True, + }, + + 'separable_16': { + 'eq': f(x).diff(x) + x*(f(x) + 1), + 'sol': [Eq(f(x), -1 + C1*exp(-x**2/2))], + }, + + 'separable_17': { + 'eq': exp(f(x)**2)*(x**2 + 2*x + 1) + (x*f(x) + f(x))*f(x).diff(x), + 'sol': [ + Eq(f(x), -sqrt(log(1/(C1 + x**2 + 2*x)))), + Eq(f(x), sqrt(log(1/(C1 + x**2 + 2*x)))) + ], + }, + + 'separable_18': { + 'eq': f(x).diff(x) + f(x), + 'sol': [Eq(f(x), C1*exp(-x))], + }, + + 'separable_19': { + 'eq': sin(x)*cos(2*f(x)) + cos(x)*sin(2*f(x))*f(x).diff(x), + 'sol': [Eq(f(x), pi - acos(C1/cos(x)**2)/2), Eq(f(x), acos(C1/cos(x)**2)/2)], + }, + + 'separable_20': { + 'eq': (1 - x)*f(x).diff(x) - x*(f(x) + 1), + 'sol': [Eq(f(x), (C1*exp(-x) - x + 1)/(x - 1))], + }, + + 'separable_21': { + 'eq': f(x)*diff(f(x), x) + x - 3*x*f(x)**2, + 'sol': [Eq(f(x), -sqrt(3)*sqrt(C1*exp(3*x**2) + 1)/3), + Eq(f(x), sqrt(3)*sqrt(C1*exp(3*x**2) + 1)/3)], + }, + + 'separable_22': { + 'eq': f(x).diff(x) - exp(x + f(x)), + 'sol': [Eq(f(x), log(-1/(C1 + exp(x))))], + 'XFAIL': ['lie_group'] #It shows 'NoneType' object is not subscriptable for lie_group. + }, + + # https://github.com/sympy/sympy/issues/7081 + 'separable_23': { + 'eq': x*(f(x).diff(x)) + 1 - f(x)**2, + 'sol': [Eq(f(x), (-C1 - x**2)/(-C1 + x**2))], + }, + + # https://github.com/sympy/sympy/issues/10379 + 'separable_24': { + 'eq': f(t).diff(t)-(1-51.05*y*f(t)), + 'sol': [Eq(f(t), (0.019588638589618023*exp(y*(C1 - 51.049999999999997*t)) + 0.019588638589618023)/y)], + 'func': f(t), + }, + + # https://github.com/sympy/sympy/issues/15999 + 'separable_25': { + 'eq': f(x).diff(x) - C1*f(x), + 'sol': [Eq(f(x), C2*exp(C1*x))], + }, + + 'separable_26': { + 'eq': f1 - k * (v(t) ** 2) - m * Derivative(v(t)), + 'sol': [Eq(v(t), -68.585712797928991/tanh(C1 - 0.14288690166235204*t))], + 'func': v(t), + 'checkodesol_XFAIL': True, + }, + + #https://github.com/sympy/sympy/issues/22155 + 'separable_27': { + 'eq': f(x).diff(x) - exp(f(x) - x), + 'sol': [Eq(f(x), log(-exp(x)/(C1*exp(x) - 1)))], + } + } + } + + +@_add_example_keys +def _get_examples_ode_sol_1st_exact(): + # Type: Exact differential equation, p(x,f) + q(x,f)*f' == 0, + # where dp/df == dq/dx + ''' + Example 7 is an exact equation that fails under the exact engine. It is caught + by first order homogeneous albeit with a much contorted solution. The + exact engine fails because of a poorly simplified integral of q(0,y)dy, + where q is the function multiplying f'. The solutions should be + Eq(sqrt(x**2+f(x)**2)**3+y**3, C1). The equation below is + equivalent, but it is so complex that checkodesol fails, and takes a long + time to do so. + ''' + return { + 'hint': "1st_exact", + 'func': f(x), + 'examples':{ + '1st_exact_01': { + 'eq': sin(x)*cos(f(x)) + cos(x)*sin(f(x))*f(x).diff(x), + 'sol': [Eq(f(x), -acos(C1/cos(x)) + 2*pi), Eq(f(x), acos(C1/cos(x)))], + 'slow': True, + }, + + '1st_exact_02': { + 'eq': (2*x*f(x) + 1)/f(x) + (f(x) - x)/f(x)**2*f(x).diff(x), + 'sol': [Eq(f(x), exp(C1 - x**2 + LambertW(-x*exp(-C1 + x**2))))], + 'XFAIL': ['lie_group'], #It shows dsolve raises an exception: List index out of range for lie_group + 'slow': True, + 'checkodesol_XFAIL':True + }, + + '1st_exact_03': { + 'eq': 2*x + f(x)*cos(x) + (2*f(x) + sin(x) - sin(f(x)))*f(x).diff(x), + 'sol': [Eq(f(x)*sin(x) + cos(f(x)) + x**2 + f(x)**2, C1)], + 'XFAIL': ['lie_group'], #It goes into infinite loop for lie_group. + 'slow': True, + }, + + '1st_exact_04': { + 'eq': cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x), + 'sol': [Eq(x*cos(f(x)) + f(x)**3/3, C1)], + 'slow': True, + }, + + '1st_exact_05': { + 'eq': 2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x), + 'sol': [Eq(x**2*f(x) + f(x)**3/3, C1)], + 'slow': True, + 'simplify_flag':False + }, + + # This was from issue: https://github.com/sympy/sympy/issues/11290 + '1st_exact_06': { + 'eq': cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x), + 'sol': [Eq(x*cos(f(x)) + f(x)**3/3, C1)], + 'simplify_flag':False + }, + + '1st_exact_07': { + 'eq': x*sqrt(x**2 + f(x)**2) - (x**2*f(x)/(f(x) - sqrt(x**2 + f(x)**2)))*f(x).diff(x), + 'sol': [Eq(log(x), + C1 - 9*sqrt(1 + f(x)**2/x**2)*asinh(f(x)/x)/(-27*f(x)/x + + 27*sqrt(1 + f(x)**2/x**2)) - 9*sqrt(1 + f(x)**2/x**2)* + log(1 - sqrt(1 + f(x)**2/x**2)*f(x)/x + 2*f(x)**2/x**2)/ + (-27*f(x)/x + 27*sqrt(1 + f(x)**2/x**2)) + + 9*asinh(f(x)/x)*f(x)/(x*(-27*f(x)/x + 27*sqrt(1 + f(x)**2/x**2))) + + 9*f(x)*log(1 - sqrt(1 + f(x)**2/x**2)*f(x)/x + 2*f(x)**2/x**2)/ + (x*(-27*f(x)/x + 27*sqrt(1 + f(x)**2/x**2))))], + 'slow': True, + 'dsolve_too_slow':True + }, + + # Type: a(x)f'(x)+b(x)*f(x)+c(x)=0 + '1st_exact_08': { + 'eq': Eq(x**2*f(x).diff(x) + 3*x*f(x) - sin(x)/x, 0), + 'sol': [Eq(f(x), (C1 - cos(x))/x**3)], + }, + + # these examples are from test_exact_enhancement + '1st_exact_09': { + 'eq': f(x)/x**2 + ((f(x)*x - 1)/x)*f(x).diff(x), + 'sol': [Eq(f(x), (i*sqrt(C1*x**2 + 1) + 1)/x) for i in (-1, 1)], + }, + + '1st_exact_10': { + 'eq': (x*f(x) - 1) + f(x).diff(x)*(x**2 - x*f(x)), + 'sol': [Eq(f(x), x - sqrt(C1 + x**2 - 2*log(x))), Eq(f(x), x + sqrt(C1 + x**2 - 2*log(x)))], + }, + + '1st_exact_11': { + 'eq': (x + 2)*sin(f(x)) + f(x).diff(x)*x*cos(f(x)), + 'sol': [Eq(f(x), -asin(C1*exp(-x)/x**2) + pi), Eq(f(x), asin(C1*exp(-x)/x**2))], + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_nth_linear_var_of_parameters(): + g = exp(-x) + f2 = f(x).diff(x, 2) + c = 3*f(x).diff(x, 3) + 5*f2 + f(x).diff(x) - f(x) - x + return { + 'hint': "nth_linear_constant_coeff_variation_of_parameters", + 'func': f(x), + 'examples':{ + 'var_of_parameters_01': { + 'eq': c - x*g, + 'sol': [Eq(f(x), C3*exp(x/3) - x + (C1 + x*(C2 - x**2/24 - 3*x/32))*exp(-x) - 1)], + 'slow': True, + }, + + 'var_of_parameters_02': { + 'eq': c - g, + 'sol': [Eq(f(x), C3*exp(x/3) - x + (C1 + x*(C2 - x/8))*exp(-x) - 1)], + 'slow': True, + }, + + 'var_of_parameters_03': { + 'eq': f(x).diff(x) - 1, + 'sol': [Eq(f(x), C1 + x)], + 'slow': True, + }, + + 'var_of_parameters_04': { + 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - 4, + 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + 2)], + 'slow': True, + }, + + 'var_of_parameters_05': { + 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - 12*exp(x), + 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + 2*exp(x))], + 'slow': True, + }, + + 'var_of_parameters_06': { + 'eq': f2 - 2*f(x).diff(x) - 8*f(x) - 9*x*exp(x) - 10*exp(-x), + 'sol': [Eq(f(x), -x*exp(x) - 2*exp(-x) + C1*exp(-2*x) + C2*exp(4*x))], + 'slow': True, + }, + + 'var_of_parameters_07': { + 'eq': f2 + 2*f(x).diff(x) + f(x) - x**2*exp(-x), + 'sol': [Eq(f(x), (C1 + x*(C2 + x**3/12))*exp(-x))], + 'slow': True, + }, + + 'var_of_parameters_08': { + 'eq': f2 - 3*f(x).diff(x) + 2*f(x) - x*exp(-x), + 'sol': [Eq(f(x), C1*exp(x) + C2*exp(2*x) + (6*x + 5)*exp(-x)/36)], + 'slow': True, + }, + + 'var_of_parameters_09': { + 'eq': f(x).diff(x, 3) - 3*f2 + 3*f(x).diff(x) - f(x) - exp(x), + 'sol': [Eq(f(x), (C1 + x*(C2 + x*(C3 + x/6)))*exp(x))], + 'slow': True, + }, + + 'var_of_parameters_10': { + 'eq': f2 + 2*f(x).diff(x) + f(x) - exp(-x)/x, + 'sol': [Eq(f(x), (C1 + x*(C2 + log(x)))*exp(-x))], + 'slow': True, + }, + + 'var_of_parameters_11': { + 'eq': f2 + f(x) - 1/sin(x)*1/cos(x), + 'sol': [Eq(f(x), (C1 + log(sin(x) - 1)/2 - log(sin(x) + 1)/2 + )*cos(x) + (C2 + log(cos(x) - 1)/2 - log(cos(x) + 1)/2)*sin(x))], + 'slow': True, + }, + + 'var_of_parameters_12': { + 'eq': f(x).diff(x, 4) - 1/x, + 'sol': [Eq(f(x), C1 + C2*x + C3*x**2 + x**3*(C4 + log(x)/6))], + 'slow': True, + }, + + # These were from issue: https://github.com/sympy/sympy/issues/15996 + 'var_of_parameters_13': { + 'eq': f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - 2*x - exp(I*x), + 'sol': [Eq(f(x), C1 + x**2 + (C2 + x*(C3 - x/8 + 3*exp(I*x)/2 + 3*exp(-I*x)/2) + 5*exp(2*I*x)/16 + 2*I*exp(I*x) - 2*I*exp(-I*x))*sin(x) + (C4 + x*(C5 + I*x/8 + 3*I*exp(I*x)/2 - 3*I*exp(-I*x)/2) + + 5*I*exp(2*I*x)/16 - 2*exp(I*x) - 2*exp(-I*x))*cos(x) - I*exp(I*x))], + }, + + 'var_of_parameters_14': { + 'eq': f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - exp(I*x), + 'sol': [Eq(f(x), C1 + (C2 + x*(C3 - x/8) + 5*exp(2*I*x)/16)*sin(x) + (C4 + x*(C5 + I*x/8) + 5*I*exp(2*I*x)/16)*cos(x) - I*exp(I*x))], + }, + + # https://github.com/sympy/sympy/issues/14395 + 'var_of_parameters_15': { + 'eq': Derivative(f(x), x, x) + 9*f(x) - sec(x), + 'sol': [Eq(f(x), (C1 - x/3 + sin(2*x)/3)*sin(3*x) + (C2 + log(cos(x)) + - 2*log(cos(x)**2)/3 + 2*cos(x)**2/3)*cos(3*x))], + 'slow': True, + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_2nd_linear_bessel(): + return { + 'hint': "2nd_linear_bessel", + 'func': f(x), + 'examples':{ + '2nd_lin_bessel_01': { + 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**2 - 4)*f(x), + 'sol': [Eq(f(x), C1*besselj(2, x) + C2*bessely(2, x))], + }, + + '2nd_lin_bessel_02': { + 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**2 +25)*f(x), + 'sol': [Eq(f(x), C1*besselj(5*I, x) + C2*bessely(5*I, x))], + }, + + '2nd_lin_bessel_03': { + 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**2)*f(x), + 'sol': [Eq(f(x), C1*besselj(0, x) + C2*bessely(0, x))], + }, + + '2nd_lin_bessel_04': { + 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (81*x**2 -S(1)/9)*f(x), + 'sol': [Eq(f(x), C1*besselj(S(1)/3, 9*x) + C2*bessely(S(1)/3, 9*x))], + }, + + '2nd_lin_bessel_05': { + 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**4 - 4)*f(x), + 'sol': [Eq(f(x), C1*besselj(1, x**2/2) + C2*bessely(1, x**2/2))], + }, + + '2nd_lin_bessel_06': { + 'eq': x**2*(f(x).diff(x, 2)) + 2*x*(f(x).diff(x)) + (x**4 - 4)*f(x), + 'sol': [Eq(f(x), (C1*besselj(sqrt(17)/4, x**2/2) + C2*bessely(sqrt(17)/4, x**2/2))/sqrt(x))], + }, + + '2nd_lin_bessel_07': { + 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**2 - S(1)/4)*f(x), + 'sol': [Eq(f(x), C1*besselj(S(1)/2, x) + C2*bessely(S(1)/2, x))], + }, + + '2nd_lin_bessel_08': { + 'eq': x**2*(f(x).diff(x, 2)) - 3*x*(f(x).diff(x)) + (4*x + 4)*f(x), + 'sol': [Eq(f(x), x**2*(C1*besselj(0, 4*sqrt(x)) + C2*bessely(0, 4*sqrt(x))))], + }, + + '2nd_lin_bessel_09': { + 'eq': x*(f(x).diff(x, 2)) - f(x).diff(x) + 4*x**3*f(x), + 'sol': [Eq(f(x), x*(C1*besselj(S(1)/2, x**2) + C2*bessely(S(1)/2, x**2)))], + }, + + '2nd_lin_bessel_10': { + 'eq': (x-2)**2*(f(x).diff(x, 2)) - (x-2)*f(x).diff(x) + 4*(x-2)**2*f(x), + 'sol': [Eq(f(x), (x - 2)*(C1*besselj(1, 2*x - 4) + C2*bessely(1, 2*x - 4)))], + }, + + # https://github.com/sympy/sympy/issues/4414 + '2nd_lin_bessel_11': { + 'eq': f(x).diff(x, x) + 2/x*f(x).diff(x) + f(x), + 'sol': [Eq(f(x), (C1*besselj(S(1)/2, x) + C2*bessely(S(1)/2, x))/sqrt(x))], + }, + '2nd_lin_bessel_12': { + 'eq': x**2*f(x).diff(x, 2) + x*f(x).diff(x) + (a**2*x**2/c**2 - b**2)*f(x), + 'sol': [Eq(f(x), C1*besselj(sqrt(b**2), x*sqrt(a**2/c**2)) + C2*bessely(sqrt(b**2), x*sqrt(a**2/c**2)))], + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_2nd_2F1_hypergeometric(): + return { + 'hint': "2nd_hypergeometric", + 'func': f(x), + 'examples':{ + '2nd_2F1_hyper_01': { + 'eq': x*(x-1)*f(x).diff(x, 2) + (S(3)/2 -2*x)*f(x).diff(x) + 2*f(x), + 'sol': [Eq(f(x), C1*x**(S(5)/2)*hyper((S(3)/2, S(1)/2), (S(7)/2,), x) + C2*hyper((-1, -2), (-S(3)/2,), x))], + }, + + '2nd_2F1_hyper_02': { + 'eq': x*(x-1)*f(x).diff(x, 2) + (S(7)/2*x)*f(x).diff(x) + f(x), + 'sol': [Eq(f(x), (C1*(1 - x)**(S(5)/2)*hyper((S(1)/2, 2), (S(7)/2,), 1 - x) + + C2*hyper((-S(1)/2, -2), (-S(3)/2,), 1 - x))/(x - 1)**(S(5)/2))], + }, + + '2nd_2F1_hyper_03': { + 'eq': x*(x-1)*f(x).diff(x, 2) + (S(3)+ S(7)/2*x)*f(x).diff(x) + f(x), + 'sol': [Eq(f(x), (C1*(1 - x)**(S(11)/2)*hyper((S(1)/2, 2), (S(13)/2,), 1 - x) + + C2*hyper((-S(7)/2, -5), (-S(9)/2,), 1 - x))/(x - 1)**(S(11)/2))], + }, + + '2nd_2F1_hyper_04': { + 'eq': -x**(S(5)/7)*(-416*x**(S(9)/7)/9 - 2385*x**(S(5)/7)/49 + S(298)*x/3)*f(x)/(196*(-x**(S(6)/7) + + x)**2*(x**(S(6)/7) + x)**2) + Derivative(f(x), (x, 2)), + 'sol': [Eq(f(x), x**(S(45)/98)*(C1*x**(S(4)/49)*hyper((S(1)/3, -S(1)/2), (S(9)/7,), x**(S(2)/7)) + + C2*hyper((S(1)/21, -S(11)/14), (S(5)/7,), x**(S(2)/7)))/(x**(S(2)/7) - 1)**(S(19)/84))], + 'checkodesol_XFAIL':True, + }, + } + } + +@_add_example_keys +def _get_examples_ode_sol_2nd_nonlinear_autonomous_conserved(): + return { + 'hint': "2nd_nonlinear_autonomous_conserved", + 'func': f(x), + 'examples': { + '2nd_nonlinear_autonomous_conserved_01': { + 'eq': f(x).diff(x, 2) + exp(f(x)) + log(f(x)), + 'sol': [ + Eq(Integral(1/sqrt(C1 - 2*_u*log(_u) + 2*_u - 2*exp(_u)), (_u, f(x))), C2 + x), + Eq(Integral(1/sqrt(C1 - 2*_u*log(_u) + 2*_u - 2*exp(_u)), (_u, f(x))), C2 - x) + ], + 'simplify_flag': False, + }, + '2nd_nonlinear_autonomous_conserved_02': { + 'eq': f(x).diff(x, 2) + cbrt(f(x)) + 1/f(x), + 'sol': [ + Eq(sqrt(2)*Integral(1/sqrt(2*C1 - 3*_u**Rational(4, 3) - 4*log(_u)), (_u, f(x))), C2 + x), + Eq(sqrt(2)*Integral(1/sqrt(2*C1 - 3*_u**Rational(4, 3) - 4*log(_u)), (_u, f(x))), C2 - x) + ], + 'simplify_flag': False, + }, + '2nd_nonlinear_autonomous_conserved_03': { + 'eq': f(x).diff(x, 2) + sin(f(x)), + 'sol': [ + Eq(Integral(1/sqrt(C1 + 2*cos(_u)), (_u, f(x))), C2 + x), + Eq(Integral(1/sqrt(C1 + 2*cos(_u)), (_u, f(x))), C2 - x) + ], + 'simplify_flag': False, + }, + '2nd_nonlinear_autonomous_conserved_04': { + 'eq': f(x).diff(x, 2) + cosh(f(x)), + 'sol': [ + Eq(Integral(1/sqrt(C1 - 2*sinh(_u)), (_u, f(x))), C2 + x), + Eq(Integral(1/sqrt(C1 - 2*sinh(_u)), (_u, f(x))), C2 - x) + ], + 'simplify_flag': False, + }, + '2nd_nonlinear_autonomous_conserved_05': { + 'eq': f(x).diff(x, 2) + asin(f(x)), + 'sol': [ + Eq(Integral(1/sqrt(C1 - 2*_u*asin(_u) - 2*sqrt(1 - _u**2)), (_u, f(x))), C2 + x), + Eq(Integral(1/sqrt(C1 - 2*_u*asin(_u) - 2*sqrt(1 - _u**2)), (_u, f(x))), C2 - x) + ], + 'simplify_flag': False, + 'XFAIL': ['2nd_nonlinear_autonomous_conserved_Integral'] + } + } + } + + +@_add_example_keys +def _get_examples_ode_sol_separable_reduced(): + df = f(x).diff(x) + return { + 'hint': "separable_reduced", + 'func': f(x), + 'examples':{ + 'separable_reduced_01': { + 'eq': x* df + f(x)* (1 / (x**2*f(x) - 1)), + 'sol': [Eq(log(x**2*f(x))/3 + log(x**2*f(x) - Rational(3, 2))/6, C1 + log(x))], + 'simplify_flag': False, + 'XFAIL': ['lie_group'], #It hangs. + }, + + #Note: 'separable_reduced_02' is referred in 'separable_reduced_11' + 'separable_reduced_02': { + 'eq': f(x).diff(x) + (f(x) / (x**4*f(x) - x)), + 'sol': [Eq(log(x**3*f(x))/4 + log(x**3*f(x) - Rational(4,3))/12, C1 + log(x))], + 'simplify_flag': False, + 'checkodesol_XFAIL':True, #It hangs for this. + }, + + 'separable_reduced_03': { + 'eq': x*df + f(x)*(x**2*f(x)), + 'sol': [Eq(log(x**2*f(x))/2 - log(x**2*f(x) - 2)/2, C1 + log(x))], + 'simplify_flag': False, + }, + + 'separable_reduced_04': { + 'eq': Eq(f(x).diff(x) + f(x)/x * (1 + (x**(S(2)/3)*f(x))**2), 0), + 'sol': [Eq(-3*log(x**(S(2)/3)*f(x)) + 3*log(3*x**(S(4)/3)*f(x)**2 + 1)/2, C1 + log(x))], + 'simplify_flag': False, + }, + + 'separable_reduced_05': { + 'eq': Eq(f(x).diff(x) + f(x)/x * (1 + (x*f(x))**2), 0), + 'sol': [Eq(f(x), -sqrt(2)*sqrt(1/(C1 + log(x)))/(2*x)),\ + Eq(f(x), sqrt(2)*sqrt(1/(C1 + log(x)))/(2*x))], + }, + + 'separable_reduced_06': { + 'eq': Eq(f(x).diff(x) + (x**4*f(x)**2 + x**2*f(x))*f(x)/(x*(x**6*f(x)**3 + x**4*f(x)**2)), 0), + 'sol': [Eq(f(x), C1 + 1/(2*x**2))], + }, + + 'separable_reduced_07': { + 'eq': Eq(f(x).diff(x) + (f(x)**2)*f(x)/(x), 0), + 'sol': [ + Eq(f(x), -sqrt(2)*sqrt(1/(C1 + log(x)))/2), + Eq(f(x), sqrt(2)*sqrt(1/(C1 + log(x)))/2) + ], + }, + + 'separable_reduced_08': { + 'eq': Eq(f(x).diff(x) + (f(x)+3)*f(x)/(x*(f(x)+2)), 0), + 'sol': [Eq(-log(f(x) + 3)/3 - 2*log(f(x))/3, C1 + log(x))], + 'simplify_flag': False, + 'XFAIL': ['lie_group'], #It hangs. + }, + + 'separable_reduced_09': { + 'eq': Eq(f(x).diff(x) + (f(x)+3)*f(x)/x, 0), + 'sol': [Eq(f(x), 3/(C1*x**3 - 1))], + }, + + 'separable_reduced_10': { + 'eq': Eq(f(x).diff(x) + (f(x)**2+f(x))*f(x)/(x), 0), + 'sol': [Eq(- log(x) - log(f(x) + 1) + log(f(x)) + 1/f(x), C1)], + 'XFAIL': ['lie_group'],#No algorithms are implemented to solve equation -C1 + x*(_y + 1)*exp(-1/_y)/_y + + }, + + # Equivalent to example_name 'separable_reduced_02'. Only difference is testing with simplify=True + 'separable_reduced_11': { + 'eq': f(x).diff(x) + (f(x) / (x**4*f(x) - x)), + 'sol': [Eq(f(x), -sqrt(2)*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) +- 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)/6 +- sqrt(2)*sqrt(-3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) ++ 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 4/x**6 +- 4*sqrt(2)/(x**9*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) +- 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)))/6 + 1/(3*x**3)), +Eq(f(x), -sqrt(2)*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) +- 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)/6 ++ sqrt(2)*sqrt(-3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) ++ 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 4/x**6 +- 4*sqrt(2)/(x**9*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) +- 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)))/6 + 1/(3*x**3)), +Eq(f(x), sqrt(2)*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) +- 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)/6 +- sqrt(2)*sqrt(-3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) ++ 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) ++ 4/x**6 + 4*sqrt(2)/(x**9*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) +- 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)))/6 + 1/(3*x**3)), +Eq(f(x), sqrt(2)*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) +- 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)/6 ++ sqrt(2)*sqrt(-3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) ++ x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 4/x**6 + 4*sqrt(2)/(x**9*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) +- exp(12*C1)/x**6)**Rational(1,3) - 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)))/6 + 1/(3*x**3))], + 'checkodesol_XFAIL':True, #It hangs for this. + 'slow': True, + }, + + #These were from issue: https://github.com/sympy/sympy/issues/6247 + 'separable_reduced_12': { + 'eq': x**2*f(x)**2 + x*Derivative(f(x), x), + 'sol': [Eq(f(x), 2*C1/(C1*x**2 - 1))], + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_lie_group(): + a, b, c = symbols("a b c") + return { + 'hint': "lie_group", + 'func': f(x), + 'examples':{ + #Example 1-4 and 19-20 were from issue: https://github.com/sympy/sympy/issues/17322 + 'lie_group_01': { + 'eq': x*f(x).diff(x)*(f(x)+4) + (f(x)**2) -2*f(x)-2*x, + 'sol': [], + 'dsolve_too_slow': True, + 'checkodesol_too_slow': True, + }, + + 'lie_group_02': { + 'eq': x*f(x).diff(x)*(f(x)+4) + (f(x)**2) -2*f(x)-2*x, + 'sol': [], + 'dsolve_too_slow': True, + }, + + 'lie_group_03': { + 'eq': Eq(x**7*Derivative(f(x), x) + 5*x**3*f(x)**2 - (2*x**2 + 2)*f(x)**3, 0), + 'sol': [], + 'dsolve_too_slow': True, + }, + + 'lie_group_04': { + 'eq': f(x).diff(x) - (f(x) - x*log(x))**2/x**2 + log(x), + 'sol': [], + 'XFAIL': ['lie_group'], + }, + + 'lie_group_05': { + 'eq': f(x).diff(x)**2, + 'sol': [Eq(f(x), C1)], + 'XFAIL': ['factorable'], #It raises Not Implemented error + }, + + 'lie_group_06': { + 'eq': Eq(f(x).diff(x), x**2*f(x)), + 'sol': [Eq(f(x), C1*exp(x**3)**Rational(1, 3))], + }, + + 'lie_group_07': { + 'eq': f(x).diff(x) + a*f(x) - c*exp(b*x), + 'sol': [Eq(f(x), Piecewise(((-C1*(a + b) + c*exp(x*(a + b)))*exp(-a*x)/(a + b),\ + Ne(a, -b)), ((-C1 + c*x)*exp(-a*x), True)))], + }, + + 'lie_group_08': { + 'eq': f(x).diff(x) + 2*x*f(x) - x*exp(-x**2), + 'sol': [Eq(f(x), (C1 + x**2/2)*exp(-x**2))], + }, + + 'lie_group_09': { + 'eq': (1 + 2*x)*(f(x).diff(x)) + 2 - 4*exp(-f(x)), + 'sol': [Eq(f(x), log(C1/(2*x + 1) + 2))], + }, + + 'lie_group_10': { + 'eq': x**2*(f(x).diff(x)) - f(x) + x**2*exp(x - (1/x)), + 'sol': [Eq(f(x), (C1 - exp(x))*exp(-1/x))], + 'XFAIL': ['factorable'], #It raises Recursion Error (maixmum depth exceeded) + }, + + 'lie_group_11': { + 'eq': x**2*f(x)**2 + x*Derivative(f(x), x), + 'sol': [Eq(f(x), 2/(C1 + x**2))], + }, + + 'lie_group_12': { + 'eq': diff(f(x),x) + 2*x*f(x) - x*exp(-x**2), + 'sol': [Eq(f(x), exp(-x**2)*(C1 + x**2/2))], + }, + + 'lie_group_13': { + 'eq': diff(f(x),x) + f(x)*cos(x) - exp(2*x), + 'sol': [Eq(f(x), exp(-sin(x))*(C1 + Integral(exp(2*x)*exp(sin(x)), x)))], + }, + + 'lie_group_14': { + 'eq': diff(f(x),x) + f(x)*cos(x) - sin(2*x)/2, + 'sol': [Eq(f(x), C1*exp(-sin(x)) + sin(x) - 1)], + }, + + 'lie_group_15': { + 'eq': x*diff(f(x),x) + f(x) - x*sin(x), + 'sol': [Eq(f(x), (C1 - x*cos(x) + sin(x))/x)], + }, + + 'lie_group_16': { + 'eq': x*diff(f(x),x) - f(x) - x/log(x), + 'sol': [Eq(f(x), x*(C1 + log(log(x))))], + }, + + 'lie_group_17': { + 'eq': (f(x).diff(x)-f(x)) * (f(x).diff(x)+f(x)), + 'sol': [Eq(f(x), C1*exp(x)), Eq(f(x), C1*exp(-x))], + }, + + 'lie_group_18': { + 'eq': f(x).diff(x) * (f(x).diff(x) - f(x)), + 'sol': [Eq(f(x), C1*exp(x)), Eq(f(x), C1)], + }, + + 'lie_group_19': { + 'eq': (f(x).diff(x)-f(x)) * (f(x).diff(x)+f(x)), + 'sol': [Eq(f(x), C1*exp(-x)), Eq(f(x), C1*exp(x))], + }, + + 'lie_group_20': { + 'eq': f(x).diff(x)*(f(x).diff(x)+f(x)), + 'sol': [Eq(f(x), C1), Eq(f(x), C1*exp(-x))], + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_2nd_linear_airy(): + return { + 'hint': "2nd_linear_airy", + 'func': f(x), + 'examples':{ + '2nd_lin_airy_01': { + 'eq': f(x).diff(x, 2) - x*f(x), + 'sol': [Eq(f(x), C1*airyai(x) + C2*airybi(x))], + }, + + '2nd_lin_airy_02': { + 'eq': f(x).diff(x, 2) + 2*x*f(x), + 'sol': [Eq(f(x), C1*airyai(-2**(S(1)/3)*x) + C2*airybi(-2**(S(1)/3)*x))], + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_nth_linear_constant_coeff_homogeneous(): + # From Exercise 20, in Ordinary Differential Equations, + # Tenenbaum and Pollard, pg. 220 + a = Symbol('a', positive=True) + k = Symbol('k', real=True) + r1, r2, r3, r4, r5 = [rootof(x**5 + 11*x - 2, n) for n in range(5)] + r6, r7, r8, r9, r10 = [rootof(x**5 - 3*x + 1, n) for n in range(5)] + r11, r12, r13, r14, r15 = [rootof(x**5 - 100*x**3 + 1000*x + 1, n) for n in range(5)] + r16, r17, r18, r19, r20 = [rootof(x**5 - x**4 + 10, n) for n in range(5)] + r21, r22, r23, r24, r25 = [rootof(x**5 - x + 1, n) for n in range(5)] + E = exp(1) + return { + 'hint': "nth_linear_constant_coeff_homogeneous", + 'func': f(x), + 'examples':{ + 'lin_const_coeff_hom_01': { + 'eq': f(x).diff(x, 2) + 2*f(x).diff(x), + 'sol': [Eq(f(x), C1 + C2*exp(-2*x))], + }, + + 'lin_const_coeff_hom_02': { + 'eq': f(x).diff(x, 2) - 3*f(x).diff(x) + 2*f(x), + 'sol': [Eq(f(x), (C1 + C2*exp(x))*exp(x))], + }, + + 'lin_const_coeff_hom_03': { + 'eq': f(x).diff(x, 2) - f(x), + 'sol': [Eq(f(x), C1*exp(-x) + C2*exp(x))], + }, + + 'lin_const_coeff_hom_04': { + 'eq': f(x).diff(x, 3) + f(x).diff(x, 2) - 6*f(x).diff(x), + 'sol': [Eq(f(x), C1 + C2*exp(-3*x) + C3*exp(2*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_05': { + 'eq': 6*f(x).diff(x, 2) - 11*f(x).diff(x) + 4*f(x), + 'sol': [Eq(f(x), C1*exp(x/2) + C2*exp(x*Rational(4, 3)))], + 'slow': True, + }, + + 'lin_const_coeff_hom_06': { + 'eq': Eq(f(x).diff(x, 2) + 2*f(x).diff(x) - f(x), 0), + 'sol': [Eq(f(x), C1*exp(x*(-1 + sqrt(2))) + C2*exp(-x*(sqrt(2) + 1)))], + 'slow': True, + }, + + 'lin_const_coeff_hom_07': { + 'eq': diff(f(x), x, 3) + diff(f(x), x, 2) - 10*diff(f(x), x) - 6*f(x), + 'sol': [Eq(f(x), C1*exp(3*x) + C3*exp(-x*(2 + sqrt(2))) + C2*exp(x*(-2 + sqrt(2))))], + 'slow': True, + }, + + 'lin_const_coeff_hom_08': { + 'eq': f(x).diff(x, 4) - f(x).diff(x, 3) - 4*f(x).diff(x, 2) + \ + 4*f(x).diff(x), + 'sol': [Eq(f(x), C1 + C2*exp(-2*x) + C3*exp(x) + C4*exp(2*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_09': { + 'eq': f(x).diff(x, 4) + 4*f(x).diff(x, 3) + f(x).diff(x, 2) - \ + 4*f(x).diff(x) - 2*f(x), + 'sol': [Eq(f(x), C3*exp(-x) + C4*exp(x) + (C1*exp(-sqrt(2)*x) + C2*exp(sqrt(2)*x))*exp(-2*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_10': { + 'eq': f(x).diff(x, 4) - a**2*f(x), + 'sol': [Eq(f(x), C1*exp(-sqrt(a)*x) + C2*exp(sqrt(a)*x) + C3*sin(sqrt(a)*x) + C4*cos(sqrt(a)*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_11': { + 'eq': f(x).diff(x, 2) - 2*k*f(x).diff(x) - 2*f(x), + 'sol': [Eq(f(x), C1*exp(x*(k - sqrt(k**2 + 2))) + C2*exp(x*(k + sqrt(k**2 + 2))))], + 'slow': True, + }, + + 'lin_const_coeff_hom_12': { + 'eq': f(x).diff(x, 2) + 4*k*f(x).diff(x) - 12*k**2*f(x), + 'sol': [Eq(f(x), C1*exp(-6*k*x) + C2*exp(2*k*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_13': { + 'eq': f(x).diff(x, 4), + 'sol': [Eq(f(x), C1 + C2*x + C3*x**2 + C4*x**3)], + 'slow': True, + }, + + 'lin_const_coeff_hom_14': { + 'eq': f(x).diff(x, 2) + 4*f(x).diff(x) + 4*f(x), + 'sol': [Eq(f(x), (C1 + C2*x)*exp(-2*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_15': { + 'eq': 3*f(x).diff(x, 3) + 5*f(x).diff(x, 2) + f(x).diff(x) - f(x), + 'sol': [Eq(f(x), (C1 + C2*x)*exp(-x) + C3*exp(x/3))], + 'slow': True, + }, + + 'lin_const_coeff_hom_16': { + 'eq': f(x).diff(x, 3) - 6*f(x).diff(x, 2) + 12*f(x).diff(x) - 8*f(x), + 'sol': [Eq(f(x), (C1 + x*(C2 + C3*x))*exp(2*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_17': { + 'eq': f(x).diff(x, 2) - 2*a*f(x).diff(x) + a**2*f(x), + 'sol': [Eq(f(x), (C1 + C2*x)*exp(a*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_18': { + 'eq': f(x).diff(x, 4) + 3*f(x).diff(x, 3), + 'sol': [Eq(f(x), C1 + C2*x + C3*x**2 + C4*exp(-3*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_19': { + 'eq': f(x).diff(x, 4) - 2*f(x).diff(x, 2), + 'sol': [Eq(f(x), C1 + C2*x + C3*exp(-sqrt(2)*x) + C4*exp(sqrt(2)*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_20': { + 'eq': f(x).diff(x, 4) + 2*f(x).diff(x, 3) - 11*f(x).diff(x, 2) - \ + 12*f(x).diff(x) + 36*f(x), + 'sol': [Eq(f(x), (C1 + C2*x)*exp(-3*x) + (C3 + C4*x)*exp(2*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_21': { + 'eq': 36*f(x).diff(x, 4) - 37*f(x).diff(x, 2) + 4*f(x).diff(x) + 5*f(x), + 'sol': [Eq(f(x), C1*exp(-x) + C2*exp(-x/3) + C3*exp(x/2) + C4*exp(x*Rational(5, 6)))], + 'slow': True, + }, + + 'lin_const_coeff_hom_22': { + 'eq': f(x).diff(x, 4) - 8*f(x).diff(x, 2) + 16*f(x), + 'sol': [Eq(f(x), (C1 + C2*x)*exp(-2*x) + (C3 + C4*x)*exp(2*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_23': { + 'eq': f(x).diff(x, 2) - 2*f(x).diff(x) + 5*f(x), + 'sol': [Eq(f(x), (C1*sin(2*x) + C2*cos(2*x))*exp(x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_24': { + 'eq': f(x).diff(x, 2) - f(x).diff(x) + f(x), + 'sol': [Eq(f(x), (C1*sin(x*sqrt(3)/2) + C2*cos(x*sqrt(3)/2))*exp(x/2))], + 'slow': True, + }, + + 'lin_const_coeff_hom_25': { + 'eq': f(x).diff(x, 4) + 5*f(x).diff(x, 2) + 6*f(x), + 'sol': [Eq(f(x), + C1*sin(sqrt(2)*x) + C2*sin(sqrt(3)*x) + C3*cos(sqrt(2)*x) + C4*cos(sqrt(3)*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_26': { + 'eq': f(x).diff(x, 2) - 4*f(x).diff(x) + 20*f(x), + 'sol': [Eq(f(x), (C1*sin(4*x) + C2*cos(4*x))*exp(2*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_27': { + 'eq': f(x).diff(x, 4) + 4*f(x).diff(x, 2) + 4*f(x), + 'sol': [Eq(f(x), (C1 + C2*x)*sin(x*sqrt(2)) + (C3 + C4*x)*cos(x*sqrt(2)))], + 'slow': True, + }, + + 'lin_const_coeff_hom_28': { + 'eq': f(x).diff(x, 3) + 8*f(x), + 'sol': [Eq(f(x), (C1*sin(x*sqrt(3)) + C2*cos(x*sqrt(3)))*exp(x) + C3*exp(-2*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_29': { + 'eq': f(x).diff(x, 4) + 4*f(x).diff(x, 2), + 'sol': [Eq(f(x), C1 + C2*x + C3*sin(2*x) + C4*cos(2*x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_30': { + 'eq': f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x), + 'sol': [Eq(f(x), C1 + (C2 + C3*x)*sin(x) + (C4 + C5*x)*cos(x))], + 'slow': True, + }, + + 'lin_const_coeff_hom_31': { + 'eq': f(x).diff(x, 4) + f(x).diff(x, 2) + f(x), + 'sol': [Eq(f(x), (C1*sin(sqrt(3)*x/2) + C2*cos(sqrt(3)*x/2))*exp(-x/2) + + (C3*sin(sqrt(3)*x/2) + C4*cos(sqrt(3)*x/2))*exp(x/2))], + 'slow': True, + }, + + 'lin_const_coeff_hom_32': { + 'eq': f(x).diff(x, 4) + 4*f(x).diff(x, 2) + f(x), + 'sol': [Eq(f(x), C1*sin(x*sqrt(-sqrt(3) + 2)) + C2*sin(x*sqrt(sqrt(3) + 2)) + + C3*cos(x*sqrt(-sqrt(3) + 2)) + C4*cos(x*sqrt(sqrt(3) + 2)))], + 'slow': True, + }, + + # One real root, two complex conjugate pairs + 'lin_const_coeff_hom_33': { + 'eq': f(x).diff(x, 5) + 11*f(x).diff(x) - 2*f(x), + 'sol': [Eq(f(x), + C5*exp(r1*x) + exp(re(r2)*x) * (C1*sin(im(r2)*x) + C2*cos(im(r2)*x)) + + exp(re(r4)*x) * (C3*sin(im(r4)*x) + C4*cos(im(r4)*x)))], + 'checkodesol_XFAIL':True, #It Hangs + }, + + # Three real roots, one complex conjugate pair + 'lin_const_coeff_hom_34': { + 'eq': f(x).diff(x,5) - 3*f(x).diff(x) + f(x), + 'sol': [Eq(f(x), + C3*exp(r6*x) + C4*exp(r7*x) + C5*exp(r8*x) + + exp(re(r9)*x) * (C1*sin(im(r9)*x) + C2*cos(im(r9)*x)))], + 'checkodesol_XFAIL':True, #It Hangs + }, + + # Five distinct real roots + 'lin_const_coeff_hom_35': { + 'eq': f(x).diff(x,5) - 100*f(x).diff(x,3) + 1000*f(x).diff(x) + f(x), + 'sol': [Eq(f(x), C1*exp(r11*x) + C2*exp(r12*x) + C3*exp(r13*x) + C4*exp(r14*x) + C5*exp(r15*x))], + 'checkodesol_XFAIL':True, #It Hangs + }, + + # Rational root and unsolvable quintic + 'lin_const_coeff_hom_36': { + 'eq': f(x).diff(x, 6) - 6*f(x).diff(x, 5) + 5*f(x).diff(x, 4) + 10*f(x).diff(x) - 50 * f(x), + 'sol': [Eq(f(x), + C5*exp(5*x) + + C6*exp(x*r16) + + exp(re(r17)*x) * (C1*sin(im(r17)*x) + C2*cos(im(r17)*x)) + + exp(re(r19)*x) * (C3*sin(im(r19)*x) + C4*cos(im(r19)*x)))], + 'checkodesol_XFAIL':True, #It Hangs + }, + + # Five double roots (this is (x**5 - x + 1)**2) + 'lin_const_coeff_hom_37': { + 'eq': f(x).diff(x, 10) - 2*f(x).diff(x, 6) + 2*f(x).diff(x, 5) + + f(x).diff(x, 2) - 2*f(x).diff(x, 1) + f(x), + 'sol': [Eq(f(x), (C1 + C2*x)*exp(x*r21) + (-((C3 + C4*x)*sin(x*im(r22))) + + (C5 + C6*x)*cos(x*im(r22)))*exp(x*re(r22)) + (-((C7 + C8*x)*sin(x*im(r24))) + + (C10*x + C9)*cos(x*im(r24)))*exp(x*re(r24)))], + 'checkodesol_XFAIL':True, #It Hangs + }, + + 'lin_const_coeff_hom_38': { + 'eq': Eq(sqrt(2) * f(x).diff(x,x,x) + f(x).diff(x), 0), + 'sol': [Eq(f(x), C1 + C2*sin(2**Rational(3, 4)*x/2) + C3*cos(2**Rational(3, 4)*x/2))], + }, + + 'lin_const_coeff_hom_39': { + 'eq': Eq(E * f(x).diff(x,x,x) + f(x).diff(x), 0), + 'sol': [Eq(f(x), C1 + C2*sin(x/sqrt(E)) + C3*cos(x/sqrt(E)))], + }, + + 'lin_const_coeff_hom_40': { + 'eq': Eq(pi * f(x).diff(x,x,x) + f(x).diff(x), 0), + 'sol': [Eq(f(x), C1 + C2*sin(x/sqrt(pi)) + C3*cos(x/sqrt(pi)))], + }, + + 'lin_const_coeff_hom_41': { + 'eq': Eq(I * f(x).diff(x,x,x) + f(x).diff(x), 0), + 'sol': [Eq(f(x), C1 + C2*exp(-sqrt(I)*x) + C3*exp(sqrt(I)*x))], + }, + + 'lin_const_coeff_hom_42': { + 'eq': f(x).diff(x, x) + y*f(x), + 'sol': [Eq(f(x), C1*exp(-x*sqrt(-y)) + C2*exp(x*sqrt(-y)))], + }, + + 'lin_const_coeff_hom_43': { + 'eq': Eq(9*f(x).diff(x, x) + f(x), 0), + 'sol': [Eq(f(x), C1*sin(x/3) + C2*cos(x/3))], + }, + + 'lin_const_coeff_hom_44': { + 'eq': Eq(9*f(x).diff(x, x), f(x)), + 'sol': [Eq(f(x), C1*exp(-x/3) + C2*exp(x/3))], + }, + + 'lin_const_coeff_hom_45': { + 'eq': Eq(f(x).diff(x, x) - 3*diff(f(x), x) + 2*f(x), 0), + 'sol': [Eq(f(x), (C1 + C2*exp(x))*exp(x))], + }, + + 'lin_const_coeff_hom_46': { + 'eq': Eq(f(x).diff(x, x) - 4*diff(f(x), x) + 4*f(x), 0), + 'sol': [Eq(f(x), (C1 + C2*x)*exp(2*x))], + }, + + # Type: 2nd order, constant coefficients (two real equal roots) + 'lin_const_coeff_hom_47': { + 'eq': Eq(f(x).diff(x, x) + 2*diff(f(x), x) + 3*f(x), 0), + 'sol': [Eq(f(x), (C1*sin(x*sqrt(2)) + C2*cos(x*sqrt(2)))*exp(-x))], + }, + + #These were from issue: https://github.com/sympy/sympy/issues/6247 + 'lin_const_coeff_hom_48': { + 'eq': f(x).diff(x, x) + 4*f(x), + 'sol': [Eq(f(x), C1*sin(2*x) + C2*cos(2*x))], + }, + } + } + + +@_add_example_keys +def _get_examples_ode_sol_1st_homogeneous_coeff_subs_dep_div_indep(): + return { + 'hint': "1st_homogeneous_coeff_subs_dep_div_indep", + 'func': f(x), + 'examples':{ + 'dep_div_indep_01': { + 'eq': f(x)/x*cos(f(x)/x) - (x/f(x)*sin(f(x)/x) + cos(f(x)/x))*f(x).diff(x), + 'sol': [Eq(log(x), C1 - log(f(x)*sin(f(x)/x)/x))], + 'slow': True + }, + + #indep_div_dep actually has a simpler solution for example 2 but it runs too slow. + 'dep_div_indep_02': { + 'eq': x*f(x).diff(x) - f(x) - x*sin(f(x)/x), + 'sol': [Eq(log(x), log(C1) + log(cos(f(x)/x) - 1)/2 - log(cos(f(x)/x) + 1)/2)], + 'simplify_flag':False, + }, + + 'dep_div_indep_03': { + 'eq': x*exp(f(x)/x) - f(x)*sin(f(x)/x) + x*sin(f(x)/x)*f(x).diff(x), + 'sol': [Eq(log(x), C1 + exp(-f(x)/x)*sin(f(x)/x)/2 + exp(-f(x)/x)*cos(f(x)/x)/2)], + 'slow': True + }, + + 'dep_div_indep_04': { + 'eq': f(x).diff(x) - f(x)/x + 1/sin(f(x)/x), + 'sol': [Eq(f(x), x*(-acos(C1 + log(x)) + 2*pi)), Eq(f(x), x*acos(C1 + log(x)))], + 'slow': True + }, + + # previous code was testing with these other solution: + # example5_solb = Eq(f(x), log(log(C1/x)**(-x))) + 'dep_div_indep_05': { + 'eq': x*exp(f(x)/x) + f(x) - x*f(x).diff(x), + 'sol': [Eq(f(x), log((1/(C1 - log(x)))**x))], + 'checkodesol_XFAIL':True, #(because of **x?) + }, + } + } + +@_add_example_keys +def _get_examples_ode_sol_linear_coefficients(): + return { + 'hint': "linear_coefficients", + 'func': f(x), + 'examples':{ + 'linear_coeff_01': { + 'eq': f(x).diff(x) + (3 + 2*f(x))/(x + 3), + 'sol': [Eq(f(x), C1/(x**2 + 6*x + 9) - Rational(3, 2))], + }, + } + } + +@_add_example_keys +def _get_examples_ode_sol_1st_homogeneous_coeff_best(): + return { + 'hint': "1st_homogeneous_coeff_best", + 'func': f(x), + 'examples':{ + # previous code was testing this with other solution: + # example1_solb = Eq(-f(x)/(1 + log(x/f(x))), C1) + '1st_homogeneous_coeff_best_01': { + 'eq': f(x) + (x*log(f(x)/x) - 2*x)*diff(f(x), x), + 'sol': [Eq(f(x), -exp(C1)*LambertW(-x*exp(-C1 + 1)))], + 'checkodesol_XFAIL':True, #(because of LambertW?) + }, + + '1st_homogeneous_coeff_best_02': { + 'eq': 2*f(x)*exp(x/f(x)) + f(x)*f(x).diff(x) - 2*x*exp(x/f(x))*f(x).diff(x), + 'sol': [Eq(log(f(x)), C1 - 2*exp(x/f(x)))], + }, + + # previous code was testing this with other solution: + # example3_solb = Eq(log(C1*x*sqrt(1/x)*sqrt(f(x))) + x**2/(2*f(x)**2), 0) + '1st_homogeneous_coeff_best_03': { + 'eq': 2*x**2*f(x) + f(x)**3 + (x*f(x)**2 - 2*x**3)*f(x).diff(x), + 'sol': [Eq(f(x), exp(2*C1 + LambertW(-2*x**4*exp(-4*C1))/2)/x)], + 'checkodesol_XFAIL':True, #(because of LambertW?) + }, + + '1st_homogeneous_coeff_best_04': { + 'eq': (x + sqrt(f(x)**2 - x*f(x)))*f(x).diff(x) - f(x), + 'sol': [Eq(log(f(x)), C1 - 2*sqrt(-x/f(x) + 1))], + 'slow': True, + }, + + '1st_homogeneous_coeff_best_05': { + 'eq': x + f(x) - (x - f(x))*f(x).diff(x), + 'sol': [Eq(log(x), C1 - log(sqrt(1 + f(x)**2/x**2)) + atan(f(x)/x))], + }, + + '1st_homogeneous_coeff_best_06': { + 'eq': x*f(x).diff(x) - f(x) - x*sin(f(x)/x), + 'sol': [Eq(f(x), 2*x*atan(C1*x))], + }, + + '1st_homogeneous_coeff_best_07': { + 'eq': x**2 + f(x)**2 - 2*x*f(x)*f(x).diff(x), + 'sol': [Eq(f(x), -sqrt(x*(C1 + x))), Eq(f(x), sqrt(x*(C1 + x)))], + }, + + '1st_homogeneous_coeff_best_08': { + 'eq': f(x)**2 + (x*sqrt(f(x)**2 - x**2) - x*f(x))*f(x).diff(x), + 'sol': [Eq(f(x), -C1*sqrt(-x/(x - 2*C1))), Eq(f(x), C1*sqrt(-x/(x - 2*C1)))], + 'checkodesol_XFAIL': True # solutions are valid in a range + }, + } + } + + +def _get_all_examples(): + all_examples = _get_examples_ode_sol_euler_homogeneous + \ + _get_examples_ode_sol_euler_undetermined_coeff + \ + _get_examples_ode_sol_euler_var_para + \ + _get_examples_ode_sol_factorable + \ + _get_examples_ode_sol_bernoulli + \ + _get_examples_ode_sol_nth_algebraic + \ + _get_examples_ode_sol_riccati + \ + _get_examples_ode_sol_1st_linear + \ + _get_examples_ode_sol_1st_exact + \ + _get_examples_ode_sol_almost_linear + \ + _get_examples_ode_sol_nth_order_reducible + \ + _get_examples_ode_sol_nth_linear_undetermined_coefficients + \ + _get_examples_ode_sol_liouville + \ + _get_examples_ode_sol_separable + \ + _get_examples_ode_sol_1st_rational_riccati + \ + _get_examples_ode_sol_nth_linear_var_of_parameters + \ + _get_examples_ode_sol_2nd_linear_bessel + \ + _get_examples_ode_sol_2nd_2F1_hypergeometric + \ + _get_examples_ode_sol_2nd_nonlinear_autonomous_conserved + \ + _get_examples_ode_sol_separable_reduced + \ + _get_examples_ode_sol_lie_group + \ + _get_examples_ode_sol_2nd_linear_airy + \ + _get_examples_ode_sol_nth_linear_constant_coeff_homogeneous +\ + _get_examples_ode_sol_1st_homogeneous_coeff_best +\ + _get_examples_ode_sol_1st_homogeneous_coeff_subs_dep_div_indep +\ + _get_examples_ode_sol_linear_coefficients + + return all_examples diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_subscheck.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_subscheck.py new file mode 100644 index 0000000000000000000000000000000000000000..799c2854e878208721b600767de350cda08cd7e5 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_subscheck.py @@ -0,0 +1,203 @@ +from sympy.core.function import (Derivative, Function, diff) +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.relational import Eq +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.functions.special.error_functions import (Ei, erf, erfi) +from sympy.integrals.integrals import Integral + +from sympy.solvers.ode.subscheck import checkodesol, checksysodesol + +from sympy.functions import besselj, bessely + +from sympy.testing.pytest import raises, slow + + +C0, C1, C2, C3, C4 = symbols('C0:5') +u, x, y, z = symbols('u,x:z', real=True) +f = Function('f') +g = Function('g') +h = Function('h') + + +@slow +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))) + 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 + assert checkodesol(f(x).diff(x), Eq(f(x), x)) == (False, 1) + sol1 = Eq(f(x)**5 + 11*f(x) - 2*f(x) + x, 0) + assert checkodesol(diff(sol1.lhs, x), sol1) == (True, 0) + assert checkodesol(diff(sol1.lhs, x)*exp(f(x)), sol1) == (True, 0) + assert checkodesol(diff(sol1.lhs, x, 2), sol1) == (True, 0) + assert checkodesol(diff(sol1.lhs, x, 2)*exp(f(x)), sol1) == (True, 0) + 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, 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, 0)) == \ + (True, 0) + assert checkodesol(diff(exp(f(x)) + x, x)*x, Eq(exp(f(x)) + x, 0), + solve_for_func=False) == (True, 0) + 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, C2)] + 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, 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) + # Based on test_1st_homogeneous_coeff_ode2_eq3sol. Make sure that + # checkodesol tries back substituting f(x) when it can. + eq3 = x*exp(f(x)/x) + f(x) - x*f(x).diff(x) + sol3 = Eq(f(x), log(log(C1/x)**(-x))) + assert not checkodesol(eq3, sol3)[1].has(f(x)) + # This case was failing intermittently depending on hash-seed: + eqn = Eq(Derivative(x*Derivative(f(x), x), x)/x, exp(x)) + sol = Eq(f(x), C1 + C2*log(x) + exp(x) - Ei(x)) + assert checkodesol(eqn, sol, order=2, solve_for_func=False)[0] + eq = x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (2*x**2 +25)*f(x) + sol = Eq(f(x), C1*besselj(5*I, sqrt(2)*x) + C2*bessely(5*I, sqrt(2)*x)) + assert checkodesol(eq, sol) == (True, 0) + + eqs = [Eq(f(x).diff(x), f(x) + g(x)), Eq(g(x).diff(x), f(x) + g(x))] + sol = [Eq(f(x), -C1 + C2*exp(2*x)), Eq(g(x), C1 + C2*exp(2*x))] + assert checkodesol(eqs, sol) == (True, [0, 0]) + + +def test_checksysodesol(): + x, y, z = symbols('x, y, z', cls=Function) + t = Symbol('t') + eq = (Eq(diff(x(t),t), 9*y(t)), Eq(diff(y(t),t), 12*x(t))) + sol = [Eq(x(t), 9*C1*exp(-6*sqrt(3)*t) + 9*C2*exp(6*sqrt(3)*t)), \ + Eq(y(t), -6*sqrt(3)*C1*exp(-6*sqrt(3)*t) + 6*sqrt(3)*C2*exp(6*sqrt(3)*t))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t), 2*x(t) + 4*y(t)), Eq(diff(y(t),t), 12*x(t) + 41*y(t))) + sol = [Eq(x(t), 4*C1*exp(t*(-sqrt(1713)/2 + Rational(43, 2))) + 4*C2*exp(t*(sqrt(1713)/2 + \ + Rational(43, 2)))), Eq(y(t), C1*(-sqrt(1713)/2 + Rational(39, 2))*exp(t*(-sqrt(1713)/2 + \ + Rational(43, 2))) + C2*(Rational(39, 2) + sqrt(1713)/2)*exp(t*(sqrt(1713)/2 + Rational(43, 2))))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t), x(t) + y(t)), Eq(diff(y(t),t), -2*x(t) + 2*y(t))) + sol = [Eq(x(t), (C1*sin(sqrt(7)*t/2) + C2*cos(sqrt(7)*t/2))*exp(t*Rational(3, 2))), \ + Eq(y(t), ((C1/2 - sqrt(7)*C2/2)*sin(sqrt(7)*t/2) + (sqrt(7)*C1/2 + \ + C2/2)*cos(sqrt(7)*t/2))*exp(t*Rational(3, 2)))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t), x(t) + y(t) + 9), Eq(diff(y(t),t), 2*x(t) + 5*y(t) + 23)) + sol = [Eq(x(t), C1*exp(t*(-sqrt(6) + 3)) + C2*exp(t*(sqrt(6) + 3)) - \ + Rational(22, 3)), Eq(y(t), C1*(-sqrt(6) + 2)*exp(t*(-sqrt(6) + 3)) + C2*(2 + \ + sqrt(6))*exp(t*(sqrt(6) + 3)) - Rational(5, 3))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t), x(t) + y(t) + 81), Eq(diff(y(t),t), -2*x(t) + y(t) + 23)) + sol = [Eq(x(t), (C1*sin(sqrt(2)*t) + C2*cos(sqrt(2)*t))*exp(t) - Rational(58, 3)), \ + Eq(y(t), (sqrt(2)*C1*cos(sqrt(2)*t) - sqrt(2)*C2*sin(sqrt(2)*t))*exp(t) - Rational(185, 3))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t), 5*t*x(t) + 2*y(t)), Eq(diff(y(t),t), 2*x(t) + 5*t*y(t))) + sol = [Eq(x(t), (C1*exp(Integral(2, t).doit()) + C2*exp(-(Integral(2, t)).doit()))*\ + exp((Integral(5*t, t)).doit())), Eq(y(t), (C1*exp((Integral(2, t)).doit()) - \ + C2*exp(-(Integral(2, t)).doit()))*exp((Integral(5*t, t)).doit()))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t)), Eq(diff(y(t),t), -t**2*x(t) + 5*t*y(t))) + sol = [Eq(x(t), (C1*cos((Integral(t**2, t)).doit()) + C2*sin((Integral(t**2, t)).doit()))*\ + exp((Integral(5*t, t)).doit())), Eq(y(t), (-C1*sin((Integral(t**2, t)).doit()) + \ + C2*cos((Integral(t**2, t)).doit()))*exp((Integral(5*t, t)).doit()))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t)), Eq(diff(y(t),t), -t**2*x(t) + (5*t+9*t**2)*y(t))) + sol = [Eq(x(t), (C1*exp((-sqrt(77)/2 + Rational(9, 2))*(Integral(t**2, t)).doit()) + \ + C2*exp((sqrt(77)/2 + Rational(9, 2))*(Integral(t**2, t)).doit()))*exp((Integral(5*t, t)).doit())), \ + Eq(y(t), (C1*(-sqrt(77)/2 + Rational(9, 2))*exp((-sqrt(77)/2 + Rational(9, 2))*(Integral(t**2, t)).doit()) + \ + C2*(sqrt(77)/2 + Rational(9, 2))*exp((sqrt(77)/2 + Rational(9, 2))*(Integral(t**2, t)).doit()))*exp((Integral(5*t, t)).doit()))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t,t), 5*x(t) + 43*y(t)), Eq(diff(y(t),t,t), x(t) + 9*y(t))) + root0 = -sqrt(-sqrt(47) + 7) + root1 = sqrt(-sqrt(47) + 7) + root2 = -sqrt(sqrt(47) + 7) + root3 = sqrt(sqrt(47) + 7) + sol = [Eq(x(t), 43*C1*exp(t*root0) + 43*C2*exp(t*root1) + 43*C3*exp(t*root2) + 43*C4*exp(t*root3)), \ + Eq(y(t), C1*(root0**2 - 5)*exp(t*root0) + C2*(root1**2 - 5)*exp(t*root1) + \ + C3*(root2**2 - 5)*exp(t*root2) + C4*(root3**2 - 5)*exp(t*root3))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t,t), 8*x(t)+3*y(t)+31), Eq(diff(y(t),t,t), 9*x(t)+7*y(t)+12)) + root0 = -sqrt(-sqrt(109)/2 + Rational(15, 2)) + root1 = sqrt(-sqrt(109)/2 + Rational(15, 2)) + root2 = -sqrt(sqrt(109)/2 + Rational(15, 2)) + root3 = sqrt(sqrt(109)/2 + Rational(15, 2)) + sol = [Eq(x(t), 3*C1*exp(t*root0) + 3*C2*exp(t*root1) + 3*C3*exp(t*root2) + 3*C4*exp(t*root3) - Rational(181, 29)), \ + Eq(y(t), C1*(root0**2 - 8)*exp(t*root0) + C2*(root1**2 - 8)*exp(t*root1) + \ + C3*(root2**2 - 8)*exp(t*root2) + C4*(root3**2 - 8)*exp(t*root3) + Rational(183, 29))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t,t) - 9*diff(y(t),t) + 7*x(t),0), Eq(diff(y(t),t,t) + 9*diff(x(t),t) + 7*y(t),0)) + sol = [Eq(x(t), C1*cos(t*(Rational(9, 2) + sqrt(109)/2)) + C2*sin(t*(Rational(9, 2) + sqrt(109)/2)) + \ + C3*cos(t*(-sqrt(109)/2 + Rational(9, 2))) + C4*sin(t*(-sqrt(109)/2 + Rational(9, 2)))), Eq(y(t), -C1*sin(t*(Rational(9, 2) + sqrt(109)/2)) \ + + C2*cos(t*(Rational(9, 2) + sqrt(109)/2)) - C3*sin(t*(-sqrt(109)/2 + Rational(9, 2))) + C4*cos(t*(-sqrt(109)/2 + Rational(9, 2))))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t,t), 9*t*diff(y(t),t)-9*y(t)), Eq(diff(y(t),t,t),7*t*diff(x(t),t)-7*x(t))) + I1 = sqrt(6)*7**Rational(1, 4)*sqrt(pi)*erfi(sqrt(6)*7**Rational(1, 4)*t/2)/2 - exp(3*sqrt(7)*t**2/2)/t + I2 = -sqrt(6)*7**Rational(1, 4)*sqrt(pi)*erf(sqrt(6)*7**Rational(1, 4)*t/2)/2 - exp(-3*sqrt(7)*t**2/2)/t + sol = [Eq(x(t), C3*t + t*(9*C1*I1 + 9*C2*I2)), Eq(y(t), C4*t + t*(3*sqrt(7)*C1*I1 - 3*sqrt(7)*C2*I2))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t), 21*x(t)), Eq(diff(y(t),t), 17*x(t)+3*y(t)), Eq(diff(z(t),t), 5*x(t)+7*y(t)+9*z(t))) + sol = [Eq(x(t), C1*exp(21*t)), Eq(y(t), 17*C1*exp(21*t)/18 + C2*exp(3*t)), \ + Eq(z(t), 209*C1*exp(21*t)/216 - 7*C2*exp(3*t)/6 + C3*exp(9*t))] + assert checksysodesol(eq, sol) == (True, [0, 0, 0]) + + eq = (Eq(diff(x(t),t),3*y(t)-11*z(t)),Eq(diff(y(t),t),7*z(t)-3*x(t)),Eq(diff(z(t),t),11*x(t)-7*y(t))) + sol = [Eq(x(t), 7*C0 + sqrt(179)*C1*cos(sqrt(179)*t) + (77*C1/3 + 130*C2/3)*sin(sqrt(179)*t)), \ + Eq(y(t), 11*C0 + sqrt(179)*C2*cos(sqrt(179)*t) + (-58*C1/3 - 77*C2/3)*sin(sqrt(179)*t)), \ + Eq(z(t), 3*C0 + sqrt(179)*(-7*C1/3 - 11*C2/3)*cos(sqrt(179)*t) + (11*C1 - 7*C2)*sin(sqrt(179)*t))] + assert checksysodesol(eq, sol) == (True, [0, 0, 0]) + + eq = (Eq(3*diff(x(t),t),4*5*(y(t)-z(t))),Eq(4*diff(y(t),t),3*5*(z(t)-x(t))),Eq(5*diff(z(t),t),3*4*(x(t)-y(t)))) + sol = [Eq(x(t), C0 + 5*sqrt(2)*C1*cos(5*sqrt(2)*t) + (12*C1/5 + 164*C2/15)*sin(5*sqrt(2)*t)), \ + Eq(y(t), C0 + 5*sqrt(2)*C2*cos(5*sqrt(2)*t) + (-51*C1/10 - 12*C2/5)*sin(5*sqrt(2)*t)), \ + Eq(z(t), C0 + 5*sqrt(2)*(-9*C1/25 - 16*C2/25)*cos(5*sqrt(2)*t) + (12*C1/5 - 12*C2/5)*sin(5*sqrt(2)*t))] + assert checksysodesol(eq, sol) == (True, [0, 0, 0]) + + eq = (Eq(diff(x(t),t),4*x(t) - z(t)),Eq(diff(y(t),t),2*x(t)+2*y(t)-z(t)),Eq(diff(z(t),t),3*x(t)+y(t))) + sol = [Eq(x(t), C1*exp(2*t) + C2*t*exp(2*t) + C2*exp(2*t) + C3*t**2*exp(2*t)/2 + C3*t*exp(2*t) + C3*exp(2*t)), \ + Eq(y(t), C1*exp(2*t) + C2*t*exp(2*t) + C2*exp(2*t) + C3*t**2*exp(2*t)/2 + C3*t*exp(2*t)), \ + Eq(z(t), 2*C1*exp(2*t) + 2*C2*t*exp(2*t) + C2*exp(2*t) + C3*t**2*exp(2*t) + C3*t*exp(2*t) + C3*exp(2*t))] + assert checksysodesol(eq, sol) == (True, [0, 0, 0]) + + eq = (Eq(diff(x(t),t),4*x(t) - y(t) - 2*z(t)),Eq(diff(y(t),t),2*x(t) + y(t)- 2*z(t)),Eq(diff(z(t),t),5*x(t)-3*z(t))) + sol = [Eq(x(t), C1*exp(2*t) + C2*(-sin(t) + 3*cos(t)) + C3*(3*sin(t) + cos(t))), \ + Eq(y(t), C2*(-sin(t) + 3*cos(t)) + C3*(3*sin(t) + cos(t))), Eq(z(t), C1*exp(2*t) + 5*C2*cos(t) + 5*C3*sin(t))] + assert checksysodesol(eq, sol) == (True, [0, 0, 0]) + + eq = (Eq(diff(x(t),t),x(t)*y(t)**3), Eq(diff(y(t),t),y(t)**5)) + sol = [Eq(x(t), C1*exp((-1/(4*C2 + 4*t))**(Rational(-1, 4)))), Eq(y(t), -(-1/(4*C2 + 4*t))**Rational(1, 4)), \ + Eq(x(t), C1*exp(-1/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), (-1/(4*C2 + 4*t))**Rational(1, 4)), \ + Eq(x(t), C1*exp(-I/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), -I*(-1/(4*C2 + 4*t))**Rational(1, 4)), \ + Eq(x(t), C1*exp(I/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), I*(-1/(4*C2 + 4*t))**Rational(1, 4))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(diff(x(t),t), exp(3*x(t))*y(t)**3),Eq(diff(y(t),t), y(t)**5)) + sol = [Eq(x(t), -log(C1 - 3/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), -(-1/(4*C2 + 4*t))**Rational(1, 4)), \ + Eq(x(t), -log(C1 + 3/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), (-1/(4*C2 + 4*t))**Rational(1, 4)), \ + Eq(x(t), -log(C1 + 3*I/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), -I*(-1/(4*C2 + 4*t))**Rational(1, 4)), \ + Eq(x(t), -log(C1 - 3*I/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), I*(-1/(4*C2 + 4*t))**Rational(1, 4))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + eq = (Eq(x(t),t*diff(x(t),t)+diff(x(t),t)*diff(y(t),t)), Eq(y(t),t*diff(y(t),t)+diff(y(t),t)**2)) + sol = {Eq(x(t), C1*C2 + C1*t), Eq(y(t), C2**2 + C2*t)} + assert checksysodesol(eq, sol) == (True, [0, 0]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_systems.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_systems.py new file mode 100644 index 0000000000000000000000000000000000000000..9d206129dfcf38c7b8c2e0ab42bd875003253f35 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/ode/tests/test_systems.py @@ -0,0 +1,2544 @@ +from sympy.core.function import (Derivative, Function, diff) +from sympy.core.mul import Mul +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.hyperbolic import sinh +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.matrices.dense import Matrix +from sympy.core.containers import Tuple +from sympy.functions import exp, cos, sin, log, Ci, Si, erf, erfi +from sympy.matrices import dotprodsimp, NonSquareMatrixError +from sympy.solvers.ode import dsolve +from sympy.solvers.ode.ode import constant_renumber +from sympy.solvers.ode.subscheck import checksysodesol +from sympy.solvers.ode.systems import (_classify_linear_system, linear_ode_to_matrix, + ODEOrderError, ODENonlinearError, _simpsol, + _is_commutative_anti_derivative, linodesolve, + canonical_odes, dsolve_system, _component_division, + _eqs2dict, _dict2graph) +from sympy.functions import airyai, airybi +from sympy.integrals.integrals import Integral +from sympy.simplify.ratsimp import ratsimp +from sympy.testing.pytest import raises, slow, tooslow, XFAIL + + +C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 = symbols('C0:11') +x = symbols('x') +f = Function('f') +g = Function('g') +h = Function('h') + + +def test_linear_ode_to_matrix(): + f, g, h = symbols("f, g, h", cls=Function) + t = Symbol("t") + funcs = [f(t), g(t), h(t)] + f1 = f(t).diff(t) + g1 = g(t).diff(t) + h1 = h(t).diff(t) + f2 = f(t).diff(t, 2) + g2 = g(t).diff(t, 2) + h2 = h(t).diff(t, 2) + + eqs_1 = [Eq(f1, g(t)), Eq(g1, f(t))] + sol_1 = ([Matrix([[1, 0], [0, 1]]), Matrix([[ 0, 1], [1, 0]])], Matrix([[0],[0]])) + assert linear_ode_to_matrix(eqs_1, funcs[:-1], t, 1) == sol_1 + + eqs_2 = [Eq(f1, f(t) + 2*g(t)), Eq(g1, h(t)), Eq(h1, g(t) + h(t) + f(t))] + sol_2 = ([Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), Matrix([[1, 2, 0], [ 0, 0, 1], [1, 1, 1]])], + Matrix([[0], [0], [0]])) + assert linear_ode_to_matrix(eqs_2, funcs, t, 1) == sol_2 + + eqs_3 = [Eq(2*f1 + 3*h1, f(t) + g(t)), Eq(4*h1 + 5*g1, f(t) + h(t)), Eq(5*f1 + 4*g1, g(t) + h(t))] + sol_3 = ([Matrix([[2, 0, 3], [0, 5, 4], [5, 4, 0]]), Matrix([[1, 1, 0], [1, 0, 1], [0, 1, 1]])], + Matrix([[0], [0], [0]])) + assert linear_ode_to_matrix(eqs_3, funcs, t, 1) == sol_3 + + eqs_4 = [Eq(f2 + h(t), f1 + g(t)), Eq(2*h2 + g2 + g1 + g(t), 0), Eq(3*h1, 4)] + sol_4 = ([Matrix([[1, 0, 0], [0, 1, 2], [0, 0, 0]]), Matrix([[1, 0, 0], [0, -1, 0], [0, 0, -3]]), + Matrix([[0, 1, -1], [0, -1, 0], [0, 0, 0]])], Matrix([[0], [0], [4]])) + assert linear_ode_to_matrix(eqs_4, funcs, t, 2) == sol_4 + + eqs_5 = [Eq(f2, g(t)), Eq(f1 + g1, f(t))] + raises(ODEOrderError, lambda: linear_ode_to_matrix(eqs_5, funcs[:-1], t, 1)) + + eqs_6 = [Eq(f1, f(t)**2), Eq(g1, f(t) + g(t))] + raises(ODENonlinearError, lambda: linear_ode_to_matrix(eqs_6, funcs[:-1], t, 1)) + + +def test__classify_linear_system(): + x, y, z, w = symbols('x, y, z, w', cls=Function) + t, k, l = symbols('t k l') + x1 = diff(x(t), t) + y1 = diff(y(t), t) + z1 = diff(z(t), t) + w1 = diff(w(t), t) + x2 = diff(x(t), t, t) + y2 = diff(y(t), t, t) + funcs = [x(t), y(t)] + funcs_2 = funcs + [z(t), w(t)] + + eqs_1 = (5 * x1 + 12 * x(t) - 6 * (y(t)), (2 * y1 - 11 * t * x(t) + 3 * y(t) + t)) + assert _classify_linear_system(eqs_1, funcs, t) is None + + eqs_2 = (5 * (x1**2) + 12 * x(t) - 6 * (y(t)), (2 * y1 - 11 * t * x(t) + 3 * y(t) + t)) + sol2 = {'is_implicit': True, + 'canon_eqs': [[Eq(Derivative(x(t), t), -sqrt(-12*x(t)/5 + 6*y(t)/5)), + Eq(Derivative(y(t), t), 11*t*x(t)/2 - t/2 - 3*y(t)/2)], + [Eq(Derivative(x(t), t), sqrt(-12*x(t)/5 + 6*y(t)/5)), + Eq(Derivative(y(t), t), 11*t*x(t)/2 - t/2 - 3*y(t)/2)]]} + assert _classify_linear_system(eqs_2, funcs, t) == sol2 + + eqs_2_1 = [Eq(Derivative(x(t), t), -sqrt(-12*x(t)/5 + 6*y(t)/5)), + Eq(Derivative(y(t), t), 11*t*x(t)/2 - t/2 - 3*y(t)/2)] + assert _classify_linear_system(eqs_2_1, funcs, t) is None + + eqs_2_2 = [Eq(Derivative(x(t), t), sqrt(-12*x(t)/5 + 6*y(t)/5)), + Eq(Derivative(y(t), t), 11*t*x(t)/2 - t/2 - 3*y(t)/2)] + assert _classify_linear_system(eqs_2_2, funcs, t) is None + + eqs_3 = (5 * x1 + 12 * x(t) - 6 * (y(t)), (2 * y1 - 11 * x(t) + 3 * y(t)), (5 * w1 + z(t)), (z1 + w(t))) + answer_3 = {'no_of_equation': 4, + 'eq': (12*x(t) - 6*y(t) + 5*Derivative(x(t), t), + -11*x(t) + 3*y(t) + 2*Derivative(y(t), t), + z(t) + 5*Derivative(w(t), t), + w(t) + Derivative(z(t), t)), + 'func': [x(t), y(t), z(t), w(t)], + 'order': {x(t): 1, y(t): 1, z(t): 1, w(t): 1}, + 'is_linear': True, + 'is_constant': True, + 'is_homogeneous': True, + 'func_coeff': -Matrix([ + [Rational(12, 5), Rational(-6, 5), 0, 0], + [Rational(-11, 2), Rational(3, 2), 0, 0], + [0, 0, 0, 1], + [0, 0, Rational(1, 5), 0]]), + 'type_of_equation': 'type1', + 'is_general': True} + assert _classify_linear_system(eqs_3, funcs_2, t) == answer_3 + + eqs_4 = (5 * x1 + 12 * x(t) - 6 * (y(t)), (2 * y1 - 11 * x(t) + 3 * y(t)), (z1 - w(t)), (w1 - z(t))) + answer_4 = {'no_of_equation': 4, + 'eq': (12 * x(t) - 6 * y(t) + 5 * Derivative(x(t), t), + -11 * x(t) + 3 * y(t) + 2 * Derivative(y(t), t), + -w(t) + Derivative(z(t), t), + -z(t) + Derivative(w(t), t)), + 'func': [x(t), y(t), z(t), w(t)], + 'order': {x(t): 1, y(t): 1, z(t): 1, w(t): 1}, + 'is_linear': True, + 'is_constant': True, + 'is_homogeneous': True, + 'func_coeff': -Matrix([ + [Rational(12, 5), Rational(-6, 5), 0, 0], + [Rational(-11, 2), Rational(3, 2), 0, 0], + [0, 0, 0, -1], + [0, 0, -1, 0]]), + 'type_of_equation': 'type1', + 'is_general': True} + assert _classify_linear_system(eqs_4, funcs_2, t) == answer_4 + + eqs_5 = (5*x1 + 12*x(t) - 6*(y(t)) + x2, (2*y1 - 11*x(t) + 3*y(t)), (z1 - w(t)), (w1 - z(t))) + answer_5 = {'no_of_equation': 4, 'eq': (12*x(t) - 6*y(t) + 5*Derivative(x(t), t) + Derivative(x(t), (t, 2)), + -11*x(t) + 3*y(t) + 2*Derivative(y(t), t), -w(t) + Derivative(z(t), t), -z(t) + Derivative(w(t), + t)), 'func': [x(t), y(t), z(t), w(t)], 'order': {x(t): 2, y(t): 1, z(t): 1, w(t): 1}, 'is_linear': + True, 'is_homogeneous': True, 'is_general': True, 'type_of_equation': 'type0', 'is_higher_order': True} + assert _classify_linear_system(eqs_5, funcs_2, t) == answer_5 + + eqs_6 = (Eq(x1, 3*y(t) - 11*z(t)), Eq(y1, 7*z(t) - 3*x(t)), Eq(z1, 11*x(t) - 7*y(t))) + answer_6 = {'no_of_equation': 3, 'eq': (Eq(Derivative(x(t), t), 3*y(t) - 11*z(t)), Eq(Derivative(y(t), t), -3*x(t) + 7*z(t)), + Eq(Derivative(z(t), t), 11*x(t) - 7*y(t))), 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, + 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, + 'func_coeff': -Matrix([ + [ 0, -3, 11], + [ 3, 0, -7], + [-11, 7, 0]]), + 'type_of_equation': 'type1', 'is_general': True} + + assert _classify_linear_system(eqs_6, funcs_2[:-1], t) == answer_6 + + eqs_7 = (Eq(x1, y(t)), Eq(y1, x(t))) + answer_7 = {'no_of_equation': 2, 'eq': (Eq(Derivative(x(t), t), y(t)), Eq(Derivative(y(t), t), x(t))), + 'func': [x(t), y(t)], 'order': {x(t): 1, y(t): 1}, 'is_linear': True, 'is_constant': True, + 'is_homogeneous': True, 'func_coeff': -Matrix([ + [ 0, -1], + [-1, 0]]), + 'type_of_equation': 'type1', 'is_general': True} + assert _classify_linear_system(eqs_7, funcs, t) == answer_7 + + eqs_8 = (Eq(x1, 21*x(t)), Eq(y1, 17*x(t) + 3*y(t)), Eq(z1, 5*x(t) + 7*y(t) + 9*z(t))) + answer_8 = {'no_of_equation': 3, 'eq': (Eq(Derivative(x(t), t), 21*x(t)), Eq(Derivative(y(t), t), 17*x(t) + 3*y(t)), + Eq(Derivative(z(t), t), 5*x(t) + 7*y(t) + 9*z(t))), 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, + 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, + 'func_coeff': -Matrix([ + [-21, 0, 0], + [-17, -3, 0], + [ -5, -7, -9]]), + 'type_of_equation': 'type1', 'is_general': True} + + assert _classify_linear_system(eqs_8, funcs_2[:-1], t) == answer_8 + + eqs_9 = (Eq(x1, 4*x(t) + 5*y(t) + 2*z(t)), Eq(y1, x(t) + 13*y(t) + 9*z(t)), Eq(z1, 32*x(t) + 41*y(t) + 11*z(t))) + answer_9 = {'no_of_equation': 3, 'eq': (Eq(Derivative(x(t), t), 4*x(t) + 5*y(t) + 2*z(t)), + Eq(Derivative(y(t), t), x(t) + 13*y(t) + 9*z(t)), Eq(Derivative(z(t), t), 32*x(t) + 41*y(t) + 11*z(t))), + 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, + 'is_constant': True, 'is_homogeneous': True, + 'func_coeff': -Matrix([ + [ -4, -5, -2], + [ -1, -13, -9], + [-32, -41, -11]]), + 'type_of_equation': 'type1', 'is_general': True} + assert _classify_linear_system(eqs_9, funcs_2[:-1], t) == answer_9 + + eqs_10 = (Eq(3*x1, 4*5*(y(t) - z(t))), Eq(4*y1, 3*5*(z(t) - x(t))), Eq(5*z1, 3*4*(x(t) - y(t)))) + answer_10 = {'no_of_equation': 3, 'eq': (Eq(3*Derivative(x(t), t), 20*y(t) - 20*z(t)), + Eq(4*Derivative(y(t), t), -15*x(t) + 15*z(t)), Eq(5*Derivative(z(t), t), 12*x(t) - 12*y(t))), + 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, + 'is_constant': True, 'is_homogeneous': True, + 'func_coeff': -Matrix([ + [ 0, Rational(-20, 3), Rational(20, 3)], + [Rational(15, 4), 0, Rational(-15, 4)], + [Rational(-12, 5), Rational(12, 5), 0]]), + 'type_of_equation': 'type1', 'is_general': True} + assert _classify_linear_system(eqs_10, funcs_2[:-1], t) == answer_10 + + eq11 = (Eq(x1, 3*y(t) - 11*z(t)), Eq(y1, 7*z(t) - 3*x(t)), Eq(z1, 11*x(t) - 7*y(t))) + sol11 = {'no_of_equation': 3, 'eq': (Eq(Derivative(x(t), t), 3*y(t) - 11*z(t)), Eq(Derivative(y(t), t), -3*x(t) + 7*z(t)), + Eq(Derivative(z(t), t), 11*x(t) - 7*y(t))), 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, + 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ + [ 0, -3, 11], [ 3, 0, -7], [-11, 7, 0]]), 'type_of_equation': 'type1', 'is_general': True} + assert _classify_linear_system(eq11, funcs_2[:-1], t) == sol11 + + eq12 = (Eq(Derivative(x(t), t), y(t)), Eq(Derivative(y(t), t), x(t))) + sol12 = {'no_of_equation': 2, 'eq': (Eq(Derivative(x(t), t), y(t)), Eq(Derivative(y(t), t), x(t))), + 'func': [x(t), y(t)], 'order': {x(t): 1, y(t): 1}, 'is_linear': True, 'is_constant': True, + 'is_homogeneous': True, 'func_coeff': -Matrix([ + [0, -1], + [-1, 0]]), 'type_of_equation': 'type1', 'is_general': True} + assert _classify_linear_system(eq12, [x(t), y(t)], t) == sol12 + + eq13 = (Eq(Derivative(x(t), t), 21*x(t)), Eq(Derivative(y(t), t), 17*x(t) + 3*y(t)), + Eq(Derivative(z(t), t), 5*x(t) + 7*y(t) + 9*z(t))) + sol13 = {'no_of_equation': 3, 'eq': ( + Eq(Derivative(x(t), t), 21 * x(t)), Eq(Derivative(y(t), t), 17 * x(t) + 3 * y(t)), + Eq(Derivative(z(t), t), 5 * x(t) + 7 * y(t) + 9 * z(t))), 'func': [x(t), y(t), z(t)], + 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, + 'func_coeff': -Matrix([ + [-21, 0, 0], + [-17, -3, 0], + [-5, -7, -9]]), 'type_of_equation': 'type1', 'is_general': True} + assert _classify_linear_system(eq13, [x(t), y(t), z(t)], t) == sol13 + + eq14 = ( + Eq(Derivative(x(t), t), 4*x(t) + 5*y(t) + 2*z(t)), Eq(Derivative(y(t), t), x(t) + 13*y(t) + 9*z(t)), + Eq(Derivative(z(t), t), 32*x(t) + 41*y(t) + 11*z(t))) + sol14 = {'no_of_equation': 3, 'eq': ( + Eq(Derivative(x(t), t), 4 * x(t) + 5 * y(t) + 2 * z(t)), Eq(Derivative(y(t), t), x(t) + 13 * y(t) + 9 * z(t)), + Eq(Derivative(z(t), t), 32 * x(t) + 41 * y(t) + 11 * z(t))), 'func': [x(t), y(t), z(t)], + 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, + 'func_coeff': -Matrix([ + [-4, -5, -2], + [-1, -13, -9], + [-32, -41, -11]]), 'type_of_equation': 'type1', 'is_general': True} + assert _classify_linear_system(eq14, [x(t), y(t), z(t)], t) == sol14 + + eq15 = (Eq(3*Derivative(x(t), t), 20*y(t) - 20*z(t)), Eq(4*Derivative(y(t), t), -15*x(t) + 15*z(t)), + Eq(5*Derivative(z(t), t), 12*x(t) - 12*y(t))) + sol15 = {'no_of_equation': 3, 'eq': ( + Eq(3 * Derivative(x(t), t), 20 * y(t) - 20 * z(t)), Eq(4 * Derivative(y(t), t), -15 * x(t) + 15 * z(t)), + Eq(5 * Derivative(z(t), t), 12 * x(t) - 12 * y(t))), 'func': [x(t), y(t), z(t)], + 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, + 'func_coeff': -Matrix([ + [0, Rational(-20, 3), Rational(20, 3)], + [Rational(15, 4), 0, Rational(-15, 4)], + [Rational(-12, 5), Rational(12, 5), 0]]), 'type_of_equation': 'type1', 'is_general': True} + assert _classify_linear_system(eq15, [x(t), y(t), z(t)], t) == sol15 + + # Constant coefficient homogeneous ODEs + eq1 = (Eq(diff(x(t), t), x(t) + y(t) + 9), Eq(diff(y(t), t), 2*x(t) + 5*y(t) + 23)) + sol1 = {'no_of_equation': 2, 'eq': (Eq(Derivative(x(t), t), x(t) + y(t) + 9), + Eq(Derivative(y(t), t), 2*x(t) + 5*y(t) + 23)), 'func': [x(t), y(t)], + 'order': {x(t): 1, y(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': False, 'is_general': True, + 'func_coeff': -Matrix([[-1, -1], [-2, -5]]), 'rhs': Matrix([[ 9], [23]]), 'type_of_equation': 'type2'} + assert _classify_linear_system(eq1, funcs, t) == sol1 + + # Non constant coefficient homogeneous ODEs + eq1 = (Eq(diff(x(t), t), 5*t*x(t) + 2*y(t)), Eq(diff(y(t), t), 2*x(t) + 5*t*y(t))) + sol1 = {'no_of_equation': 2, 'eq': (Eq(Derivative(x(t), t), 5*t*x(t) + 2*y(t)), Eq(Derivative(y(t), t), 5*t*y(t) + 2*x(t))), + 'func': [x(t), y(t)], 'order': {x(t): 1, y(t): 1}, 'is_linear': True, 'is_constant': False, + 'is_homogeneous': True, 'func_coeff': -Matrix([ [-5*t, -2], [ -2, -5*t]]), 'commutative_antiderivative': Matrix([ + [5*t**2/2, 2*t], [ 2*t, 5*t**2/2]]), 'type_of_equation': 'type3', 'is_general': True} + assert _classify_linear_system(eq1, funcs, t) == sol1 + + # Non constant coefficient non-homogeneous ODEs + eq1 = [Eq(x1, x(t) + t*y(t) + t), Eq(y1, t*x(t) + y(t))] + sol1 = {'no_of_equation': 2, 'eq': [Eq(Derivative(x(t), t), t*y(t) + t + x(t)), Eq(Derivative(y(t), t), + t*x(t) + y(t))], 'func': [x(t), y(t)], 'order': {x(t): 1, y(t): 1}, 'is_linear': True, + 'is_constant': False, 'is_homogeneous': False, 'is_general': True, 'func_coeff': -Matrix([ [-1, -t], + [-t, -1]]), 'commutative_antiderivative': Matrix([ [ t, t**2/2], [t**2/2, t]]), 'rhs': + Matrix([ [t], [0]]), 'type_of_equation': 'type4'} + assert _classify_linear_system(eq1, funcs, t) == sol1 + + eq2 = [Eq(x1, t*x(t) + t*y(t) + t), Eq(y1, t*x(t) + t*y(t) + cos(t))] + sol2 = {'no_of_equation': 2, 'eq': [Eq(Derivative(x(t), t), t*x(t) + t*y(t) + t), Eq(Derivative(y(t), t), + t*x(t) + t*y(t) + cos(t))], 'func': [x(t), y(t)], 'order': {x(t): 1, y(t): 1}, 'is_linear': True, + 'is_homogeneous': False, 'is_general': True, 'rhs': Matrix([ [ t], [cos(t)]]), 'func_coeff': + Matrix([ [t, t], [t, t]]), 'is_constant': False, 'type_of_equation': 'type4', + 'commutative_antiderivative': Matrix([ [t**2/2, t**2/2], [t**2/2, t**2/2]])} + assert _classify_linear_system(eq2, funcs, t) == sol2 + + eq3 = [Eq(x1, t*(x(t) + y(t) + z(t) + 1)), Eq(y1, t*(x(t) + y(t) + z(t))), Eq(z1, t*(x(t) + y(t) + z(t)))] + sol3 = {'no_of_equation': 3, 'eq': [Eq(Derivative(x(t), t), t*(x(t) + y(t) + z(t) + 1)), + Eq(Derivative(y(t), t), t*(x(t) + y(t) + z(t))), Eq(Derivative(z(t), t), t*(x(t) + y(t) + z(t)))], + 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': + False, 'is_homogeneous': False, 'is_general': True, 'func_coeff': -Matrix([ [-t, -t, -t], [-t, -t, + -t], [-t, -t, -t]]), 'commutative_antiderivative': Matrix([ [t**2/2, t**2/2, t**2/2], [t**2/2, + t**2/2, t**2/2], [t**2/2, t**2/2, t**2/2]]), 'rhs': Matrix([ [t], [0], [0]]), 'type_of_equation': + 'type4'} + assert _classify_linear_system(eq3, funcs_2[:-1], t) == sol3 + + eq4 = [Eq(x1, x(t) + y(t) + t*z(t) + 1), Eq(y1, x(t) + t*y(t) + z(t) + 10), Eq(z1, t*x(t) + y(t) + z(t) + t)] + sol4 = {'no_of_equation': 3, 'eq': [Eq(Derivative(x(t), t), t*z(t) + x(t) + y(t) + 1), Eq(Derivative(y(t), + t), t*y(t) + x(t) + z(t) + 10), Eq(Derivative(z(t), t), t*x(t) + t + y(t) + z(t))], 'func': [x(t), + y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': False, + 'is_homogeneous': False, 'is_general': True, 'func_coeff': -Matrix([ [-1, -1, -t], [-1, -t, -1], [-t, + -1, -1]]), 'commutative_antiderivative': Matrix([ [ t, t, t**2/2], [ t, t**2/2, + t], [t**2/2, t, t]]), 'rhs': Matrix([ [ 1], [10], [ t]]), 'type_of_equation': 'type4'} + assert _classify_linear_system(eq4, funcs_2[:-1], t) == sol4 + + sum_terms = t*(x(t) + y(t) + z(t) + w(t)) + eq5 = [Eq(x1, sum_terms), Eq(y1, sum_terms), Eq(z1, sum_terms + 1), Eq(w1, sum_terms)] + sol5 = {'no_of_equation': 4, 'eq': [Eq(Derivative(x(t), t), t*(w(t) + x(t) + y(t) + z(t))), + Eq(Derivative(y(t), t), t*(w(t) + x(t) + y(t) + z(t))), Eq(Derivative(z(t), t), t*(w(t) + x(t) + + y(t) + z(t)) + 1), Eq(Derivative(w(t), t), t*(w(t) + x(t) + y(t) + z(t)))], 'func': [x(t), y(t), + z(t), w(t)], 'order': {x(t): 1, y(t): 1, z(t): 1, w(t): 1}, 'is_linear': True, 'is_constant': False, + 'is_homogeneous': False, 'is_general': True, 'func_coeff': -Matrix([ [-t, -t, -t, -t], [-t, -t, -t, + -t], [-t, -t, -t, -t], [-t, -t, -t, -t]]), 'commutative_antiderivative': Matrix([ [t**2/2, t**2/2, + t**2/2, t**2/2], [t**2/2, t**2/2, t**2/2, t**2/2], [t**2/2, t**2/2, t**2/2, t**2/2], [t**2/2, + t**2/2, t**2/2, t**2/2]]), 'rhs': Matrix([ [0], [0], [1], [0]]), 'type_of_equation': 'type4'} + assert _classify_linear_system(eq5, funcs_2, t) == sol5 + + # Second Order + t_ = symbols("t_") + + eq1 = (Eq(9*x(t) + 7*y(t) + 4*Derivative(x(t), t) + Derivative(x(t), (t, 2)) + 3*Derivative(y(t), t), 11*exp(I*t)), + Eq(3*x(t) + 12*y(t) + 5*Derivative(x(t), t) + 8*Derivative(y(t), t) + Derivative(y(t), (t, 2)), 2*exp(I*t))) + sol1 = {'no_of_equation': 2, 'eq': (Eq(9*x(t) + 7*y(t) + 4*Derivative(x(t), t) + Derivative(x(t), (t, 2)) + + 3*Derivative(y(t), t), 11*exp(I*t)), Eq(3*x(t) + 12*y(t) + 5*Derivative(x(t), t) + + 8*Derivative(y(t), t) + Derivative(y(t), (t, 2)), 2*exp(I*t))), 'func': [x(t), y(t)], 'order': + {x(t): 2, y(t): 2}, 'is_linear': True, 'is_homogeneous': False, 'is_general': True, 'rhs': Matrix([ + [11*exp(I*t)], [ 2*exp(I*t)]]), 'type_of_equation': 'type0', 'is_second_order': True, + 'is_higher_order': True} + assert _classify_linear_system(eq1, funcs, t) == sol1 + + eq2 = (Eq((4*t**2 + 7*t + 1)**2*Derivative(x(t), (t, 2)), 5*x(t) + 35*y(t)), + Eq((4*t**2 + 7*t + 1)**2*Derivative(y(t), (t, 2)), x(t) + 9*y(t))) + sol2 = {'no_of_equation': 2, 'eq': (Eq((4*t**2 + 7*t + 1)**2*Derivative(x(t), (t, 2)), 5*x(t) + 35*y(t)), + Eq((4*t**2 + 7*t + 1)**2*Derivative(y(t), (t, 2)), x(t) + 9*y(t))), 'func': [x(t), y(t)], 'order': + {x(t): 2, y(t): 2}, 'is_linear': True, 'is_homogeneous': True, 'is_general': True, + 'type_of_equation': 'type2', 'A0': Matrix([ [Rational(53, 4), 35], [ 1, Rational(69, 4)]]), 'g(t)': sqrt(4*t**2 + 7*t + + 1), 'tau': sqrt(33)*log(t - sqrt(33)/8 + Rational(7, 8))/33 - sqrt(33)*log(t + sqrt(33)/8 + Rational(7, 8))/33, + 'is_transformed': True, 't_': t_, 'is_second_order': True, 'is_higher_order': True} + assert _classify_linear_system(eq2, funcs, t) == sol2 + + eq3 = ((t*Derivative(x(t), t) - x(t))*log(t) + (t*Derivative(y(t), t) - y(t))*exp(t) + Derivative(x(t), (t, 2)), + t**2*(t*Derivative(x(t), t) - x(t)) + t*(t*Derivative(y(t), t) - y(t)) + Derivative(y(t), (t, 2))) + sol3 = {'no_of_equation': 2, 'eq': ((t*Derivative(x(t), t) - x(t))*log(t) + (t*Derivative(y(t), t) - + y(t))*exp(t) + Derivative(x(t), (t, 2)), t**2*(t*Derivative(x(t), t) - x(t)) + t*(t*Derivative(y(t), + t) - y(t)) + Derivative(y(t), (t, 2))), 'func': [x(t), y(t)], 'order': {x(t): 2, y(t): 2}, + 'is_linear': True, 'is_homogeneous': True, 'is_general': True, 'type_of_equation': 'type1', 'A1': + Matrix([ [-t*log(t), -t*exp(t)], [ -t**3, -t**2]]), 'is_second_order': True, + 'is_higher_order': True} + assert _classify_linear_system(eq3, funcs, t) == sol3 + + eq4 = (Eq(x2, k*x(t) - l*y1), Eq(y2, l*x1 + k*y(t))) + sol4 = {'no_of_equation': 2, 'eq': (Eq(Derivative(x(t), (t, 2)), k*x(t) - l*Derivative(y(t), t)), + Eq(Derivative(y(t), (t, 2)), k*y(t) + l*Derivative(x(t), t))), 'func': [x(t), y(t)], 'order': {x(t): + 2, y(t): 2}, 'is_linear': True, 'is_homogeneous': True, 'is_general': True, 'type_of_equation': + 'type0', 'is_second_order': True, 'is_higher_order': True} + assert _classify_linear_system(eq4, funcs, t) == sol4 + + + # Multiple matches + + f, g = symbols("f g", cls=Function) + y, t_ = symbols("y t_") + funcs = [f(t), g(t)] + + eq1 = [Eq(Derivative(f(t), t)**2 - 2*Derivative(f(t), t) + 1, 4), + Eq(-y*f(t) + Derivative(g(t), t), 0)] + sol1 = {'is_implicit': True, + 'canon_eqs': [[Eq(Derivative(f(t), t), -1), Eq(Derivative(g(t), t), y*f(t))], + [Eq(Derivative(f(t), t), 3), Eq(Derivative(g(t), t), y*f(t))]]} + assert _classify_linear_system(eq1, funcs, t) == sol1 + + raises(ValueError, lambda: _classify_linear_system(eq1, funcs[:1], t)) + + eq2 = [Eq(Derivative(f(t), t), (2*f(t) + g(t) + 1)/t), Eq(Derivative(g(t), t), (f(t) + 2*g(t))/t)] + sol2 = {'no_of_equation': 2, 'eq': [Eq(Derivative(f(t), t), (2*f(t) + g(t) + 1)/t), Eq(Derivative(g(t), t), + (f(t) + 2*g(t))/t)], 'func': [f(t), g(t)], 'order': {f(t): 1, g(t): 1}, 'is_linear': True, + 'is_homogeneous': False, 'is_general': True, 'rhs': Matrix([ [1], [0]]), 'func_coeff': Matrix([ [2, + 1], [1, 2]]), 'is_constant': False, 'type_of_equation': 'type6', 't_': t_, 'tau': log(t), + 'commutative_antiderivative': Matrix([ [2*log(t), log(t)], [ log(t), 2*log(t)]])} + assert _classify_linear_system(eq2, funcs, t) == sol2 + + eq3 = [Eq(Derivative(f(t), t), (2*f(t) + g(t))/t), Eq(Derivative(g(t), t), (f(t) + 2*g(t))/t)] + sol3 = {'no_of_equation': 2, 'eq': [Eq(Derivative(f(t), t), (2*f(t) + g(t))/t), Eq(Derivative(g(t), t), + (f(t) + 2*g(t))/t)], 'func': [f(t), g(t)], 'order': {f(t): 1, g(t): 1}, 'is_linear': True, + 'is_homogeneous': True, 'is_general': True, 'func_coeff': Matrix([ [2, 1], [1, 2]]), 'is_constant': + False, 'type_of_equation': 'type5', 't_': t_, 'rhs': Matrix([ [0], [0]]), 'tau': log(t), + 'commutative_antiderivative': Matrix([ [2*log(t), log(t)], [ log(t), 2*log(t)]])} + assert _classify_linear_system(eq3, funcs, t) == sol3 + + +def test_matrix_exp(): + from sympy.matrices.dense import Matrix, eye, zeros + from sympy.solvers.ode.systems import matrix_exp + t = Symbol('t') + + for n in range(1, 6+1): + assert matrix_exp(zeros(n), t) == eye(n) + + for n in range(1, 6+1): + A = eye(n) + expAt = exp(t) * eye(n) + assert matrix_exp(A, t) == expAt + + for n in range(1, 6+1): + A = Matrix(n, n, lambda i,j: i+1 if i==j else 0) + expAt = Matrix(n, n, lambda i,j: exp((i+1)*t) if i==j else 0) + assert matrix_exp(A, t) == expAt + + A = Matrix([[0, 1], [-1, 0]]) + expAt = Matrix([[cos(t), sin(t)], [-sin(t), cos(t)]]) + assert matrix_exp(A, t) == expAt + + A = Matrix([[2, -5], [2, -4]]) + expAt = Matrix([ + [3*exp(-t)*sin(t) + exp(-t)*cos(t), -5*exp(-t)*sin(t)], + [2*exp(-t)*sin(t), -3*exp(-t)*sin(t) + exp(-t)*cos(t)] + ]) + assert matrix_exp(A, t) == expAt + + A = Matrix([[21, 17, 6], [-5, -1, -6], [4, 4, 16]]) + # TO update this. + # expAt = Matrix([ + # [(8*t*exp(12*t) + 5*exp(12*t) - 1)*exp(4*t)/4, + # (8*t*exp(12*t) + 5*exp(12*t) - 5)*exp(4*t)/4, + # (exp(12*t) - 1)*exp(4*t)/2], + # [(-8*t*exp(12*t) - exp(12*t) + 1)*exp(4*t)/4, + # (-8*t*exp(12*t) - exp(12*t) + 5)*exp(4*t)/4, + # (-exp(12*t) + 1)*exp(4*t)/2], + # [4*t*exp(16*t), 4*t*exp(16*t), exp(16*t)]]) + expAt = Matrix([ + [2*t*exp(16*t) + 5*exp(16*t)/4 - exp(4*t)/4, 2*t*exp(16*t) + 5*exp(16*t)/4 - 5*exp(4*t)/4, exp(16*t)/2 - exp(4*t)/2], + [ -2*t*exp(16*t) - exp(16*t)/4 + exp(4*t)/4, -2*t*exp(16*t) - exp(16*t)/4 + 5*exp(4*t)/4, -exp(16*t)/2 + exp(4*t)/2], + [ 4*t*exp(16*t), 4*t*exp(16*t), exp(16*t)] + ]) + assert matrix_exp(A, t) == expAt + + A = Matrix([[1, 1, 0, 0], + [0, 1, 1, 0], + [0, 0, 1, -S(1)/8], + [0, 0, S(1)/2, S(1)/2]]) + expAt = Matrix([ + [exp(t), t*exp(t), 4*t*exp(3*t/4) + 8*t*exp(t) + 48*exp(3*t/4) - 48*exp(t), + -2*t*exp(3*t/4) - 2*t*exp(t) - 16*exp(3*t/4) + 16*exp(t)], + [0, exp(t), -t*exp(3*t/4) - 8*exp(3*t/4) + 8*exp(t), t*exp(3*t/4)/2 + 2*exp(3*t/4) - 2*exp(t)], + [0, 0, t*exp(3*t/4)/4 + exp(3*t/4), -t*exp(3*t/4)/8], + [0, 0, t*exp(3*t/4)/2, -t*exp(3*t/4)/4 + exp(3*t/4)] + ]) + assert matrix_exp(A, t) == expAt + + A = Matrix([ + [ 0, 1, 0, 0], + [-1, 0, 0, 0], + [ 0, 0, 0, 1], + [ 0, 0, -1, 0]]) + + expAt = Matrix([ + [ cos(t), sin(t), 0, 0], + [-sin(t), cos(t), 0, 0], + [ 0, 0, cos(t), sin(t)], + [ 0, 0, -sin(t), cos(t)]]) + assert matrix_exp(A, t) == expAt + + A = Matrix([ + [ 0, 1, 1, 0], + [-1, 0, 0, 1], + [ 0, 0, 0, 1], + [ 0, 0, -1, 0]]) + + expAt = Matrix([ + [ cos(t), sin(t), t*cos(t), t*sin(t)], + [-sin(t), cos(t), -t*sin(t), t*cos(t)], + [ 0, 0, cos(t), sin(t)], + [ 0, 0, -sin(t), cos(t)]]) + assert matrix_exp(A, t) == expAt + + # This case is unacceptably slow right now but should be solvable... + #a, b, c, d, e, f = symbols('a b c d e f') + #A = Matrix([ + #[-a, b, c, d], + #[ a, -b, e, 0], + #[ 0, 0, -c - e - f, 0], + #[ 0, 0, f, -d]]) + + A = Matrix([[0, I], [I, 0]]) + expAt = Matrix([ + [exp(I*t)/2 + exp(-I*t)/2, exp(I*t)/2 - exp(-I*t)/2], + [exp(I*t)/2 - exp(-I*t)/2, exp(I*t)/2 + exp(-I*t)/2]]) + assert matrix_exp(A, t) == expAt + + # Testing Errors + M = Matrix([[1, 2, 3], [4, 5, 6], [7, 7, 7]]) + M1 = Matrix([[t, 1], [1, 1]]) + + raises(ValueError, lambda: matrix_exp(M[:, :2], t)) + raises(ValueError, lambda: matrix_exp(M[:2, :], t)) + raises(ValueError, lambda: matrix_exp(M1, t)) + raises(ValueError, lambda: matrix_exp(M1[:1, :1], t)) + + +def test_canonical_odes(): + f, g, h = symbols('f g h', cls=Function) + x = symbols('x') + funcs = [f(x), g(x), h(x)] + + eqs1 = [Eq(f(x).diff(x, x), f(x) + 2*g(x)), Eq(g(x) + 1, g(x).diff(x) + f(x))] + sol1 = [[Eq(Derivative(f(x), (x, 2)), f(x) + 2*g(x)), Eq(Derivative(g(x), x), -f(x) + g(x) + 1)]] + assert canonical_odes(eqs1, funcs[:2], x) == sol1 + + eqs2 = [Eq(f(x).diff(x), h(x).diff(x) + f(x)), Eq(g(x).diff(x)**2, f(x) + h(x)), Eq(h(x).diff(x), f(x))] + sol2 = [[Eq(Derivative(f(x), x), 2*f(x)), Eq(Derivative(g(x), x), -sqrt(f(x) + h(x))), Eq(Derivative(h(x), x), f(x))], + [Eq(Derivative(f(x), x), 2*f(x)), Eq(Derivative(g(x), x), sqrt(f(x) + h(x))), Eq(Derivative(h(x), x), f(x))]] + assert canonical_odes(eqs2, funcs, x) == sol2 + + +def test_sysode_linear_neq_order1_type1(): + + f, g, x, y, h = symbols('f g x y h', cls=Function) + a, b, c, t = symbols('a b c t') + + eqs1 = [Eq(Derivative(x(t), t), x(t)), + Eq(Derivative(y(t), t), y(t))] + sol1 = [Eq(x(t), C1*exp(t)), + Eq(y(t), C2*exp(t))] + assert dsolve(eqs1) == sol1 + assert checksysodesol(eqs1, sol1) == (True, [0, 0]) + + eqs2 = [Eq(Derivative(x(t), t), 2*x(t)), + Eq(Derivative(y(t), t), 3*y(t))] + sol2 = [Eq(x(t), C1*exp(2*t)), + Eq(y(t), C2*exp(3*t))] + assert dsolve(eqs2) == sol2 + assert checksysodesol(eqs2, sol2) == (True, [0, 0]) + + eqs3 = [Eq(Derivative(x(t), t), a*x(t)), + Eq(Derivative(y(t), t), a*y(t))] + sol3 = [Eq(x(t), C1*exp(a*t)), + Eq(y(t), C2*exp(a*t))] + assert dsolve(eqs3) == sol3 + assert checksysodesol(eqs3, sol3) == (True, [0, 0]) + + # Regression test case for issue #15474 + # https://github.com/sympy/sympy/issues/15474 + eqs4 = [Eq(Derivative(x(t), t), a*x(t)), + Eq(Derivative(y(t), t), b*y(t))] + sol4 = [Eq(x(t), C1*exp(a*t)), + Eq(y(t), C2*exp(b*t))] + assert dsolve(eqs4) == sol4 + assert checksysodesol(eqs4, sol4) == (True, [0, 0]) + + eqs5 = [Eq(Derivative(x(t), t), -y(t)), + Eq(Derivative(y(t), t), x(t))] + sol5 = [Eq(x(t), -C1*sin(t) - C2*cos(t)), + Eq(y(t), C1*cos(t) - C2*sin(t))] + assert dsolve(eqs5) == sol5 + assert checksysodesol(eqs5, sol5) == (True, [0, 0]) + + eqs6 = [Eq(Derivative(x(t), t), -2*y(t)), + Eq(Derivative(y(t), t), 2*x(t))] + sol6 = [Eq(x(t), -C1*sin(2*t) - C2*cos(2*t)), + Eq(y(t), C1*cos(2*t) - C2*sin(2*t))] + assert dsolve(eqs6) == sol6 + assert checksysodesol(eqs6, sol6) == (True, [0, 0]) + + eqs7 = [Eq(Derivative(x(t), t), I*y(t)), + Eq(Derivative(y(t), t), I*x(t))] + sol7 = [Eq(x(t), -C1*exp(-I*t) + C2*exp(I*t)), + Eq(y(t), C1*exp(-I*t) + C2*exp(I*t))] + assert dsolve(eqs7) == sol7 + assert checksysodesol(eqs7, sol7) == (True, [0, 0]) + + eqs8 = [Eq(Derivative(x(t), t), -a*y(t)), + Eq(Derivative(y(t), t), a*x(t))] + sol8 = [Eq(x(t), -I*C1*exp(-I*a*t) + I*C2*exp(I*a*t)), + Eq(y(t), C1*exp(-I*a*t) + C2*exp(I*a*t))] + assert dsolve(eqs8) == sol8 + assert checksysodesol(eqs8, sol8) == (True, [0, 0]) + + eqs9 = [Eq(Derivative(x(t), t), x(t) + y(t)), + Eq(Derivative(y(t), t), x(t) - y(t))] + sol9 = [Eq(x(t), C1*(1 - sqrt(2))*exp(-sqrt(2)*t) + C2*(1 + sqrt(2))*exp(sqrt(2)*t)), + Eq(y(t), C1*exp(-sqrt(2)*t) + C2*exp(sqrt(2)*t))] + assert dsolve(eqs9) == sol9 + assert checksysodesol(eqs9, sol9) == (True, [0, 0]) + + eqs10 = [Eq(Derivative(x(t), t), x(t) + y(t)), + Eq(Derivative(y(t), t), x(t) + y(t))] + sol10 = [Eq(x(t), -C1 + C2*exp(2*t)), + Eq(y(t), C1 + C2*exp(2*t))] + assert dsolve(eqs10) == sol10 + assert checksysodesol(eqs10, sol10) == (True, [0, 0]) + + eqs11 = [Eq(Derivative(x(t), t), 2*x(t) + y(t)), + Eq(Derivative(y(t), t), -x(t) + 2*y(t))] + sol11 = [Eq(x(t), C1*exp(2*t)*sin(t) + C2*exp(2*t)*cos(t)), + Eq(y(t), C1*exp(2*t)*cos(t) - C2*exp(2*t)*sin(t))] + assert dsolve(eqs11) == sol11 + assert checksysodesol(eqs11, sol11) == (True, [0, 0]) + + eqs12 = [Eq(Derivative(x(t), t), x(t) + 2*y(t)), + Eq(Derivative(y(t), t), 2*x(t) + y(t))] + sol12 = [Eq(x(t), -C1*exp(-t) + C2*exp(3*t)), + Eq(y(t), C1*exp(-t) + C2*exp(3*t))] + assert dsolve(eqs12) == sol12 + assert checksysodesol(eqs12, sol12) == (True, [0, 0]) + + eqs13 = [Eq(Derivative(x(t), t), 4*x(t) + y(t)), + Eq(Derivative(y(t), t), -x(t) + 2*y(t))] + sol13 = [Eq(x(t), C2*t*exp(3*t) + (C1 + C2)*exp(3*t)), + Eq(y(t), -C1*exp(3*t) - C2*t*exp(3*t))] + assert dsolve(eqs13) == sol13 + assert checksysodesol(eqs13, sol13) == (True, [0, 0]) + + eqs14 = [Eq(Derivative(x(t), t), a*y(t)), + Eq(Derivative(y(t), t), a*x(t))] + sol14 = [Eq(x(t), -C1*exp(-a*t) + C2*exp(a*t)), + Eq(y(t), C1*exp(-a*t) + C2*exp(a*t))] + assert dsolve(eqs14) == sol14 + assert checksysodesol(eqs14, sol14) == (True, [0, 0]) + + eqs15 = [Eq(Derivative(x(t), t), a*y(t)), + Eq(Derivative(y(t), t), b*x(t))] + sol15 = [Eq(x(t), -C1*a*exp(-t*sqrt(a*b))/sqrt(a*b) + C2*a*exp(t*sqrt(a*b))/sqrt(a*b)), + Eq(y(t), C1*exp(-t*sqrt(a*b)) + C2*exp(t*sqrt(a*b)))] + assert dsolve(eqs15) == sol15 + assert checksysodesol(eqs15, sol15) == (True, [0, 0]) + + eqs16 = [Eq(Derivative(x(t), t), a*x(t) + b*y(t)), + Eq(Derivative(y(t), t), c*x(t))] + sol16 = [Eq(x(t), -2*C1*b*exp(t*(a + sqrt(a**2 + 4*b*c))/2)/(a - sqrt(a**2 + 4*b*c)) - 2*C2*b*exp(t*(a - + sqrt(a**2 + 4*b*c))/2)/(a + sqrt(a**2 + 4*b*c))), + Eq(y(t), C1*exp(t*(a + sqrt(a**2 + 4*b*c))/2) + C2*exp(t*(a - sqrt(a**2 + 4*b*c))/2))] + assert dsolve(eqs16) == sol16 + assert checksysodesol(eqs16, sol16) == (True, [0, 0]) + + # Regression test case for issue #18562 + # https://github.com/sympy/sympy/issues/18562 + eqs17 = [Eq(Derivative(x(t), t), a*y(t) + x(t)), + Eq(Derivative(y(t), t), a*x(t) - y(t))] + sol17 = [Eq(x(t), C1*a*exp(t*sqrt(a**2 + 1))/(sqrt(a**2 + 1) - 1) - C2*a*exp(-t*sqrt(a**2 + 1))/(sqrt(a**2 + + 1) + 1)), + Eq(y(t), C1*exp(t*sqrt(a**2 + 1)) + C2*exp(-t*sqrt(a**2 + 1)))] + assert dsolve(eqs17) == sol17 + assert checksysodesol(eqs17, sol17) == (True, [0, 0]) + + eqs18 = [Eq(Derivative(x(t), t), 0), + Eq(Derivative(y(t), t), 0)] + sol18 = [Eq(x(t), C1), + Eq(y(t), C2)] + assert dsolve(eqs18) == sol18 + assert checksysodesol(eqs18, sol18) == (True, [0, 0]) + + eqs19 = [Eq(Derivative(x(t), t), 2*x(t) - y(t)), + Eq(Derivative(y(t), t), x(t))] + sol19 = [Eq(x(t), C2*t*exp(t) + (C1 + C2)*exp(t)), + Eq(y(t), C1*exp(t) + C2*t*exp(t))] + assert dsolve(eqs19) == sol19 + assert checksysodesol(eqs19, sol19) == (True, [0, 0]) + + eqs20 = [Eq(Derivative(x(t), t), x(t)), + Eq(Derivative(y(t), t), x(t) + y(t))] + sol20 = [Eq(x(t), C1*exp(t)), + Eq(y(t), C1*t*exp(t) + C2*exp(t))] + assert dsolve(eqs20) == sol20 + assert checksysodesol(eqs20, sol20) == (True, [0, 0]) + + eqs21 = [Eq(Derivative(x(t), t), 3*x(t)), + Eq(Derivative(y(t), t), x(t) + y(t))] + sol21 = [Eq(x(t), 2*C1*exp(3*t)), + Eq(y(t), C1*exp(3*t) + C2*exp(t))] + assert dsolve(eqs21) == sol21 + assert checksysodesol(eqs21, sol21) == (True, [0, 0]) + + eqs22 = [Eq(Derivative(x(t), t), 3*x(t)), + Eq(Derivative(y(t), t), y(t))] + sol22 = [Eq(x(t), C1*exp(3*t)), + Eq(y(t), C2*exp(t))] + assert dsolve(eqs22) == sol22 + assert checksysodesol(eqs22, sol22) == (True, [0, 0]) + + +@slow +def test_sysode_linear_neq_order1_type1_slow(): + + t = Symbol('t') + Z0 = Function('Z0') + Z1 = Function('Z1') + Z2 = Function('Z2') + Z3 = Function('Z3') + + k01, k10, k20, k21, k23, k30 = symbols('k01 k10 k20 k21 k23 k30') + + eqs1 = [Eq(Derivative(Z0(t), t), -k01*Z0(t) + k10*Z1(t) + k20*Z2(t) + k30*Z3(t)), + Eq(Derivative(Z1(t), t), k01*Z0(t) - k10*Z1(t) + k21*Z2(t)), + Eq(Derivative(Z2(t), t), (-k20 - k21 - k23)*Z2(t)), + Eq(Derivative(Z3(t), t), k23*Z2(t) - k30*Z3(t))] + sol1 = [Eq(Z0(t), C1*k10/k01 - C2*(k10 - k30)*exp(-k30*t)/(k01 + k10 - k30) - C3*(k10*(k20 + k21 - k30) - + k20**2 - k20*(k21 + k23 - k30) + k23*k30)*exp(-t*(k20 + k21 + k23))/(k23*(-k01 - k10 + k20 + k21 + + k23)) - C4*exp(-t*(k01 + k10))), + Eq(Z1(t), C1 - C2*k01*exp(-k30*t)/(k01 + k10 - k30) + C3*(-k01*(k20 + k21 - k30) + k20*k21 + k21**2 + + k21*(k23 - k30))*exp(-t*(k20 + k21 + k23))/(k23*(-k01 - k10 + k20 + k21 + k23)) + C4*exp(-t*(k01 + + k10))), + Eq(Z2(t), -C3*(k20 + k21 + k23 - k30)*exp(-t*(k20 + k21 + k23))/k23), + Eq(Z3(t), C2*exp(-k30*t) + C3*exp(-t*(k20 + k21 + k23)))] + assert dsolve(eqs1) == sol1 + assert checksysodesol(eqs1, sol1) == (True, [0, 0, 0, 0]) + + x, y, z, u, v, w = symbols('x y z u v w', cls=Function) + k2, k3 = symbols('k2 k3') + a_b, a_c = symbols('a_b a_c', real=True) + + eqs2 = [Eq(Derivative(z(t), t), k2*y(t)), + Eq(Derivative(x(t), t), k3*y(t)), + Eq(Derivative(y(t), t), (-k2 - k3)*y(t))] + sol2 = [Eq(z(t), C1 - C2*k2*exp(-t*(k2 + k3))/(k2 + k3)), + Eq(x(t), -C2*k3*exp(-t*(k2 + k3))/(k2 + k3) + C3), + Eq(y(t), C2*exp(-t*(k2 + k3)))] + assert dsolve(eqs2) == sol2 + assert checksysodesol(eqs2, sol2) == (True, [0, 0, 0]) + + eqs3 = [4*u(t) - v(t) - 2*w(t) + Derivative(u(t), t), + 2*u(t) + v(t) - 2*w(t) + Derivative(v(t), t), + 5*u(t) + v(t) - 3*w(t) + Derivative(w(t), t)] + sol3 = [Eq(u(t), C3*exp(-2*t) + (C1/2 + sqrt(3)*C2/6)*cos(sqrt(3)*t) + sin(sqrt(3)*t)*(sqrt(3)*C1/6 + + C2*Rational(-1, 2))), + Eq(v(t), (C1/2 + sqrt(3)*C2/6)*cos(sqrt(3)*t) + sin(sqrt(3)*t)*(sqrt(3)*C1/6 + C2*Rational(-1, 2))), + Eq(w(t), C1*cos(sqrt(3)*t) - C2*sin(sqrt(3)*t) + C3*exp(-2*t))] + assert dsolve(eqs3) == sol3 + assert checksysodesol(eqs3, sol3) == (True, [0, 0, 0]) + + eqs4 = [Eq(Derivative(x(t), t), w(t)*Rational(-2, 9) + 2*x(t) + y(t) + z(t)*Rational(-8, 9)), + Eq(Derivative(y(t), t), w(t)*Rational(4, 9) + 2*y(t) + z(t)*Rational(16, 9)), + Eq(Derivative(z(t), t), w(t)*Rational(-2, 9) + z(t)*Rational(37, 9)), + Eq(Derivative(w(t), t), w(t)*Rational(44, 9) + z(t)*Rational(-4, 9))] + sol4 = [Eq(x(t), C1*exp(2*t) + C2*t*exp(2*t)), + Eq(y(t), C2*exp(2*t) + 2*C3*exp(4*t)), + Eq(z(t), 2*C3*exp(4*t) + C4*exp(5*t)*Rational(-1, 4)), + Eq(w(t), C3*exp(4*t) + C4*exp(5*t))] + assert dsolve(eqs4) == sol4 + assert checksysodesol(eqs4, sol4) == (True, [0, 0, 0, 0]) + + # Regression test case for issue #15574 + # https://github.com/sympy/sympy/issues/15574 + eq5 = [Eq(x(t).diff(t), x(t)), Eq(y(t).diff(t), y(t)), Eq(z(t).diff(t), z(t)), Eq(w(t).diff(t), w(t))] + sol5 = [Eq(x(t), C1*exp(t)), Eq(y(t), C2*exp(t)), Eq(z(t), C3*exp(t)), Eq(w(t), C4*exp(t))] + assert dsolve(eq5) == sol5 + assert checksysodesol(eq5, sol5) == (True, [0, 0, 0, 0]) + + eqs6 = [Eq(Derivative(x(t), t), x(t) + y(t)), + Eq(Derivative(y(t), t), y(t) + z(t)), + Eq(Derivative(z(t), t), w(t)*Rational(-1, 8) + z(t)), + Eq(Derivative(w(t), t), w(t)/2 + z(t)/2)] + sol6 = [Eq(x(t), C1*exp(t) + C2*t*exp(t) + 4*C4*t*exp(t*Rational(3, 4)) + (4*C3 + 48*C4)*exp(t*Rational(3, + 4))), + Eq(y(t), C2*exp(t) - C4*t*exp(t*Rational(3, 4)) - (C3 + 8*C4)*exp(t*Rational(3, 4))), + Eq(z(t), C4*t*exp(t*Rational(3, 4))/4 + (C3/4 + C4)*exp(t*Rational(3, 4))), + Eq(w(t), C3*exp(t*Rational(3, 4))/2 + C4*t*exp(t*Rational(3, 4))/2)] + assert dsolve(eqs6) == sol6 + assert checksysodesol(eqs6, sol6) == (True, [0, 0, 0, 0]) + + # Regression test case for issue #15574 + # https://github.com/sympy/sympy/issues/15574 + eq7 = [Eq(Derivative(x(t), t), x(t)), Eq(Derivative(y(t), t), y(t)), Eq(Derivative(z(t), t), z(t)), + Eq(Derivative(w(t), t), w(t)), Eq(Derivative(u(t), t), u(t))] + sol7 = [Eq(x(t), C1*exp(t)), Eq(y(t), C2*exp(t)), Eq(z(t), C3*exp(t)), Eq(w(t), C4*exp(t)), + Eq(u(t), C5*exp(t))] + assert dsolve(eq7) == sol7 + assert checksysodesol(eq7, sol7) == (True, [0, 0, 0, 0, 0]) + + eqs8 = [Eq(Derivative(x(t), t), 2*x(t) + y(t)), + Eq(Derivative(y(t), t), 2*y(t)), + Eq(Derivative(z(t), t), 4*z(t)), + Eq(Derivative(w(t), t), u(t) + 5*w(t)), + Eq(Derivative(u(t), t), 5*u(t))] + sol8 = [Eq(x(t), C1*exp(2*t) + C2*t*exp(2*t)), + Eq(y(t), C2*exp(2*t)), + Eq(z(t), C3*exp(4*t)), + Eq(w(t), C4*exp(5*t) + C5*t*exp(5*t)), + Eq(u(t), C5*exp(5*t))] + assert dsolve(eqs8) == sol8 + assert checksysodesol(eqs8, sol8) == (True, [0, 0, 0, 0, 0]) + + # Regression test case for issue #15574 + # https://github.com/sympy/sympy/issues/15574 + eq9 = [Eq(Derivative(x(t), t), x(t)), Eq(Derivative(y(t), t), y(t)), Eq(Derivative(z(t), t), z(t))] + sol9 = [Eq(x(t), C1*exp(t)), Eq(y(t), C2*exp(t)), Eq(z(t), C3*exp(t))] + assert dsolve(eq9) == sol9 + assert checksysodesol(eq9, sol9) == (True, [0, 0, 0]) + + # Regression test case for issue #15407 + # https://github.com/sympy/sympy/issues/15407 + eqs10 = [Eq(Derivative(x(t), t), (-a_b - a_c)*x(t)), + Eq(Derivative(y(t), t), a_b*y(t)), + Eq(Derivative(z(t), t), a_c*x(t))] + sol10 = [Eq(x(t), -C1*(a_b + a_c)*exp(-t*(a_b + a_c))/a_c), + Eq(y(t), C2*exp(a_b*t)), + Eq(z(t), C1*exp(-t*(a_b + a_c)) + C3)] + assert dsolve(eqs10) == sol10 + assert checksysodesol(eqs10, sol10) == (True, [0, 0, 0]) + + # Regression test case for issue #14312 + # https://github.com/sympy/sympy/issues/14312 + eqs11 = [Eq(Derivative(x(t), t), k3*y(t)), + Eq(Derivative(y(t), t), (-k2 - k3)*y(t)), + Eq(Derivative(z(t), t), k2*y(t))] + sol11 = [Eq(x(t), C1 + C2*k3*exp(-t*(k2 + k3))/k2), + Eq(y(t), -C2*(k2 + k3)*exp(-t*(k2 + k3))/k2), + Eq(z(t), C2*exp(-t*(k2 + k3)) + C3)] + assert dsolve(eqs11) == sol11 + assert checksysodesol(eqs11, sol11) == (True, [0, 0, 0]) + + # Regression test case for issue #14312 + # https://github.com/sympy/sympy/issues/14312 + eqs12 = [Eq(Derivative(z(t), t), k2*y(t)), + Eq(Derivative(x(t), t), k3*y(t)), + Eq(Derivative(y(t), t), (-k2 - k3)*y(t))] + sol12 = [Eq(z(t), C1 - C2*k2*exp(-t*(k2 + k3))/(k2 + k3)), + Eq(x(t), -C2*k3*exp(-t*(k2 + k3))/(k2 + k3) + C3), + Eq(y(t), C2*exp(-t*(k2 + k3)))] + assert dsolve(eqs12) == sol12 + assert checksysodesol(eqs12, sol12) == (True, [0, 0, 0]) + + f, g, h = symbols('f, g, h', cls=Function) + a, b, c = symbols('a, b, c') + + # Regression test case for issue #15474 + # https://github.com/sympy/sympy/issues/15474 + eqs13 = [Eq(Derivative(f(t), t), 2*f(t) + g(t)), + Eq(Derivative(g(t), t), a*f(t))] + sol13 = [Eq(f(t), C1*exp(t*(sqrt(a + 1) + 1))/(sqrt(a + 1) - 1) - C2*exp(-t*(sqrt(a + 1) - 1))/(sqrt(a + 1) + + 1)), + Eq(g(t), C1*exp(t*(sqrt(a + 1) + 1)) + C2*exp(-t*(sqrt(a + 1) - 1)))] + assert dsolve(eqs13) == sol13 + assert checksysodesol(eqs13, sol13) == (True, [0, 0]) + + eqs14 = [Eq(Derivative(f(t), t), 2*g(t) - 3*h(t)), + Eq(Derivative(g(t), t), -2*f(t) + 4*h(t)), + Eq(Derivative(h(t), t), 3*f(t) - 4*g(t))] + sol14 = [Eq(f(t), 2*C1 - sin(sqrt(29)*t)*(sqrt(29)*C2*Rational(3, 25) + C3*Rational(-8, 25)) - + cos(sqrt(29)*t)*(C2*Rational(8, 25) + sqrt(29)*C3*Rational(3, 25))), + Eq(g(t), C1*Rational(3, 2) + sin(sqrt(29)*t)*(sqrt(29)*C2*Rational(4, 25) + C3*Rational(6, 25)) - + cos(sqrt(29)*t)*(C2*Rational(6, 25) + sqrt(29)*C3*Rational(-4, 25))), + Eq(h(t), C1 + C2*cos(sqrt(29)*t) - C3*sin(sqrt(29)*t))] + assert dsolve(eqs14) == sol14 + assert checksysodesol(eqs14, sol14) == (True, [0, 0, 0]) + + eqs15 = [Eq(2*Derivative(f(t), t), 12*g(t) - 12*h(t)), + Eq(3*Derivative(g(t), t), -8*f(t) + 8*h(t)), + Eq(4*Derivative(h(t), t), 6*f(t) - 6*g(t))] + sol15 = [Eq(f(t), C1 - sin(sqrt(29)*t)*(sqrt(29)*C2*Rational(6, 13) + C3*Rational(-16, 13)) - + cos(sqrt(29)*t)*(C2*Rational(16, 13) + sqrt(29)*C3*Rational(6, 13))), + Eq(g(t), C1 + sin(sqrt(29)*t)*(sqrt(29)*C2*Rational(8, 39) + C3*Rational(16, 13)) - + cos(sqrt(29)*t)*(C2*Rational(16, 13) + sqrt(29)*C3*Rational(-8, 39))), + Eq(h(t), C1 + C2*cos(sqrt(29)*t) - C3*sin(sqrt(29)*t))] + assert dsolve(eqs15) == sol15 + assert checksysodesol(eqs15, sol15) == (True, [0, 0, 0]) + + eq16 = (Eq(diff(x(t), t), 21*x(t)), Eq(diff(y(t), t), 17*x(t) + 3*y(t)), + Eq(diff(z(t), t), 5*x(t) + 7*y(t) + 9*z(t))) + sol16 = [Eq(x(t), 216*C1*exp(21*t)/209), + Eq(y(t), 204*C1*exp(21*t)/209 - 6*C2*exp(3*t)/7), + Eq(z(t), C1*exp(21*t) + C2*exp(3*t) + C3*exp(9*t))] + assert dsolve(eq16) == sol16 + assert checksysodesol(eq16, sol16) == (True, [0, 0, 0]) + + eqs17 = [Eq(Derivative(x(t), t), 3*y(t) - 11*z(t)), + Eq(Derivative(y(t), t), -3*x(t) + 7*z(t)), + Eq(Derivative(z(t), t), 11*x(t) - 7*y(t))] + sol17 = [Eq(x(t), C1*Rational(7, 3) - sin(sqrt(179)*t)*(sqrt(179)*C2*Rational(11, 170) + C3*Rational(-21, + 170)) - cos(sqrt(179)*t)*(C2*Rational(21, 170) + sqrt(179)*C3*Rational(11, 170))), + Eq(y(t), C1*Rational(11, 3) + sin(sqrt(179)*t)*(sqrt(179)*C2*Rational(7, 170) + C3*Rational(33, + 170)) - cos(sqrt(179)*t)*(C2*Rational(33, 170) + sqrt(179)*C3*Rational(-7, 170))), + Eq(z(t), C1 + C2*cos(sqrt(179)*t) - C3*sin(sqrt(179)*t))] + assert dsolve(eqs17) == sol17 + assert checksysodesol(eqs17, sol17) == (True, [0, 0, 0]) + + eqs18 = [Eq(3*Derivative(x(t), t), 20*y(t) - 20*z(t)), + Eq(4*Derivative(y(t), t), -15*x(t) + 15*z(t)), + Eq(5*Derivative(z(t), t), 12*x(t) - 12*y(t))] + sol18 = [Eq(x(t), C1 - sin(5*sqrt(2)*t)*(sqrt(2)*C2*Rational(4, 3) - C3) - cos(5*sqrt(2)*t)*(C2 + + sqrt(2)*C3*Rational(4, 3))), + Eq(y(t), C1 + sin(5*sqrt(2)*t)*(sqrt(2)*C2*Rational(3, 4) + C3) - cos(5*sqrt(2)*t)*(C2 + + sqrt(2)*C3*Rational(-3, 4))), + Eq(z(t), C1 + C2*cos(5*sqrt(2)*t) - C3*sin(5*sqrt(2)*t))] + assert dsolve(eqs18) == sol18 + assert checksysodesol(eqs18, sol18) == (True, [0, 0, 0]) + + eqs19 = [Eq(Derivative(x(t), t), 4*x(t) - z(t)), + Eq(Derivative(y(t), t), 2*x(t) + 2*y(t) - z(t)), + Eq(Derivative(z(t), t), 3*x(t) + y(t))] + sol19 = [Eq(x(t), C2*t**2*exp(2*t)/2 + t*(2*C2 + C3)*exp(2*t) + (C1 + C2 + 2*C3)*exp(2*t)), + Eq(y(t), C2*t**2*exp(2*t)/2 + t*(2*C2 + C3)*exp(2*t) + (C1 + 2*C3)*exp(2*t)), + Eq(z(t), C2*t**2*exp(2*t) + t*(3*C2 + 2*C3)*exp(2*t) + (2*C1 + 3*C3)*exp(2*t))] + assert dsolve(eqs19) == sol19 + assert checksysodesol(eqs19, sol19) == (True, [0, 0, 0]) + + eqs20 = [Eq(Derivative(x(t), t), 4*x(t) - y(t) - 2*z(t)), + Eq(Derivative(y(t), t), 2*x(t) + y(t) - 2*z(t)), + Eq(Derivative(z(t), t), 5*x(t) - 3*z(t))] + sol20 = [Eq(x(t), C1*exp(2*t) - sin(t)*(C2*Rational(3, 5) + C3/5) - cos(t)*(C2/5 + C3*Rational(-3, 5))), + Eq(y(t), -sin(t)*(C2*Rational(3, 5) + C3/5) - cos(t)*(C2/5 + C3*Rational(-3, 5))), + Eq(z(t), C1*exp(2*t) - C2*sin(t) + C3*cos(t))] + assert dsolve(eqs20) == sol20 + assert checksysodesol(eqs20, sol20) == (True, [0, 0, 0]) + + eq21 = (Eq(diff(x(t), t), 9*y(t)), Eq(diff(y(t), t), 12*x(t))) + sol21 = [Eq(x(t), -sqrt(3)*C1*exp(-6*sqrt(3)*t)/2 + sqrt(3)*C2*exp(6*sqrt(3)*t)/2), + Eq(y(t), C1*exp(-6*sqrt(3)*t) + C2*exp(6*sqrt(3)*t))] + + assert dsolve(eq21) == sol21 + assert checksysodesol(eq21, sol21) == (True, [0, 0]) + + eqs22 = [Eq(Derivative(x(t), t), 2*x(t) + 4*y(t)), + Eq(Derivative(y(t), t), 12*x(t) + 41*y(t))] + sol22 = [Eq(x(t), C1*(39 - sqrt(1713))*exp(t*(sqrt(1713) + 43)/2)*Rational(-1, 24) + C2*(39 + + sqrt(1713))*exp(t*(43 - sqrt(1713))/2)*Rational(-1, 24)), + Eq(y(t), C1*exp(t*(sqrt(1713) + 43)/2) + C2*exp(t*(43 - sqrt(1713))/2))] + assert dsolve(eqs22) == sol22 + assert checksysodesol(eqs22, sol22) == (True, [0, 0]) + + eqs23 = [Eq(Derivative(x(t), t), x(t) + y(t)), + Eq(Derivative(y(t), t), -2*x(t) + 2*y(t))] + sol23 = [Eq(x(t), (C1/4 + sqrt(7)*C2/4)*cos(sqrt(7)*t/2)*exp(t*Rational(3, 2)) + + sin(sqrt(7)*t/2)*(sqrt(7)*C1/4 + C2*Rational(-1, 4))*exp(t*Rational(3, 2))), + Eq(y(t), C1*cos(sqrt(7)*t/2)*exp(t*Rational(3, 2)) - C2*sin(sqrt(7)*t/2)*exp(t*Rational(3, 2)))] + assert dsolve(eqs23) == sol23 + assert checksysodesol(eqs23, sol23) == (True, [0, 0]) + + # Regression test case for issue #15474 + # https://github.com/sympy/sympy/issues/15474 + a = Symbol("a", real=True) + eq24 = [x(t).diff(t) - a*y(t), y(t).diff(t) + a*x(t)] + sol24 = [Eq(x(t), C1*sin(a*t) + C2*cos(a*t)), Eq(y(t), C1*cos(a*t) - C2*sin(a*t))] + assert dsolve(eq24) == sol24 + assert checksysodesol(eq24, sol24) == (True, [0, 0]) + + # Regression test case for issue #19150 + # https://github.com/sympy/sympy/issues/19150 + eqs25 = [Eq(Derivative(f(t), t), 0), + Eq(Derivative(g(t), t), (f(t) - 2*g(t) + x(t))/(b*c)), + Eq(Derivative(x(t), t), (g(t) - 2*x(t) + y(t))/(b*c)), + Eq(Derivative(y(t), t), (h(t) + x(t) - 2*y(t))/(b*c)), + Eq(Derivative(h(t), t), 0)] + sol25 = [Eq(f(t), -3*C1 + 4*C2), + Eq(g(t), -2*C1 + 3*C2 - C3*exp(-2*t/(b*c)) + C4*exp(-t*(sqrt(2) + 2)/(b*c)) + C5*exp(-t*(2 - + sqrt(2))/(b*c))), + Eq(x(t), -C1 + 2*C2 - sqrt(2)*C4*exp(-t*(sqrt(2) + 2)/(b*c)) + sqrt(2)*C5*exp(-t*(2 - + sqrt(2))/(b*c))), + Eq(y(t), C2 + C3*exp(-2*t/(b*c)) + C4*exp(-t*(sqrt(2) + 2)/(b*c)) + C5*exp(-t*(2 - sqrt(2))/(b*c))), + Eq(h(t), C1)] + assert dsolve(eqs25) == sol25 + assert checksysodesol(eqs25, sol25) == (True, [0, 0, 0, 0, 0]) + + eq26 = [Eq(Derivative(f(t), t), 2*f(t)), Eq(Derivative(g(t), t), 3*f(t) + 7*g(t))] + sol26 = [Eq(f(t), -5*C1*exp(2*t)/3), Eq(g(t), C1*exp(2*t) + C2*exp(7*t))] + assert dsolve(eq26) == sol26 + assert checksysodesol(eq26, sol26) == (True, [0, 0]) + + eq27 = [Eq(Derivative(f(t), t), -9*I*f(t) - 4*g(t)), Eq(Derivative(g(t), t), -4*I*g(t))] + sol27 = [Eq(f(t), 4*I*C1*exp(-4*I*t)/5 + C2*exp(-9*I*t)), Eq(g(t), C1*exp(-4*I*t))] + assert dsolve(eq27) == sol27 + assert checksysodesol(eq27, sol27) == (True, [0, 0]) + + eq28 = [Eq(Derivative(f(t), t), -9*I*f(t)), Eq(Derivative(g(t), t), -4*I*g(t))] + sol28 = [Eq(f(t), C1*exp(-9*I*t)), Eq(g(t), C2*exp(-4*I*t))] + assert dsolve(eq28) == sol28 + assert checksysodesol(eq28, sol28) == (True, [0, 0]) + + eq29 = [Eq(Derivative(f(t), t), 0), Eq(Derivative(g(t), t), 0)] + sol29 = [Eq(f(t), C1), Eq(g(t), C2)] + assert dsolve(eq29) == sol29 + assert checksysodesol(eq29, sol29) == (True, [0, 0]) + + eq30 = [Eq(Derivative(f(t), t), f(t)), Eq(Derivative(g(t), t), 0)] + sol30 = [Eq(f(t), C1*exp(t)), Eq(g(t), C2)] + assert dsolve(eq30) == sol30 + assert checksysodesol(eq30, sol30) == (True, [0, 0]) + + eq31 = [Eq(Derivative(f(t), t), g(t)), Eq(Derivative(g(t), t), 0)] + sol31 = [Eq(f(t), C1 + C2*t), Eq(g(t), C2)] + assert dsolve(eq31) == sol31 + assert checksysodesol(eq31, sol31) == (True, [0, 0]) + + eq32 = [Eq(Derivative(f(t), t), 0), Eq(Derivative(g(t), t), f(t))] + sol32 = [Eq(f(t), C1), Eq(g(t), C1*t + C2)] + assert dsolve(eq32) == sol32 + assert checksysodesol(eq32, sol32) == (True, [0, 0]) + + eq33 = [Eq(Derivative(f(t), t), 0), Eq(Derivative(g(t), t), g(t))] + sol33 = [Eq(f(t), C1), Eq(g(t), C2*exp(t))] + assert dsolve(eq33) == sol33 + assert checksysodesol(eq33, sol33) == (True, [0, 0]) + + eq34 = [Eq(Derivative(f(t), t), f(t)), Eq(Derivative(g(t), t), I*g(t))] + sol34 = [Eq(f(t), C1*exp(t)), Eq(g(t), C2*exp(I*t))] + assert dsolve(eq34) == sol34 + assert checksysodesol(eq34, sol34) == (True, [0, 0]) + + eq35 = [Eq(Derivative(f(t), t), I*f(t)), Eq(Derivative(g(t), t), -I*g(t))] + sol35 = [Eq(f(t), C1*exp(I*t)), Eq(g(t), C2*exp(-I*t))] + assert dsolve(eq35) == sol35 + assert checksysodesol(eq35, sol35) == (True, [0, 0]) + + eq36 = [Eq(Derivative(f(t), t), I*g(t)), Eq(Derivative(g(t), t), 0)] + sol36 = [Eq(f(t), I*C1 + I*C2*t), Eq(g(t), C2)] + assert dsolve(eq36) == sol36 + assert checksysodesol(eq36, sol36) == (True, [0, 0]) + + eq37 = [Eq(Derivative(f(t), t), I*g(t)), Eq(Derivative(g(t), t), I*f(t))] + sol37 = [Eq(f(t), -C1*exp(-I*t) + C2*exp(I*t)), Eq(g(t), C1*exp(-I*t) + C2*exp(I*t))] + assert dsolve(eq37) == sol37 + assert checksysodesol(eq37, sol37) == (True, [0, 0]) + + # Multiple systems + eq1 = [Eq(Derivative(f(t), t)**2, g(t)**2), Eq(-f(t) + Derivative(g(t), t), 0)] + sol1 = [[Eq(f(t), -C1*sin(t) - C2*cos(t)), + Eq(g(t), C1*cos(t) - C2*sin(t))], + [Eq(f(t), -C1*exp(-t) + C2*exp(t)), + Eq(g(t), C1*exp(-t) + C2*exp(t))]] + assert dsolve(eq1) == sol1 + for sol in sol1: + assert checksysodesol(eq1, sol) == (True, [0, 0]) + + +def test_sysode_linear_neq_order1_type2(): + + f, g, h, k = symbols('f g h k', cls=Function) + x, t, a, b, c, d, y = symbols('x t a b c d y') + k1, k2 = symbols('k1 k2') + + + eqs1 = [Eq(Derivative(f(x), x), f(x) + g(x) + 5), + Eq(Derivative(g(x), x), -f(x) - g(x) + 7)] + sol1 = [Eq(f(x), C1 + C2 + 6*x**2 + x*(C2 + 5)), + Eq(g(x), -C1 - 6*x**2 - x*(C2 - 7))] + assert dsolve(eqs1) == sol1 + assert checksysodesol(eqs1, sol1) == (True, [0, 0]) + + eqs2 = [Eq(Derivative(f(x), x), f(x) + g(x) + 5), + Eq(Derivative(g(x), x), f(x) + g(x) + 7)] + sol2 = [Eq(f(x), -C1 + C2*exp(2*x) - x - 3), + Eq(g(x), C1 + C2*exp(2*x) + x - 3)] + assert dsolve(eqs2) == sol2 + assert checksysodesol(eqs2, sol2) == (True, [0, 0]) + + eqs3 = [Eq(Derivative(f(x), x), f(x) + 5), + Eq(Derivative(g(x), x), f(x) + 7)] + sol3 = [Eq(f(x), C1*exp(x) - 5), + Eq(g(x), C1*exp(x) + C2 + 2*x - 5)] + assert dsolve(eqs3) == sol3 + assert checksysodesol(eqs3, sol3) == (True, [0, 0]) + + eqs4 = [Eq(Derivative(f(x), x), f(x) + exp(x)), + Eq(Derivative(g(x), x), x*exp(x) + f(x) + g(x))] + sol4 = [Eq(f(x), C1*exp(x) + x*exp(x)), + Eq(g(x), C1*x*exp(x) + C2*exp(x) + x**2*exp(x))] + assert dsolve(eqs4) == sol4 + assert checksysodesol(eqs4, sol4) == (True, [0, 0]) + + eqs5 = [Eq(Derivative(f(x), x), 5*x + f(x) + g(x)), + Eq(Derivative(g(x), x), f(x) - g(x))] + sol5 = [Eq(f(x), C1*(1 + sqrt(2))*exp(sqrt(2)*x) + C2*(1 - sqrt(2))*exp(-sqrt(2)*x) + x*Rational(-5, 2) + + Rational(-5, 2)), + Eq(g(x), C1*exp(sqrt(2)*x) + C2*exp(-sqrt(2)*x) + x*Rational(-5, 2))] + assert dsolve(eqs5) == sol5 + assert checksysodesol(eqs5, sol5) == (True, [0, 0]) + + eqs6 = [Eq(Derivative(f(x), x), -9*f(x) - 4*g(x)), + Eq(Derivative(g(x), x), -4*g(x)), + Eq(Derivative(h(x), x), h(x) + exp(x))] + sol6 = [Eq(f(x), C2*exp(-4*x)*Rational(-4, 5) + C1*exp(-9*x)), + Eq(g(x), C2*exp(-4*x)), + Eq(h(x), C3*exp(x) + x*exp(x))] + assert dsolve(eqs6) == sol6 + assert checksysodesol(eqs6, sol6) == (True, [0, 0, 0]) + + # Regression test case for issue #8859 + # https://github.com/sympy/sympy/issues/8859 + eqs7 = [Eq(Derivative(f(t), t), 3*t + f(t)), + Eq(Derivative(g(t), t), g(t))] + sol7 = [Eq(f(t), C1*exp(t) - 3*t - 3), + Eq(g(t), C2*exp(t))] + assert dsolve(eqs7) == sol7 + assert checksysodesol(eqs7, sol7) == (True, [0, 0]) + + # Regression test case for issue #8567 + # https://github.com/sympy/sympy/issues/8567 + eqs8 = [Eq(Derivative(f(t), t), f(t) + 2*g(t)), + Eq(Derivative(g(t), t), -2*f(t) + g(t) + 2*exp(t))] + sol8 = [Eq(f(t), C1*exp(t)*sin(2*t) + C2*exp(t)*cos(2*t) + + exp(t)*sin(2*t)**2 + exp(t)*cos(2*t)**2), + Eq(g(t), C1*exp(t)*cos(2*t) - C2*exp(t)*sin(2*t))] + assert dsolve(eqs8) == sol8 + assert checksysodesol(eqs8, sol8) == (True, [0, 0]) + + # Regression test case for issue #19150 + # https://github.com/sympy/sympy/issues/19150 + eqs9 = [Eq(Derivative(f(t), t), (c - 2*f(t) + g(t))/(a*b)), + Eq(Derivative(g(t), t), (f(t) - 2*g(t) + h(t))/(a*b)), + Eq(Derivative(h(t), t), (d + g(t) - 2*h(t))/(a*b))] + sol9 = [Eq(f(t), -C1*exp(-2*t/(a*b)) + C2*exp(-t*(sqrt(2) + 2)/(a*b)) + C3*exp(-t*(2 - sqrt(2))/(a*b)) + + Mul(Rational(1, 4), 3*c + d, evaluate=False)), + Eq(g(t), -sqrt(2)*C2*exp(-t*(sqrt(2) + 2)/(a*b)) + sqrt(2)*C3*exp(-t*(2 - sqrt(2))/(a*b)) + + Mul(Rational(1, 2), c + d, evaluate=False)), + Eq(h(t), C1*exp(-2*t/(a*b)) + C2*exp(-t*(sqrt(2) + 2)/(a*b)) + C3*exp(-t*(2 - sqrt(2))/(a*b)) + + Mul(Rational(1, 4), c + 3*d, evaluate=False))] + assert dsolve(eqs9) == sol9 + assert checksysodesol(eqs9, sol9) == (True, [0, 0, 0]) + + # Regression test case for issue #16635 + # https://github.com/sympy/sympy/issues/16635 + eqs10 = [Eq(Derivative(f(t), t), 15*t + f(t) - g(t) - 10), + Eq(Derivative(g(t), t), -15*t + f(t) - g(t) - 5)] + sol10 = [Eq(f(t), C1 + C2 + 5*t**3 + 5*t**2 + t*(C2 - 10)), + Eq(g(t), C1 + 5*t**3 - 10*t**2 + t*(C2 - 5))] + assert dsolve(eqs10) == sol10 + assert checksysodesol(eqs10, sol10) == (True, [0, 0]) + + # Multiple solutions + eqs11 = [Eq(Derivative(f(t), t)**2 - 2*Derivative(f(t), t) + 1, 4), + Eq(-y*f(t) + Derivative(g(t), t), 0)] + sol11 = [[Eq(f(t), C1 - t), Eq(g(t), C1*t*y + C2*y + t**2*y*Rational(-1, 2))], + [Eq(f(t), C1 + 3*t), Eq(g(t), C1*t*y + C2*y + t**2*y*Rational(3, 2))]] + assert dsolve(eqs11) == sol11 + for s11 in sol11: + assert checksysodesol(eqs11, s11) == (True, [0, 0]) + + # test case for issue #19831 + # https://github.com/sympy/sympy/issues/19831 + n = symbols('n', positive=True) + x0 = symbols('x_0') + t0 = symbols('t_0') + x_0 = symbols('x_0') + t_0 = symbols('t_0') + t = symbols('t') + x = Function('x') + y = Function('y') + T = symbols('T') + + eqs12 = [Eq(Derivative(y(t), t), x(t)), + Eq(Derivative(x(t), t), n*(y(t) + 1))] + sol12 = [Eq(y(t), C1*exp(sqrt(n)*t)*n**Rational(-1, 2) - C2*exp(-sqrt(n)*t)*n**Rational(-1, 2) - 1), + Eq(x(t), C1*exp(sqrt(n)*t) + C2*exp(-sqrt(n)*t))] + assert dsolve(eqs12) == sol12 + assert checksysodesol(eqs12, sol12) == (True, [0, 0]) + + sol12b = [ + Eq(y(t), (T*exp(-sqrt(n)*t_0)/2 + exp(-sqrt(n)*t_0)/2 + + x_0*exp(-sqrt(n)*t_0)/(2*sqrt(n)))*exp(sqrt(n)*t) + + (T*exp(sqrt(n)*t_0)/2 + exp(sqrt(n)*t_0)/2 - + x_0*exp(sqrt(n)*t_0)/(2*sqrt(n)))*exp(-sqrt(n)*t) - 1), + Eq(x(t), (T*sqrt(n)*exp(-sqrt(n)*t_0)/2 + sqrt(n)*exp(-sqrt(n)*t_0)/2 + + x_0*exp(-sqrt(n)*t_0)/2)*exp(sqrt(n)*t) + - (T*sqrt(n)*exp(sqrt(n)*t_0)/2 + sqrt(n)*exp(sqrt(n)*t_0)/2 - + x_0*exp(sqrt(n)*t_0)/2)*exp(-sqrt(n)*t)) + ] + assert dsolve(eqs12, ics={y(t0): T, x(t0): x0}) == sol12b + assert checksysodesol(eqs12, sol12b) == (True, [0, 0]) + + #Test cases added for the issue 19763 + #https://github.com/sympy/sympy/issues/19763 + + eq13 = [Eq(Derivative(f(t), t), f(t) + g(t) + 9), + Eq(Derivative(g(t), t), 2*f(t) + 5*g(t) + 23)] + sol13 = [Eq(f(t), -C1*(2 + sqrt(6))*exp(t*(3 - sqrt(6)))/2 - C2*(2 - sqrt(6))*exp(t*(sqrt(6) + 3))/2 - + Rational(22,3)), + Eq(g(t), C1*exp(t*(3 - sqrt(6))) + C2*exp(t*(sqrt(6) + 3)) - Rational(5,3))] + assert dsolve(eq13) == sol13 + assert checksysodesol(eq13, sol13) == (True, [0, 0]) + + eq14 = [Eq(Derivative(f(t), t), f(t) + g(t) + 81), + Eq(Derivative(g(t), t), -2*f(t) + g(t) + 23)] + sol14 = [Eq(f(t), sqrt(2)*C1*exp(t)*sin(sqrt(2)*t)/2 + + sqrt(2)*C2*exp(t)*cos(sqrt(2)*t)/2 + - 58*sin(sqrt(2)*t)**2/3 - 58*cos(sqrt(2)*t)**2/3), + Eq(g(t), C1*exp(t)*cos(sqrt(2)*t) - C2*exp(t)*sin(sqrt(2)*t) + - 185*sin(sqrt(2)*t)**2/3 - 185*cos(sqrt(2)*t)**2/3)] + assert dsolve(eq14) == sol14 + assert checksysodesol(eq14, sol14) == (True, [0,0]) + + eq15 = [Eq(Derivative(f(t), t), f(t) + 2*g(t) + k1), + Eq(Derivative(g(t), t), 3*f(t) + 4*g(t) + k2)] + sol15 = [Eq(f(t), -C1*(3 - sqrt(33))*exp(t*(5 + sqrt(33))/2)/6 - + C2*(3 + sqrt(33))*exp(t*(5 - sqrt(33))/2)/6 + 2*k1 - k2), + Eq(g(t), C1*exp(t*(5 + sqrt(33))/2) + C2*exp(t*(5 - sqrt(33))/2) - + Mul(Rational(1,2), 3*k1 - k2, evaluate = False))] + assert dsolve(eq15) == sol15 + assert checksysodesol(eq15, sol15) == (True, [0,0]) + + eq16 = [Eq(Derivative(f(t), t), k1), + Eq(Derivative(g(t), t), k2)] + sol16 = [Eq(f(t), C1 + k1*t), + Eq(g(t), C2 + k2*t)] + assert dsolve(eq16) == sol16 + assert checksysodesol(eq16, sol16) == (True, [0,0]) + + eq17 = [Eq(Derivative(f(t), t), 0), + Eq(Derivative(g(t), t), c*f(t) + k2)] + sol17 = [Eq(f(t), C1), + Eq(g(t), C2*c + t*(C1*c + k2))] + assert dsolve(eq17) == sol17 + assert checksysodesol(eq17 , sol17) == (True , [0,0]) + + eq18 = [Eq(Derivative(f(t), t), k1), + Eq(Derivative(g(t), t), f(t) + k2)] + sol18 = [Eq(f(t), C1 + k1*t), + Eq(g(t), C2 + k1*t**2/2 + t*(C1 + k2))] + assert dsolve(eq18) == sol18 + assert checksysodesol(eq18 , sol18) == (True , [0,0]) + + eq19 = [Eq(Derivative(f(t), t), k1), + Eq(Derivative(g(t), t), f(t) + 2*g(t) + k2)] + sol19 = [Eq(f(t), -2*C1 + k1*t), + Eq(g(t), C1 + C2*exp(2*t) - k1*t/2 - Mul(Rational(1,4), k1 + 2*k2 , evaluate = False))] + assert dsolve(eq19) == sol19 + assert checksysodesol(eq19 , sol19) == (True , [0,0]) + + eq20 = [Eq(diff(f(t), t), f(t) + k1), + Eq(diff(g(t), t), k2)] + sol20 = [Eq(f(t), C1*exp(t) - k1), + Eq(g(t), C2 + k2*t)] + assert dsolve(eq20) == sol20 + assert checksysodesol(eq20 , sol20) == (True , [0,0]) + + eq21 = [Eq(diff(f(t), t), g(t) + k1), + Eq(diff(g(t), t), 0)] + sol21 = [Eq(f(t), C1 + t*(C2 + k1)), + Eq(g(t), C2)] + assert dsolve(eq21) == sol21 + assert checksysodesol(eq21 , sol21) == (True , [0,0]) + + eq22 = [Eq(Derivative(f(t), t), f(t) + 2*g(t) + k1), + Eq(Derivative(g(t), t), k2)] + sol22 = [Eq(f(t), -2*C1 + C2*exp(t) - k1 - 2*k2*t - 2*k2), + Eq(g(t), C1 + k2*t)] + assert dsolve(eq22) == sol22 + assert checksysodesol(eq22 , sol22) == (True , [0,0]) + + eq23 = [Eq(Derivative(f(t), t), g(t) + k1), + Eq(Derivative(g(t), t), 2*g(t) + k2)] + sol23 = [Eq(f(t), C1 + C2*exp(2*t)/2 - k2/4 + t*(2*k1 - k2)/2), + Eq(g(t), C2*exp(2*t) - k2/2)] + assert dsolve(eq23) == sol23 + assert checksysodesol(eq23 , sol23) == (True , [0,0]) + + eq24 = [Eq(Derivative(f(t), t), f(t) + k1), + Eq(Derivative(g(t), t), 2*f(t) + k2)] + sol24 = [Eq(f(t), C1*exp(t)/2 - k1), + Eq(g(t), C1*exp(t) + C2 - 2*k1 - t*(2*k1 - k2))] + assert dsolve(eq24) == sol24 + assert checksysodesol(eq24 , sol24) == (True , [0,0]) + + eq25 = [Eq(Derivative(f(t), t), f(t) + 2*g(t) + k1), + Eq(Derivative(g(t), t), 3*f(t) + 6*g(t) + k2)] + sol25 = [Eq(f(t), -2*C1 + C2*exp(7*t)/3 + 2*t*(3*k1 - k2)/7 - + Mul(Rational(1,49), k1 + 2*k2 , evaluate = False)), + Eq(g(t), C1 + C2*exp(7*t) - t*(3*k1 - k2)/7 - + Mul(Rational(3,49), k1 + 2*k2 , evaluate = False))] + assert dsolve(eq25) == sol25 + assert checksysodesol(eq25 , sol25) == (True , [0,0]) + + eq26 = [Eq(Derivative(f(t), t), 2*f(t) - g(t) + k1), + Eq(Derivative(g(t), t), 4*f(t) - 2*g(t) + 2*k1)] + sol26 = [Eq(f(t), C1 + 2*C2 + t*(2*C1 + k1)), + Eq(g(t), 4*C2 + t*(4*C1 + 2*k1))] + assert dsolve(eq26) == sol26 + assert checksysodesol(eq26 , sol26) == (True , [0,0]) + + # Test Case added for issue #22715 + # https://github.com/sympy/sympy/issues/22715 + + eq27 = [Eq(diff(x(t),t),-1*y(t)+10), Eq(diff(y(t),t),5*x(t)-2*y(t)+3)] + sol27 = [Eq(x(t), (C1/5 - 2*C2/5)*exp(-t)*cos(2*t) + - (2*C1/5 + C2/5)*exp(-t)*sin(2*t) + + 17*sin(2*t)**2/5 + 17*cos(2*t)**2/5), + Eq(y(t), C1*exp(-t)*cos(2*t) - C2*exp(-t)*sin(2*t) + + 10*sin(2*t)**2 + 10*cos(2*t)**2)] + assert dsolve(eq27) == sol27 + assert checksysodesol(eq27 , sol27) == (True , [0,0]) + + +def test_sysode_linear_neq_order1_type3(): + + f, g, h, k, x0 , y0 = symbols('f g h k x0 y0', cls=Function) + x, t, a = symbols('x t a') + r = symbols('r', real=True) + + eqs1 = [Eq(Derivative(f(r), r), r*g(r) + f(r)), + Eq(Derivative(g(r), r), -r*f(r) + g(r))] + sol1 = [Eq(f(r), C1*exp(r)*sin(r**2/2) + C2*exp(r)*cos(r**2/2)), + Eq(g(r), C1*exp(r)*cos(r**2/2) - C2*exp(r)*sin(r**2/2))] + assert dsolve(eqs1) == sol1 + assert checksysodesol(eqs1, sol1) == (True, [0, 0]) + + eqs2 = [Eq(Derivative(f(x), x), x**2*g(x) + x*f(x)), + Eq(Derivative(g(x), x), 2*x**2*f(x) + (3*x**2 + x)*g(x))] + sol2 = [Eq(f(x), (sqrt(17)*C1/17 + C2*(17 - 3*sqrt(17))/34)*exp(x**3*(3 + sqrt(17))/6 + x**2/2) - + exp(x**3*(3 - sqrt(17))/6 + x**2/2)*(sqrt(17)*C1/17 + C2*(3*sqrt(17) + 17)*Rational(-1, 34))), + Eq(g(x), exp(x**3*(3 - sqrt(17))/6 + x**2/2)*(C1*(17 - 3*sqrt(17))/34 + sqrt(17)*C2*Rational(-2, + 17)) + exp(x**3*(3 + sqrt(17))/6 + x**2/2)*(C1*(3*sqrt(17) + 17)/34 + sqrt(17)*C2*Rational(2, 17)))] + assert dsolve(eqs2) == sol2 + assert checksysodesol(eqs2, sol2) == (True, [0, 0]) + + eqs3 = [Eq(f(x).diff(x), x*f(x) + g(x)), + Eq(g(x).diff(x), -f(x) + x*g(x))] + sol3 = [Eq(f(x), (C1/2 + I*C2/2)*exp(x**2/2 - I*x) + exp(x**2/2 + I*x)*(C1/2 + I*C2*Rational(-1, 2))), + Eq(g(x), (I*C1/2 + C2/2)*exp(x**2/2 + I*x) - exp(x**2/2 - I*x)*(I*C1/2 + C2*Rational(-1, 2)))] + assert dsolve(eqs3) == sol3 + assert checksysodesol(eqs3, sol3) == (True, [0, 0]) + + eqs4 = [Eq(f(x).diff(x), x*(f(x) + g(x) + h(x))), Eq(g(x).diff(x), x*(f(x) + g(x) + h(x))), + Eq(h(x).diff(x), x*(f(x) + g(x) + h(x)))] + sol4 = [Eq(f(x), -C1/3 - C2/3 + 2*C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2)), + Eq(g(x), 2*C1/3 - C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2)), + Eq(h(x), -C1/3 + 2*C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2))] + assert dsolve(eqs4) == sol4 + assert checksysodesol(eqs4, sol4) == (True, [0, 0, 0]) + + eqs5 = [Eq(f(x).diff(x), x**2*(f(x) + g(x) + h(x))), Eq(g(x).diff(x), x**2*(f(x) + g(x) + h(x))), + Eq(h(x).diff(x), x**2*(f(x) + g(x) + h(x)))] + sol5 = [Eq(f(x), -C1/3 - C2/3 + 2*C3/3 + (C1/3 + C2/3 + C3/3)*exp(x**3)), + Eq(g(x), 2*C1/3 - C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(x**3)), + Eq(h(x), -C1/3 + 2*C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(x**3))] + assert dsolve(eqs5) == sol5 + assert checksysodesol(eqs5, sol5) == (True, [0, 0, 0]) + + eqs6 = [Eq(Derivative(f(x), x), x*(f(x) + g(x) + h(x) + k(x))), + Eq(Derivative(g(x), x), x*(f(x) + g(x) + h(x) + k(x))), + Eq(Derivative(h(x), x), x*(f(x) + g(x) + h(x) + k(x))), + Eq(Derivative(k(x), x), x*(f(x) + g(x) + h(x) + k(x)))] + sol6 = [Eq(f(x), -C1/4 - C2/4 - C3/4 + 3*C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2)), + Eq(g(x), 3*C1/4 - C2/4 - C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2)), + Eq(h(x), -C1/4 + 3*C2/4 - C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2)), + Eq(k(x), -C1/4 - C2/4 + 3*C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2))] + assert dsolve(eqs6) == sol6 + assert checksysodesol(eqs6, sol6) == (True, [0, 0, 0, 0]) + + y = symbols("y", real=True) + + eqs7 = [Eq(Derivative(f(y), y), y*f(y) + g(y)), + Eq(Derivative(g(y), y), y*g(y) - f(y))] + sol7 = [Eq(f(y), C1*exp(y**2/2)*sin(y) + C2*exp(y**2/2)*cos(y)), + Eq(g(y), C1*exp(y**2/2)*cos(y) - C2*exp(y**2/2)*sin(y))] + assert dsolve(eqs7) == sol7 + assert checksysodesol(eqs7, sol7) == (True, [0, 0]) + + #Test cases added for the issue 19763 + #https://github.com/sympy/sympy/issues/19763 + + eqs8 = [Eq(Derivative(f(t), t), 5*t*f(t) + 2*h(t)), + Eq(Derivative(h(t), t), 2*f(t) + 5*t*h(t))] + sol8 = [Eq(f(t), Mul(-1, (C1/2 - C2/2), evaluate = False)*exp(5*t**2/2 - 2*t) + (C1/2 + C2/2)*exp(5*t**2/2 + 2*t)), + Eq(h(t), (C1/2 - C2/2)*exp(5*t**2/2 - 2*t) + (C1/2 + C2/2)*exp(5*t**2/2 + 2*t))] + assert dsolve(eqs8) == sol8 + assert checksysodesol(eqs8, sol8) == (True, [0, 0]) + + eqs9 = [Eq(diff(f(t), t), 5*t*f(t) + t**2*g(t)), + Eq(diff(g(t), t), -t**2*f(t) + 5*t*g(t))] + sol9 = [Eq(f(t), (C1/2 - I*C2/2)*exp(I*t**3/3 + 5*t**2/2) + (C1/2 + I*C2/2)*exp(-I*t**3/3 + 5*t**2/2)), + Eq(g(t), Mul(-1, (I*C1/2 - C2/2) , evaluate = False)*exp(-I*t**3/3 + 5*t**2/2) + (I*C1/2 + C2/2)*exp(I*t**3/3 + 5*t**2/2))] + assert dsolve(eqs9) == sol9 + assert checksysodesol(eqs9 , sol9) == (True , [0,0]) + + eqs10 = [Eq(diff(f(t), t), t**2*g(t) + 5*t*f(t)), + Eq(diff(g(t), t), -t**2*f(t) + (9*t**2 + 5*t)*g(t))] + sol10 = [Eq(f(t), (C1*(77 - 9*sqrt(77))/154 + sqrt(77)*C2/77)*exp(t**3*(sqrt(77) + 9)/6 + 5*t**2/2) + (C1*(77 + 9*sqrt(77))/154 - sqrt(77)*C2/77)*exp(t**3*(9 - sqrt(77))/6 + 5*t**2/2)), + Eq(g(t), (sqrt(77)*C1/77 + C2*(77 - 9*sqrt(77))/154)*exp(t**3*(9 - sqrt(77))/6 + 5*t**2/2) - (sqrt(77)*C1/77 - C2*(77 + 9*sqrt(77))/154)*exp(t**3*(sqrt(77) + 9)/6 + 5*t**2/2))] + assert dsolve(eqs10) == sol10 + assert checksysodesol(eqs10 , sol10) == (True , [0,0]) + + eqs11 = [Eq(diff(f(t), t), 5*t*f(t) + t**2*g(t)), + Eq(diff(g(t), t), (1-t**2)*f(t) + (5*t + 9*t**2)*g(t))] + sol11 = [Eq(f(t), C1*x0(t) + C2*x0(t)*Integral(t**2*exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)**2, t)), + Eq(g(t), C1*y0(t) + C2*(y0(t)*Integral(t**2*exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)**2, t) + exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)))] + assert dsolve(eqs11) == sol11 + +@slow +def test_sysode_linear_neq_order1_type4(): + + f, g, h, k = symbols('f g h k', cls=Function) + x, t, a = symbols('x t a') + r = symbols('r', real=True) + + eqs1 = [Eq(diff(f(r), r), f(r) + r*g(r) + r**2), Eq(diff(g(r), r), -r*f(r) + g(r) + r)] + sol1 = [Eq(f(r), C1*exp(r)*sin(r**2/2) + C2*exp(r)*cos(r**2/2) + exp(r)*sin(r**2/2)*Integral(r**2*exp(-r)*sin(r**2/2) + + r*exp(-r)*cos(r**2/2), r) + exp(r)*cos(r**2/2)*Integral(r**2*exp(-r)*cos(r**2/2) - r*exp(-r)*sin(r**2/2), r)), + Eq(g(r), C1*exp(r)*cos(r**2/2) - C2*exp(r)*sin(r**2/2) - exp(r)*sin(r**2/2)*Integral(r**2*exp(-r)*cos(r**2/2) - + r*exp(-r)*sin(r**2/2), r) + exp(r)*cos(r**2/2)*Integral(r**2*exp(-r)*sin(r**2/2) + r*exp(-r)*cos(r**2/2), r))] + assert dsolve(eqs1) == sol1 + assert checksysodesol(eqs1, sol1) == (True, [0, 0]) + + eqs2 = [Eq(diff(f(r), r), f(r) + r*g(r) + r), Eq(diff(g(r), r), -r*f(r) + g(r) + log(r))] + sol2 = [Eq(f(r), C1*exp(r)*sin(r**2/2) + C2*exp(r)*cos(r**2/2) + exp(r)*sin(r**2/2)*Integral(r*exp(-r)*sin(r**2/2) + + exp(-r)*log(r)*cos(r**2/2), r) + exp(r)*cos(r**2/2)*Integral(r*exp(-r)*cos(r**2/2) - exp(-r)*log(r)*sin( + r**2/2), r)), + Eq(g(r), C1*exp(r)*cos(r**2/2) - C2*exp(r)*sin(r**2/2) - exp(r)*sin(r**2/2)*Integral(r*exp(-r)*cos(r**2/2) - + exp(-r)*log(r)*sin(r**2/2), r) + exp(r)*cos(r**2/2)*Integral(r*exp(-r)*sin(r**2/2) + exp(-r)*log(r)*cos( + r**2/2), r))] + # XXX: dsolve hangs for this in integration + assert dsolve_system(eqs2, simplify=False, doit=False) == [sol2] + assert checksysodesol(eqs2, sol2) == (True, [0, 0]) + + eqs3 = [Eq(Derivative(f(x), x), x*(f(x) + g(x) + h(x)) + x), + Eq(Derivative(g(x), x), x*(f(x) + g(x) + h(x)) + x), + Eq(Derivative(h(x), x), x*(f(x) + g(x) + h(x)) + 1)] + sol3 = [Eq(f(x), C1*Rational(-1, 3) + C2*Rational(-1, 3) + C3*Rational(2, 3) + x**2/6 + x*Rational(-1, 3) + + (C1/3 + C2/3 + C3/3)*exp(x**2*Rational(3, 2)) + + sqrt(6)*sqrt(pi)*erf(sqrt(6)*x/2)*exp(x**2*Rational(3, 2))/18 + Rational(-2, 9)), + Eq(g(x), C1*Rational(2, 3) + C2*Rational(-1, 3) + C3*Rational(-1, 3) + x**2/6 + x*Rational(-1, 3) + + (C1/3 + C2/3 + C3/3)*exp(x**2*Rational(3, 2)) + + sqrt(6)*sqrt(pi)*erf(sqrt(6)*x/2)*exp(x**2*Rational(3, 2))/18 + Rational(-2, 9)), + Eq(h(x), C1*Rational(-1, 3) + C2*Rational(2, 3) + C3*Rational(-1, 3) + x**2*Rational(-1, 3) + + x*Rational(2, 3) + (C1/3 + C2/3 + C3/3)*exp(x**2*Rational(3, 2)) + + sqrt(6)*sqrt(pi)*erf(sqrt(6)*x/2)*exp(x**2*Rational(3, 2))/18 + Rational(-2, 9))] + assert dsolve(eqs3) == sol3 + assert checksysodesol(eqs3, sol3) == (True, [0, 0, 0]) + + eqs4 = [Eq(Derivative(f(x), x), x*(f(x) + g(x) + h(x)) + sin(x)), + Eq(Derivative(g(x), x), x*(f(x) + g(x) + h(x)) + sin(x)), + Eq(Derivative(h(x), x), x*(f(x) + g(x) + h(x)) + sin(x))] + sol4 = [Eq(f(x), C1*Rational(-1, 3) + C2*Rational(-1, 3) + C3*Rational(2, 3) + (C1/3 + C2/3 + + C3/3)*exp(x**2*Rational(3, 2)) + Integral(sin(x)*exp(x**2*Rational(-3, 2)), x)*exp(x**2*Rational(3, + 2))), + Eq(g(x), C1*Rational(2, 3) + C2*Rational(-1, 3) + C3*Rational(-1, 3) + (C1/3 + C2/3 + + C3/3)*exp(x**2*Rational(3, 2)) + Integral(sin(x)*exp(x**2*Rational(-3, 2)), x)*exp(x**2*Rational(3, + 2))), + Eq(h(x), C1*Rational(-1, 3) + C2*Rational(2, 3) + C3*Rational(-1, 3) + (C1/3 + C2/3 + + C3/3)*exp(x**2*Rational(3, 2)) + Integral(sin(x)*exp(x**2*Rational(-3, 2)), x)*exp(x**2*Rational(3, + 2)))] + assert dsolve(eqs4) == sol4 + assert checksysodesol(eqs4, sol4) == (True, [0, 0, 0]) + + eqs5 = [Eq(Derivative(f(x), x), x*(f(x) + g(x) + h(x) + k(x) + 1)), + Eq(Derivative(g(x), x), x*(f(x) + g(x) + h(x) + k(x) + 1)), + Eq(Derivative(h(x), x), x*(f(x) + g(x) + h(x) + k(x) + 1)), + Eq(Derivative(k(x), x), x*(f(x) + g(x) + h(x) + k(x) + 1))] + sol5 = [Eq(f(x), C1*Rational(-1, 4) + C2*Rational(-1, 4) + C3*Rational(-1, 4) + C4*Rational(3, 4) + (C1/4 + + C2/4 + C3/4 + C4/4)*exp(2*x**2) + Rational(-1, 4)), + Eq(g(x), C1*Rational(3, 4) + C2*Rational(-1, 4) + C3*Rational(-1, 4) + C4*Rational(-1, 4) + (C1/4 + + C2/4 + C3/4 + C4/4)*exp(2*x**2) + Rational(-1, 4)), + Eq(h(x), C1*Rational(-1, 4) + C2*Rational(3, 4) + C3*Rational(-1, 4) + C4*Rational(-1, 4) + (C1/4 + + C2/4 + C3/4 + C4/4)*exp(2*x**2) + Rational(-1, 4)), + Eq(k(x), C1*Rational(-1, 4) + C2*Rational(-1, 4) + C3*Rational(3, 4) + C4*Rational(-1, 4) + (C1/4 + + C2/4 + C3/4 + C4/4)*exp(2*x**2) + Rational(-1, 4))] + assert dsolve(eqs5) == sol5 + assert checksysodesol(eqs5, sol5) == (True, [0, 0, 0, 0]) + + eqs6 = [Eq(Derivative(f(x), x), x**2*(f(x) + g(x) + h(x) + k(x) + 1)), + Eq(Derivative(g(x), x), x**2*(f(x) + g(x) + h(x) + k(x) + 1)), + Eq(Derivative(h(x), x), x**2*(f(x) + g(x) + h(x) + k(x) + 1)), + Eq(Derivative(k(x), x), x**2*(f(x) + g(x) + h(x) + k(x) + 1))] + sol6 = [Eq(f(x), C1*Rational(-1, 4) + C2*Rational(-1, 4) + C3*Rational(-1, 4) + C4*Rational(3, 4) + (C1/4 + + C2/4 + C3/4 + C4/4)*exp(x**3*Rational(4, 3)) + Rational(-1, 4)), + Eq(g(x), C1*Rational(3, 4) + C2*Rational(-1, 4) + C3*Rational(-1, 4) + C4*Rational(-1, 4) + (C1/4 + + C2/4 + C3/4 + C4/4)*exp(x**3*Rational(4, 3)) + Rational(-1, 4)), + Eq(h(x), C1*Rational(-1, 4) + C2*Rational(3, 4) + C3*Rational(-1, 4) + C4*Rational(-1, 4) + (C1/4 + + C2/4 + C3/4 + C4/4)*exp(x**3*Rational(4, 3)) + Rational(-1, 4)), + Eq(k(x), C1*Rational(-1, 4) + C2*Rational(-1, 4) + C3*Rational(3, 4) + C4*Rational(-1, 4) + (C1/4 + + C2/4 + C3/4 + C4/4)*exp(x**3*Rational(4, 3)) + Rational(-1, 4))] + assert dsolve(eqs6) == sol6 + assert checksysodesol(eqs6, sol6) == (True, [0, 0, 0, 0]) + + eqs7 = [Eq(Derivative(f(x), x), (f(x) + g(x) + h(x))*log(x) + sin(x)), Eq(Derivative(g(x), x), (f(x) + g(x) + + h(x))*log(x) + sin(x)), Eq(Derivative(h(x), x), (f(x) + g(x) + h(x))*log(x) + sin(x))] + sol7 = [Eq(f(x), -C1/3 - C2/3 + 2*C3/3 + (C1/3 + C2/3 + + C3/3)*exp(x*(3*log(x) - 3)) + exp(x*(3*log(x) - + 3))*Integral(exp(3*x)*exp(-3*x*log(x))*sin(x), x)), + Eq(g(x), 2*C1/3 - C2/3 - C3/3 + (C1/3 + C2/3 + + C3/3)*exp(x*(3*log(x) - 3)) + exp(x*(3*log(x) - + 3))*Integral(exp(3*x)*exp(-3*x*log(x))*sin(x), x)), + Eq(h(x), -C1/3 + 2*C2/3 - C3/3 + (C1/3 + C2/3 + + C3/3)*exp(x*(3*log(x) - 3)) + exp(x*(3*log(x) - + 3))*Integral(exp(3*x)*exp(-3*x*log(x))*sin(x), x))] + with dotprodsimp(True): + assert dsolve(eqs7, simplify=False, doit=False) == sol7 + assert checksysodesol(eqs7, sol7) == (True, [0, 0, 0]) + + eqs8 = [Eq(Derivative(f(x), x), (f(x) + g(x) + h(x) + k(x))*log(x) + sin(x)), Eq(Derivative(g(x), x), (f(x) + + g(x) + h(x) + k(x))*log(x) + sin(x)), Eq(Derivative(h(x), x), (f(x) + g(x) + h(x) + k(x))*log(x) + + sin(x)), Eq(Derivative(k(x), x), (f(x) + g(x) + h(x) + k(x))*log(x) + sin(x))] + sol8 = [Eq(f(x), -C1/4 - C2/4 - C3/4 + 3*C4/4 + (C1/4 + C2/4 + C3/4 + + C4/4)*exp(x*(4*log(x) - 4)) + exp(x*(4*log(x) - + 4))*Integral(exp(4*x)*exp(-4*x*log(x))*sin(x), x)), + Eq(g(x), 3*C1/4 - C2/4 - C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + + C4/4)*exp(x*(4*log(x) - 4)) + exp(x*(4*log(x) - + 4))*Integral(exp(4*x)*exp(-4*x*log(x))*sin(x), x)), + Eq(h(x), -C1/4 + 3*C2/4 - C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + + C4/4)*exp(x*(4*log(x) - 4)) + exp(x*(4*log(x) - + 4))*Integral(exp(4*x)*exp(-4*x*log(x))*sin(x), x)), + Eq(k(x), -C1/4 - C2/4 + 3*C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + + C4/4)*exp(x*(4*log(x) - 4)) + exp(x*(4*log(x) - + 4))*Integral(exp(4*x)*exp(-4*x*log(x))*sin(x), x))] + with dotprodsimp(True): + assert dsolve(eqs8) == sol8 + assert checksysodesol(eqs8, sol8) == (True, [0, 0, 0, 0]) + + +def test_sysode_linear_neq_order1_type5_type6(): + f, g = symbols("f g", cls=Function) + x, x_ = symbols("x x_") + + # Type 5 + eqs1 = [Eq(Derivative(f(x), x), (2*f(x) + g(x))/x), Eq(Derivative(g(x), x), (f(x) + 2*g(x))/x)] + sol1 = [Eq(f(x), -C1*x + C2*x**3), Eq(g(x), C1*x + C2*x**3)] + assert dsolve(eqs1) == sol1 + assert checksysodesol(eqs1, sol1) == (True, [0, 0]) + + # Type 6 + eqs2 = [Eq(Derivative(f(x), x), (2*f(x) + g(x) + 1)/x), + Eq(Derivative(g(x), x), (x + f(x) + 2*g(x))/x)] + sol2 = [Eq(f(x), C2*x**3 - x*(C1 + Rational(1, 4)) + x*log(x)*Rational(-1, 2) + Rational(-2, 3)), + Eq(g(x), C2*x**3 + x*log(x)/2 + x*(C1 + Rational(-1, 4)) + Rational(1, 3))] + assert dsolve(eqs2) == sol2 + assert checksysodesol(eqs2, sol2) == (True, [0, 0]) + + +def test_higher_order_to_first_order(): + f, g = symbols('f g', cls=Function) + x = symbols('x') + + eqs1 = [Eq(Derivative(f(x), (x, 2)), 2*f(x) + g(x)), + Eq(Derivative(g(x), (x, 2)), -f(x))] + sol1 = [Eq(f(x), -C2*x*exp(-x) + C3*x*exp(x) - (C1 - C2)*exp(-x) + (C3 + C4)*exp(x)), + Eq(g(x), C2*x*exp(-x) - C3*x*exp(x) + (C1 + C2)*exp(-x) + (C3 - C4)*exp(x))] + assert dsolve(eqs1) == sol1 + assert checksysodesol(eqs1, sol1) == (True, [0, 0]) + + eqs2 = [Eq(f(x).diff(x, 2), 0), Eq(g(x).diff(x, 2), f(x))] + sol2 = [Eq(f(x), C1 + C2*x), Eq(g(x), C1*x**2/2 + C2*x**3/6 + C3 + C4*x)] + assert dsolve(eqs2) == sol2 + assert checksysodesol(eqs2, sol2) == (True, [0, 0]) + + eqs3 = [Eq(Derivative(f(x), (x, 2)), 2*f(x)), + Eq(Derivative(g(x), (x, 2)), -f(x) + 2*g(x))] + sol3 = [Eq(f(x), 4*C1*exp(-sqrt(2)*x) + 4*C2*exp(sqrt(2)*x)), + Eq(g(x), sqrt(2)*C1*x*exp(-sqrt(2)*x) - sqrt(2)*C2*x*exp(sqrt(2)*x) + (C1 + + sqrt(2)*C4)*exp(-sqrt(2)*x) + (C2 - sqrt(2)*C3)*exp(sqrt(2)*x))] + assert dsolve(eqs3) == sol3 + assert checksysodesol(eqs3, sol3) == (True, [0, 0]) + + eqs4 = [Eq(Derivative(f(x), (x, 2)), 2*f(x) + g(x)), + Eq(Derivative(g(x), (x, 2)), 2*g(x))] + sol4 = [Eq(f(x), C1*x*exp(sqrt(2)*x)/4 + C3*x*exp(-sqrt(2)*x)/4 + (C2/4 + sqrt(2)*C3/8)*exp(-sqrt(2)*x) - + exp(sqrt(2)*x)*(sqrt(2)*C1/8 + C4*Rational(-1, 4))), + Eq(g(x), sqrt(2)*C1*exp(sqrt(2)*x)/2 + sqrt(2)*C3*exp(-sqrt(2)*x)*Rational(-1, 2))] + assert dsolve(eqs4) == sol4 + assert checksysodesol(eqs4, sol4) == (True, [0, 0]) + + eqs5 = [Eq(f(x).diff(x, 2), f(x)), Eq(g(x).diff(x, 2), f(x))] + sol5 = [Eq(f(x), -C1*exp(-x) + C2*exp(x)), Eq(g(x), -C1*exp(-x) + C2*exp(x) + C3 + C4*x)] + assert dsolve(eqs5) == sol5 + assert checksysodesol(eqs5, sol5) == (True, [0, 0]) + + eqs6 = [Eq(Derivative(f(x), (x, 2)), f(x) + g(x)), + Eq(Derivative(g(x), (x, 2)), -f(x) - g(x))] + sol6 = [Eq(f(x), C1 + C2*x**2/2 + C2 + C4*x**3/6 + x*(C3 + C4)), + Eq(g(x), -C1 + C2*x**2*Rational(-1, 2) - C3*x + C4*x**3*Rational(-1, 6))] + assert dsolve(eqs6) == sol6 + assert checksysodesol(eqs6, sol6) == (True, [0, 0]) + + eqs7 = [Eq(Derivative(f(x), (x, 2)), f(x) + g(x) + 1), + Eq(Derivative(g(x), (x, 2)), f(x) + g(x) + 1)] + sol7 = [Eq(f(x), -C1 - C2*x + sqrt(2)*C3*exp(sqrt(2)*x)/2 + sqrt(2)*C4*exp(-sqrt(2)*x)*Rational(-1, 2) + + Rational(-1, 2)), + Eq(g(x), C1 + C2*x + sqrt(2)*C3*exp(sqrt(2)*x)/2 + sqrt(2)*C4*exp(-sqrt(2)*x)*Rational(-1, 2) + + Rational(-1, 2))] + assert dsolve(eqs7) == sol7 + assert checksysodesol(eqs7, sol7) == (True, [0, 0]) + + eqs8 = [Eq(Derivative(f(x), (x, 2)), f(x) + g(x) + 1), + Eq(Derivative(g(x), (x, 2)), -f(x) - g(x) + 1)] + sol8 = [Eq(f(x), C1 + C2 + C4*x**3/6 + x**4/12 + x**2*(C2/2 + Rational(1, 2)) + x*(C3 + C4)), + Eq(g(x), -C1 - C3*x + C4*x**3*Rational(-1, 6) + x**4*Rational(-1, 12) - x**2*(C2/2 + Rational(-1, + 2)))] + assert dsolve(eqs8) == sol8 + assert checksysodesol(eqs8, sol8) == (True, [0, 0]) + + x, y = symbols('x, y', cls=Function) + t, l = symbols('t, l') + + eqs10 = [Eq(Derivative(x(t), (t, 2)), 5*x(t) + 43*y(t)), + Eq(Derivative(y(t), (t, 2)), x(t) + 9*y(t))] + sol10 = [Eq(x(t), C1*(61 - 9*sqrt(47))*sqrt(sqrt(47) + 7)*exp(-t*sqrt(sqrt(47) + 7))/2 + C2*sqrt(7 - + sqrt(47))*(61 + 9*sqrt(47))*exp(-t*sqrt(7 - sqrt(47)))/2 + C3*(61 - 9*sqrt(47))*sqrt(sqrt(47) + + 7)*exp(t*sqrt(sqrt(47) + 7))*Rational(-1, 2) + C4*sqrt(7 - sqrt(47))*(61 + 9*sqrt(47))*exp(t*sqrt(7 + - sqrt(47)))*Rational(-1, 2)), + Eq(y(t), C1*(7 - sqrt(47))*sqrt(sqrt(47) + 7)*exp(-t*sqrt(sqrt(47) + 7))*Rational(-1, 2) + C2*sqrt(7 + - sqrt(47))*(sqrt(47) + 7)*exp(-t*sqrt(7 - sqrt(47)))*Rational(-1, 2) + C3*(7 - + sqrt(47))*sqrt(sqrt(47) + 7)*exp(t*sqrt(sqrt(47) + 7))/2 + C4*sqrt(7 - sqrt(47))*(sqrt(47) + + 7)*exp(t*sqrt(7 - sqrt(47)))/2)] + assert dsolve(eqs10) == sol10 + assert checksysodesol(eqs10, sol10) == (True, [0, 0]) + + eqs11 = [Eq(7*x(t) + Derivative(x(t), (t, 2)) - 9*Derivative(y(t), t), 0), + Eq(7*y(t) + 9*Derivative(x(t), t) + Derivative(y(t), (t, 2)), 0)] + sol11 = [Eq(y(t), C1*(9 - sqrt(109))*sin(sqrt(2)*t*sqrt(9*sqrt(109) + 95)/2)/14 + C2*(9 - + sqrt(109))*cos(sqrt(2)*t*sqrt(9*sqrt(109) + 95)/2)*Rational(-1, 14) + C3*(9 + + sqrt(109))*sin(sqrt(2)*t*sqrt(95 - 9*sqrt(109))/2)/14 + C4*(9 + sqrt(109))*cos(sqrt(2)*t*sqrt(95 - + 9*sqrt(109))/2)*Rational(-1, 14)), + Eq(x(t), C1*(9 - sqrt(109))*cos(sqrt(2)*t*sqrt(9*sqrt(109) + 95)/2)*Rational(-1, 14) + C2*(9 - + sqrt(109))*sin(sqrt(2)*t*sqrt(9*sqrt(109) + 95)/2)*Rational(-1, 14) + C3*(9 + + sqrt(109))*cos(sqrt(2)*t*sqrt(95 - 9*sqrt(109))/2)/14 + C4*(9 + sqrt(109))*sin(sqrt(2)*t*sqrt(95 - + 9*sqrt(109))/2)/14)] + assert dsolve(eqs11) == sol11 + assert checksysodesol(eqs11, sol11) == (True, [0, 0]) + + # Euler Systems + # Note: To add examples of euler systems solver with non-homogeneous term. + eqs13 = [Eq(Derivative(f(t), (t, 2)), Derivative(f(t), t)/t + f(t)/t**2 + g(t)/t**2), + Eq(Derivative(g(t), (t, 2)), g(t)/t**2)] + sol13 = [Eq(f(t), C1*(sqrt(5) + 3)*Rational(-1, 2)*t**(Rational(1, 2) + + sqrt(5)*Rational(-1, 2)) + C2*t**(Rational(1, 2) + + sqrt(5)/2)*(3 - sqrt(5))*Rational(-1, 2) - C3*t**(1 - + sqrt(2))*(1 + sqrt(2)) - C4*t**(1 + sqrt(2))*(1 - sqrt(2))), + Eq(g(t), C1*(1 + sqrt(5))*Rational(-1, 2)*t**(Rational(1, 2) + + sqrt(5)*Rational(-1, 2)) + C2*t**(Rational(1, 2) + + sqrt(5)/2)*(1 - sqrt(5))*Rational(-1, 2))] + assert dsolve(eqs13) == sol13 + assert checksysodesol(eqs13, sol13) == (True, [0, 0]) + + # Solving systems using dsolve separately + eqs14 = [Eq(Derivative(f(t), (t, 2)), t*f(t)), + Eq(Derivative(g(t), (t, 2)), t*g(t))] + sol14 = [Eq(f(t), C1*airyai(t) + C2*airybi(t)), + Eq(g(t), C3*airyai(t) + C4*airybi(t))] + assert dsolve(eqs14) == sol14 + assert checksysodesol(eqs14, sol14) == (True, [0, 0]) + + + eqs15 = [Eq(Derivative(x(t), (t, 2)), t*(4*Derivative(x(t), t) + 8*Derivative(y(t), t))), + Eq(Derivative(y(t), (t, 2)), t*(12*Derivative(x(t), t) - 6*Derivative(y(t), t)))] + sol15 = [Eq(x(t), C1 - erf(sqrt(6)*t)*(sqrt(6)*sqrt(pi)*C2/33 + sqrt(6)*sqrt(pi)*C3*Rational(-1, 44)) + + erfi(sqrt(5)*t)*(sqrt(5)*sqrt(pi)*C2*Rational(2, 55) + sqrt(5)*sqrt(pi)*C3*Rational(4, 55))), + Eq(y(t), C4 + erf(sqrt(6)*t)*(sqrt(6)*sqrt(pi)*C2*Rational(2, 33) + sqrt(6)*sqrt(pi)*C3*Rational(-1, + 22)) + erfi(sqrt(5)*t)*(sqrt(5)*sqrt(pi)*C2*Rational(3, 110) + sqrt(5)*sqrt(pi)*C3*Rational(3, 55)))] + assert dsolve(eqs15) == sol15 + assert checksysodesol(eqs15, sol15) == (True, [0, 0]) + + +@slow +def test_higher_order_to_first_order_9(): + f, g = symbols('f g', cls=Function) + x = symbols('x') + + eqs9 = [f(x) + g(x) - 2*exp(I*x) + 2*Derivative(f(x), x) + Derivative(f(x), (x, 2)), + f(x) + g(x) - 2*exp(I*x) + 2*Derivative(g(x), x) + Derivative(g(x), (x, 2))] + sol9 = [Eq(f(x), -C1 + C4*exp(-2*x)/2 - (C2/2 - C3/2)*exp(-x)*cos(x) + + (C2/2 + C3/2)*exp(-x)*sin(x) + 2*((1 - 2*I)*exp(I*x)*sin(x)**2/5) + + 2*((1 - 2*I)*exp(I*x)*cos(x)**2/5)), + Eq(g(x), C1 - C4*exp(-2*x)/2 - (C2/2 - C3/2)*exp(-x)*cos(x) + + (C2/2 + C3/2)*exp(-x)*sin(x) + 2*((1 - 2*I)*exp(I*x)*sin(x)**2/5) + + 2*((1 - 2*I)*exp(I*x)*cos(x)**2/5))] + assert dsolve(eqs9) == sol9 + assert checksysodesol(eqs9, sol9) == (True, [0, 0]) + + +def test_higher_order_to_first_order_12(): + f, g = symbols('f g', cls=Function) + x = symbols('x') + + x, y = symbols('x, y', cls=Function) + t, l = symbols('t, l') + + eqs12 = [Eq(4*x(t) + Derivative(x(t), (t, 2)) + 8*Derivative(y(t), t), 0), + Eq(4*y(t) - 8*Derivative(x(t), t) + Derivative(y(t), (t, 2)), 0)] + sol12 = [Eq(y(t), C1*(2 - sqrt(5))*sin(2*t*sqrt(4*sqrt(5) + 9))*Rational(-1, 2) + C2*(2 - + sqrt(5))*cos(2*t*sqrt(4*sqrt(5) + 9))/2 + C3*(2 + sqrt(5))*sin(2*t*sqrt(9 - 4*sqrt(5)))*Rational(-1, + 2) + C4*(2 + sqrt(5))*cos(2*t*sqrt(9 - 4*sqrt(5)))/2), + Eq(x(t), C1*(2 - sqrt(5))*cos(2*t*sqrt(4*sqrt(5) + 9))*Rational(-1, 2) + C2*(2 - + sqrt(5))*sin(2*t*sqrt(4*sqrt(5) + 9))*Rational(-1, 2) + C3*(2 + sqrt(5))*cos(2*t*sqrt(9 - + 4*sqrt(5)))/2 + C4*(2 + sqrt(5))*sin(2*t*sqrt(9 - 4*sqrt(5)))/2)] + assert dsolve(eqs12) == sol12 + assert checksysodesol(eqs12, sol12) == (True, [0, 0]) + + +def test_second_order_to_first_order_2(): + f, g = symbols("f g", cls=Function) + x, t, x_, t_, d, a, m = symbols("x t x_ t_ d a m") + + eqs2 = [Eq(f(x).diff(x, 2), 2*(x*g(x).diff(x) - g(x))), + Eq(g(x).diff(x, 2),-2*(x*f(x).diff(x) - f(x)))] + sol2 = [Eq(f(x), C1*x + x*Integral(C2*exp(-x_)*exp(I*exp(2*x_))/2 + C2*exp(-x_)*exp(-I*exp(2*x_))/2 - + I*C3*exp(-x_)*exp(I*exp(2*x_))/2 + I*C3*exp(-x_)*exp(-I*exp(2*x_))/2, (x_, log(x)))), + Eq(g(x), C4*x + x*Integral(I*C2*exp(-x_)*exp(I*exp(2*x_))/2 - I*C2*exp(-x_)*exp(-I*exp(2*x_))/2 + + C3*exp(-x_)*exp(I*exp(2*x_))/2 + C3*exp(-x_)*exp(-I*exp(2*x_))/2, (x_, log(x))))] + # XXX: dsolve hangs for this in integration + assert dsolve_system(eqs2, simplify=False, doit=False) == [sol2] + assert checksysodesol(eqs2, sol2) == (True, [0, 0]) + + eqs3 = (Eq(diff(f(t),t,t), 9*t*diff(g(t),t)-9*g(t)), Eq(diff(g(t),t,t),7*t*diff(f(t),t)-7*f(t))) + sol3 = [Eq(f(t), C1*t + t*Integral(C2*exp(-t_)*exp(3*sqrt(7)*exp(2*t_)/2)/2 + C2*exp(-t_)* + exp(-3*sqrt(7)*exp(2*t_)/2)/2 + 3*sqrt(7)*C3*exp(-t_)*exp(3*sqrt(7)*exp(2*t_)/2)/14 - + 3*sqrt(7)*C3*exp(-t_)*exp(-3*sqrt(7)*exp(2*t_)/2)/14, (t_, log(t)))), + Eq(g(t), C4*t + t*Integral(sqrt(7)*C2*exp(-t_)*exp(3*sqrt(7)*exp(2*t_)/2)/6 - sqrt(7)*C2*exp(-t_)* + exp(-3*sqrt(7)*exp(2*t_)/2)/6 + C3*exp(-t_)*exp(3*sqrt(7)*exp(2*t_)/2)/2 + C3*exp(-t_)*exp(-3*sqrt(7)* + exp(2*t_)/2)/2, (t_, log(t))))] + # XXX: dsolve hangs for this in integration + assert dsolve_system(eqs3, simplify=False, doit=False) == [sol3] + assert checksysodesol(eqs3, sol3) == (True, [0, 0]) + + # Regression Test case for sympy#19238 + # https://github.com/sympy/sympy/issues/19238 + # Note: When the doit method is removed, these particular types of systems + # can be divided first so that we have lesser number of big matrices. + eqs5 = [Eq(Derivative(g(t), (t, 2)), a*m), + Eq(Derivative(f(t), (t, 2)), 0)] + sol5 = [Eq(g(t), C1 + C2*t + a*m*t**2/2), + Eq(f(t), C3 + C4*t)] + assert dsolve(eqs5) == sol5 + assert checksysodesol(eqs5, sol5) == (True, [0, 0]) + + # Type 2 + eqs6 = [Eq(Derivative(f(t), (t, 2)), f(t)/t**4), + Eq(Derivative(g(t), (t, 2)), d*g(t)/t**4)] + sol6 = [Eq(f(t), C1*sqrt(t**2)*exp(-1/t) - C2*sqrt(t**2)*exp(1/t)), + Eq(g(t), C3*sqrt(t**2)*exp(-sqrt(d)/t)*d**Rational(-1, 2) - + C4*sqrt(t**2)*exp(sqrt(d)/t)*d**Rational(-1, 2))] + assert dsolve(eqs6) == sol6 + assert checksysodesol(eqs6, sol6) == (True, [0, 0]) + + +@slow +def test_second_order_to_first_order_slow1(): + f, g = symbols("f g", cls=Function) + x, t, x_, t_, d, a, m = symbols("x t x_ t_ d a m") + + # Type 1 + + eqs1 = [Eq(f(x).diff(x, 2), 2/x *(x*g(x).diff(x) - g(x))), + Eq(g(x).diff(x, 2),-2/x *(x*f(x).diff(x) - f(x)))] + sol1 = [Eq(f(x), C1*x + 2*C2*x*Ci(2*x) - C2*sin(2*x) - 2*C3*x*Si(2*x) - C3*cos(2*x)), + Eq(g(x), -2*C2*x*Si(2*x) - C2*cos(2*x) - 2*C3*x*Ci(2*x) + C3*sin(2*x) + C4*x)] + assert dsolve(eqs1) == sol1 + assert checksysodesol(eqs1, sol1) == (True, [0, 0]) + + +def test_second_order_to_first_order_slow4(): + f, g = symbols("f g", cls=Function) + x, t, x_, t_, d, a, m = symbols("x t x_ t_ d a m") + + eqs4 = [Eq(Derivative(f(t), (t, 2)), t*sin(t)*Derivative(g(t), t) - g(t)*sin(t)), + Eq(Derivative(g(t), (t, 2)), t*sin(t)*Derivative(f(t), t) - f(t)*sin(t))] + sol4 = [Eq(f(t), C1*t + t*Integral(C2*exp(-t_)*exp(exp(t_)*cos(exp(t_)))*exp(-sin(exp(t_)))/2 + + C2*exp(-t_)*exp(-exp(t_)*cos(exp(t_)))*exp(sin(exp(t_)))/2 - C3*exp(-t_)*exp(exp(t_)*cos(exp(t_)))* + exp(-sin(exp(t_)))/2 + + C3*exp(-t_)*exp(-exp(t_)*cos(exp(t_)))*exp(sin(exp(t_)))/2, (t_, log(t)))), + Eq(g(t), C4*t + t*Integral(-C2*exp(-t_)*exp(exp(t_)*cos(exp(t_)))*exp(-sin(exp(t_)))/2 + + C2*exp(-t_)*exp(-exp(t_)*cos(exp(t_)))*exp(sin(exp(t_)))/2 + C3*exp(-t_)*exp(exp(t_)*cos(exp(t_)))* + exp(-sin(exp(t_)))/2 + C3*exp(-t_)*exp(-exp(t_)*cos(exp(t_)))*exp(sin(exp(t_)))/2, (t_, log(t))))] + # XXX: dsolve hangs for this in integration + assert dsolve_system(eqs4, simplify=False, doit=False) == [sol4] + assert checksysodesol(eqs4, sol4) == (True, [0, 0]) + + +def test_component_division(): + f, g, h, k = symbols('f g h k', cls=Function) + x = symbols("x") + funcs = [f(x), g(x), h(x), k(x)] + + eqs1 = [Eq(Derivative(f(x), x), 2*f(x)), + Eq(Derivative(g(x), x), f(x)), + Eq(Derivative(h(x), x), h(x)), + Eq(Derivative(k(x), x), h(x)**4 + k(x))] + sol1 = [Eq(f(x), 2*C1*exp(2*x)), + Eq(g(x), C1*exp(2*x) + C2), + Eq(h(x), C3*exp(x)), + Eq(k(x), C3**4*exp(4*x)/3 + C4*exp(x))] + assert dsolve(eqs1) == sol1 + assert checksysodesol(eqs1, sol1) == (True, [0, 0, 0, 0]) + + components1 = {((Eq(Derivative(f(x), x), 2*f(x)),), (Eq(Derivative(g(x), x), f(x)),)), + ((Eq(Derivative(h(x), x), h(x)),), (Eq(Derivative(k(x), x), h(x)**4 + k(x)),))} + eqsdict1 = ({f(x): set(), g(x): {f(x)}, h(x): set(), k(x): {h(x)}}, + {f(x): Eq(Derivative(f(x), x), 2*f(x)), + g(x): Eq(Derivative(g(x), x), f(x)), + h(x): Eq(Derivative(h(x), x), h(x)), + k(x): Eq(Derivative(k(x), x), h(x)**4 + k(x))}) + graph1 = [{f(x), g(x), h(x), k(x)}, {(g(x), f(x)), (k(x), h(x))}] + assert {tuple(tuple(scc) for scc in wcc) for wcc in _component_division(eqs1, funcs, x)} == components1 + assert _eqs2dict(eqs1, funcs) == eqsdict1 + assert [set(element) for element in _dict2graph(eqsdict1[0])] == graph1 + + eqs2 = [Eq(Derivative(f(x), x), 2*f(x)), + Eq(Derivative(g(x), x), f(x)), + Eq(Derivative(h(x), x), h(x)), + Eq(Derivative(k(x), x), f(x)**4 + k(x))] + sol2 = [Eq(f(x), C1*exp(2*x)), + Eq(g(x), C1*exp(2*x)/2 + C2), + Eq(h(x), C3*exp(x)), + Eq(k(x), C1**4*exp(8*x)/7 + C4*exp(x))] + assert dsolve(eqs2) == sol2 + assert checksysodesol(eqs2, sol2) == (True, [0, 0, 0, 0]) + + components2 = {frozenset([(Eq(Derivative(f(x), x), 2*f(x)),), + (Eq(Derivative(g(x), x), f(x)),), + (Eq(Derivative(k(x), x), f(x)**4 + k(x)),)]), + frozenset([(Eq(Derivative(h(x), x), h(x)),)])} + eqsdict2 = ({f(x): set(), g(x): {f(x)}, h(x): set(), k(x): {f(x)}}, + {f(x): Eq(Derivative(f(x), x), 2*f(x)), + g(x): Eq(Derivative(g(x), x), f(x)), + h(x): Eq(Derivative(h(x), x), h(x)), + k(x): Eq(Derivative(k(x), x), f(x)**4 + k(x))}) + graph2 = [{f(x), g(x), h(x), k(x)}, {(g(x), f(x)), (k(x), f(x))}] + assert {frozenset(tuple(scc) for scc in wcc) for wcc in _component_division(eqs2, funcs, x)} == components2 + assert _eqs2dict(eqs2, funcs) == eqsdict2 + assert [set(element) for element in _dict2graph(eqsdict2[0])] == graph2 + + eqs3 = [Eq(Derivative(f(x), x), 2*f(x)), + Eq(Derivative(g(x), x), x + f(x)), + Eq(Derivative(h(x), x), h(x)), + Eq(Derivative(k(x), x), f(x)**4 + k(x))] + sol3 = [Eq(f(x), C1*exp(2*x)), + Eq(g(x), C1*exp(2*x)/2 + C2 + x**2/2), + Eq(h(x), C3*exp(x)), + Eq(k(x), C1**4*exp(8*x)/7 + C4*exp(x))] + assert dsolve(eqs3) == sol3 + assert checksysodesol(eqs3, sol3) == (True, [0, 0, 0, 0]) + + components3 = {frozenset([(Eq(Derivative(f(x), x), 2*f(x)),), + (Eq(Derivative(g(x), x), x + f(x)),), + (Eq(Derivative(k(x), x), f(x)**4 + k(x)),)]), + frozenset([(Eq(Derivative(h(x), x), h(x)),),])} + eqsdict3 = ({f(x): set(), g(x): {f(x)}, h(x): set(), k(x): {f(x)}}, + {f(x): Eq(Derivative(f(x), x), 2*f(x)), + g(x): Eq(Derivative(g(x), x), x + f(x)), + h(x): Eq(Derivative(h(x), x), h(x)), + k(x): Eq(Derivative(k(x), x), f(x)**4 + k(x))}) + graph3 = [{f(x), g(x), h(x), k(x)}, {(g(x), f(x)), (k(x), f(x))}] + assert {frozenset(tuple(scc) for scc in wcc) for wcc in _component_division(eqs3, funcs, x)} == components3 + assert _eqs2dict(eqs3, funcs) == eqsdict3 + assert [set(l) for l in _dict2graph(eqsdict3[0])] == graph3 + + # Note: To be uncommented when the default option to call dsolve first for + # single ODE system can be rearranged. This can be done after the doit + # option in dsolve is made False by default. + + eqs4 = [Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), + Eq(Derivative(g(x), x), f(x) + x*g(x) + x), + Eq(Derivative(h(x), x), h(x)), + Eq(Derivative(k(x), x), f(x)**4 + k(x))] + sol4 = [Eq(f(x), (C1/2 - sqrt(2)*C2/2 - sqrt(2)*Integral(x*exp(-x**2/2 - sqrt(2)*x)/2 + x*exp(-x**2/2 +\ + sqrt(2)*x)/2, x)/2 + Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 - sqrt(2)*x*exp(-x**2/2 +\ + sqrt(2)*x)/2, x)/2)*exp(x**2/2 - sqrt(2)*x) + (C1/2 + sqrt(2)*C2/2 + sqrt(2)*Integral(x*exp(-x**2/2 + - sqrt(2)*x)/2 + x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2 + Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 + - sqrt(2)*x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2)*exp(x**2/2 + sqrt(2)*x)), + Eq(g(x), (-sqrt(2)*C1/4 + C2/2 + Integral(x*exp(-x**2/2 - sqrt(2)*x)/2 + x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2 -\ + sqrt(2)*Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 - sqrt(2)*x*exp(-x**2/2 + sqrt(2)*x)/2, + x)/4)*exp(x**2/2 - sqrt(2)*x) + (sqrt(2)*C1/4 + C2/2 + Integral(x*exp(-x**2/2 - sqrt(2)*x)/2 + + x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2 + sqrt(2)*Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 - + sqrt(2)*x*exp(-x**2/2 + sqrt(2)*x)/2, x)/4)*exp(x**2/2 + sqrt(2)*x)), + Eq(h(x), C3*exp(x)), + Eq(k(x), C4*exp(x) + exp(x)*Integral((C1*exp(x**2/2 - sqrt(2)*x)/2 + C1*exp(x**2/2 + sqrt(2)*x)/2 - + sqrt(2)*C2*exp(x**2/2 - sqrt(2)*x)/2 + sqrt(2)*C2*exp(x**2/2 + sqrt(2)*x)/2 - sqrt(2)*exp(x**2/2 - + sqrt(2)*x)*Integral(x*exp(-x**2/2 - sqrt(2)*x)/2 + x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2 + exp(x**2/2 - + sqrt(2)*x)*Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 - sqrt(2)*x*exp(-x**2/2 + sqrt(2)*x)/2, + x)/2 + sqrt(2)*exp(x**2/2 + sqrt(2)*x)*Integral(x*exp(-x**2/2 - sqrt(2)*x)/2 + x*exp(-x**2/2 + + sqrt(2)*x)/2, x)/2 + exp(x**2/2 + sqrt(2)*x)*Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 - + sqrt(2)*x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2)**4*exp(-x), x))] + components4 = {(frozenset([Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), + Eq(Derivative(g(x), x), x*g(x) + x + f(x))]), + frozenset([Eq(Derivative(k(x), x), f(x)**4 + k(x)),])), + (frozenset([Eq(Derivative(h(x), x), h(x)),]),)} + eqsdict4 = ({f(x): {g(x)}, g(x): {f(x)}, h(x): set(), k(x): {f(x)}}, + {f(x): Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), + g(x): Eq(Derivative(g(x), x), x*g(x) + x + f(x)), + h(x): Eq(Derivative(h(x), x), h(x)), + k(x): Eq(Derivative(k(x), x), f(x)**4 + k(x))}) + graph4 = [{f(x), g(x), h(x), k(x)}, {(f(x), g(x)), (g(x), f(x)), (k(x), f(x))}] + assert {tuple(frozenset(scc) for scc in wcc) for wcc in _component_division(eqs4, funcs, x)} == components4 + assert _eqs2dict(eqs4, funcs) == eqsdict4 + assert [set(element) for element in _dict2graph(eqsdict4[0])] == graph4 + # XXX: dsolve hangs in integration here: + assert dsolve_system(eqs4, simplify=False, doit=False) == [sol4] + assert checksysodesol(eqs4, sol4) == (True, [0, 0, 0, 0]) + + eqs5 = [Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), + Eq(Derivative(g(x), x), x*g(x) + f(x)), + Eq(Derivative(h(x), x), h(x)), + Eq(Derivative(k(x), x), f(x)**4 + k(x))] + sol5 = [Eq(f(x), (C1/2 - sqrt(2)*C2/2)*exp(x**2/2 - sqrt(2)*x) + (C1/2 + sqrt(2)*C2/2)*exp(x**2/2 + sqrt(2)*x)), + Eq(g(x), (-sqrt(2)*C1/4 + C2/2)*exp(x**2/2 - sqrt(2)*x) + (sqrt(2)*C1/4 + C2/2)*exp(x**2/2 + sqrt(2)*x)), + Eq(h(x), C3*exp(x)), + Eq(k(x), C4*exp(x) + exp(x)*Integral((C1*exp(x**2/2 - sqrt(2)*x)/2 + C1*exp(x**2/2 + sqrt(2)*x)/2 - + sqrt(2)*C2*exp(x**2/2 - sqrt(2)*x)/2 + sqrt(2)*C2*exp(x**2/2 + sqrt(2)*x)/2)**4*exp(-x), x))] + components5 = {(frozenset([Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), + Eq(Derivative(g(x), x), x*g(x) + f(x))]), + frozenset([Eq(Derivative(k(x), x), f(x)**4 + k(x)),])), + (frozenset([Eq(Derivative(h(x), x), h(x)),]),)} + eqsdict5 = ({f(x): {g(x)}, g(x): {f(x)}, h(x): set(), k(x): {f(x)}}, + {f(x): Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), + g(x): Eq(Derivative(g(x), x), x*g(x) + f(x)), + h(x): Eq(Derivative(h(x), x), h(x)), + k(x): Eq(Derivative(k(x), x), f(x)**4 + k(x))}) + graph5 = [{f(x), g(x), h(x), k(x)}, {(f(x), g(x)), (g(x), f(x)), (k(x), f(x))}] + assert {tuple(frozenset(scc) for scc in wcc) for wcc in _component_division(eqs5, funcs, x)} == components5 + assert _eqs2dict(eqs5, funcs) == eqsdict5 + assert [set(element) for element in _dict2graph(eqsdict5[0])] == graph5 + # XXX: dsolve hangs in integration here: + assert dsolve_system(eqs5, simplify=False, doit=False) == [sol5] + assert checksysodesol(eqs5, sol5) == (True, [0, 0, 0, 0]) + + +def test_linodesolve(): + t, x, a = symbols("t x a") + f, g, h = symbols("f g h", cls=Function) + + # Testing the Errors + raises(ValueError, lambda: linodesolve(1, t)) + raises(ValueError, lambda: linodesolve(a, t)) + + A1 = Matrix([[1, 2], [2, 4], [4, 6]]) + raises(NonSquareMatrixError, lambda: linodesolve(A1, t)) + + A2 = Matrix([[1, 2, 1], [3, 1, 2]]) + raises(NonSquareMatrixError, lambda: linodesolve(A2, t)) + + # Testing auto functionality + func = [f(t), g(t)] + eq = [Eq(f(t).diff(t) + g(t).diff(t), g(t)), Eq(g(t).diff(t), f(t))] + ceq = canonical_odes(eq, func, t) + (A1, A0), b = linear_ode_to_matrix(ceq[0], func, t, 1) + A = A0 + sol = [C1*(-Rational(1, 2) + sqrt(5)/2)*exp(t*(-Rational(1, 2) + sqrt(5)/2)) + C2*(-sqrt(5)/2 - Rational(1, 2))* + exp(t*(-sqrt(5)/2 - Rational(1, 2))), + C1*exp(t*(-Rational(1, 2) + sqrt(5)/2)) + C2*exp(t*(-sqrt(5)/2 - Rational(1, 2)))] + assert constant_renumber(linodesolve(A, t), variables=Tuple(*eq).free_symbols) == sol + + # Testing the Errors + raises(ValueError, lambda: linodesolve(1, t, b=Matrix([t+1]))) + raises(ValueError, lambda: linodesolve(a, t, b=Matrix([log(t) + sin(t)]))) + + raises(ValueError, lambda: linodesolve(Matrix([7]), t, b=t**2)) + raises(ValueError, lambda: linodesolve(Matrix([a+10]), t, b=log(t)*cos(t))) + + raises(ValueError, lambda: linodesolve(7, t, b=t**2)) + raises(ValueError, lambda: linodesolve(a, t, b=log(t) + sin(t))) + + A1 = Matrix([[1, 2], [2, 4], [4, 6]]) + b1 = Matrix([t, 1, t**2]) + raises(NonSquareMatrixError, lambda: linodesolve(A1, t, b=b1)) + + A2 = Matrix([[1, 2, 1], [3, 1, 2]]) + b2 = Matrix([t, t**2]) + raises(NonSquareMatrixError, lambda: linodesolve(A2, t, b=b2)) + + raises(ValueError, lambda: linodesolve(A1[:2, :], t, b=b1)) + raises(ValueError, lambda: linodesolve(A1[:2, :], t, b=b1[:1])) + + # DOIT check + A1 = Matrix([[1, -1], [1, -1]]) + b1 = Matrix([15*t - 10, -15*t - 5]) + sol1 = [C1 + C2*t + C2 - 10*t**3 + 10*t**2 + t*(15*t**2 - 5*t) - 10*t, + C1 + C2*t - 10*t**3 - 5*t**2 + t*(15*t**2 - 5*t) - 5*t] + assert constant_renumber(linodesolve(A1, t, b=b1, type="type2", doit=True), + variables=[t]) == sol1 + + # Testing auto functionality + func = [f(t), g(t)] + eq = [Eq(f(t).diff(t) + g(t).diff(t), g(t) + t), Eq(g(t).diff(t), f(t))] + ceq = canonical_odes(eq, func, t) + (A1, A0), b = linear_ode_to_matrix(ceq[0], func, t, 1) + A = A0 + sol = [-C1*exp(-t/2 + sqrt(5)*t/2)/2 + sqrt(5)*C1*exp(-t/2 + sqrt(5)*t/2)/2 - sqrt(5)*C2*exp(-sqrt(5)*t/2 - + t/2)/2 - C2*exp(-sqrt(5)*t/2 - t/2)/2 - exp(-t/2 + sqrt(5)*t/2)*Integral(t*exp(-sqrt(5)*t/2 + + t/2)/(-5 + sqrt(5)) - sqrt(5)*t*exp(-sqrt(5)*t/2 + t/2)/(-5 + sqrt(5)), t)/2 + sqrt(5)*exp(-t/2 + + sqrt(5)*t/2)*Integral(t*exp(-sqrt(5)*t/2 + t/2)/(-5 + sqrt(5)) - sqrt(5)*t*exp(-sqrt(5)*t/2 + + t/2)/(-5 + sqrt(5)), t)/2 - sqrt(5)*exp(-sqrt(5)*t/2 - t/2)*Integral(-sqrt(5)*t*exp(t/2 + + sqrt(5)*t/2)/5, t)/2 - exp(-sqrt(5)*t/2 - t/2)*Integral(-sqrt(5)*t*exp(t/2 + sqrt(5)*t/2)/5, t)/2, + C1*exp(-t/2 + sqrt(5)*t/2) + C2*exp(-sqrt(5)*t/2 - t/2) + exp(-t/2 + + sqrt(5)*t/2)*Integral(t*exp(-sqrt(5)*t/2 + t/2)/(-5 + sqrt(5)) - sqrt(5)*t*exp(-sqrt(5)*t/2 + + t/2)/(-5 + sqrt(5)), t) + exp(-sqrt(5)*t/2 - + t/2)*Integral(-sqrt(5)*t*exp(t/2 + sqrt(5)*t/2)/5, t)] + assert constant_renumber(linodesolve(A, t, b=b), variables=[t]) == sol + + # non-homogeneous term assumed to be 0 + sol1 = [-C1*exp(-t/2 + sqrt(5)*t/2)/2 + sqrt(5)*C1*exp(-t/2 + sqrt(5)*t/2)/2 - sqrt(5)*C2*exp(-sqrt(5)*t/2 + - t/2)/2 - C2*exp(-sqrt(5)*t/2 - t/2)/2, + C1*exp(-t/2 + sqrt(5)*t/2) + C2*exp(-sqrt(5)*t/2 - t/2)] + assert constant_renumber(linodesolve(A, t, type="type2"), variables=[t]) == sol1 + + # Testing the Errors + raises(ValueError, lambda: linodesolve(t+10, t)) + raises(ValueError, lambda: linodesolve(a*t, t)) + + A1 = Matrix([[1, t], [-t, 1]]) + B1, _ = _is_commutative_anti_derivative(A1, t) + raises(NonSquareMatrixError, lambda: linodesolve(A1[:, :1], t, B=B1)) + raises(ValueError, lambda: linodesolve(A1, t, B=1)) + + A2 = Matrix([[t, t, t], [t, t, t], [t, t, t]]) + B2, _ = _is_commutative_anti_derivative(A2, t) + raises(NonSquareMatrixError, lambda: linodesolve(A2, t, B=B2[:2, :])) + raises(ValueError, lambda: linodesolve(A2, t, B=2)) + raises(ValueError, lambda: linodesolve(A2, t, B=B2, type="type31")) + + raises(ValueError, lambda: linodesolve(A1, t, B=B2)) + raises(ValueError, lambda: linodesolve(A2, t, B=B1)) + + # Testing auto functionality + func = [f(t), g(t)] + eq = [Eq(f(t).diff(t), f(t) + t*g(t)), Eq(g(t).diff(t), -t*f(t) + g(t))] + ceq = canonical_odes(eq, func, t) + (A1, A0), b = linear_ode_to_matrix(ceq[0], func, t, 1) + A = A0 + sol = [(C1/2 - I*C2/2)*exp(I*t**2/2 + t) + (C1/2 + I*C2/2)*exp(-I*t**2/2 + t), + (-I*C1/2 + C2/2)*exp(-I*t**2/2 + t) + (I*C1/2 + C2/2)*exp(I*t**2/2 + t)] + assert constant_renumber(linodesolve(A, t), variables=Tuple(*eq).free_symbols) == sol + assert constant_renumber(linodesolve(A, t, type="type3"), variables=Tuple(*eq).free_symbols) == sol + + A1 = Matrix([[t, 1], [t, -1]]) + raises(NotImplementedError, lambda: linodesolve(A1, t)) + + # Testing the Errors + raises(ValueError, lambda: linodesolve(t+10, t, b=Matrix([t+1]))) + raises(ValueError, lambda: linodesolve(a*t, t, b=Matrix([log(t) + sin(t)]))) + + raises(ValueError, lambda: linodesolve(Matrix([7*t]), t, b=t**2)) + raises(ValueError, lambda: linodesolve(Matrix([a + 10*log(t)]), t, b=log(t)*cos(t))) + + raises(ValueError, lambda: linodesolve(7*t, t, b=t**2)) + raises(ValueError, lambda: linodesolve(a*t**2, t, b=log(t) + sin(t))) + + A1 = Matrix([[1, t], [-t, 1]]) + b1 = Matrix([t, t ** 2]) + B1, _ = _is_commutative_anti_derivative(A1, t) + raises(NonSquareMatrixError, lambda: linodesolve(A1[:, :1], t, b=b1)) + + A2 = Matrix([[t, t, t], [t, t, t], [t, t, t]]) + b2 = Matrix([t, 1, t**2]) + B2, _ = _is_commutative_anti_derivative(A2, t) + raises(NonSquareMatrixError, lambda: linodesolve(A2[:2, :], t, b=b2)) + + raises(ValueError, lambda: linodesolve(A1, t, b=b2)) + raises(ValueError, lambda: linodesolve(A2, t, b=b1)) + + raises(ValueError, lambda: linodesolve(A1, t, b=b1, B=B2)) + raises(ValueError, lambda: linodesolve(A2, t, b=b2, B=B1)) + + # Testing auto functionality + func = [f(x), g(x), h(x)] + eq = [Eq(f(x).diff(x), x*(f(x) + g(x) + h(x)) + x), + Eq(g(x).diff(x), x*(f(x) + g(x) + h(x)) + x), + Eq(h(x).diff(x), x*(f(x) + g(x) + h(x)) + 1)] + ceq = canonical_odes(eq, func, x) + (A1, A0), b = linear_ode_to_matrix(ceq[0], func, x, 1) + A = A0 + _x1 = exp(-3*x**2/2) + _x2 = exp(3*x**2/2) + _x3 = Integral(2*_x1*x/3 + _x1/3 + x/3 - Rational(1, 3), x) + _x4 = 2*_x2*_x3/3 + _x5 = Integral(2*_x1*x/3 + _x1/3 - 2*x/3 + Rational(2, 3), x) + sol = [ + C1*_x2/3 - C1/3 + C2*_x2/3 - C2/3 + C3*_x2/3 + 2*C3/3 + _x2*_x5/3 + _x3/3 + _x4 - _x5/3, + C1*_x2/3 + 2*C1/3 + C2*_x2/3 - C2/3 + C3*_x2/3 - C3/3 + _x2*_x5/3 + _x3/3 + _x4 - _x5/3, + C1*_x2/3 - C1/3 + C2*_x2/3 + 2*C2/3 + C3*_x2/3 - C3/3 + _x2*_x5/3 - 2*_x3/3 + _x4 + 2*_x5/3, + ] + assert constant_renumber(linodesolve(A, x, b=b), variables=Tuple(*eq).free_symbols) == sol + assert constant_renumber(linodesolve(A, x, b=b, type="type4"), + variables=Tuple(*eq).free_symbols) == sol + + A1 = Matrix([[t, 1], [t, -1]]) + raises(NotImplementedError, lambda: linodesolve(A1, t, b=b1)) + + # non-homogeneous term not passed + sol1 = [-C1/3 - C2/3 + 2*C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2), 2*C1/3 - C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2), + -C1/3 + 2*C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2)] + assert constant_renumber(linodesolve(A, x, type="type4", doit=True), variables=Tuple(*eq).free_symbols) == sol1 + + +@slow +def test_linear_3eq_order1_type4_slow(): + x, y, z = symbols('x, y, z', cls=Function) + t = Symbol('t') + + f = t ** 3 + log(t) + g = t ** 2 + sin(t) + eq1 = (Eq(diff(x(t), t), (4 * f + g) * x(t) - f * y(t) - 2 * f * z(t)), + Eq(diff(y(t), t), 2 * f * x(t) + (f + g) * y(t) - 2 * f * z(t)), Eq(diff(z(t), t), 5 * f * x(t) + f * y( + t) + (-3 * f + g) * z(t))) + with dotprodsimp(True): + dsolve(eq1) + + +@slow +def test_linear_neq_order1_type2_slow1(): + i, r1, c1, r2, c2, t = symbols('i, r1, c1, r2, c2, t') + x1 = Function('x1') + x2 = Function('x2') + + eq1 = r1*c1*Derivative(x1(t), t) + x1(t) - x2(t) - r1*i + eq2 = r2*c1*Derivative(x1(t), t) + r2*c2*Derivative(x2(t), t) + x2(t) - r2*i + eq = [eq1, eq2] + + # XXX: Solution is too complicated + [sol] = dsolve_system(eq, simplify=False, doit=False) + assert checksysodesol(eq, sol) == (True, [0, 0]) + + +# Regression test case for issue #9204 +# https://github.com/sympy/sympy/issues/9204 +@tooslow +def test_linear_new_order1_type2_de_lorentz_slow_check(): + m = Symbol("m", real=True) + q = Symbol("q", real=True) + t = Symbol("t", real=True) + + e1, e2, e3 = symbols("e1:4", real=True) + b1, b2, b3 = symbols("b1:4", real=True) + v1, v2, v3 = symbols("v1:4", cls=Function, real=True) + + eqs = [ + -e1*q + m*Derivative(v1(t), t) - q*(-b2*v3(t) + b3*v2(t)), + -e2*q + m*Derivative(v2(t), t) - q*(b1*v3(t) - b3*v1(t)), + -e3*q + m*Derivative(v3(t), t) - q*(-b1*v2(t) + b2*v1(t)) + ] + sol = dsolve(eqs) + assert checksysodesol(eqs, sol) == (True, [0, 0, 0]) + + +# Regression test case for issue #14001 +# https://github.com/sympy/sympy/issues/14001 +@slow +def test_linear_neq_order1_type2_slow_check(): + RC, t, C, Vs, L, R1, V0, I0 = symbols("RC t C Vs L R1 V0 I0") + V = Function("V") + I = Function("I") + system = [Eq(V(t).diff(t), -1/RC*V(t) + I(t)/C), Eq(I(t).diff(t), -R1/L*I(t) - 1/L*V(t) + Vs/L)] + [sol] = dsolve_system(system, simplify=False, doit=False) + + assert checksysodesol(system, sol) == (True, [0, 0]) + + +def _linear_3eq_order1_type4_long(): + x, y, z = symbols('x, y, z', cls=Function) + t = Symbol('t') + + f = t ** 3 + log(t) + g = t ** 2 + sin(t) + + eq1 = (Eq(diff(x(t), t), (4*f + g)*x(t) - f*y(t) - 2*f*z(t)), + Eq(diff(y(t), t), 2*f*x(t) + (f + g)*y(t) - 2*f*z(t)), Eq(diff(z(t), t), 5*f*x(t) + f*y( + t) + (-3*f + g)*z(t))) + + dsolve_sol = dsolve(eq1) + dsolve_sol1 = [_simpsol(sol) for sol in dsolve_sol] + + x_1 = sqrt(-t**6 - 8*t**3*log(t) + 8*t**3 - 16*log(t)**2 + 32*log(t) - 16) + x_2 = sqrt(3) + x_3 = 8324372644*C1*x_1*x_2 + 4162186322*C2*x_1*x_2 - 8324372644*C3*x_1*x_2 + x_4 = 1 / (1903457163*t**3 + 3825881643*x_1*x_2 + 7613828652*log(t) - 7613828652) + x_5 = exp(t**3/3 + t*x_1*x_2/4 - cos(t)) + x_6 = exp(t**3/3 - t*x_1*x_2/4 - cos(t)) + x_7 = exp(t**4/2 + t**3/3 + 2*t*log(t) - 2*t - cos(t)) + x_8 = 91238*C1*x_1*x_2 + 91238*C2*x_1*x_2 - 91238*C3*x_1*x_2 + x_9 = 1 / (66049*t**3 - 50629*x_1*x_2 + 264196*log(t) - 264196) + x_10 = 50629 * C1 / 25189 + 37909*C2/25189 - 50629*C3/25189 - x_3*x_4 + x_11 = -50629*C1/25189 - 12720*C2/25189 + 50629*C3/25189 + x_3*x_4 + sol = [Eq(x(t), x_10*x_5 + x_11*x_6 + x_7*(C1 - C2)), Eq(y(t), x_10*x_5 + x_11*x_6), Eq(z(t), x_5*( + -424*C1/257 - 167*C2/257 + 424*C3/257 - x_8*x_9) + x_6*(167*C1/257 + 424*C2/257 - + 167*C3/257 + x_8*x_9) + x_7*(C1 - C2))] + + assert dsolve_sol1 == sol + assert checksysodesol(eq1, dsolve_sol1) == (True, [0, 0, 0]) + + +@slow +def test_neq_order1_type4_slow_check1(): + f, g = symbols("f g", cls=Function) + x = symbols("x") + + eqs = [Eq(diff(f(x), x), x*f(x) + x**2*g(x) + x), + Eq(diff(g(x), x), 2*x**2*f(x) + (x + 3*x**2)*g(x) + 1)] + sol = dsolve(eqs) + assert checksysodesol(eqs, sol) == (True, [0, 0]) + + +@slow +def test_neq_order1_type4_slow_check2(): + f, g, h = symbols("f, g, h", cls=Function) + x = Symbol("x") + + eqs = [ + Eq(Derivative(f(x), x), x*h(x) + f(x) + g(x) + 1), + Eq(Derivative(g(x), x), x*g(x) + f(x) + h(x) + 10), + Eq(Derivative(h(x), x), x*f(x) + x + g(x) + h(x)) + ] + with dotprodsimp(True): + sol = dsolve(eqs) + assert checksysodesol(eqs, sol) == (True, [0, 0, 0]) + + +def _neq_order1_type4_slow3(): + f, g = symbols("f g", cls=Function) + x = symbols("x") + + eqs = [ + Eq(Derivative(f(x), x), x*f(x) + g(x) + sin(x)), + Eq(Derivative(g(x), x), x**2 + x*g(x) - f(x)) + ] + sol = [ + Eq(f(x), (C1/2 - I*C2/2 - I*Integral(x**2*exp(-x**2/2 - I*x)/2 + + x**2*exp(-x**2/2 + I*x)/2 + I*exp(-x**2/2 - I*x)*sin(x)/2 - + I*exp(-x**2/2 + I*x)*sin(x)/2, x)/2 + Integral(-I*x**2*exp(-x**2/2 + - I*x)/2 + I*x**2*exp(-x**2/2 + I*x)/2 + exp(-x**2/2 - + I*x)*sin(x)/2 + exp(-x**2/2 + I*x)*sin(x)/2, x)/2)*exp(x**2/2 + + I*x) + (C1/2 + I*C2/2 + I*Integral(x**2*exp(-x**2/2 - I*x)/2 + + x**2*exp(-x**2/2 + I*x)/2 + I*exp(-x**2/2 - I*x)*sin(x)/2 - + I*exp(-x**2/2 + I*x)*sin(x)/2, x)/2 + Integral(-I*x**2*exp(-x**2/2 + - I*x)/2 + I*x**2*exp(-x**2/2 + I*x)/2 + exp(-x**2/2 - + I*x)*sin(x)/2 + exp(-x**2/2 + I*x)*sin(x)/2, x)/2)*exp(x**2/2 - + I*x)), + Eq(g(x), (-I*C1/2 + C2/2 + Integral(x**2*exp(-x**2/2 - I*x)/2 + + x**2*exp(-x**2/2 + I*x)/2 + I*exp(-x**2/2 - I*x)*sin(x)/2 - + I*exp(-x**2/2 + I*x)*sin(x)/2, x)/2 - + I*Integral(-I*x**2*exp(-x**2/2 - I*x)/2 + I*x**2*exp(-x**2/2 + + I*x)/2 + exp(-x**2/2 - I*x)*sin(x)/2 + exp(-x**2/2 + + I*x)*sin(x)/2, x)/2)*exp(x**2/2 - I*x) + (I*C1/2 + C2/2 + + Integral(x**2*exp(-x**2/2 - I*x)/2 + x**2*exp(-x**2/2 + I*x)/2 + + I*exp(-x**2/2 - I*x)*sin(x)/2 - I*exp(-x**2/2 + I*x)*sin(x)/2, + x)/2 + I*Integral(-I*x**2*exp(-x**2/2 - I*x)/2 + + I*x**2*exp(-x**2/2 + I*x)/2 + exp(-x**2/2 - I*x)*sin(x)/2 + + exp(-x**2/2 + I*x)*sin(x)/2, x)/2)*exp(x**2/2 + I*x)) + ] + + return eqs, sol + + +def test_neq_order1_type4_slow3(): + eqs, sol = _neq_order1_type4_slow3() + assert dsolve_system(eqs, simplify=False, doit=False) == [sol] + # XXX: dsolve gives an error in integration: + # assert dsolve(eqs) == sol + # https://github.com/sympy/sympy/issues/20155 + + +@slow +def test_neq_order1_type4_slow_check3(): + eqs, sol = _neq_order1_type4_slow3() + assert checksysodesol(eqs, sol) == (True, [0, 0]) + + +@tooslow +@XFAIL +def test_linear_3eq_order1_type4_long_dsolve_slow_xfail(): + eq, sol = _linear_3eq_order1_type4_long() + + dsolve_sol = dsolve(eq) + dsolve_sol1 = [_simpsol(sol) for sol in dsolve_sol] + + assert dsolve_sol1 == sol + + +@tooslow +def test_linear_3eq_order1_type4_long_dsolve_dotprodsimp(): + eq, sol = _linear_3eq_order1_type4_long() + + # XXX: Only works with dotprodsimp see + # test_linear_3eq_order1_type4_long_dsolve_slow_xfail which is too slow + with dotprodsimp(True): + dsolve_sol = dsolve(eq) + + dsolve_sol1 = [_simpsol(sol) for sol in dsolve_sol] + assert dsolve_sol1 == sol + + +@tooslow +def test_linear_3eq_order1_type4_long_check(): + eq, sol = _linear_3eq_order1_type4_long() + assert checksysodesol(eq, sol) == (True, [0, 0, 0]) + + +def test_dsolve_system(): + f, g = symbols("f g", cls=Function) + x = symbols("x") + eqs = [Eq(f(x).diff(x), f(x) + g(x)), Eq(g(x).diff(x), f(x) + g(x))] + funcs = [f(x), g(x)] + + sol = [[Eq(f(x), -C1 + C2*exp(2*x)), Eq(g(x), C1 + C2*exp(2*x))]] + assert dsolve_system(eqs, funcs=funcs, t=x, doit=True) == sol + + raises(ValueError, lambda: dsolve_system(1)) + raises(ValueError, lambda: dsolve_system(eqs, 1)) + raises(ValueError, lambda: dsolve_system(eqs, funcs, 1)) + raises(ValueError, lambda: dsolve_system(eqs, funcs[:1], x)) + + eq = (Eq(f(x).diff(x), 12 * f(x) - 6 * g(x)), Eq(g(x).diff(x) ** 2, 11 * f(x) + 3 * g(x))) + raises(NotImplementedError, lambda: dsolve_system(eq) == ([], [])) + + raises(NotImplementedError, lambda: dsolve_system(eq, funcs=[f(x), g(x)]) == ([], [])) + raises(NotImplementedError, lambda: dsolve_system(eq, funcs=[f(x), g(x)], t=x) == ([], [])) + raises(NotImplementedError, lambda: dsolve_system(eq, funcs=[f(x), g(x)], t=x, ics={f(0): 1, g(0): 1}) == ([], [])) + raises(NotImplementedError, lambda: dsolve_system(eq, t=x, ics={f(0): 1, g(0): 1}) == ([], [])) + raises(NotImplementedError, lambda: dsolve_system(eq, ics={f(0): 1, g(0): 1}) == ([], [])) + raises(NotImplementedError, lambda: dsolve_system(eq, funcs=[f(x), g(x)], ics={f(0): 1, g(0): 1}) == ([], [])) + +def test_dsolve(): + + f, g = symbols('f g', cls=Function) + x, y = symbols('x y') + + eqs = [f(x).diff(x) - x, f(x).diff(x) + x] + with raises(ValueError): + dsolve(eqs) + + eqs = [f(x, y).diff(x)] + with raises(ValueError): + dsolve(eqs) + + eqs = [f(x, y).diff(x)+g(x).diff(x), g(x).diff(x)] + with raises(ValueError): + dsolve(eqs) + + +@slow +def test_higher_order1_slow1(): + x, y = symbols("x y", cls=Function) + t = symbols("t") + + eq = [ + Eq(diff(x(t),t,t), (log(t)+t**2)*diff(x(t),t)+(log(t)+t**2)*3*diff(y(t),t)), + Eq(diff(y(t),t,t), (log(t)+t**2)*2*diff(x(t),t)+(log(t)+t**2)*9*diff(y(t),t)) + ] + sol, = dsolve_system(eq, simplify=False, doit=False) + # The solution is too long to write out explicitly and checkodesol is too + # slow so we test for particular values of t: + for e in eq: + res = (e.lhs - e.rhs).subs({sol[0].lhs:sol[0].rhs, sol[1].lhs:sol[1].rhs}) + res = res.subs({d: d.doit(deep=False) for d in res.atoms(Derivative)}) + assert ratsimp(res.subs(t, 1)) == 0 + + +def test_second_order_type2_slow1(): + x, y, z = symbols('x, y, z', cls=Function) + t, l = symbols('t, l') + + eqs1 = [Eq(Derivative(x(t), (t, 2)), t*(2*x(t) + y(t))), + Eq(Derivative(y(t), (t, 2)), t*(-x(t) + 2*y(t)))] + sol1 = [Eq(x(t), I*C1*airyai(t*(2 - I)**(S(1)/3)) + I*C2*airybi(t*(2 - I)**(S(1)/3)) - I*C3*airyai(t*(2 + + I)**(S(1)/3)) - I*C4*airybi(t*(2 + I)**(S(1)/3))), + Eq(y(t), C1*airyai(t*(2 - I)**(S(1)/3)) + C2*airybi(t*(2 - I)**(S(1)/3)) + C3*airyai(t*(2 + I)**(S(1)/3)) + + C4*airybi(t*(2 + I)**(S(1)/3)))] + assert dsolve(eqs1) == sol1 + assert checksysodesol(eqs1, sol1) == (True, [0, 0]) + + +@tooslow +@XFAIL +def test_nonlinear_3eq_order1_type1(): + a, b, c = symbols('a b c') + + eqs = [ + a * f(x).diff(x) - (b - c) * g(x) * h(x), + b * g(x).diff(x) - (c - a) * h(x) * f(x), + c * h(x).diff(x) - (a - b) * f(x) * g(x), + ] + + assert dsolve(eqs) # NotImplementedError + + +@XFAIL +def test_nonlinear_3eq_order1_type4(): + eqs = [ + Eq(f(x).diff(x), (2*h(x)*g(x) - 3*g(x)*h(x))), + Eq(g(x).diff(x), (4*f(x)*h(x) - 2*h(x)*f(x))), + Eq(h(x).diff(x), (3*g(x)*f(x) - 4*f(x)*g(x))), + ] + dsolve(eqs) # KeyError when matching + # sol = ? + # assert dsolve_sol == sol + # assert checksysodesol(eqs, dsolve_sol) == (True, [0, 0, 0]) + + +@tooslow +@XFAIL +def test_nonlinear_3eq_order1_type3(): + eqs = [ + Eq(f(x).diff(x), (2*f(x)**2 - 3 )), + Eq(g(x).diff(x), (4 - 2*h(x) )), + Eq(h(x).diff(x), (3*h(x) - 4*f(x)**2)), + ] + dsolve(eqs) # Not sure if this finishes... + # sol = ? + # assert dsolve_sol == sol + # assert checksysodesol(eqs, dsolve_sol) == (True, [0, 0, 0]) + + +@XFAIL +def test_nonlinear_3eq_order1_type5(): + eqs = [ + Eq(f(x).diff(x), f(x)*(2*f(x) - 3*g(x))), + Eq(g(x).diff(x), g(x)*(4*g(x) - 2*h(x))), + Eq(h(x).diff(x), h(x)*(3*h(x) - 4*f(x))), + ] + dsolve(eqs) # KeyError + # sol = ? + # assert dsolve_sol == sol + # assert checksysodesol(eqs, dsolve_sol) == (True, [0, 0, 0]) + + +def test_linear_2eq_order1(): + x, y, z = symbols('x, y, z', cls=Function) + k, l, m, n = symbols('k, l, m, n', Integer=True) + t = Symbol('t') + x0, y0 = symbols('x0, y0', cls=Function) + + eq1 = (Eq(diff(x(t),t), x(t) + y(t) + 9), Eq(diff(y(t),t), 2*x(t) + 5*y(t) + 23)) + sol1 = [Eq(x(t), C1*exp(t*(sqrt(6) + 3)) + C2*exp(t*(-sqrt(6) + 3)) - Rational(22, 3)), \ + Eq(y(t), C1*(2 + sqrt(6))*exp(t*(sqrt(6) + 3)) + C2*(-sqrt(6) + 2)*exp(t*(-sqrt(6) + 3)) - Rational(5, 3))] + assert checksysodesol(eq1, sol1) == (True, [0, 0]) + + eq2 = (Eq(diff(x(t),t), x(t) + y(t) + 81), Eq(diff(y(t),t), -2*x(t) + y(t) + 23)) + sol2 = [Eq(x(t), (C1*cos(sqrt(2)*t) + C2*sin(sqrt(2)*t))*exp(t) - Rational(58, 3)), \ + Eq(y(t), (-sqrt(2)*C1*sin(sqrt(2)*t) + sqrt(2)*C2*cos(sqrt(2)*t))*exp(t) - Rational(185, 3))] + assert checksysodesol(eq2, sol2) == (True, [0, 0]) + + eq3 = (Eq(diff(x(t),t), 5*t*x(t) + 2*y(t)), Eq(diff(y(t),t), 2*x(t) + 5*t*y(t))) + sol3 = [Eq(x(t), (C1*exp(2*t) + C2*exp(-2*t))*exp(Rational(5, 2)*t**2)), \ + Eq(y(t), (C1*exp(2*t) - C2*exp(-2*t))*exp(Rational(5, 2)*t**2))] + assert checksysodesol(eq3, sol3) == (True, [0, 0]) + + eq4 = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t)), Eq(diff(y(t),t), -t**2*x(t) + 5*t*y(t))) + sol4 = [Eq(x(t), (C1*cos((t**3)/3) + C2*sin((t**3)/3))*exp(Rational(5, 2)*t**2)), \ + Eq(y(t), (-C1*sin((t**3)/3) + C2*cos((t**3)/3))*exp(Rational(5, 2)*t**2))] + assert checksysodesol(eq4, sol4) == (True, [0, 0]) + + eq5 = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t)), Eq(diff(y(t),t), -t**2*x(t) + (5*t+9*t**2)*y(t))) + sol5 = [Eq(x(t), (C1*exp((sqrt(77)/2 + Rational(9, 2))*(t**3)/3) + \ + C2*exp((-sqrt(77)/2 + Rational(9, 2))*(t**3)/3))*exp(Rational(5, 2)*t**2)), \ + Eq(y(t), (C1*(sqrt(77)/2 + Rational(9, 2))*exp((sqrt(77)/2 + Rational(9, 2))*(t**3)/3) + \ + C2*(-sqrt(77)/2 + Rational(9, 2))*exp((-sqrt(77)/2 + Rational(9, 2))*(t**3)/3))*exp(Rational(5, 2)*t**2))] + assert checksysodesol(eq5, sol5) == (True, [0, 0]) + + eq6 = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t)), Eq(diff(y(t),t), (1-t**2)*x(t) + (5*t+9*t**2)*y(t))) + sol6 = [Eq(x(t), C1*x0(t) + C2*x0(t)*Integral(t**2*exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)**2, t)), \ + Eq(y(t), C1*y0(t) + C2*(y0(t)*Integral(t**2*exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)**2, t) + \ + exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)))] + s = dsolve(eq6) + assert s == sol6 # too complicated to test with subs and simplify + # assert checksysodesol(eq10, sol10) == (True, [0, 0]) # this one fails + + +def test_nonlinear_2eq_order1(): + x, y, z = symbols('x, y, z', cls=Function) + t = Symbol('t') + eq1 = (Eq(diff(x(t),t),x(t)*y(t)**3), Eq(diff(y(t),t),y(t)**5)) + sol1 = [ + Eq(x(t), C1*exp((-1/(4*C2 + 4*t))**(Rational(-1, 4)))), + Eq(y(t), -(-1/(4*C2 + 4*t))**Rational(1, 4)), + Eq(x(t), C1*exp(-1/(-1/(4*C2 + 4*t))**Rational(1, 4))), + Eq(y(t), (-1/(4*C2 + 4*t))**Rational(1, 4)), + Eq(x(t), C1*exp(-I/(-1/(4*C2 + 4*t))**Rational(1, 4))), + Eq(y(t), -I*(-1/(4*C2 + 4*t))**Rational(1, 4)), + Eq(x(t), C1*exp(I/(-1/(4*C2 + 4*t))**Rational(1, 4))), + Eq(y(t), I*(-1/(4*C2 + 4*t))**Rational(1, 4))] + assert dsolve(eq1) == sol1 + assert checksysodesol(eq1, sol1) == (True, [0, 0]) + + eq2 = (Eq(diff(x(t),t), exp(3*x(t))*y(t)**3),Eq(diff(y(t),t), y(t)**5)) + sol2 = [ + Eq(x(t), -log(C1 - 3/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), + Eq(y(t), -(-1/(4*C2 + 4*t))**Rational(1, 4)), + Eq(x(t), -log(C1 + 3/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), + Eq(y(t), (-1/(4*C2 + 4*t))**Rational(1, 4)), + Eq(x(t), -log(C1 + 3*I/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), + Eq(y(t), -I*(-1/(4*C2 + 4*t))**Rational(1, 4)), + Eq(x(t), -log(C1 - 3*I/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), + Eq(y(t), I*(-1/(4*C2 + 4*t))**Rational(1, 4))] + assert dsolve(eq2) == sol2 + assert checksysodesol(eq2, sol2) == (True, [0, 0]) + + eq3 = (Eq(diff(x(t),t), y(t)*x(t)), Eq(diff(y(t),t), x(t)**3)) + tt = Rational(2, 3) + sol3 = [ + Eq(x(t), 6**tt/(6*(-sinh(sqrt(C1)*(C2 + t)/2)/sqrt(C1))**tt)), + Eq(y(t), sqrt(C1 + C1/sinh(sqrt(C1)*(C2 + t)/2)**2)/3)] + assert dsolve(eq3) == sol3 + # FIXME: assert checksysodesol(eq3, sol3) == (True, [0, 0]) + + eq4 = (Eq(diff(x(t),t),x(t)*y(t)*sin(t)**2), Eq(diff(y(t),t),y(t)**2*sin(t)**2)) + sol4 = {Eq(x(t), -2*exp(C1)/(C2*exp(C1) + t - sin(2*t)/2)), Eq(y(t), -2/(C1 + t - sin(2*t)/2))} + assert dsolve(eq4) == sol4 + # FIXME: assert checksysodesol(eq4, sol4) == (True, [0, 0]) + + eq5 = (Eq(x(t),t*diff(x(t),t)+diff(x(t),t)*diff(y(t),t)), Eq(y(t),t*diff(y(t),t)+diff(y(t),t)**2)) + sol5 = {Eq(x(t), C1*C2 + C1*t), Eq(y(t), C2**2 + C2*t)} + assert dsolve(eq5) == sol5 + assert checksysodesol(eq5, sol5) == (True, [0, 0]) + + eq6 = (Eq(diff(x(t),t),x(t)**2*y(t)**3), Eq(diff(y(t),t),y(t)**5)) + sol6 = [ + Eq(x(t), 1/(C1 - 1/(-1/(4*C2 + 4*t))**Rational(1, 4))), + Eq(y(t), -(-1/(4*C2 + 4*t))**Rational(1, 4)), + Eq(x(t), 1/(C1 + (-1/(4*C2 + 4*t))**(Rational(-1, 4)))), + Eq(y(t), (-1/(4*C2 + 4*t))**Rational(1, 4)), + Eq(x(t), 1/(C1 + I/(-1/(4*C2 + 4*t))**Rational(1, 4))), + Eq(y(t), -I*(-1/(4*C2 + 4*t))**Rational(1, 4)), + Eq(x(t), 1/(C1 - I/(-1/(4*C2 + 4*t))**Rational(1, 4))), + Eq(y(t), I*(-1/(4*C2 + 4*t))**Rational(1, 4))] + assert dsolve(eq6) == sol6 + assert checksysodesol(eq6, sol6) == (True, [0, 0]) + + +@slow +def test_nonlinear_3eq_order1(): + x, y, z = symbols('x, y, z', cls=Function) + t, u = symbols('t u') + eq1 = (4*diff(x(t),t) + 2*y(t)*z(t), 3*diff(y(t),t) - z(t)*x(t), 5*diff(z(t),t) - x(t)*y(t)) + sol1 = [Eq(4*Integral(1/(sqrt(-4*u**2 - 3*C1 + C2)*sqrt(-4*u**2 + 5*C1 - C2)), (u, x(t))), + C3 - sqrt(15)*t/15), Eq(3*Integral(1/(sqrt(-6*u**2 - C1 + 5*C2)*sqrt(3*u**2 + C1 - 4*C2)), + (u, y(t))), C3 + sqrt(5)*t/10), Eq(5*Integral(1/(sqrt(-10*u**2 - 3*C1 + C2)* + sqrt(5*u**2 + 4*C1 - C2)), (u, z(t))), C3 + sqrt(3)*t/6)] + assert [i.dummy_eq(j) for i, j in zip(dsolve(eq1), sol1)] + # FIXME: assert checksysodesol(eq1, sol1) == (True, [0, 0, 0]) + + eq2 = (4*diff(x(t),t) + 2*y(t)*z(t)*sin(t), 3*diff(y(t),t) - z(t)*x(t)*sin(t), 5*diff(z(t),t) - x(t)*y(t)*sin(t)) + sol2 = [Eq(3*Integral(1/(sqrt(-6*u**2 - C1 + 5*C2)*sqrt(3*u**2 + C1 - 4*C2)), (u, x(t))), C3 + + sqrt(5)*cos(t)/10), Eq(4*Integral(1/(sqrt(-4*u**2 - 3*C1 + C2)*sqrt(-4*u**2 + 5*C1 - C2)), + (u, y(t))), C3 - sqrt(15)*cos(t)/15), Eq(5*Integral(1/(sqrt(-10*u**2 - 3*C1 + C2)* + sqrt(5*u**2 + 4*C1 - C2)), (u, z(t))), C3 + sqrt(3)*cos(t)/6)] + assert [i.dummy_eq(j) for i, j in zip(dsolve(eq2), sol2)] + # FIXME: assert checksysodesol(eq2, sol2) == (True, [0, 0, 0]) + + +def test_C1_function_9239(): + t = Symbol('t') + C1 = Function('C1') + C2 = Function('C2') + C3 = Symbol('C3') + C4 = Symbol('C4') + eq = (Eq(diff(C1(t), t), 9*C2(t)), Eq(diff(C2(t), t), 12*C1(t))) + sol = [Eq(C1(t), 9*C3*exp(6*sqrt(3)*t) + 9*C4*exp(-6*sqrt(3)*t)), + Eq(C2(t), 6*sqrt(3)*C3*exp(6*sqrt(3)*t) - 6*sqrt(3)*C4*exp(-6*sqrt(3)*t))] + assert checksysodesol(eq, sol) == (True, [0, 0]) + + +def test_dsolve_linsystem_symbol(): + eps = Symbol('epsilon', positive=True) + eq1 = (Eq(diff(f(x), x), -eps*g(x)), Eq(diff(g(x), x), eps*f(x))) + sol1 = [Eq(f(x), -C1*eps*cos(eps*x) - C2*eps*sin(eps*x)), + Eq(g(x), -C1*eps*sin(eps*x) + C2*eps*cos(eps*x))] + assert checksysodesol(eq1, sol1) == (True, [0, 0]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f3dc43618240d103a93b85247c1dfd30af74dcfb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_constantsimp.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_constantsimp.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2e9ded86e14d2146265c22bad8089653ef42ac80 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_constantsimp.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_decompogen.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_decompogen.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6afc624f11c56adc1e67697a6f53133c14a6e09 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_decompogen.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_inequalities.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_inequalities.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..665c96d260078dcb13362bb830790d7970a19550 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_inequalities.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_numeric.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_numeric.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9765a57c75965b682a4db7788a37e5dd7114bbc5 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_numeric.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_pde.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_pde.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..049e333f2b87a223a11dcf14da3431a019a9e14d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_pde.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_polysys.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_polysys.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e706d91986802417e779dc00840048ce0f4711ad Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_polysys.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_recurr.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_recurr.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..186f03797f9950695bec3f5ef08e9af09b5d68e9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_recurr.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_simplex.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_simplex.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..62ddd6fdf61635e0bb5afbd381400a76a57b709f Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/__pycache__/test_simplex.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_constantsimp.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_constantsimp.py new file mode 100644 index 0000000000000000000000000000000000000000..efb966a4c8c2f93558d05e7c330f06530e69180c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_constantsimp.py @@ -0,0 +1,179 @@ +""" +If the arbitrary constant class from issue 4435 is ever implemented, this +should serve as a set of test cases. +""" + +from sympy.core.function import Function +from sympy.core.numbers import I +from sympy.core.power import Pow +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.hyperbolic import (cosh, sinh) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (acos, cos, sin) +from sympy.integrals.integrals import Integral +from sympy.solvers.ode.ode import constantsimp, constant_renumber +from sympy.testing.pytest import XFAIL + + +x = Symbol('x') +y = Symbol('y') +z = Symbol('z') +u2 = Symbol('u2') +_a = Symbol('_a') +C1 = Symbol('C1') +C2 = Symbol('C2') +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, [C1])) == C1*y + assert constant_renumber(constantsimp(C1*y, [C1])) == C1*y + assert constant_renumber(constantsimp(x*C1, [C1])) == x*C1 + assert constant_renumber(constantsimp(C1*x, [C1])) == x*C1 + assert constant_renumber(constantsimp(2*C1, [C1])) == C1 + assert constant_renumber(constantsimp(C1*2, [C1])) == C1 + assert constant_renumber(constantsimp(y*C1*x, [C1, y])) == C1*x + assert constant_renumber(constantsimp(x*y*C1, [C1, y])) == x*C1 + assert constant_renumber(constantsimp(y*x*C1, [C1, y])) == x*C1 + assert constant_renumber(constantsimp(C1*x*y, [C1, y])) == C1*x + assert constant_renumber(constantsimp(x*C1*y, [C1, y])) == x*C1 + assert constant_renumber(constantsimp(C1*y*(y + 1), [C1])) == C1*y*(y+1) + assert constant_renumber(constantsimp(y*C1*(y + 1), [C1])) == C1*y*(y+1) + assert constant_renumber(constantsimp(x*(y*C1), [C1])) == x*y*C1 + assert constant_renumber(constantsimp(x*(C1*y), [C1])) == x*y*C1 + assert constant_renumber(constantsimp(C1*(x*y), [C1, y])) == C1*x + assert constant_renumber(constantsimp((x*y)*C1, [C1, y])) == x*C1 + assert constant_renumber(constantsimp((y*x)*C1, [C1, y])) == x*C1 + assert constant_renumber(constantsimp(y*(y + 1)*C1, [C1, y])) == C1 + assert constant_renumber(constantsimp((C1*x)*y, [C1, y])) == C1*x + assert constant_renumber(constantsimp(y*(x*C1), [C1, y])) == x*C1 + assert constant_renumber(constantsimp((x*C1)*y, [C1, y])) == x*C1 + assert constant_renumber(constantsimp(C1*x*y*x*y*2, [C1, y])) == C1*x**2 + assert constant_renumber(constantsimp(C1*x*y*z, [C1, y, z])) == C1*x + assert constant_renumber(constantsimp(C1*x*y**2*sin(z), [C1, y, z])) == C1*x + assert constant_renumber(constantsimp(C1*C1, [C1])) == C1 + assert constant_renumber(constantsimp(C1*C2, [C1, C2])) == C1 + assert constant_renumber(constantsimp(C2*C2, [C1, C2])) == C1 + assert constant_renumber(constantsimp(C1*C1*C2, [C1, C2])) == C1 + assert constant_renumber(constantsimp(C1*x*2**x, [C1])) == C1*x*2**x + +def test_constant_add(): + assert constant_renumber(constantsimp(C1 + C1, [C1])) == C1 + assert constant_renumber(constantsimp(C1 + 2, [C1])) == C1 + assert constant_renumber(constantsimp(2 + C1, [C1])) == C1 + assert constant_renumber(constantsimp(C1 + y, [C1, y])) == C1 + assert constant_renumber(constantsimp(C1 + x, [C1])) == C1 + x + assert constant_renumber(constantsimp(C1 + C1, [C1])) == C1 + assert constant_renumber(constantsimp(C1 + C2, [C1, C2])) == C1 + assert constant_renumber(constantsimp(C2 + C1, [C1, C2])) == C1 + assert constant_renumber(constantsimp(C1 + C2 + C1, [C1, C2])) == C1 + + +def test_constant_power_as_base(): + assert constant_renumber(constantsimp(C1**C1, [C1])) == C1 + assert constant_renumber(constantsimp(Pow(C1, C1), [C1])) == C1 + assert constant_renumber(constantsimp(C1**C1, [C1])) == C1 + assert constant_renumber(constantsimp(C1**C2, [C1, C2])) == C1 + assert constant_renumber(constantsimp(C2**C1, [C1, C2])) == C1 + assert constant_renumber(constantsimp(C2**C2, [C1, C2])) == C1 + assert constant_renumber(constantsimp(C1**y, [C1, y])) == C1 + assert constant_renumber(constantsimp(C1**x, [C1])) == C1**x + assert constant_renumber(constantsimp(C1**2, [C1])) == C1 + assert constant_renumber( + constantsimp(C1**(x*y), [C1])) == C1**(x*y) + + +def test_constant_power_as_exp(): + assert constant_renumber(constantsimp(x**C1, [C1])) == x**C1 + assert constant_renumber(constantsimp(y**C1, [C1, y])) == C1 + assert constant_renumber(constantsimp(x**y**C1, [C1, y])) == x**C1 + assert constant_renumber( + constantsimp((x**y)**C1, [C1])) == (x**y)**C1 + assert constant_renumber( + constantsimp(x**(y**C1), [C1, y])) == x**C1 + assert constant_renumber(constantsimp(x**C1**y, [C1, y])) == x**C1 + assert constant_renumber( + constantsimp(x**(C1**y), [C1, y])) == x**C1 + assert constant_renumber( + constantsimp((x**C1)**y, [C1])) == (x**C1)**y + assert constant_renumber(constantsimp(2**C1, [C1])) == C1 + assert constant_renumber(constantsimp(S(2)**C1, [C1])) == C1 + assert constant_renumber(constantsimp(exp(C1), [C1])) == C1 + assert constant_renumber( + constantsimp(exp(C1 + x), [C1])) == C1*exp(x) + assert constant_renumber(constantsimp(Pow(2, C1), [C1])) == C1 + + +def test_constant_function(): + assert constant_renumber(constantsimp(sin(C1), [C1])) == C1 + assert constant_renumber(constantsimp(f(C1), [C1])) == C1 + assert constant_renumber(constantsimp(f(C1, C1), [C1])) == C1 + assert constant_renumber(constantsimp(f(C1, C2), [C1, C2])) == C1 + assert constant_renumber(constantsimp(f(C2, C1), [C1, C2])) == C1 + assert constant_renumber(constantsimp(f(C2, C2), [C1, C2])) == C1 + assert constant_renumber( + constantsimp(f(C1, x), [C1])) == f(C1, x) + assert constant_renumber(constantsimp(f(C1, y), [C1, y])) == C1 + assert constant_renumber(constantsimp(f(y, C1), [C1, y])) == C1 + assert constant_renumber(constantsimp(f(C1, y, C2), [C1, C2, y])) == C1 + + +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), [C1])) == f(C1, C1, x) + + +def test_constant_multiple(): + assert constant_renumber(constantsimp(C1*2 + 2, [C1])) == C1 + assert constant_renumber(constantsimp(x*2/C1, [C1])) == C1*x + assert constant_renumber(constantsimp(C1**2*2 + 2, [C1])) == C1 + assert constant_renumber( + constantsimp(sin(2*C1) + x + sqrt(2), [C1])) == C1 + x + assert constant_renumber(constantsimp(2*C1 + C2, [C1, C2])) == C1 + +def test_constant_repeated(): + assert C1 + C1*x == constant_renumber( C1 + C1*x) + +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), [C1, C2, C3])) == \ + constant_renumber(C1*exp(x) + C2*exp(2*x)) + assert constant_renumber( + constantsimp(Eq(f(x), I*C1*sinh(x/3) + C2*cosh(x/3)), [C1, C2]) + ) == constant_renumber(Eq(f(x), C1*sinh(x/3) + C2*cosh(x/3))) + assert constant_renumber(constantsimp(Eq(f(x), acos((-C1)/cos(x))), [C1])) == \ + Eq(f(x), acos(C1/cos(x))) + assert constant_renumber( + constantsimp(Eq(log(f(x)/C1) + 2*exp(x/f(x)), 0), [C1]) + ) == 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), [C1])) == \ + Eq(log(C1*sqrt(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) - + cos(f(x)/x)*exp(-f(x)/x)/2, 0), [C1])) == \ + Eq(-exp(-f(x)/x)*sin(f(x)/x)/2 + log(C1*x) - cos(f(x)/x)* + exp(-f(x)/x)/2, 0) + assert constant_renumber(constantsimp(Eq(-Integral(-1/(sqrt(1 - u2**2)*u2), + (u2, _a, x/f(x))) + log(f(x)/C1), 0), [C1])) == \ + Eq(-Integral(-1/(u2*sqrt(1 - u2**2)), (u2, _a, x/f(x))) + + log(C1*f(x)), 0) + assert [constantsimp(i, [C1]) 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)))] + + +@XFAIL +def test_nonlocal_simplification(): + assert constantsimp(C1 + C2+x*C2, [C1, C2]) == C1 + C2*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), [C1]) == Eq(x*f(x), C1) + assert constantsimp(Eq(C1, 3 * f(x)*x), [C1]) == Eq(f(x)*x, C1) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_decompogen.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_decompogen.py new file mode 100644 index 0000000000000000000000000000000000000000..1ba03f4b42558231b626b6ed169f8b0a81a72bf9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_decompogen.py @@ -0,0 +1,59 @@ +from sympy.solvers.decompogen import decompogen, compogen +from sympy.core.symbol import symbols +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt, Max +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.testing.pytest import XFAIL, raises + +x, y = symbols('x y') + + +def test_decompogen(): + assert decompogen(sin(cos(x)), x) == [sin(x), cos(x)] + assert decompogen(sin(x)**2 + sin(x) + 1, x) == [x**2 + x + 1, sin(x)] + assert decompogen(sqrt(6*x**2 - 5), x) == [sqrt(x), 6*x**2 - 5] + assert decompogen(sin(sqrt(cos(x**2 + 1))), x) == [sin(x), sqrt(x), cos(x), x**2 + 1] + assert decompogen(Abs(cos(x)**2 + 3*cos(x) - 4), x) == [Abs(x), x**2 + 3*x - 4, cos(x)] + assert decompogen(sin(x)**2 + sin(x) - sqrt(3)/2, x) == [x**2 + x - sqrt(3)/2, sin(x)] + assert decompogen(Abs(cos(y)**2 + 3*cos(x) - 4), x) == [Abs(x), 3*x + cos(y)**2 - 4, cos(x)] + assert decompogen(x, y) == [x] + assert decompogen(1, x) == [1] + assert decompogen(Max(3, x), x) == [Max(3, x)] + raises(TypeError, lambda: decompogen(x < 5, x)) + u = 2*x + 3 + assert decompogen(Max(sqrt(u),(u)**2), x) == [Max(sqrt(x), x**2), u] + assert decompogen(Max(u, u**2, y), x) == [Max(x, x**2, y), u] + assert decompogen(Max(sin(x), u), x) == [Max(2*x + 3, sin(x))] + + +def test_decompogen_poly(): + assert decompogen(x**4 + 2*x**2 + 1, x) == [x**2 + 2*x + 1, x**2] + assert decompogen(x**4 + 2*x**3 - x - 1, x) == [x**2 - x - 1, x**2 + x] + + +@XFAIL +def test_decompogen_fails(): + A = lambda x: x**2 + 2*x + 3 + B = lambda x: 4*x**2 + 5*x + 6 + assert decompogen(A(x*exp(x)), x) == [x**2 + 2*x + 3, x*exp(x)] + assert decompogen(A(B(x)), x) == [x**2 + 2*x + 3, 4*x**2 + 5*x + 6] + assert decompogen(A(1/x + 1/x**2), x) == [x**2 + 2*x + 3, 1/x + 1/x**2] + assert decompogen(A(1/x + 2/(x + 1)), x) == [x**2 + 2*x + 3, 1/x + 2/(x + 1)] + + +def test_compogen(): + assert compogen([sin(x), cos(x)], x) == sin(cos(x)) + assert compogen([x**2 + x + 1, sin(x)], x) == sin(x)**2 + sin(x) + 1 + assert compogen([sqrt(x), 6*x**2 - 5], x) == sqrt(6*x**2 - 5) + assert compogen([sin(x), sqrt(x), cos(x), x**2 + 1], x) == sin(sqrt( + cos(x**2 + 1))) + assert compogen([Abs(x), x**2 + 3*x - 4, cos(x)], x) == Abs(cos(x)**2 + + 3*cos(x) - 4) + assert compogen([x**2 + x - sqrt(3)/2, sin(x)], x) == (sin(x)**2 + sin(x) - + sqrt(3)/2) + assert compogen([Abs(x), 3*x + cos(y)**2 - 4, cos(x)], x) == \ + Abs(3*cos(x) + cos(y)**2 - 4) + assert compogen([x**2 + 2*x + 1, x**2], x) == x**4 + 2*x**2 + 1 + # the result is in unsimplified form + assert compogen([x**2 - x - 1, x**2 + x], x) == -x**2 - x + (x**2 + x)**2 - 1 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_inequalities.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_inequalities.py new file mode 100644 index 0000000000000000000000000000000000000000..6ce6f4520b52d8714102c95457c90d44543c685c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_inequalities.py @@ -0,0 +1,500 @@ +"""Tests for tools for solving inequalities and systems of inequalities. """ + +from sympy.concrete.summations import Sum +from sympy.core.function import Function +from sympy.core.numbers import I, Rational, oo, pi +from sympy.core.relational import Eq, Ge, Gt, Le, Lt, Ne +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol) +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.exponential import exp, log +from sympy.functions.elementary.miscellaneous import root, sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import cos, sin, tan +from sympy.integrals.integrals import Integral +from sympy.logic.boolalg import And, Or +from sympy.polys.polytools import Poly, PurePoly +from sympy.sets.sets import FiniteSet, Interval, Union +from sympy.solvers.inequalities import (reduce_inequalities, + solve_poly_inequality as psolve, + reduce_rational_inequalities, + solve_univariate_inequality as isolve, + reduce_abs_inequality, + _solve_inequality) +from sympy.polys.rootoftools import rootof +from sympy.solvers.solvers import solve +from sympy.solvers.solveset import solveset +from sympy.core.mod import Mod +from sympy.abc import x, y + +from sympy.testing.pytest import raises, XFAIL + + +inf = oo.evalf() + + +def test_solve_poly_inequality(): + assert psolve(Poly(0, x), '==') == [S.Reals] + assert psolve(Poly(1, x), '==') == [S.EmptySet] + assert psolve(PurePoly(x + 1, x), ">") == [Interval(-1, oo, True, False)] + + +def test_reduce_poly_inequalities_real_interval(): + 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) == \ + S.Reals if x.is_real else Interval(-oo, oo) + assert reduce_rational_inequalities( + [[Gt(x**2, 0)]], x, relational=False) == \ + FiniteSet(0).complement(S.Reals) + assert reduce_rational_inequalities( + [[Ne(x**2, 0)]], x, relational=False) == \ + FiniteSet(0).complement(S.Reals) + + 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(S.Reals) + assert reduce_rational_inequalities( + [[Ne(x**2, 1)]], x, relational=False) == \ + FiniteSet(-1, 1).complement(S.Reals) + 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.Reals) + + 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_rational_inequalities([[Lt(x**2, -1.)]], x) is S.false + + +def test_reduce_poly_inequalities_complex_relational(): + 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) == False + assert reduce_rational_inequalities( + [[Ge(x**2, 0)]], x, relational=True) == And(Lt(-oo, x), Lt(x, oo)) + assert reduce_rational_inequalities( + [[Gt(x**2, 0)]], x, relational=True) == \ + And(Gt(x, -oo), Lt(x, oo), Ne(x, 0)) + assert reduce_rational_inequalities( + [[Ne(x**2, 0)]], x, relational=True) == \ + And(Gt(x, -oo), Lt(x, oo), Ne(x, 0)) + + for one in (S.One, S(1.0)): + inf = one*oo + assert reduce_rational_inequalities( + [[Eq(x**2, one)]], x, relational=True) == \ + Or(Eq(x, -one), Eq(x, one)) + assert reduce_rational_inequalities( + [[Le(x**2, one)]], x, relational=True) == \ + And(And(Le(-one, x), Le(x, one))) + assert reduce_rational_inequalities( + [[Lt(x**2, one)]], x, relational=True) == \ + And(And(Lt(-one, x), Lt(x, one))) + assert reduce_rational_inequalities( + [[Ge(x**2, one)]], x, relational=True) == \ + And(Or(And(Le(one, x), Lt(x, inf)), And(Le(x, -one), Lt(-inf, x)))) + assert reduce_rational_inequalities( + [[Gt(x**2, one)]], x, relational=True) == \ + And(Or(And(Lt(-inf, x), Lt(x, -one)), And(Lt(one, x), Lt(x, inf)))) + assert reduce_rational_inequalities( + [[Ne(x**2, one)]], x, relational=True) == \ + Or(And(Lt(-inf, x), Lt(x, -one)), + And(Lt(-one, x), Lt(x, one)), + And(Lt(one, x), Lt(x, inf))) + + +def test_reduce_rational_inequalities_real_relational(): + assert reduce_rational_inequalities([], x) == False + assert reduce_rational_inequalities( + [[(x**2 + 3*x + 2)/(x**2 - 16) >= 0]], x, relational=False) == \ + Union(Interval.open(-oo, -4), Interval(-2, -1), Interval.open(4, oo)) + + assert reduce_rational_inequalities( + [[((-2*x - 10)*(3 - x))/((x**2 + 5)*(x - 2)**2) < 0]], x, + relational=False) == \ + Union(Interval.open(-5, 2), Interval.open(2, 3)) + + assert reduce_rational_inequalities([[(x + 1)/(x - 5) <= 0]], x, + relational=False) == \ + Interval.Ropen(-1, 5) + + assert reduce_rational_inequalities([[(x**2 + 4*x + 3)/(x - 1) > 0]], x, + relational=False) == \ + Union(Interval.open(-3, -1), Interval.open(1, oo)) + + assert reduce_rational_inequalities([[(x**2 - 16)/(x - 1)**2 < 0]], x, + relational=False) == \ + Union(Interval.open(-4, 1), Interval.open(1, 4)) + + assert reduce_rational_inequalities([[(3*x + 1)/(x + 4) >= 1]], x, + relational=False) == \ + Union(Interval.open(-oo, -4), Interval.Ropen(Rational(3, 2), oo)) + + assert reduce_rational_inequalities([[(x - 8)/x <= 3 - x]], x, + relational=False) == \ + Union(Interval.Lopen(-oo, -2), Interval.Lopen(0, 4)) + + # issue sympy/sympy#10237 + assert reduce_rational_inequalities( + [[x < oo, x >= 0, -oo < x]], x, relational=False) == Interval(0, oo) + + +def test_reduce_abs_inequalities(): + e = abs(x - 5) < 3 + ans = And(Lt(2, x), Lt(x, 8)) + assert reduce_inequalities(e) == ans + assert reduce_inequalities(e, x) == ans + assert reduce_inequalities(abs(x - 5)) == Eq(x, 5) + assert reduce_inequalities( + abs(2*x + 3) >= 8) == Or(And(Le(Rational(5, 2), x), Lt(x, oo)), + And(Le(x, Rational(-11, 2)), Lt(-oo, x))) + assert reduce_inequalities(abs(x - 4) + abs( + 3*x - 5) < 7) == And(Lt(S.Half, x), Lt(x, 4)) + assert reduce_inequalities(abs(x - 4) + abs(3*abs(x) - 5) < 7) == \ + Or(And(S(-2) < x, x < -1), And(S.Half < x, x < 4)) + + nr = Symbol('nr', extended_real=False) + raises(TypeError, lambda: reduce_inequalities(abs(nr - 5) < 3)) + assert reduce_inequalities(x < 3, symbols=[x, nr]) == And(-oo < x, x < 3) + + +def test_reduce_inequalities_general(): + assert reduce_inequalities(Ge(sqrt(2)*x, 1)) == And(sqrt(2)/2 <= x, x < oo) + assert reduce_inequalities(x + 1 > 0) == And(S.NegativeOne < x, x < oo) + + +def test_reduce_inequalities_boolean(): + assert reduce_inequalities( + [Eq(x**2, 0), True]) == Eq(x, 0) + assert reduce_inequalities([Eq(x**2, 0), False]) == False + assert reduce_inequalities(x**2 >= 0) is S.true # issue 10196 + + +def test_reduce_inequalities_multivariate(): + assert reduce_inequalities([Ge(x**2, 1), Ge(y**2, 1)]) == And( + Or(And(Le(S.One, x), Lt(x, oo)), And(Le(x, -1), Lt(-oo, x))), + Or(And(Le(S.One, y), Lt(y, oo)), And(Le(y, -1), Lt(-oo, y)))) + + +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))) + + +def test__solve_inequalities(): + assert reduce_inequalities(x + y < 1, symbols=[x]) == (x < 1 - y) + assert reduce_inequalities(x + y >= 1, symbols=[x]) == (x < oo) & (x >= -y + 1) + assert reduce_inequalities(Eq(0, x - y), symbols=[x]) == Eq(x, y) + assert reduce_inequalities(Ne(0, x - y), symbols=[x]) == Ne(x, y) + + +def test_issue_6343(): + eq = -3*x**2/2 - x*Rational(45, 4) + Rational(33, 2) > 0 + assert reduce_inequalities(eq) == \ + And(x < Rational(-15, 4) + sqrt(401)/4, -sqrt(401)/4 - Rational(15, 4) < x) + + +def test_issue_8235(): + assert reduce_inequalities(x**2 - 1 < 0) == \ + And(S.NegativeOne < x, x < 1) + assert reduce_inequalities(x**2 - 1 <= 0) == \ + And(S.NegativeOne <= x, x <= 1) + assert reduce_inequalities(x**2 - 1 > 0) == \ + Or(And(-oo < x, x < -1), And(x < oo, S.One < x)) + assert reduce_inequalities(x**2 - 1 >= 0) == \ + Or(And(-oo < x, x <= -1), And(S.One <= x, x < oo)) + + eq = x**8 + x - 9 # we want CRootOf solns here + sol = solve(eq >= 0) + tru = Or(And(rootof(eq, 1) <= x, x < oo), And(-oo < x, x <= rootof(eq, 0))) + assert sol == tru + + # recast vanilla as real + assert solve(sqrt((-x + 1)**2) < 1) == And(S.Zero < x, x < 2) + + +def test_issue_5526(): + assert reduce_inequalities(0 <= + x + Integral(y**2, (y, 1, 3)) - 1, [x]) == \ + (x >= -Integral(y**2, (y, 1, 3)) + 1) + f = Function('f') + e = Sum(f(x), (x, 1, 3)) + assert reduce_inequalities(0 <= x + e + y**2, [x]) == \ + (x >= -y**2 - Sum(f(x), (x, 1, 3))) + + +def test_solve_univariate_inequality(): + assert isolve(x**2 >= 4, x, relational=False) == Union(Interval(-oo, -2), + Interval(2, oo)) + assert isolve(x**2 >= 4, x) == Or(And(Le(2, x), Lt(x, oo)), And(Le(x, -2), + Lt(-oo, x))) + assert isolve((x - 1)*(x - 2)*(x - 3) >= 0, x, relational=False) == \ + Union(Interval(1, 2), Interval(3, oo)) + assert isolve((x - 1)*(x - 2)*(x - 3) >= 0, x) == \ + Or(And(Le(1, x), Le(x, 2)), And(Le(3, x), Lt(x, oo))) + assert isolve((x - 1)*(x - 2)*(x - 4) < 0, x, domain = FiniteSet(0, 3)) == \ + Or(Eq(x, 0), Eq(x, 3)) + # issue 2785: + assert isolve(x**3 - 2*x - 1 > 0, x, relational=False) == \ + Union(Interval(-1, -sqrt(5)/2 + S.Half, True, True), + Interval(S.Half + sqrt(5)/2, oo, True, True)) + # issue 2794: + assert isolve(x**3 - x**2 + x - 1 > 0, x, relational=False) == \ + Interval(1, oo, True) + #issue 13105 + assert isolve((x + I)*(x + 2*I) < 0, x) == Eq(x, 0) + assert isolve(((x - 1)*(x - 2) + I)*((x - 1)*(x - 2) + 2*I) < 0, x) == Or(Eq(x, 1), Eq(x, 2)) + assert isolve((((x - 1)*(x - 2) + I)*((x - 1)*(x - 2) + 2*I))/(x - 2) > 0, x) == Eq(x, 1) + raises (ValueError, lambda: isolve((x**2 - 3*x*I + 2)/x < 0, x)) + + # numerical testing in valid() is needed + assert isolve(x**7 - x - 2 > 0, x) == \ + And(rootof(x**7 - x - 2, 0) < x, x < oo) + + # handle numerator and denominator; although these would be handled as + # rational inequalities, these test confirm that the right thing is done + # when the domain is EX (e.g. when 2 is replaced with sqrt(2)) + assert isolve(1/(x - 2) > 0, x) == And(S(2) < x, x < oo) + den = ((x - 1)*(x - 2)).expand() + assert isolve((x - 1)/den <= 0, x) == \ + (x > -oo) & (x < 2) & Ne(x, 1) + + n = Dummy('n') + raises(NotImplementedError, lambda: isolve(Abs(x) <= n, x, relational=False)) + c1 = Dummy("c1", positive=True) + raises(NotImplementedError, lambda: isolve(n/c1 < 0, c1)) + n = Dummy('n', negative=True) + assert isolve(n/c1 > -2, c1) == (-n/2 < c1) + assert isolve(n/c1 < 0, c1) == True + assert isolve(n/c1 > 0, c1) == False + + zero = cos(1)**2 + sin(1)**2 - 1 + raises(NotImplementedError, lambda: isolve(x**2 < zero, x)) + raises(NotImplementedError, lambda: isolve( + x**2 < zero*I, x)) + raises(NotImplementedError, lambda: isolve(1/(x - y) < 2, x)) + raises(NotImplementedError, lambda: isolve(1/(x - y) < 0, x)) + raises(TypeError, lambda: isolve(x - I < 0, x)) + + zero = x**2 + x - x*(x + 1) + assert isolve(zero < 0, x, relational=False) is S.EmptySet + assert isolve(zero <= 0, x, relational=False) is S.Reals + + # make sure iter_solutions gets a default value + raises(NotImplementedError, lambda: isolve( + Eq(cos(x)**2 + sin(x)**2, 1), x)) + + +def test_trig_inequalities(): + # all the inequalities are solved in a periodic interval. + assert isolve(sin(x) < S.Half, x, relational=False) == \ + Union(Interval(0, pi/6, False, True), Interval.open(pi*Rational(5, 6), 2*pi)) + assert isolve(sin(x) > S.Half, x, relational=False) == \ + Interval(pi/6, pi*Rational(5, 6), True, True) + assert isolve(cos(x) < S.Zero, x, relational=False) == \ + Interval(pi/2, pi*Rational(3, 2), True, True) + assert isolve(cos(x) >= S.Zero, x, relational=False) == \ + Union(Interval(0, pi/2), Interval.Ropen(pi*Rational(3, 2), 2*pi)) + + assert isolve(tan(x) < S.One, x, relational=False) == \ + Union(Interval.Ropen(0, pi/4), Interval.open(pi/2, pi)) + + assert isolve(sin(x) <= S.Zero, x, relational=False) == \ + Union(FiniteSet(S.Zero), Interval.Ropen(pi, 2*pi)) + + assert isolve(sin(x) <= S.One, x, relational=False) == S.Reals + assert isolve(cos(x) < S(-2), x, relational=False) == S.EmptySet + assert isolve(sin(x) >= S.NegativeOne, x, relational=False) == S.Reals + assert isolve(cos(x) > S.One, x, relational=False) == S.EmptySet + + +def test_issue_9954(): + assert isolve(x**2 >= 0, x, relational=False) == S.Reals + assert isolve(x**2 >= 0, x, relational=True) == S.Reals.as_relational(x) + assert isolve(x**2 < 0, x, relational=False) == S.EmptySet + assert isolve(x**2 < 0, x, relational=True) == S.EmptySet.as_relational(x) + + +@XFAIL +def test_slow_general_univariate(): + r = rootof(x**5 - x**2 + 1, 0) + assert solve(sqrt(x) + 1/root(x, 3) > 1) == \ + Or(And(0 < x, x < r**6), And(r**6 < x, x < oo)) + + +def test_issue_8545(): + eq = 1 - x - abs(1 - x) + ans = And(Lt(1, x), Lt(x, oo)) + assert reduce_abs_inequality(eq, '<', x) == ans + eq = 1 - x - sqrt((1 - x)**2) + assert reduce_inequalities(eq < 0) == ans + + +def test_issue_8974(): + assert isolve(-oo < x, x) == And(-oo < x, x < oo) + assert isolve(oo > x, x) == And(-oo < x, x < oo) + + +def test_issue_10198(): + assert reduce_inequalities( + -1 + 1/abs(1/x - 1) < 0) == (x > -oo) & (x < S(1)/2) & Ne(x, 0) + + assert reduce_inequalities(abs(1/sqrt(x)) - 1, x) == Eq(x, 1) + assert reduce_abs_inequality(-3 + 1/abs(1 - 1/x), '<', x) == \ + Or(And(-oo < x, x < 0), + And(S.Zero < x, x < Rational(3, 4)), And(Rational(3, 2) < x, x < oo)) + raises(ValueError,lambda: reduce_abs_inequality(-3 + 1/abs( + 1 - 1/sqrt(x)), '<', x)) + + +def test_issue_10047(): + # issue 10047: this must remain an inequality, not True, since if x + # is not real the inequality is invalid + # assert solve(sin(x) < 2) == (x <= oo) + + # with PR 16956, (x <= oo) autoevaluates when x is extended_real + # which is assumed in the current implementation of inequality solvers + assert solve(sin(x) < 2) == True + assert solveset(sin(x) < 2, domain=S.Reals) == S.Reals + + +def test_issue_10268(): + assert solve(log(x) < 1000) == And(S.Zero < x, x < exp(1000)) + + +@XFAIL +def test_isolve_Sets(): + n = Dummy('n') + assert isolve(Abs(x) <= n, x, relational=False) == \ + Piecewise((S.EmptySet, n < 0), (Interval(-n, n), True)) + + +def test_integer_domain_relational_isolve(): + + dom = FiniteSet(0, 3) + x = Symbol('x',zero=False) + assert isolve((x - 1)*(x - 2)*(x - 4) < 0, x, domain=dom) == Eq(x, 3) + + x = Symbol('x') + assert isolve(x + 2 < 0, x, domain=S.Integers) == \ + (x <= -3) & (x > -oo) & Eq(Mod(x, 1), 0) + assert isolve(2 * x + 3 > 0, x, domain=S.Integers) == \ + (x >= -1) & (x < oo) & Eq(Mod(x, 1), 0) + assert isolve((x ** 2 + 3 * x - 2) < 0, x, domain=S.Integers) == \ + (x >= -3) & (x <= 0) & Eq(Mod(x, 1), 0) + assert isolve((x ** 2 + 3 * x - 2) > 0, x, domain=S.Integers) == \ + ((x >= 1) & (x < oo) & Eq(Mod(x, 1), 0)) | ( + (x <= -4) & (x > -oo) & Eq(Mod(x, 1), 0)) + + +def test_issue_10671_12466(): + assert solveset(sin(y), y, Interval(0, pi)) == FiniteSet(0, pi) + i = Interval(1, 10) + assert solveset((1/x).diff(x) < 0, x, i) == i + assert solveset((log(x - 6)/x) <= 0, x, S.Reals) == \ + Interval.Lopen(6, 7) + + +def test__solve_inequality(): + for op in (Gt, Lt, Le, Ge, Eq, Ne): + assert _solve_inequality(op(x, 1), x).lhs == x + assert _solve_inequality(op(S.One, x), x).lhs == x + # don't get tricked by symbol on right: solve it + assert _solve_inequality(Eq(2*x - 1, x), x) == Eq(x, 1) + ie = Eq(S.One, y) + assert _solve_inequality(ie, x) == ie + for fx in (x**2, exp(x), sin(x) + cos(x), x*(1 + x)): + for c in (0, 1): + e = 2*fx - c > 0 + assert _solve_inequality(e, x, linear=True) == ( + fx > c/S(2)) + assert _solve_inequality(2*x**2 + 2*x - 1 < 0, x, linear=True) == ( + x*(x + 1) < S.Half) + assert _solve_inequality(Eq(x*y, 1), x) == Eq(x*y, 1) + nz = Symbol('nz', nonzero=True) + assert _solve_inequality(Eq(x*nz, 1), x) == Eq(x, 1/nz) + assert _solve_inequality(x*nz < 1, x) == (x*nz < 1) + a = Symbol('a', positive=True) + assert _solve_inequality(a/x > 1, x) == (S.Zero < x) & (x < a) + assert _solve_inequality(a/x > 1, x, linear=True) == (1/x > 1/a) + # make sure to include conditions under which solution is valid + e = Eq(1 - x, x*(1/x - 1)) + assert _solve_inequality(e, x) == Ne(x, 0) + assert _solve_inequality(x < x*(1/x - 1), x) == (x < S.Half) & Ne(x, 0) + + +def test__pt(): + from sympy.solvers.inequalities import _pt + assert _pt(-oo, oo) == 0 + assert _pt(S.One, S(3)) == 2 + assert _pt(S.One, oo) == _pt(oo, S.One) == 2 + assert _pt(S.One, -oo) == _pt(-oo, S.One) == S.Half + assert _pt(S.NegativeOne, oo) == _pt(oo, S.NegativeOne) == Rational(-1, 2) + assert _pt(S.NegativeOne, -oo) == _pt(-oo, S.NegativeOne) == -2 + assert _pt(x, oo) == _pt(oo, x) == x + 1 + assert _pt(x, -oo) == _pt(-oo, x) == x - 1 + raises(ValueError, lambda: _pt(Dummy('i', infinite=True), S.One)) + + +def test_issue_25697(): + assert _solve_inequality(log(x, 3) <= 2, x) == (x <= 9) & (S.Zero < x) + + +def test_issue_25738(): + assert reduce_inequalities(3 < abs(x) + ) == reduce_inequalities(pi < abs(x)).subs(pi, 3) + + +def test_issue_25983(): + assert(reduce_inequalities(pi/Abs(x) <= 1) == ((pi <= x) & (x < oo)) | ((-oo < x) & (x <= -pi))) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_numeric.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_numeric.py new file mode 100644 index 0000000000000000000000000000000000000000..12abd38c80f07279ed41aefc7952762da0f9f430 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_numeric.py @@ -0,0 +1,139 @@ +from sympy.core.function import nfloat +from sympy.core.numbers import (Float, I, Rational, pi) +from sympy.core.relational import Eq +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import sin +from sympy.integrals.integrals import Integral +from sympy.matrices.dense import Matrix +from mpmath import mnorm, mpf +from sympy.solvers import nsolve +from sympy.utilities.lambdify import lambdify +from sympy.testing.pytest import raises, XFAIL +from sympy.utilities.decorator import conserve_mpmath_dps + +@XFAIL +def test_nsolve_fail(): + x = symbols('x') + # Sometimes it is better to use the numerator (issue 4829) + # but sometimes it is not (issue 11768) so leave this to + # the discretion of the user + ans = nsolve(x**2/(1 - x)/(1 - 2*x)**2 - 100, x, 0) + assert ans > 0.46 and ans < 0.47 + + +def test_nsolve_denominator(): + x = symbols('x') + # Test that nsolve uses the full expression (numerator and denominator). + ans = nsolve((x**2 + 3*x + 2)/(x + 2), -2.1) + # The root -2 was divided out, so make sure we don't find it. + assert ans == -1.0 + +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)) + # multidimensional + x1 = Symbol('x1') + x2 = Symbol('x2') + f1 = 3 * x1**2 - 2 * x2**2 - 1 + f2 = x1**2 - 2 * x1 + x2**2 + 2 * x2 - 8 + f = Matrix((f1, f2)).T + 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 + # 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) + 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 + return root + assert list(map(round, getroot((1, 1, 1)))) == [2, 1, 0] + assert nsolve([Eq( + f1, 0), Eq(f2, 0), Eq(f3, 0)], [x, y, z], (1, 1, 1)) # just see that it works + a = Symbol('a') + assert abs(nsolve(1/(0.001 + a)**3 - 6/(0.9 - a)**3, a, 0.3) - + mpf('0.31883011387318591')) < 1e-15 + + +def test_issue_6408(): + x = Symbol('x') + assert nsolve(Piecewise((x, x < 1), (x**2, True)), x, 2) == 0 + + +def test_issue_6408_integral(): + x, y = symbols('x y') + assert nsolve(Integral(x*y, (x, 0, 5)), y, 2) == 0 + + +@conserve_mpmath_dps +def test_increased_dps(): + # Issue 8564 + import mpmath + mpmath.mp.dps = 128 + x = Symbol('x') + e1 = x**2 - pi + q = nsolve(e1, x, 3.0) + + assert abs(sqrt(pi).evalf(128) - q) < 1e-128 + +def test_nsolve_precision(): + x, y = symbols('x y') + sol = nsolve(x**2 - pi, x, 3, prec=128) + assert abs(sqrt(pi).evalf(128) - sol) < 1e-128 + assert isinstance(sol, Float) + + sols = nsolve((y**2 - x, x**2 - pi), (x, y), (3, 3), prec=128) + assert isinstance(sols, Matrix) + assert sols.shape == (2, 1) + assert abs(sqrt(pi).evalf(128) - sols[0]) < 1e-128 + assert abs(sqrt(sqrt(pi)).evalf(128) - sols[1]) < 1e-128 + assert all(isinstance(i, Float) for i in sols) + +def test_nsolve_complex(): + x, y = symbols('x y') + + assert nsolve(x**2 + 2, 1j) == sqrt(2.)*I + assert nsolve(x**2 + 2, I) == sqrt(2.)*I + + assert nsolve([x**2 + 2, y**2 + 2], [x, y], [I, I]) == Matrix([sqrt(2.)*I, sqrt(2.)*I]) + assert nsolve([x**2 + 2, y**2 + 2], [x, y], [I, I]) == Matrix([sqrt(2.)*I, sqrt(2.)*I]) + +def test_nsolve_dict_kwarg(): + x, y = symbols('x y') + # one variable + assert nsolve(x**2 - 2, 1, dict = True) == \ + [{x: sqrt(2.)}] + # one variable with complex solution + assert nsolve(x**2 + 2, I, dict = True) == \ + [{x: sqrt(2.)*I}] + # two variables + assert nsolve([x**2 + y**2 - 5, x**2 - y**2 + 1], [x, y], [1, 1], dict = True) == \ + [{x: sqrt(2.), y: sqrt(3.)}] + +def test_nsolve_rational(): + x = symbols('x') + assert nsolve(x - Rational(1, 3), 0, prec=100) == Rational(1, 3).evalf(100) + + +def test_issue_14950(): + x = Matrix(symbols('t s')) + x0 = Matrix([17, 23]) + eqn = x + x0 + assert nsolve(eqn, x, x0) == nfloat(-x0) + assert nsolve(eqn.T, x.T, x0.T) == nfloat(-x0) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_pde.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_pde.py new file mode 100644 index 0000000000000000000000000000000000000000..948d90c7be21a9e0e03753e723ef04f1fb08a5d6 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_pde.py @@ -0,0 +1,239 @@ +from sympy.core.function import (Derivative as D, Function) +from sympy.core.relational import Eq +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.core import S +from sympy.solvers.pde import (pde_separate, pde_separate_add, pde_separate_mul, + pdsolve, classify_pde, checkpdesol) +from sympy.testing.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 = map(Function, 'FTXYZu') + + eq = Eq(D(u(x, t), x), D(u(x, t), t)*exp(u(x, t))) + 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(): + x, y, z, t = symbols("x,y,z,t") + F, T, X, Y, Z, u = map(Function, 'FTXYZu') + + eq = Eq(D(u(x, t), x), D(u(x, t), t)*exp(u(x, t))) + raises(ValueError, lambda: pde_separate(eq, u(x, t), [X(x), T(t)], 'div')) + + +def test_pde_separate_mul(): + x, y, z, t = symbols("x,y,z,t") + c = Symbol("C", real=True) + Phi = Function('Phi') + F, R, T, X, Y, Z, u = map(Function, 'FRTXYZu') + r, theta, z = symbols('r,theta,z') + + # Something simple :) + eq = Eq(D(F(x, y, z), x) + D(F(x, y, z), y) + D(F(x, y, z), z), 0) + + # Duplicate arguments in functions + 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)])) + # Wrong variables: [x, y] -> [x, z] + 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)] + 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)] + + # wave equation + wave = Eq(D(u(x, t), t, t), c**2*D(u(x, t), x, x)) + res = pde_separate_mul(wave, u(x, t), [X(x), T(t)]) + 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) + + 1/r**2 * D(Phi(r, theta, z), theta, 2) + D(Phi(r, theta, z), z, 2), 0) + # 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))] + # 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), + -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, + -D(T(theta), theta, theta)/T(theta)] + + +def test_issue_11726(): + x, t = symbols("x t") + f = symbols("f", cls=Function) + X, T = symbols("X T", cls=Function) + + u = f(x, t) + eq = u.diff(x, 2) - u.diff(t, 2) + res = pde_separate(eq, u, [T(x), X(t)]) + assert res == [D(T(x), x, x)/T(x),D(X(t), t, t)/X(t)] + + +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) == ('1st_linear_variable_coeff',) + + +def test_checkpdesol(): + f, F = 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)))] + for eq in [eq4, eq5, eq6]: + assert checkpdesol(eq, pdsolve(eq))[0] + sol = pdsolve(eq4) + sol4 = Eq(sol.lhs - sol.rhs, 0) + raises(NotImplementedError, lambda: + checkpdesol(eq4, sol4, solve_for_func=False)) + + +def test_solvefun(): + f, F, G, H = 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 = 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 = 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/2) + exp(x + 4*y)/15)*exp(-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)/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/5 - 3*y/5) - 2*sin(x)/5 - cos(x)/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.expand() == Eq(f(x, y), + x + y + (x - y)**2/4 - (x + y)**2/4 + F(x - y)*exp(-x/2 - y/2) - 2).expand() + 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 = 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'].expand() == Eq(f(x, y), + -x**2*y + x**2 + 2*x*y - 4*x - 2*y + F(x - y)*exp(-x/2 - y/2) + 6).expand() + + +def test_pdsolve_variable_coeff(): + f, F = map(Function, ['f', 'F']) + u = f(x, y) + eq = x*(u.diff(x)) - y*(u.diff(y)) + y**2*u - y**2 + sol = pdsolve(eq, hint="1st_linear_variable_coeff") + assert sol == Eq(u, F(x*y)*exp(y**2/2) + 1) + assert checkpdesol(eq, sol)[0] + + eq = x**2*u + x*u.diff(x) + x*y*u.diff(y) + sol = pdsolve(eq, hint='1st_linear_variable_coeff') + assert sol == Eq(u, F(y*exp(-x))*exp(-x**2/2)) + assert checkpdesol(eq, sol)[0] + + eq = y*x**2*u + y*u.diff(x) + u.diff(y) + sol = pdsolve(eq, hint='1st_linear_variable_coeff') + assert sol == Eq(u, F(-2*x + y**2)*exp(-x**3/3)) + assert checkpdesol(eq, sol)[0] + + eq = exp(x)**2*(u.diff(x)) + y + sol = pdsolve(eq, hint='1st_linear_variable_coeff') + assert sol == Eq(u, y*exp(-2*x)/2 + F(y)) + assert checkpdesol(eq, sol)[0] + + eq = exp(2*x)*(u.diff(y)) + y*u - u + sol = pdsolve(eq, hint='1st_linear_variable_coeff') + assert sol == Eq(u, F(x)*exp(-y*(y - 2)*exp(-2*x)/2)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_polysys.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_polysys.py new file mode 100644 index 0000000000000000000000000000000000000000..a119591a0354ba377a18767eae6e8b7812810a0d --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_polysys.py @@ -0,0 +1,462 @@ +"""Tests for solvers of systems of polynomial equations. """ +from sympy.polys.domains import ZZ, QQ_I +from sympy.core.numbers import (I, Integer, Rational) +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.polys.domains.rationalfield import QQ +from sympy.polys.polyerrors import UnsolvableFactorError +from sympy.polys.polyoptions import Options +from sympy.polys.polytools import Poly +from sympy.polys.rootoftools import CRootOf +from sympy.solvers.solvers import solve +from sympy.utilities.iterables import flatten +from sympy.abc import a, b, c, x, y, z +from sympy.polys import PolynomialError +from sympy.solvers.polysys import (solve_poly_system, + solve_triangulated, + solve_biquadratic, SolveFailed, + solve_generic, factor_system_bool, + factor_system_cond, factor_system_poly, + factor_system, _factor_sets, _factor_sets_slow) +from sympy.polys.polytools import parallel_poly_from_expr +from sympy.testing.pytest import raises +from sympy.core.relational import Eq +from sympy.functions.elementary.trigonometric import sin, cos + +from sympy.functions.elementary.exponential import exp + + +def test_solve_poly_system(): + assert solve_poly_system([x - 1], x) == [(S.One,)] + + 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)] + + assert solve_poly_system([2*x - 3, y*Rational(3, 2) - 2*x, z - 5*y], x, y, z) == \ + [(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))] + + assert solve_poly_system([y - x**2, y + x**2 + 1], x, y) == \ + [(-I*sqrt(S.Half), Rational(-1, 2)), (I*sqrt(S.Half), Rational(-1, 2))] + + f_1 = x**2 + y + z - 1 + f_2 = x + y**2 + z - 1 + f_3 = x + y + z**2 - 1 + + a, b = sqrt(2) - 1, -sqrt(2) - 1 + + assert solve_poly_system([f_1, f_2, f_3], x, y, z) == \ + [(0, 0, 1), (0, 1, 0), (1, 0, 0), (a, a, a), (b, b, b)] + + solution = [(1, -1), (1, 1)] + + assert solve_poly_system([Poly(x**2 - y**2), Poly(x - 1)]) == solution + 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)] + + raises(NotImplementedError, lambda: solve_poly_system([x**3 - y**3], x, y)) + raises(NotImplementedError, lambda: solve_poly_system( + [z, -2*x*y**2 + x + y**2*z, y**2*(-z - 4) + 2])) + raises(PolynomialError, lambda: solve_poly_system([1/x], x)) + + raises(NotImplementedError, lambda: solve_poly_system( + [x-1,], (x, y))) + raises(NotImplementedError, lambda: solve_poly_system( + [y-1,], (x, y))) + + # solve_poly_system should ideally construct solutions using + # CRootOf for the following four tests + assert solve_poly_system([x**5 - x + 1], [x], strict=False) == [] + raises(UnsolvableFactorError, lambda: solve_poly_system( + [x**5 - x + 1], [x], strict=True)) + + assert solve_poly_system([(x - 1)*(x**5 - x + 1), y**2 - 1], [x, y], + strict=False) == [(1, -1), (1, 1)] + raises(UnsolvableFactorError, + lambda: solve_poly_system([(x - 1)*(x**5 - x + 1), y**2-1], + [x, y], strict=True)) + + +def test_solve_generic(): + NewOption = Options((x, y), {'domain': 'ZZ'}) + assert solve_generic([x**2 - 2*y**2, y**2 - y + 1], NewOption) == \ + [(-sqrt(-1 - sqrt(3)*I), Rational(1, 2) - sqrt(3)*I/2), + (sqrt(-1 - sqrt(3)*I), Rational(1, 2) - sqrt(3)*I/2), + (-sqrt(-1 + sqrt(3)*I), Rational(1, 2) + sqrt(3)*I/2), + (sqrt(-1 + sqrt(3)*I), Rational(1, 2) + sqrt(3)*I/2)] + + # solve_generic should ideally construct solutions using + # CRootOf for the following two tests + assert solve_generic( + [2*x - y, (y - 1)*(y**5 - y + 1)], NewOption, strict=False) == \ + [(Rational(1, 2), 1)] + raises(UnsolvableFactorError, lambda: solve_generic( + [2*x - y, (y - 1)*(y**5 - y + 1)], NewOption, strict=True)) + + +def test_solve_biquadratic(): + x0, y0, x1, y1, r = symbols('x0 y0 x1 y1 r') + + f_1 = (x - 1)**2 + (y - 1)**2 - r**2 + f_2 = (x - 2)**2 + (y - 2)**2 - r**2 + s = sqrt(2*r**2 - 1) + a = (3 - s)/2 + b = (3 + s)/2 + assert solve_poly_system([f_1, f_2], x, y) == [(a, b), (b, a)] + + f_1 = (x - 1)**2 + (y - 2)**2 - r**2 + f_2 = (x - 1)**2 + (y - 1)**2 - r**2 + + assert solve_poly_system([f_1, f_2], x, y) == \ + [(1 - sqrt((2*r - 1)*(2*r + 1))/2, Rational(3, 2)), + (1 + sqrt((2*r - 1)*(2*r + 1))/2, Rational(3, 2))] + + query = lambda expr: expr.is_Pow and expr.exp is S.Half + + f_1 = (x - 1 )**2 + (y - 2)**2 - r**2 + f_2 = (x - x1)**2 + (y - 1)**2 - r**2 + + result = solve_poly_system([f_1, f_2], x, y) + + assert len(result) == 2 and all(len(r) == 2 for r in result) + assert all(r.count(query) == 1 for r in flatten(result)) + + f_1 = (x - x0)**2 + (y - y0)**2 - r**2 + f_2 = (x - x1)**2 + (y - y1)**2 - r**2 + + result = solve_poly_system([f_1, f_2], x, y) + + 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)) + + s1 = (x*y - y, x**2 - x) + assert solve(s1) == [{x: 1}, {x: 0, y: 0}] + s2 = (x*y - x, y**2 - y) + assert solve(s2) == [{y: 1}, {x: 0, y: 0}] + gens = (x, y) + for seq in (s1, s2): + (f, g), opt = parallel_poly_from_expr(seq, *gens) + raises(SolveFailed, lambda: solve_biquadratic(f, g, opt)) + seq = (x**2 + y**2 - 2, y**2 - 1) + (f, g), opt = parallel_poly_from_expr(seq, *gens) + assert solve_biquadratic(f, g, opt) == [ + (-1, -1), (-1, 1), (1, -1), (1, 1)] + ans = [(0, -1), (0, 1)] + seq = (x**2 + y**2 - 1, y**2 - 1) + (f, g), opt = parallel_poly_from_expr(seq, *gens) + assert solve_biquadratic(f, g, opt) == ans + seq = (x**2 + y**2 - 1, x**2 - x + y**2 - 1) + (f, g), opt = parallel_poly_from_expr(seq, *gens) + assert solve_biquadratic(f, g, opt) == ans + + +def test_solve_triangulated(): + f_1 = x**2 + y + z - 1 + f_2 = x + y**2 + z - 1 + f_3 = x + y + z**2 - 1 + + a, b = sqrt(2) - 1, -sqrt(2) - 1 + + assert solve_triangulated([f_1, f_2, f_3], x, y, z) == \ + [(0, 0, 1), (0, 1, 0), (1, 0, 0)] + + dom = QQ.algebraic_field(sqrt(2)) + + assert solve_triangulated([f_1, f_2, f_3], x, y, z, domain=dom) == \ + [(0, 0, 1), (0, 1, 0), (1, 0, 0), (a, a, a), (b, b, b)] + + a, b = CRootOf(z**2 + 2*z - 1, 0), CRootOf(z**2 + 2*z - 1, 1) + assert solve_triangulated([f_1, f_2, f_3], x, y, z, extension=True) == \ + [(0, 0, 1), (0, 1, 0), (1, 0, 0), (a, a, a), (b, b, b)] + + +def test_solve_issue_3686(): + roots = solve_poly_system([((x - 5)**2/250000 + (y - Rational(5, 10))**2/250000) - 1, x], x, y) + assert roots == [(0, S.Half - 15*sqrt(1111)), (0, S.Half + 15*sqrt(1111))] + + roots = solve_poly_system([((x - 5)**2/250000 + (y - 5.0/10)**2/250000) - 1, x], x, y) + # TODO: does this really have to be so complicated?! + assert len(roots) == 2 + assert roots[0][0] == 0 + assert roots[0][1].epsilon_eq(-499.474999374969, 1e12) + assert roots[1][0] == 0 + assert roots[1][1].epsilon_eq(500.474999374969, 1e12) + + +def test_factor_system(): + + assert factor_system([x**2 + 2*x + 1]) == [[x + 1]] + assert factor_system([x**2 + 2*x + 1, y**2 + 2*y + 1]) == [[x + 1, y + 1]] + assert factor_system([x**2 + 1]) == [[x**2 + 1]] + assert factor_system([]) == [[]] + + assert factor_system([x**2 + y**2 + 2*x*y, x**2 - 2], extension=sqrt(2)) == [ + [x + y, x + sqrt(2)], + [x + y, x - sqrt(2)], + ] + + assert factor_system([x**2 + 1, y**2 + 1], gaussian=True) == [ + [x + I, y + I], + [x + I, y - I], + [x - I, y + I], + [x - I, y - I], + ] + + assert factor_system([x**2 + 1, y**2 + 1], domain=QQ_I) == [ + [x + I, y + I], + [x + I, y - I], + [x - I, y + I], + [x - I, y - I], + ] + + assert factor_system([0]) == [[]] + assert factor_system([1]) == [] + assert factor_system([0 , x]) == [[x]] + assert factor_system([1, 0, x]) == [] + + assert factor_system([x**4 - 1, y**6 - 1]) == [ + [x**2 + 1, y**2 + y + 1], + [x**2 + 1, y**2 - y + 1], + [x**2 + 1, y + 1], + [x**2 + 1, y - 1], + [x + 1, y**2 + y + 1], + [x + 1, y**2 - y + 1], + [x - 1, y**2 + y + 1], + [x - 1, y**2 - y + 1], + [x + 1, y + 1], + [x + 1, y - 1], + [x - 1, y + 1], + [x - 1, y - 1], + ] + + assert factor_system([(x - 1)*(y - 2), (y - 2)*(z - 3)]) == [ + [x - 1, z - 3], + [y - 2] + ] + + assert factor_system([sin(x)**2 + cos(x)**2 - 1, x]) == [ + [x, sin(x)**2 + cos(x)**2 - 1], + ] + + assert factor_system([sin(x)**2 + cos(x)**2 - 1]) == [ + [sin(x)**2 + cos(x)**2 - 1] + ] + + assert factor_system([sin(x)**2 + cos(x)**2]) == [ + [sin(x)**2 + cos(x)**2] + ] + + assert factor_system([a*x, y, a]) == [[y, a]] + + assert factor_system([a*x, y, a], [x, y]) == [] + + assert factor_system([a ** 2 * x, y], [x, y]) == [[x, y]] + + assert factor_system([a*x*(x - 1), b*y, c], [x, y]) == [] + + assert factor_system([a*x*(x - 1), b*y, c], [x, y, c]) == [ + [x - 1, y, c], + [x, y, c], + ] + + assert factor_system([a*x*(x - 1), b*y, c]) == [ + [x - 1, y, c], + [x, y, c], + [x - 1, b, c], + [x, b, c], + [y, a, c], + [a, b, c], + ] + + assert factor_system([x**2 - 2], [y]) == [] + + assert factor_system([x**2 - 2], [x]) == [[x**2 - 2]] + + assert factor_system([cos(x)**2 - sin(x)**2, cos(x)**2 + sin(x)**2 - 1]) == [ + [sin(x)**2 + cos(x)**2 - 1, sin(x) + cos(x)], + [sin(x)**2 + cos(x)**2 - 1, -sin(x) + cos(x)], + ] + + assert factor_system([(cos(x) + sin(x))**2 - 1, cos(x)**2 - sin(x)**2 - cos(2*x)]) == [ + [sin(x)**2 - cos(x)**2 + cos(2*x), sin(x) + cos(x) + 1], + [sin(x)**2 - cos(x)**2 + cos(2*x), sin(x) + cos(x) - 1], + ] + + assert factor_system([(cos(x) + sin(x))*exp(y) - 1, (cos(x) - sin(x))*exp(y) - 1]) == [ + [exp(y)*sin(x) + exp(y)*cos(x) - 1, -exp(y)*sin(x) + exp(y)*cos(x) - 1] + ] + + +def test_factor_system_poly(): + + px = lambda e: Poly(e, x) + pxab = lambda e: Poly(e, x, domain=ZZ[a, b]) + pxI = lambda e: Poly(e, x, domain=QQ_I) + pxyz = lambda e: Poly(e, (x, y, z)) + + assert factor_system_poly([px(x**2 - 1), px(x**2 - 4)]) == [ + [px(x + 2), px(x + 1)], + [px(x + 2), px(x - 1)], + [px(x + 1), px(x - 2)], + [px(x - 1), px(x - 2)], + ] + + assert factor_system_poly([px(x**2 - 1)]) == [[px(x + 1)], [px(x - 1)]] + + assert factor_system_poly([pxyz(x**2*y - y), pxyz(x**2*z - z)]) == [ + [pxyz(x + 1)], + [pxyz(x - 1)], + [pxyz(y), pxyz(z)], + ] + + assert factor_system_poly([px(x**2*(x - 1)**2), px(x*(x - 1))]) == [ + [px(x)], + [px(x - 1)], + ] + + assert factor_system_poly([pxyz(x**2 + y*x), pxyz(x**2 + z*x)]) == [ + [pxyz(x + y), pxyz(x + z)], + [pxyz(x)], + ] + + assert factor_system_poly([pxab((a - 1)*(x - 2)), pxab((b - 3)*(x - 2))]) == [ + [pxab(x - 2)], + [pxab(a - 1), pxab(b - 3)], + ] + + assert factor_system_poly([pxI(x**2 + 1)]) == [[pxI(x + I)], [pxI(x - I)]] + + assert factor_system_poly([]) == [[]] + + assert factor_system_poly([px(1)]) == [] + assert factor_system_poly([px(0), px(x)]) == [[px(x)]] + + +def test_factor_system_cond(): + + assert factor_system_cond([x ** 2 - 1, x ** 2 - 4]) == [ + [x + 2, x + 1], + [x + 2, x - 1], + [x + 1, x - 2], + [x - 1, x - 2], + ] + + assert factor_system_cond([1]) == [] + assert factor_system_cond([0]) == [[]] + assert factor_system_cond([1, x]) == [] + assert factor_system_cond([0, x]) == [[x]] + assert factor_system_cond([]) == [[]] + + assert factor_system_cond([x**2 + y*x]) == [[x + y], [x]] + + assert factor_system_cond([(a - 1)*(x - 2), (b - 3)*(x - 2)], [x]) == [ + [x - 2], + [a - 1, b - 3], + ] + + assert factor_system_cond([a * (x - 1), b], [x]) == [[x - 1, b], [a, b]] + + assert factor_system_cond([a*x*(x-1), b*y, c], [x, y]) == [ + [x - 1, y, c], + [x, y, c], + [x - 1, b, c], + [x, b, c], + [y, a, c], + [a, b, c], + ] + + assert factor_system_cond([x*(x-1), y], [x, y]) == [[x - 1, y], [x, y]] + + assert factor_system_cond([a*x, y, a], [x, y]) == [[y, a]] + + assert factor_system_cond([a*x, b*x], [x, y]) == [[x], [a, b]] + + assert factor_system_cond([a*b*x, y], [x, y]) == [[x, y], [y, a*b]] + + assert factor_system_cond([a*b*x, y]) == [[x, y], [y, a], [y, b]] + + assert factor_system_cond([a**2*x, y], [x, y]) == [[x, y], [y, a]] + +def test_factor_system_bool(): + + eqs = [a*(x - 1)*(y - 1), b*(x - 2)*(y - 1)*(y - 2)] + assert factor_system_bool(eqs, [x, y]) == ( + Eq(y - 1, 0) + | (Eq(a, 0) & Eq(b, 0)) + | (Eq(a, 0) & Eq(x - 2, 0)) + | (Eq(a, 0) & Eq(y - 2, 0)) + | (Eq(b, 0) & Eq(x - 1, 0)) + | (Eq(x - 2, 0) & Eq(x - 1, 0)) + | (Eq(x - 1, 0) & Eq(y - 2, 0)) + ) + + assert factor_system_bool([x - 1], [x]) == Eq(x - 1, 0) + + assert factor_system_bool([(x - 1)*(x - 2)], [x]) == Eq(x - 2, 0) | Eq(x - 1, 0) + + assert factor_system_bool([], [x]) == True + assert factor_system_bool([0], [x]) == True + assert factor_system_bool([1], [x]) == False + assert factor_system_bool([a], [x]) == Eq(a, 0) + + assert factor_system_bool([a * x, y, a], [x, y]) == Eq(a, 0) & Eq(y, 0) + + assert (factor_system_bool([a*x, b*y*x, a], [x, y]) == ( + Eq(a, 0) & Eq(b, 0)) + | (Eq(a, 0) & Eq(x, 0)) + | (Eq(a, 0) & Eq(y, 0))) + + assert (factor_system_bool([a*x, b*x], [x, y]) == Eq(x, 0) | + (Eq(a, 0) & Eq(b, 0))) + + assert (factor_system_bool([a*b*x, y], [x, y]) == ( + Eq(x, 0) & Eq(y, 0)) | + (Eq(y, 0) & Eq(a*b, 0))) + + assert (factor_system_bool([a**2*x, y], [x, y]) == ( + Eq(a, 0) & Eq(y, 0)) | + (Eq(x, 0) & Eq(y, 0))) + + assert factor_system_bool([a*x*y, b*y*z], [x, y, z]) == ( + Eq(y, 0) + | (Eq(a, 0) & Eq(b, 0)) + | (Eq(a, 0) & Eq(z, 0)) + | (Eq(b, 0) & Eq(x, 0)) + | (Eq(x, 0) & Eq(z, 0)) + ) + + assert factor_system_bool([a*(x - 1), b], [x]) == ( + (Eq(a, 0) & Eq(b, 0)) + | (Eq(x - 1, 0) & Eq(b, 0)) + ) + + +def test_factor_sets(): + # + from random import randint + + def generate_random_system(n_eqs=3, n_factors=2, max_val=10): + return [ + [randint(0, max_val) for _ in range(randint(1, n_factors))] + for _ in range(n_eqs) + ] + + test_cases = [ + [[1, 2], [1, 3]], + [[1, 2], [3, 4]], + [[1], [1, 2], [2]], + ] + + for case in test_cases: + assert _factor_sets(case) == _factor_sets_slow(case) + + for _ in range(100): + system = generate_random_system() + assert _factor_sets(system) == _factor_sets_slow(system) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_recurr.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_recurr.py new file mode 100644 index 0000000000000000000000000000000000000000..5a6306b51a5cf33ccd9fae131430a24690d540a7 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_recurr.py @@ -0,0 +1,295 @@ +from sympy.core.function import (Function, Lambda, expand) +from sympy.core.numbers import (I, Rational) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.combinatorial.factorials import (rf, binomial, factorial) +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.polys.polytools import factor +from sympy.solvers.recurr import rsolve, rsolve_hyper, rsolve_poly, rsolve_ratio +from sympy.testing.pytest import raises, slow, XFAIL +from sympy.abc import a, b + +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, 1], n, n) == C0 + (n**2 - n)/2 + assert rsolve_poly([-n - 1, n], 1, n) == C0*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 + + +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) + assert solution == C0*(2*n - 3)/(n**2 - 1)/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 [ + 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 [ + 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( + [n + 2, -(2*n + 3)*(17*n**2 + 51*n + 39), n + 1], 0, n) == 0 + + assert rsolve_hyper([-n - 1, -1, 1], 0, n) == 0 + + 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], 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*(Rational(-1, 2) - sqrt(3)*I/2)**n + C1*(Rational(-1, 2) + sqrt(3)*I/2)**n + + assert rsolve_hyper([1, -2*n/a - 2/a, 1], 0, n) == 0 + + +@XFAIL +def test_rsolve_ratio_missed(): + # this arises during computation + # assert rsolve_hyper([-1, 1], 3*(n + n**2), n).expand() == C0 + n**3 - n + assert rsolve_ratio([-n, n + 2], n, n) is not None + + +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))) + + +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] ] + for p in funcs: + # compute difference + for c in coeffs: + q = recurrence_term(c, p) + if p.is_polynomial(n): + assert rsolve_poly(c, q, n) == p + # See issue 3956: + if p.is_hypergeometric(n) and len(c) <= 3: + assert rsolve_hyper(c, q, n).subs(zip(symbols('C:3'), [0, 0, 0])).expand() == p + + +def test_rsolve_0_sol_homogeneous(): + # fixed by cherry-pick from + # https://github.com/diofant/diofant/commit/e1d2e52125199eb3df59f12e8944f8a5f24b00a5 + assert rsolve_hyper([n**2 - n + 12, 1], n*(n**2 - n + 12) + n + 1, n) == n + + +def test_rsolve(): + 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 + + 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(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) + 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) - b*(-sqrt(a))**n + + f = (-16*n**2 + 32*n - 12)*y(n - 1) + (4*n**2 - 12*n + 9)*y(n) + + yn = rsolve(f, y(n), {y(1): binomial(2*n + 1, 3)}) + sol = 2**(2*n)*n*(2*n - 1)**2*(2*n + 1)/12 + assert factor(expand(yn, func=True)) == sol + + sol = rsolve(y(n) + a*(y(n + 1) + y(n - 1))/2, y(n)) + assert str(sol) == 'C0*((-sqrt(1 - a**2) - 1)/a)**n + C1*((sqrt(1 - a**2) - 1)/a)**n' + + assert rsolve((k + 1)*y(k), y(k)) is None + assert (rsolve((k + 1)*y(k) + (k + 3)*y(k + 1) + (k + 5)*y(k + 2), y(k)) + is None) + + assert rsolve(y(n) + y(n + 1) + 2**n + 3**n, y(n)) == (-1)**n*C0 - 2**n/3 - 3**n/4 + + +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})) + raises(ValueError, lambda: rsolve(y(n) + y(n + 1) + 2**n + cos(n), y(n))) + + +def test_issue_6844(): + f = y(n + 2) - y(n + 1) + y(n)/4 + assert rsolve(f, y(n)) == 2**(-n + 1)*C1*n + 2**(-n)*C0 + assert rsolve(f, y(n), {y(0): 0, y(1): 1}) == 2**(1 - n)*n + + +def test_issue_18751(): + r = Symbol('r', positive=True) + theta = Symbol('theta', real=True) + f = y(n) - 2 * r * cos(theta) * y(n - 1) + r**2 * y(n - 2) + assert rsolve(f, y(n)) == \ + C0*(r*(cos(theta) - I*Abs(sin(theta))))**n + C1*(r*(cos(theta) + I*Abs(sin(theta))))**n + + +def test_constant_naming(): + #issue 8697 + assert rsolve(y(n+3) - y(n+2) - y(n+1) + y(n), y(n)) == (-1)**n*C1 + C0 + C2*n + assert rsolve(y(n+3)+3*y(n+2)+3*y(n+1)+y(n), y(n)).expand() == (-1)**n*C0 - (-1)**n*C1*n - (-1)**n*C2*n**2 + assert rsolve(y(n) - 2*y(n - 3) + 5*y(n - 2) - 4*y(n - 1),y(n),[1,3,8]) == 3*2**n - n - 2 + + #issue 19630 + assert rsolve(y(n+3) - 3*y(n+1) + 2*y(n), y(n), {y(1):0, y(2):8, y(3):-2}) == (-2)**n + 2*n + + +@slow +def test_issue_15751(): + f = y(n) + 21*y(n + 1) - 273*y(n + 2) - 1092*y(n + 3) + 1820*y(n + 4) + 1092*y(n + 5) - 273*y(n + 6) - 21*y(n + 7) + y(n + 8) + assert rsolve(f, y(n)) is not None + + +def test_issue_17990(): + f = -10*y(n) + 4*y(n + 1) + 6*y(n + 2) + 46*y(n + 3) + sol = rsolve(f, y(n)) + expected = C0*((86*18**(S(1)/3)/69 + (-12 + (-1 + sqrt(3)*I)*(290412 + + 3036*sqrt(9165))**(S(1)/3))*(1 - sqrt(3)*I)*(24201 + 253*sqrt(9165))** + (S(1)/3)/276)/((1 - sqrt(3)*I)*(24201 + 253*sqrt(9165))**(S(1)/3)) + )**n + C1*((86*18**(S(1)/3)/69 + (-12 + (-1 - sqrt(3)*I)*(290412 + 3036 + *sqrt(9165))**(S(1)/3))*(1 + sqrt(3)*I)*(24201 + 253*sqrt(9165))** + (S(1)/3)/276)/((1 + sqrt(3)*I)*(24201 + 253*sqrt(9165))**(S(1)/3)) + )**n + C2*(-43*18**(S(1)/3)/(69*(24201 + 253*sqrt(9165))**(S(1)/3)) - + S(1)/23 + (290412 + 3036*sqrt(9165))**(S(1)/3)/138)**n + assert sol == expected + e = sol.subs({C0: 1, C1: 1, C2: 1, n: 1}).evalf() + assert abs(e + 0.130434782608696) < 1e-13 + + +def test_issue_8697(): + a = Function('a') + eq = a(n + 3) - a(n + 2) - a(n + 1) + a(n) + assert rsolve(eq, a(n)) == (-1)**n*C1 + C0 + C2*n + eq2 = a(n + 3) + 3*a(n + 2) + 3*a(n + 1) + a(n) + assert (rsolve(eq2, a(n)) == + (-1)**n*C0 + (-1)**(n + 1)*C1*n + (-1)**(n + 1)*C2*n**2) + + assert rsolve(a(n) - 2*a(n - 3) + 5*a(n - 2) - 4*a(n - 1), + a(n), {a(0): 1, a(1): 3, a(2): 8}) == 3*2**n - n - 2 + + # From issue thread (but fixed by https://github.com/diofant/diofant/commit/da9789c6cd7d0c2ceeea19fbf59645987125b289): + assert rsolve(a(n) - 2*a(n - 1) - n, a(n), {a(0): 1}) == 3*2**n - n - 2 + + +def test_diofantissue_294(): + f = y(n) - y(n - 1) - 2*y(n - 2) - 2*n + assert rsolve(f, y(n)) == (-1)**n*C0 + 2**n*C1 - n - Rational(5, 2) + # issue sympy/sympy#11261 + assert rsolve(f, y(n), {y(0): -1, y(1): 1}) == (-(-1)**n/2 + 2*2**n - + n - Rational(5, 2)) + # issue sympy/sympy#7055 + assert rsolve(-2*y(n) + y(n + 1) + n - 1, y(n)) == 2**n*C0 + n + + +def test_issue_15553(): + f = Function("f") + assert rsolve(Eq(f(n), 2*f(n - 1) + n), f(n)) == 2**n*C0 - n - 2 + assert rsolve(Eq(f(n + 1), 2*f(n) + n**2 + 1), f(n)) == 2**n*C0 - n**2 - 2*n - 4 + assert rsolve(Eq(f(n + 1), 2*f(n) + n**2 + 1), f(n), {f(1): 0}) == 7*2**n/2 - n**2 - 2*n - 4 + assert rsolve(Eq(f(n), 2*f(n - 1) + 3*n**2), f(n)) == 2**n*C0 - 3*n**2 - 12*n - 18 + assert rsolve(Eq(f(n), 2*f(n - 1) + n**2), f(n)) == 2**n*C0 - n**2 - 4*n - 6 + assert rsolve(Eq(f(n), 2*f(n - 1) + n), f(n), {f(0): 1}) == 3*2**n - n - 2 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_simplex.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_simplex.py new file mode 100644 index 0000000000000000000000000000000000000000..611205f5df009a6d0de6e687501695b63bb932c9 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_simplex.py @@ -0,0 +1,254 @@ +from sympy.core.numbers import Rational +from sympy.core.relational import Eq, Ne +from sympy.core.symbol import symbols +from sympy.core.sympify import sympify +from sympy.core.singleton import S +from sympy.core.random import random, choice +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.ntheory.generate import randprime +from sympy.matrices.dense import Matrix +from sympy.solvers.solveset import linear_eq_to_matrix +from sympy.solvers.simplex import (_lp as lp, _primal_dual, + UnboundedLPError, InfeasibleLPError, lpmin, lpmax, + _m, _abcd, _simplex, linprog) + +from sympy.external.importtools import import_module + +from sympy.testing.pytest import raises + +from sympy.abc import x, y, z + + +np = import_module("numpy") +scipy = import_module("scipy") + + +def test_lp(): + r1 = y + 2*z <= 3 + r2 = -x - 3*z <= -2 + r3 = 2*x + y + 7*z <= 5 + constraints = [r1, r2, r3, x >= 0, y >= 0, z >= 0] + objective = -x - y - 5 * z + ans = optimum, argmax = lp(max, objective, constraints) + assert ans == lpmax(objective, constraints) + assert objective.subs(argmax) == optimum + for constr in constraints: + assert constr.subs(argmax) == True + + r1 = x - y + 2*z <= 3 + r2 = -x + 2*y - 3*z <= -2 + r3 = 2*x + y - 7*z <= -5 + constraints = [r1, r2, r3, x >= 0, y >= 0, z >= 0] + objective = -x - y - 5*z + ans = optimum, argmax = lp(max, objective, constraints) + assert ans == lpmax(objective, constraints) + assert objective.subs(argmax) == optimum + for constr in constraints: + assert constr.subs(argmax) == True + + r1 = x - y + 2*z <= -4 + r2 = -x + 2*y - 3*z <= 8 + r3 = 2*x + y - 7*z <= 10 + constraints = [r1, r2, r3, x >= 0, y >= 0, z >= 0] + const = 2 + objective = -x-y-5*z+const # has constant term + ans = optimum, argmax = lp(max, objective, constraints) + assert ans == lpmax(objective, constraints) + assert objective.subs(argmax) == optimum + for constr in constraints: + assert constr.subs(argmax) == True + + # Section 4 Problem 1 from + # http://web.tecnico.ulisboa.pt/mcasquilho/acad/or/ftp/FergusonUCLA_LP.pdf + # answer on page 55 + v = x1, x2, x3, x4 = symbols('x1 x2 x3 x4') + r1 = x1 - x2 - 2*x3 - x4 <= 4 + r2 = 2*x1 + x3 -4*x4 <= 2 + r3 = -2*x1 + x2 + x4 <= 1 + objective, constraints = x1 - 2*x2 - 3*x3 - x4, [r1, r2, r3] + [ + i >= 0 for i in v] + ans = optimum, argmax = lp(max, objective, constraints) + assert ans == lpmax(objective, constraints) + assert ans == (4, {x1: 7, x2: 0, x3: 0, x4: 3}) + + # input contains Floats + r1 = x - y + 2.0*z <= -4 + r2 = -x + 2*y - 3.0*z <= 8 + r3 = 2*x + y - 7*z <= 10 + constraints = [r1, r2, r3] + [i >= 0 for i in (x, y, z)] + objective = -x-y-5*z + optimum, argmax = lp(max, objective, constraints) + assert objective.subs(argmax) == optimum + for constr in constraints: + assert constr.subs(argmax) == True + + # input contains non-float or non-Rational + r1 = x - y + sqrt(2) * z <= -4 + r2 = -x + 2*y - 3*z <= 8 + r3 = 2*x + y - 7*z <= 10 + raises(TypeError, lambda: lp(max, -x-y-5*z, [r1, r2, r3])) + + r1 = x >= 0 + raises(UnboundedLPError, lambda: lp(max, x, [r1])) + r2 = x <= -1 + raises(InfeasibleLPError, lambda: lp(max, x, [r1, r2])) + + # strict inequalities are not allowed + r1 = x > 0 + raises(TypeError, lambda: lp(max, x, [r1])) + + # not equals not allowed + r1 = Ne(x, 0) + raises(TypeError, lambda: lp(max, x, [r1])) + + def make_random_problem(nvar=2, num_constraints=2, sparsity=.1): + def rand(): + if random() < sparsity: + return sympify(0) + int1, int2 = [randprime(0, 200) for _ in range(2)] + return Rational(int1, int2)*choice([-1, 1]) + variables = symbols('x1:%s' % (nvar + 1)) + constraints = [(sum(rand()*x for x in variables) <= rand()) + for _ in range(num_constraints)] + objective = sum(rand() * x for x in variables) + return objective, constraints, variables + + # equality + r1 = Eq(x, y) + r2 = Eq(y, z) + r3 = z <= 3 + constraints = [r1, r2, r3] + objective = x + ans = optimum, argmax = lp(max, objective, constraints) + assert ans == lpmax(objective, constraints) + assert objective.subs(argmax) == optimum + for constr in constraints: + assert constr.subs(argmax) == True + + +def test_simplex(): + L = [ + [[1, 1], [-1, 1], [0, 1], [-1, 0]], + [5, 1, 2, -1], + [[1, 1]], + [-1]] + A, B, C, D = _abcd(_m(*L), list=False) + assert _simplex(A, B, -C, -D) == (-6, [3, 2], [1, 0, 0, 0]) + assert _simplex(A, B, -C, -D, dual=True) == (-6, + [1, 0, 0, 0], [5, 0]) + + assert _simplex([[]],[],[[1]],[0]) == (0, [0], []) + + # handling of Eq (or Eq-like x<=y, x>=y conditions) + assert lpmax(x - y, [x <= y + 2, x >= y + 2, x >= 0, y >= 0] + ) == (2, {x: 2, y: 0}) + assert lpmax(x - y, [x <= y + 2, Eq(x, y + 2), x >= 0, y >= 0] + ) == (2, {x: 2, y: 0}) + assert lpmax(x - y, [x <= y + 2, Eq(x, 2)]) == (2, {x: 2, y: 0}) + assert lpmax(y, [Eq(y, 2)]) == (2, {y: 2}) + + # the conditions are equivalent to Eq(x, y + 2) + assert lpmin(y, [x <= y + 2, x >= y + 2, y >= 0] + ) == (0, {x: 2, y: 0}) + # equivalent to Eq(y, -2) + assert lpmax(y, [0 <= y + 2, 0 >= y + 2]) == (-2, {y: -2}) + assert lpmax(y, [0 <= y + 2, 0 >= y + 2, y <= 0] + ) == (-2, {y: -2}) + + # extra symbols symbols + assert lpmin(x, [y >= 1, x >= y]) == (1, {x: 1, y: 1}) + assert lpmin(x, [y >= 1, x >= y + z, x >= 0, z >= 0] + ) == (1, {x: 1, y: 1, z: 0}) + + # detect oscillation + # o1 + v = x1, x2, x3, x4 = symbols('x1 x2 x3 x4') + raises(InfeasibleLPError, lambda: lpmin( + 9*x2 - 8*x3 + 3*x4 + 6, + [5*x2 - 2*x3 <= 0, + -x1 - 8*x2 + 9*x3 <= -3, + 10*x1 - x2+ 9*x4 <= -4] + [i >= 0 for i in v])) + # o2 - equations fed to lpmin are changed into a matrix + # system that doesn't oscillate and has the same solution + # as below + M = linear_eq_to_matrix + f = 5*x2 + x3 + 4*x4 - x1 + L = 5*x2 + 2*x3 + 5*x4 - (x1 + 5) + cond = [L <= 0] + [Eq(3*x2 + x4, 2), Eq(-x1 + x3 + 2*x4, 1)] + c, d = M(f, v) + a, b = M(L, v) + aeq, beq = M(cond[1:], v) + ans = (S(9)/2, [0, S(1)/2, 0, S(1)/2]) + assert linprog(c, a, b, aeq, beq, bounds=(0, 1)) == ans + lpans = lpmin(f, cond + [x1 >= 0, x1 <= 1, + x2 >= 0, x2 <= 1, x3 >= 0, x3 <= 1, x4 >= 0, x4 <= 1]) + assert (lpans[0], list(lpans[1].values())) == ans + + +def test_lpmin_lpmax(): + v = x1, x2, y1, y2 = symbols('x1 x2 y1 y2') + L = [[1, -1]], [1], [[1, 1]], [2] + a, b, c, d = [Matrix(i) for i in L] + m = Matrix([[a, b], [c, d]]) + f, constr = _primal_dual(m)[0] + ans = lpmin(f, constr + [i >= 0 for i in v[:2]]) + assert ans == (-1, {x1: 1, x2: 0}),ans + + L = [[1, -1], [1, 1]], [1, 1], [[1, 1]], [2] + a, b, c, d = [Matrix(i) for i in L] + m = Matrix([[a, b], [c, d]]) + f, constr = _primal_dual(m)[1] + ans = lpmax(f, constr + [i >= 0 for i in v[-2:]]) + assert ans == (-1, {y1: 1, y2: 0}) + + +def test_linprog(): + for do in range(2): + if not do: + M = lambda a, b: linear_eq_to_matrix(a, b) + else: + # check matrices as list + M = lambda a, b: tuple([ + i.tolist() for i in linear_eq_to_matrix(a, b)]) + + v = x, y, z = symbols('x1:4') + f = x + y - 2*z + c = M(f, v)[0] + ineq = [7*x + 4*y - 7*z <= 3, + 3*x - y + 10*z <= 6, + x >= 0, y >= 0, z >= 0] + ab = M([i.lts - i.gts for i in ineq], v) + ans = (-S(6)/5, [0, 0, S(3)/5]) + assert lpmin(f, ineq) == (ans[0], dict(zip(v, ans[1]))) + assert linprog(c, *ab) == ans + + f += 1 + c = M(f, v)[0] + eq = [Eq(y - 9*x, 1)] + abeq = M([i.lhs - i.rhs for i in eq], v) + ans = (1 - S(2)/5, [0, 1, S(7)/10]) + assert lpmin(f, ineq + eq) == (ans[0], dict(zip(v, ans[1]))) + assert linprog(c, *ab, *abeq) == (ans[0] - 1, ans[1]) + + eq = [z - y <= S.Half] + abeq = M([i.lhs - i.rhs for i in eq], v) + ans = (1 - S(10)/9, [0, S(1)/9, S(11)/18]) + assert lpmin(f, ineq + eq) == (ans[0], dict(zip(v, ans[1]))) + assert linprog(c, *ab, *abeq) == (ans[0] - 1, ans[1]) + + bounds = [(0, None), (0, None), (None, S.Half)] + ans = (0, [0, 0, S.Half]) + assert lpmin(f, ineq + [z <= S.Half]) == ( + ans[0], dict(zip(v, ans[1]))) + assert linprog(c, *ab, bounds=bounds) == (ans[0] - 1, ans[1]) + assert linprog(c, *ab, bounds={v.index(z): bounds[-1]} + ) == (ans[0] - 1, ans[1]) + eq = [z - y <= S.Half] + + assert linprog([[1]], [], [], bounds=(2, 3)) == (2, [2]) + assert linprog([1], [], [], bounds=(2, 3)) == (2, [2]) + assert linprog([1], bounds=(2, 3)) == (2, [2]) + assert linprog([1, -1], [[1, 1]], [2], bounds={1:(None, None)} + ) == (-2, [0, 2]) + assert linprog([1, -1], [[1, 1]], [5], bounds={1:(3, None)} + ) == (-5, [0, 5]) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_solvers.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_solvers.py new file mode 100644 index 0000000000000000000000000000000000000000..ac9550ad404c2ec7592caf6afd2910f425138987 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_solvers.py @@ -0,0 +1,2725 @@ +from sympy.assumptions.ask import (Q, ask) +from sympy.core.add import Add +from sympy.core.containers import Tuple +from sympy.core.function import (Derivative, Function, diff) +from sympy.core.mod import Mod +from sympy.core.mul import Mul +from sympy.core import (GoldenRatio, TribonacciConstant) +from sympy.core.numbers import (E, Float, I, Rational, oo, pi) +from sympy.core.relational import (Eq, Gt, Lt, Ne) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol, Wild, symbols) +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import binomial +from sympy.functions.elementary.complexes import (Abs, arg, conjugate, im, re) +from sympy.functions.elementary.exponential import (LambertW, exp, log) +from sympy.functions.elementary.hyperbolic import (atanh, cosh, sinh, tanh) +from sympy.functions.elementary.integers import floor +from sympy.functions.elementary.miscellaneous import (cbrt, root, sqrt) +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (acos, asin, atan, atan2, cos, sec, sin, tan) +from sympy.functions.special.error_functions import (erf, erfc, erfcinv, erfinv) +from sympy.integrals.integrals import Integral +from sympy.logic.boolalg import (And, Or) +from sympy.matrices.dense import Matrix +from sympy.matrices import MatrixSymbol, SparseMatrix +from sympy.polys.polytools import Poly, groebner +from sympy.printing.str import sstr +from sympy.simplify.radsimp import denom +from sympy.solvers.solvers import (nsolve, solve, solve_linear) + +from sympy.core.function import nfloat +from sympy.solvers import solve_linear_system, solve_linear_system_LU, \ + solve_undetermined_coeffs +from sympy.solvers.bivariate import _filtered_gens, _solve_lambert, _lambert +from sympy.solvers.solvers import _invert, unrad, checksol, posify, _ispow, \ + det_quick, det_perm, det_minor, _simple_dens, denoms + +from sympy.physics.units import cm +from sympy.polys.rootoftools import CRootOf + +from sympy.testing.pytest import slow, XFAIL, SKIP, raises +from sympy.core.random import verify_numerically as tn + +from sympy.abc import a, b, c, d, e, k, h, p, x, y, z, t, q, m, R + + +def NS(e, n=15, **options): + return sstr(sympify(e).evalf(n, **options), full_prec=True) + + +def test_swap_back(): + f, g = 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} + assert solve(fx + gx*x - 2, [fx, gx], dict=True) == [{fx: 2, gx: 0}] + assert solve(fx + gx**2*x - y, [fx, gx], dict=True) == [{fx: y, gx: 0}] + assert solve([f(1) - 2, x + 2], dict=True) == [{x: -2, f(1): 2}] + + +def guess_solve_strategy(eq, symbol): + try: + solve(eq, symbol) + return True + 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 + + +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 + + # polynomial equation multiplying both sides by x**n + 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 + + # 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 + + +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(a*x**b - y, x) # == GS_TRANSCENDENTAL + + +def test_solve_args(): + # equation container, issue 5113 + ans = {x: -3, y: 1} + eqs = (x + 5*y - 2, -3*x + 6*y - 15) + assert all(solve(container(eqs), x, y) == ans for container in + (tuple, list, set, frozenset)) + assert solve(Tuple(*eqs), x, y) == ans + # implicit symbol to solve for + assert set(solve(x**2 - 4)) == {S(2), -S(2)} + assert solve([x + y - 3, x - y - 5]) == {x: 4, y: -1} + assert solve(x - exp(x), x, implicit=True) == [exp(x)] + # no symbol to solve for + assert solve(42) == solve(42, x) == [] + assert solve([1, 2]) == [] + assert solve([sqrt(2)],[x]) == [] + # duplicate symbols raises + raises(ValueError, lambda: solve((x - 3, y + 2), x, y, x)) + raises(ValueError, lambda: solve(x, x, x)) + # no error in exclude + assert solve(x, x, exclude=[y, y]) == [0] + # duplicate symbols raises + raises(ValueError, lambda: solve((x - 3, y + 2), x, y, x)) + raises(ValueError, lambda: solve(x, x, x)) + # no error in exclude + assert solve(x, x, exclude=[y, y]) == [0] + # unordered symbols + # only 1 + assert solve(y - 3, {y}) == [3] + # more than 1 + assert solve(y - 3, {x, y}) == [{y: 3}] + # multiple symbols: take the first linear solution+ + # - return as tuple with values for all requested symbols + assert solve(x + y - 3, [x, y]) == [(3 - y, y)] + # - unless dict is True + assert solve(x + y - 3, [x, y], dict=True) == [{x: 3 - y}] + # - or no symbols are given + assert solve(x + y - 3) == [{x: 3 - y}] + # multiple symbols might represent an undetermined coefficients system + assert solve(a + b*x - 2, [a, b]) == {a: 2, b: 0} + assert solve((a + b)*x + b - c, [a, b]) == {a: -c, b: c} + eq = a*x**2 + b*x + c - ((x - h)**2 + 4*p*k)/4/p + # - check that flags are obeyed + sol = solve(eq, [h, p, k], exclude=[a, b, c]) + assert sol == {h: -b/(2*a), k: (4*a*c - b**2)/(4*a), p: 1/(4*a)} + assert solve(eq, [h, p, k], dict=True) == [sol] + assert solve(eq, [h, p, k], set=True) == \ + ([h, p, k], {(-b/(2*a), 1/(4*a), (4*a*c - b**2)/(4*a))}) + # issue 23889 - polysys not simplified + assert solve(eq, [h, p, k], exclude=[a, b, c], simplify=False) == \ + {h: -b/(2*a), k: (4*a*c - b**2)/(4*a), p: 1/(4*a)} + # but this only happens when system has a single solution + args = (a + b)*x - b**2 + 2, a, b + assert solve(*args) == [((b**2 - b*x - 2)/x, b)] + # and if the system has a solution; the following doesn't so + # an algebraic solution is returned + assert solve(a*x + b**2/(x + 4) - 3*x - 4/x, a, b, dict=True) == \ + [{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))) + # 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)}] + # -- when symbols given + assert solve([y, exp(x) + x], x, y) == [(-LambertW(1), 0)] + # symbol is a number + assert solve(x**2 - pi, pi) == [x**2] + # no equations + assert solve([], [x]) == [] + # nonlinear system + assert solve((x**2 - 4, y - 2), x, y) == [(-2, 2), (2, 2)] + assert solve((x**2 - 4, y - 2), y, x) == [(2, -2), (2, 2)] + assert solve((x**2 - 4 + z, y - 2 - z), a, z, y, x, set=True + ) == ([a, z, y, x], { + (a, z, z + 2, -sqrt(4 - z)), + (a, z, z + 2, sqrt(4 - z))}) + # overdetermined system + # - nonlinear + assert solve([(x + y)**2 - 4, x + y - 2]) == [{x: -y + 2}] + # - linear + assert solve((x + y - 2, 2*x + 2*y - 4)) == {x: -y + 2} + # When one or more args are Boolean + assert solve(Eq(x**2, 0.0)) == [0.0] # issue 19048 + assert solve([True, Eq(x, 0)], [x], dict=True) == [{x: 0}] + assert solve([Eq(x, x), Eq(x, 0), Eq(x, x+1)], [x], dict=True) == [] + assert not solve([Eq(x, x+1), x < 2], x) + assert solve([Eq(x, 0), x+1<2]) == Eq(x, 0) + assert solve([Eq(x, x), Eq(x, x+1)], x) == [] + assert solve(True, x) == [] + assert solve([x - 1, False], [x], set=True) == ([], set()) + assert solve([-y*(x + y - 1)/2, (y - 1)/x/y + 1/y], + set=True, check=False) == ([x, y], {(1 - y, y), (x, 0)}) + # ordering should be canonical, fastest to order by keys instead + # of by size + assert list(solve((y - 1, x - sqrt(3)*z)).keys()) == [x, y] + # as set always returns as symbols, set even if no solution + assert solve([x - 1, x], (y, x), set=True) == ([y, x], set()) + assert solve([x - 1, x], {y, x}, set=True) == ([x, y], set()) + + +def test_solve_polynomial1(): + 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)) == {-S.One, S.One} + assert set(solve(Eq(x**2, 1), x)) == {-S.One, S.One} + + assert solve(x - y**3, x) == [y**3] + rx = root(x, 3) + assert solve(x - y**3, y) == [ + rx, -rx/2 - sqrt(3)*I*rx/2, -rx/2 + sqrt(3)*I*rx/2] + 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), + } + + solution = {x: S.Zero, y: 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)) == { + -2 + 3**S.Half, + S(4), + -2 - 3**S.Half + } + + assert set(solve((x**2 - 1)**2 - a, x)) == \ + {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 + using the change of variable y -> x**Rational(p, q) + """ + 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] + + +def test_solve_polynomial_cv_1b(): + assert set(solve(4*x*(1 - a*sqrt(x)), x)) == {S.Zero, 1/a**2} + assert set(solve(x*(root(x, 3) - 3), x)) == {S.Zero, 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 \ + [[ S.Half + I*sqrt(3)/2, S.Half - I*sqrt(3)/2], + [ S.Half - I*sqrt(3)/2, S.Half + 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 r in s: + res = f.subs(x, r.n()).n() + assert tn(res, 0) + + f = x**5 - 15*x**3 - 5*x**2 + 10*x + 20 + s = solve(f) + for r in s: + assert r.func == CRootOf + + # if one uses solve to get the roots of a polynomial that has a CRootOf + # solution, make sure that the use of nfloat during the solve process + # doesn't fail. Note: if you want numerical solutions to a polynomial + # it is *much* faster to use nroots to get them than to solve the + # equation only to get RootOf solutions which are then numerically + # evaluated. So for eq = x**5 + 3*x + 7 do Poly(eq).nroots() rather + # than [i.n() for i in solve(eq)] to get the numerical roots of eq. + assert nfloat(solve(x**5 + 3*x**3 + 7)[0], exponent=False) == \ + CRootOf(x**5 + 3*x**3 + 7, 0).n() + + +def test_quintics_2(): + f = x**5 + 15*x + 12 + s = solve(f, check=False) + for r in s: + res = f.subs(x, r.n()).n() + assert tn(res, 0) + + f = x**5 - 15*x**3 - 5*x**2 + 10*x + 20 + s = solve(f) + for r in s: + assert r.func == CRootOf + + assert solve(x**5 - 6*x**3 - 6*x**2 + x - 6) == [ + CRootOf(x**5 - 6*x**3 - 6*x**2 + x - 6, 0), + CRootOf(x**5 - 6*x**3 - 6*x**2 + x - 6, 1), + CRootOf(x**5 - 6*x**3 - 6*x**2 + x - 6, 2), + CRootOf(x**5 - 6*x**3 - 6*x**2 + x - 6, 3), + CRootOf(x**5 - 6*x**3 - 6*x**2 + x - 6, 4)] + +def test_quintics_3(): + y = x**5 + x**3 - 2**Rational(1, 3) + assert solve(y) == solve(-y) == [] + + +def test_highorder_poly(): + # just testing that the uniq generator is unpacked + sol = solve(x**6 - 2*x + 2) + assert all(isinstance(i, CRootOf) for i in sol) and len(sol) == 6 + + +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_solve_conjugate(): + """Test solve for simple conjugate functions""" + assert solve(conjugate(x) -3 + I) == [3 + I] + + +def test_solve_nonlinear(): + assert solve(x**2 - y**2, x, y, dict=True) == [{x: -y}, {x: y}] + assert solve(x**2 - y**2/exp(x), y, x, dict=True) == [{y: -x*sqrt(exp(x))}, + {y: x*sqrt(exp(x))}] + + +def test_issue_8666(): + x = symbols('x') + assert solve(Eq(x**2 - 1/(x**2 - 4), 4 - 1/(x**2 - 4)), x) == [] + assert solve(Eq(x + 1/x, 1/x), x) == [] + + +def test_issue_7228(): + assert solve(4**(2*(x**2) + 2*x) - 8, x) == [Rational(-3, 2), S.Half] + + +def test_issue_7190(): + assert solve(log(x-3) + log(x+3), x) == [sqrt(10)] + + +def test_issue_21004(): + x = symbols('x') + f = x/sqrt(x**2+1) + f_diff = f.diff(x) + assert solve(f_diff, x) == [] + + +def test_issue_24650(): + x = symbols('x') + r = solve(Eq(Piecewise((x, Eq(x, 0) | (x > 1))), 0)) + assert r == [0] + r = checksol(Eq(Piecewise((x, Eq(x, 0) | (x > 1))), 0), x, sol=0) + assert r is True + + +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, 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], + [-1, 0, 1, 0, 0]]) + + assert solve_linear_system(M, x, y, z, t) == \ + {x: t*(-n-1)/n, y: 0, z: t*(-n-1)/n} + + assert solve([x + y + z + t, -z - t], x, y, z, t) == {x: -y, z: -t} + + +@XFAIL +def test_linear_system_xfail(): + # https://github.com/sympy/sympy/issues/6420 + M = Matrix([[0, 15.0, 10.0, 700.0], + [1, 1, 1, 100.0], + [0, 10.0, 5.0, 200.0], + [-5.0, 0, 0, 0 ]]) + + assert solve_linear_system(M, x, y, z) == {x: 0, y: -60.0, z: 160.0} + + +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_system_symbols_doesnt_hang_1(): + + def _mk_eqs(wy): + # Equations for fitting a wy*2 - 1 degree polynomial between two points, + # at end points derivatives are known up to order: wy - 1 + order = 2*wy - 1 + x, x0, x1 = symbols('x, x0, x1', real=True) + y0s = symbols('y0_:{}'.format(wy), real=True) + y1s = symbols('y1_:{}'.format(wy), real=True) + c = symbols('c_:{}'.format(order+1), real=True) + + expr = sum(coeff*x**o for o, coeff in enumerate(c)) + eqs = [] + for i in range(wy): + eqs.append(expr.diff(x, i).subs({x: x0}) - y0s[i]) + eqs.append(expr.diff(x, i).subs({x: x1}) - y1s[i]) + return eqs, c + + # + # The purpose of this test is just to see that these calls don't hang. The + # expressions returned are complicated so are not included here. Testing + # their correctness takes longer than solving the system. + # + + for n in range(1, 7+1): + eqs, c = _mk_eqs(n) + solve(eqs, c) + + +def test_linear_system_symbols_doesnt_hang_2(): + + M = Matrix([ + [66, 24, 39, 50, 88, 40, 37, 96, 16, 65, 31, 11, 37, 72, 16, 19, 55, 37, 28, 76], + [10, 93, 34, 98, 59, 44, 67, 74, 74, 94, 71, 61, 60, 23, 6, 2, 57, 8, 29, 78], + [19, 91, 57, 13, 64, 65, 24, 53, 77, 34, 85, 58, 87, 39, 39, 7, 36, 67, 91, 3], + [74, 70, 15, 53, 68, 43, 86, 83, 81, 72, 25, 46, 67, 17, 59, 25, 78, 39, 63, 6], + [69, 40, 67, 21, 67, 40, 17, 13, 93, 44, 46, 89, 62, 31, 30, 38, 18, 20, 12, 81], + [50, 22, 74, 76, 34, 45, 19, 76, 28, 28, 11, 99, 97, 82, 8, 46, 99, 57, 68, 35], + [58, 18, 45, 88, 10, 64, 9, 34, 90, 82, 17, 41, 43, 81, 45, 83, 22, 88, 24, 39], + [42, 21, 70, 68, 6, 33, 64, 81, 83, 15, 86, 75, 86, 17, 77, 34, 62, 72, 20, 24], + [ 7, 8, 2, 72, 71, 52, 96, 5, 32, 51, 31, 36, 79, 88, 25, 77, 29, 26, 33, 13], + [19, 31, 30, 85, 81, 39, 63, 28, 19, 12, 16, 49, 37, 66, 38, 13, 3, 71, 61, 51], + [29, 82, 80, 49, 26, 85, 1, 37, 2, 74, 54, 82, 26, 47, 54, 9, 35, 0, 99, 40], + [15, 49, 82, 91, 93, 57, 45, 25, 45, 97, 15, 98, 48, 52, 66, 24, 62, 54, 97, 37], + [62, 23, 73, 53, 52, 86, 28, 38, 0, 74, 92, 38, 97, 70, 71, 29, 26, 90, 67, 45], + [ 2, 32, 23, 24, 71, 37, 25, 71, 5, 41, 97, 65, 93, 13, 65, 45, 25, 88, 69, 50], + [40, 56, 1, 29, 79, 98, 79, 62, 37, 28, 45, 47, 3, 1, 32, 74, 98, 35, 84, 32], + [33, 15, 87, 79, 65, 9, 14, 63, 24, 19, 46, 28, 74, 20, 29, 96, 84, 91, 93, 1], + [97, 18, 12, 52, 1, 2, 50, 14, 52, 76, 19, 82, 41, 73, 51, 79, 13, 3, 82, 96], + [40, 28, 52, 10, 10, 71, 56, 78, 82, 5, 29, 48, 1, 26, 16, 18, 50, 76, 86, 52], + [38, 89, 83, 43, 29, 52, 90, 77, 57, 0, 67, 20, 81, 88, 48, 96, 88, 58, 14, 3]]) + + syms = x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18 = symbols('x:19') + + sol = { + x0: -S(1967374186044955317099186851240896179)/3166636564687820453598895768302256588, + x1: -S(84268280268757263347292368432053826)/791659141171955113399723942075564147, + x2: -S(229962957341664730974463872411844965)/1583318282343910226799447884151128294, + x3: S(990156781744251750886760432229180537)/6333273129375640907197791536604513176, + x4: -S(2169830351210066092046760299593096265)/18999819388126922721593374609813539528, + x5: S(4680868883477577389628494526618745355)/9499909694063461360796687304906769764, + x6: -S(1590820774344371990683178396480879213)/3166636564687820453598895768302256588, + x7: -S(54104723404825537735226491634383072)/339282489073695048599881689460956063, + x8: S(3182076494196560075964847771774733847)/6333273129375640907197791536604513176, + x9: -S(10870817431029210431989147852497539675)/18999819388126922721593374609813539528, + x10: -S(13118019242576506476316318268573312603)/18999819388126922721593374609813539528, + x11: -S(5173852969886775824855781403820641259)/4749954847031730680398343652453384882, + x12: S(4261112042731942783763341580651820563)/4749954847031730680398343652453384882, + x13: -S(821833082694661608993818117038209051)/6333273129375640907197791536604513176, + x14: S(906881575107250690508618713632090559)/904753304196520129599684505229216168, + x15: -S(732162528717458388995329317371283987)/6333273129375640907197791536604513176, + x16: S(4524215476705983545537087360959896817)/9499909694063461360796687304906769764, + x17: -S(3898571347562055611881270844646055217)/6333273129375640907197791536604513176, + x18: S(7513502486176995632751685137907442269)/18999819388126922721593374609813539528 + } + + eqs = list(M * Matrix(syms + (1,))) + assert solve(eqs, syms) == sol + + y = Symbol('y') + eqs = list(y * M * Matrix(syms + (1,))) + assert solve(eqs, syms) == sol + + +def test_linear_systemLU(): + n = Symbol('n') + + 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)} + +# 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 + +@slow +def test_solve_transcendental(): + from sympy.abc import a, b + + assert solve(exp(x) - 3, x) == [log(3)] + assert set(solve((a*x + b)*(exp(x) - 3), x)) == {-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) == [pi/4] + + assert set(solve(exp(x) + exp(-x) - y, x)) in [{ + log(y/2 - sqrt(y**2 - 4)/2), + log(y/2 + sqrt(y**2 - 4)/2), + }, { + log(y - sqrt(y**2 - 4)) - log(2), + log(y + sqrt(y**2 - 4)) - log(2)}, + { + 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(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)) == {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] + + eq = 2*(3*x + 4)**5 - 6*7**(3*x + 9) + result = solve(eq, x) + x0 = -log(2401) + x1 = 3**Rational(1, 5) + x2 = log(7**(7*x1/20)) + x3 = sqrt(2) + x4 = sqrt(5) + x5 = x3*sqrt(x4 - 5) + x6 = x4 + 1 + x7 = 1/(3*log(7)) + x8 = -x4 + x9 = x3*sqrt(x8 - 5) + x10 = x8 + 1 + ans = [x7*(x0 - 5*LambertW(x2*(-x5 + x6))), + x7*(x0 - 5*LambertW(x2*(x5 + x6))), + x7*(x0 - 5*LambertW(x2*(x10 - x9))), + x7*(x0 - 5*LambertW(x2*(x10 + x9))), + x7*(x0 - 5*LambertW(-log(7**(7*x1/5))))] + assert result == ans, result + # 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) == [ + pi - asin(acos(y/z)), asin(acos(y/z) - 2*pi) + pi, + -asin(acos(y/z) - 2*pi), asin(acos(y/z))] + + assert solve(z*cos(x), x) == [pi/2, pi*Rational(3, 2)] + + # issue 4508 + 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 4507 + assert solve(y - b/(1 + a*x), x) in [[(b - y)/(a*y)], [-((y - b)/(a*y))]] + # issue 4506 + assert solve(y - a*x**b, x) == [(y/a)**(1/b)] + # issue 4505 + assert solve(z**x - y, x) == [log(y)/log(z)] + # issue 4504 + assert solve(2**x - 10, x) == [1 + log(5)/log(2)] + # issue 6744 + 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 4739 + assert solve(exp(log(5)*x) - 2**x, x) == [0] + # issue 14791 + assert solve(exp(log(5)*x) - exp(log(2)*x), x) == [0] + f = Function('f') + assert solve(y*f(log(5)*x) - y*f(log(2)*x), x) == [0] + assert solve(f(x) - f(0), x) == [0] + assert solve(f(x) - f(2 - x), x) == [1] + raises(NotImplementedError, lambda: solve(f(x, y) - f(1, 2), x)) + raises(NotImplementedError, lambda: solve(f(x, y) - f(2 - x, 2), x)) + raises(ValueError, lambda: solve(f(x, y) - f(1 - x), x)) + raises(ValueError, lambda: solve(f(x, y) - f(1), x)) + + # misc + # make sure that the right variables is picked up in tsolve + # 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 + raises(NotImplementedError, lambda: + solve(sinh(x)*sinh(sinh(x)) + cosh(x)*cosh(sinh(x)) - 3)) + + # watch out for recursive loop in tsolve + raises(NotImplementedError, lambda: solve((x + 2)**y*x - 3, x)) + + # issue 7245 + assert solve(sin(sqrt(x))) == [0, pi**2] + + # issue 7602 + a, b = symbols('a, b', real=True, negative=False) + assert str(solve(Eq(a, 0.5 - cos(pi*b)/2), b)) == \ + '[2.0 - 0.318309886183791*acos(1.0 - 2.0*a), 0.318309886183791*acos(1.0 - 2.0*a)]' + + # issue 15325 + assert solve(y**(1/x) - z, x) == [log(y)/log(z)] + + # issue 25685 (basic trig identities should give simple solutions) + for yi in [cos(2*x),sin(2*x),cos(x - pi/3)]: + sol = solve([cos(x) - S(3)/5, yi - y]) + assert (sol[0][y] + sol[1][y]).is_Rational, (yi,sol) + # don't allow massive expansion + assert solve(cos(1000*x) - S.Half) == [pi/3000, pi/600] + assert solve(cos(x - 1000*y) - 1, x) == [1000*y, 1000*y + 2*pi] + assert solve(cos(x + y + z) - 1, x) == [-y - z, -y - z + 2*pi] + + # issue 26008 + assert solve(sin(x + pi/6)) == [-pi/6, 5*pi/6] + + +def test_solve_for_functions_derivatives(): + t = Symbol('t') + x = Function('x')(t) + y = Function('y')(t) + a11, a12, a21, a22, b1, b2 = symbols('a11,a12,a21,a22,b1,b2') + + 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), + } + + 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 solve(x.diff(t) - 1, x.diff(t)) == [1] + assert solve(3*x.diff(t) - 2, x.diff(t)) == [Rational(2, 3)] + + eqns = {3*x - 1, 2*y - 4} + assert solve(eqns, {x, y}) == { x: Rational(1, 3), y: 2 } + x = Symbol('x') + f = Function('f') + F = x**2 + f(x)**2 - 4*x - 1 + assert solve(F.diff(x), diff(f(x), x)) == [(-x + 2)/f(x)] + + # Mixed cased with a Symbol and a Function + x = Symbol('x') + y = Function('y')(t) + + 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) } + + # issue 13263 + x = Symbol('x') + f = Function('f') + soln = solve([f(x).diff(x) + f(x).diff(x, 2) - 1, f(x).diff(x) - f(x).diff(x, 2)], + f(x).diff(x), f(x).diff(x, 2)) + assert soln == { f(x).diff(x, 2): S(1)/2, f(x).diff(x): S(1)/2 } + + soln = solve([f(x).diff(x, 2) + f(x).diff(x, 3) - 1, 1 - f(x).diff(x, 2) - + f(x).diff(x, 3), 1 - f(x).diff(x,3)], f(x).diff(x, 2), f(x).diff(x, 3)) + assert soln == { f(x).diff(x, 2): 0, f(x).diff(x, 3): 1 } + + +def test_issue_3725(): + f = Function('f') + F = x**2 + f(x)**2 - 4*x - 1 + e = F.diff(x) + assert solve(e, f(x).diff(x)) in [[(2 - x)/f(x)], [-((x - 2)/f(x))]] + + +def test_solve_Matrix(): + # https://github.com/sympy/sympy/issues/3870 + 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: Rational(-1, 3), c: 2, d: -1} + assert solve([A*B - C], [a, b, c, d]) == {a: 1, b: Rational(-1, 3), c: 2, d: -1} + assert solve(Eq(A*B, C), [a, b, c, d]) == {a: 1, b: Rational(-1, 3), c: 2, d: -1} + + assert solve([A*B - B*A], [a, b, c, d]) == {a: d, b: Rational(-2, 3)*c} + assert solve([A*C - C*A], [a, b, c, d]) == {a: d - c, b: Rational(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: Rational(-2, 3)*c} + assert solve([Eq(A*C, C*A)], [a, b, c, d]) == {a: d - c, b: Rational(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} + + # https://github.com/sympy/sympy/issues/27854 + m, n = symbols("m n") + A = MatrixSymbol("A", m, n) + x = MatrixSymbol("x", n, 1) + b = MatrixSymbol('b', m, 1) + r = A * x - b + f = r.T * r + grad_f = f.diff(x) + raises(ValueError, lambda: solve(grad_f, x)) + + +def test_solve_linear(): + w = Wild('w') + assert solve_linear(x, x) == (0, 1) + assert solve_linear(x, exclude=[x]) == (0, 1) + assert solve_linear(x, symbols=[w]) == (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(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) + 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) + assert solve_linear((x + 1)*exp(x), symbols=[x]) == ((x + 1)*exp(x), 1) + assert solve_linear(x*exp(-x**2), symbols=[x]) == (x, 0) + assert solve_linear(0**x - 1) == (0**x - 1, 1) + assert solve_linear(1 + 1/(x - 1)) == (x, 0) + eq = y*cos(x)**2 + y*sin(x)**2 - y # = y*(1 - 1) = 0 + assert solve_linear(eq) == (0, 1) + eq = cos(x)**2 + sin(x)**2 # = 1 + assert solve_linear(eq) == (0, 1) + 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 + ) == {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) == {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) == \ + {a: -2, b: 2, c: -1} + # multivariate + X, Y, Z = y, x**y, y*x**y + eq = a*X + b*Y + c*Z - X - 2*Y - 3*Z + coeffs = a, b, c + syms = x, y + assert solve_undetermined_coeffs(eq, coeffs) == { + a: 1, b: 2, c: 3} + assert solve_undetermined_coeffs(eq, coeffs, syms) == { + a: 1, b: 2, c: 3} + assert solve_undetermined_coeffs(eq, coeffs, *syms) == { + a: 1, b: 2, c: 3} + # check output format + assert solve_undetermined_coeffs(a*x + a - 2, [a]) == [] + assert solve_undetermined_coeffs(a**2*x - 4*x, [a]) == [ + {a: -2}, {a: 2}] + assert solve_undetermined_coeffs(0, [a]) == [] + assert solve_undetermined_coeffs(0, [a], dict=True) == [] + assert solve_undetermined_coeffs(0, [a], set=True) == ([], {}) + assert solve_undetermined_coeffs(1, [a]) == [] + abeq = a*x - 2*x + b - 3 + s = {b, a} + assert solve_undetermined_coeffs(abeq, s, x) == {a: 2, b: 3} + assert solve_undetermined_coeffs(abeq, s, x, set=True) == ([a, b], {(2, 3)}) + assert solve_undetermined_coeffs(sin(a*x) - sin(2*x), (a,)) is None + assert solve_undetermined_coeffs(a*x + b*x - 2*x, (a, b)) == {a: 2 - b} + + +def test_solve_inequalities(): + x = Symbol('x') + sol = And(S.Zero < x, x < oo) + assert solve(x + 1 > 1) == sol + assert solve([x + 1 > 1]) == sol + assert solve([x + 1 > 1], x) == sol + assert solve([x + 1 > 1], [x]) == sol + + system = [Lt(x**2 - 2, 0), Gt(x**2 - 1, 0)] + assert solve(system) == \ + And(Or(And(Lt(-sqrt(2), x), Lt(x, -1)), + And(Lt(1, x), Lt(x, sqrt(2)))), Eq(0, 0)) + + x = Symbol('x', real=True) + system = [Lt(x**2 - 2, 0), Gt(x**2 - 1, 0)] + assert solve(system) == \ + Or(And(Lt(-sqrt(2), x), Lt(x, -1)), And(Lt(1, x), Lt(x, sqrt(2)))) + + # issues 6627, 3448 + assert solve((x - 3)/(x - 2) < 0, x) == And(Lt(2, x), Lt(x, 3)) + assert solve(x/(x + 1) > 1, x) == And(Lt(-oo, x), Lt(x, -1)) + + assert solve(sin(x) > S.Half) == And(pi/6 < x, x < pi*Rational(5, 6)) + + assert solve(Eq(False, x < 1)) == (S.One <= x) & (x < oo) + assert solve(Eq(True, x < 1)) == (-oo < x) & (x < 1) + assert solve(Eq(x < 1, False)) == (S.One <= x) & (x < oo) + assert solve(Eq(x < 1, True)) == (-oo < x) & (x < 1) + + assert solve(Eq(False, x)) == False + assert solve(Eq(0, x)) == [0] + assert solve(Eq(True, x)) == True + assert solve(Eq(1, x)) == [1] + assert solve(Eq(False, ~x)) == True + assert solve(Eq(True, ~x)) == False + assert solve(Ne(True, x)) == False + assert solve(Ne(1, x)) == (x > -oo) & (x < oo) & Ne(x, 1) + + +def test_issue_4793(): + assert solve(1/x) == [] + assert solve(x*(1 - 5/x)) == [5] + assert solve(x + sqrt(x) - 2) == [1] + 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(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]] + eq = 4*3**(5*x + 2) - 7 + ans = solve(eq, x) + assert len(ans) == 5 and all(eq.subs(x, a).n(chop=True) == 0 for a in ans) + assert solve(log(x**2) - y**2/exp(x), x, y, set=True) == ( + [x, y], + {(x, sqrt(exp(x) * log(x ** 2))), (x, -sqrt(exp(x) * log(x ** 2)))}) + 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(): + # issue 5171 + assert solve(sqrt(x)) == solve(sqrt(x**3)) == [0] + assert solve(sqrt(x - 1)) == [1] + # issue 4462 + a = Symbol('a') + assert solve(-3*a/sqrt(x), x) == [] + # issue 4486 + assert solve(2*x/(x + 2) - 1, x) == [2] + # issue 4496 + assert set(solve((x**2/(7 - x)).diff(x))) == {S.Zero, S(14)} + # issue 4695 + f = Function('f') + assert solve((3 - 5*x/f(x))*f(x), f(x)) == [x*Rational(5, 3)] + # issue 4497 + assert solve(1/root(5 + x, 5) - 9, x) == [Rational(-295244, 59049)] + + assert solve(sqrt(x) + sqrt(sqrt(x)) - 4) == [(Rational(-1, 2) + sqrt(17)/2)**4] + assert set(solve(Poly(sqrt(exp(x)) + sqrt(exp(-x)) - 4))) in \ + [ + {log((-sqrt(3) + 2)**2), log((sqrt(3) + 2)**2)}, + {2*log(-sqrt(3) + 2), 2*log(sqrt(3) + 2)}, + {log(-4*sqrt(3) + 7), log(4*sqrt(3) + 7)}, + ] + assert set(solve(Poly(exp(x) + exp(-x) - 4))) == \ + {log(-sqrt(3) + 2), log(sqrt(3) + 2)} + assert set(solve(x**y + x**(2*y) - 1, x)) == \ + {(Rational(-1, 2) + sqrt(5)/2)**(1/y), (Rational(-1, 2) - 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))]] + # 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 solve(exp(3*x) - exp(3), x) in [ + [1, log(E*(Rational(-1, 2) - sqrt(3)*I/2)), log(E*(Rational(-1, 2) + sqrt(3)*I/2))], + [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_5197(): + x = Symbol('x', real=True) + assert solve(x**2 + 1, x) == [] + n = Symbol('n', integer=True, positive=True) + 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 + # The solution following should not contain (-sqrt(2), sqrt(2)) + assert solve([(x + y), 2 - y**2], x, y) == [(sqrt(2), -sqrt(2))] + y = Symbol('y', positive=True) + # The solution following should not contain {y: -x*exp(x/2)} + assert solve(x**2 - y**2/exp(x), y, x, dict=True) == [{y: x*exp(x/2)}] + x, y, z = symbols('x y z', positive=True) + assert solve(z**2*x**2 - z**2*y**2/exp(x), y, x, z, dict=True) == [{y: x*exp(x/2)}] + + +def test_checking(): + assert set( + solve(x*(x - y/x), x, check=False)) == {sqrt(y), S.Zero, -sqrt(y)} + assert set(solve(x*(x - y/x), x, check=True)) == {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_4671_4463_4467(): + assert solve(sqrt(x**2 - 1) - 2) in ([sqrt(5), -sqrt(5)], + [-sqrt(5), sqrt(5)]) + assert solve((2**exp(y**2/x) + 2)/(x**2 + 15), y) == [ + -sqrt(x*log(1 + I*pi/log(2))), sqrt(x*log(1 + I*pi/log(2)))] + + C1, C2 = symbols('C1 C2') + f = Function('f') + assert solve(C1 + C2/x**2 - exp(-f(x)), f(x)) == [log(x**2/(C1*x**2 + C2))] + 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] + ) + 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))],) + 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 solve((a**2 + 1)*(sin(a*x) + cos(a*x)), x) == [-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)) == \ + {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_5132(): + r, t = symbols('r,t') + assert set(solve([r - x**2 - y**2, tan(t) - y/x], [x, y])) == \ + {( + -sqrt(r*cos(t)**2), -1*sqrt(r*cos(t)**2)*tan(t)), + (sqrt(r*cos(t)**2), sqrt(r*cos(t)**2)*tan(t))} + assert solve([exp(x) - sin(y), 1/y - 3], [x, y]) == \ + [(log(sin(Rational(1, 3))), Rational(1, 3))] + assert solve([exp(x) - sin(y), 1/exp(y) - 3], [x, y]) == \ + [(log(-sin(log(3))), -log(3))] + assert set(solve([exp(x) - sin(y), y**2 - 4], [x, y])) == \ + {(log(-sin(2)), -S(2)), (log(sin(2)), S(2))} + eqs = [exp(x)**2 - sin(y) + z**2, 1/exp(y) - 3] + assert solve(eqs, set=True) == \ + ([y, z], { + (-log(3), sqrt(-exp(2*x) - sin(log(3)))), + (-log(3), -sqrt(-exp(2*x) - sin(log(3))))}) + assert solve(eqs, x, z, set=True) == ( + [x, z], + {(x, sqrt(-exp(2*x) + sin(y))), (x, -sqrt(-exp(2*x) + sin(y)))}) + assert set(solve(eqs, x, y)) == \ + { + (log(-sqrt(-z**2 - sin(log(3)))), -log(3)), + (log(-z**2 - sin(log(3)))/2, -log(3))} + assert set(solve(eqs, y, z)) == \ + { + (-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) == ([y, z], { + (-log(3), -exp(2*x) - sin(log(3)))}) + assert solve(eqs, x, z, set=True) == ( + [x, z], {(x, -exp(2*x) + sin(y))}) + assert set(solve(eqs, x, y)) == { + (log(-sqrt(-z - sin(log(3)))), -log(3)), + (log(-z - sin(log(3)))/2, -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) == ( + [x, y], {(S.One, S(3)), (S(3), S.One)}) + assert set(solve((sqrt(x**2 + y**2) - sqrt(10), x + y - 4), x, y)) == \ + {(S.One, S(3)), (S(3), S.One)} + + +def test_issue_5335(): + lam, a0, conc = symbols('lam a0 conc') + a = 0.005 + b = 0.743436700916726 + eqs = [lam + 2*y - a0*(1 - x/2)*x - a*x/2*x, + a0*(1 - x/2)*x - 1*y - b*y, + x + y - conc] + sym = [x, y, a0] + # there are 4 solutions obtained manually but only two are valid + assert len(solve(eqs, sym, manual=True, minimal=True)) == 2 + assert len(solve(eqs, sym)) == 2 # cf below with rational=False + + +@SKIP("Hangs") +def _test_issue_5335_float(): + # gives ZeroDivisionError: polynomial division + lam, a0, conc = symbols('lam a0 conc') + a = 0.005 + b = 0.743436700916726 + eqs = [lam + 2*y - a0*(1 - x/2)*x - a*x/2*x, + a0*(1 - x/2)*x - 1*y - b*y, + x + y - conc] + sym = [x, y, a0] + assert len(solve(eqs, sym, rational=False)) == 2 + + +def test_issue_5767(): + assert set(solve([x**2 + y + 4], [x])) == \ + {(-sqrt(-y - 4),), (sqrt(-y - 4),)} + + +def _make_example_24609(): + D, R, H, B_g, V, D_c = symbols("D, R, H, B_g, V, D_c", real=True, positive=True) + Sigma_f, Sigma_a, nu = symbols("Sigma_f, Sigma_a, nu", real=True, positive=True) + x = symbols("x", real=True, positive=True) + eq = ( + 2**(S(2)/3)*pi**(S(2)/3)*D_c*(S(231361)/10000 + pi**2/x**2) + /(6*V**(S(2)/3)*x**(S(1)/3)) + - 2**(S(2)/3)*pi**(S(8)/3)*D_c/(2*V**(S(2)/3)*x**(S(7)/3)) + ) + expected = 100*sqrt(2)*pi/481 + return eq, expected, x + + +def test_issue_24609(): + # https://github.com/sympy/sympy/issues/24609 + eq, expected, x = _make_example_24609() + assert solve(eq, x, simplify=True) == [expected] + [solapprox] = solve(eq.n(), x) + assert abs(solapprox - expected.n()) < 1e-14 + + +@XFAIL +def test_issue_24609_xfail(): + # + # This returns 5 solutions when it should be 1 (with x positive). + # Simplification reveals all solutions to be equivalent. It is expected + # that solve without simplify=True returns duplicate solutions in some + # cases but the core of this equation is a simple quadratic that can easily + # be solved without introducing any redundant solutions: + # + # >>> print(factor_terms(eq.as_numer_denom()[0])) + # 2**(2/3)*pi**(2/3)*D_c*V**(2/3)*x**(7/3)*(231361*x**2 - 20000*pi**2) + # + eq, expected, x = _make_example_24609() + assert len(solve(eq, x)) == [expected] + # + # We do not want to pass this test just by using simplify so if the above + # passes then uncomment the additional test below: + # + # assert len(solve(eq, x, simplify=False)) == 1 + + +def test_polysys(): + assert set(solve([x**2 + 2/y - 2, x + y - 3], [x, y])) == \ + {(S.One, 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)) + + +@slow +def test_unrad1(): + raises(NotImplementedError, lambda: + unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) + 3)) + raises(NotImplementedError, lambda: + unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2*sqrt(y))) + + s = symbols('s', cls=Dummy) + + # checkers to deal with possibility of answer coming + # back with a sign change (cf issue 5203) + def check(rv, ans): + assert bool(rv[1]) == bool(ans[1]) + if ans[1]: + return s_check(rv, ans) + e = rv[0].expand() + a = ans[0].expand() + return e in [a, -a] and rv[1] == ans[1] + + def s_check(rv, ans): + # get the dummy + rv = list(rv) + d = rv[0].atoms(Dummy) + reps = list(zip(d, [s]*len(d))) + # replace s with this dummy + rv = (rv[0].subs(reps).expand(), [rv[1][0].subs(reps), rv[1][1].subs(reps)]) + ans = (ans[0].subs(reps).expand(), [ans[1][0].subs(reps), ans[1][1].subs(reps)]) + return str(rv[0]) in [str(ans[0]), str(-ans[0])] and \ + str(rv[1]) == str(ans[1]) + + assert unrad(1) is None + assert check(unrad(sqrt(x)), + (x, [])) + assert check(unrad(sqrt(x) + 1), + (x - 1, [])) + assert check(unrad(sqrt(x) + root(x, 3) + 2), + (s**3 + s**2 + 2, [s, s**6 - x])) + assert check(unrad(sqrt(x)*root(x, 3) + 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), + (16*x - 9, [])) + assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - x)), + (5*x**2 - 4*x, [])) + assert check(unrad(a*sqrt(x) + b*sqrt(x) + c*sqrt(y) + d*sqrt(y)), + ((a*sqrt(x) + b*sqrt(x))**2 - (c*sqrt(y) + d*sqrt(y))**2, [])) + assert check(unrad(sqrt(x) + sqrt(1 - x)), + (2*x - 1, [])) + assert check(unrad(sqrt(x) + sqrt(1 - x) - 3), + (x**2 - x + 16, [])) + assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x)), + (5*x**2 - 2*x + 1, [])) + assert unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - 3) in [ + (25*x**4 + 376*x**3 + 1256*x**2 - 2272*x + 784, []), + (25*x**8 - 476*x**6 + 2534*x**4 - 1468*x**2 + 169, [])] + assert unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - sqrt(1 - 2*x)) == \ + (41*x**4 + 40*x**3 + 232*x**2 - 160*x + 16, []) # orig root at 0.487 + assert check(unrad(sqrt(x) + sqrt(x + 1)), (S.One, [])) + + eq = sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) + assert check(unrad(eq), + (16*x**2 - 9*x, [])) + assert set(solve(eq, check=False)) == {S.Zero, Rational(9, 16)} + assert solve(eq) == [] + # but this one really does have those solutions + assert set(solve(sqrt(x) - sqrt(x + 1) + sqrt(1 - sqrt(x)))) == \ + {S.Zero, Rational(9, 16)} + + assert check(unrad(sqrt(x) + root(x + 1, 3) + 2*sqrt(y), y), + (S('2*sqrt(x)*(x + 1)**(1/3) + x - 4*y + (x + 1)**(2/3)'), [])) + assert check(unrad(sqrt(x/(1 - x)) + (x + 1)**Rational(1, 3)), + (x**5 - x**4 - x**3 + 2*x**2 + x - 1, [])) + assert check(unrad(sqrt(x/(1 - x)) + 2*sqrt(y), y), + (4*x*y + x - 4*y, [])) + assert check(unrad(sqrt(x)*sqrt(1 - x) + 2, x), + (x**2 - x + 4, [])) + + # http://tutorial.math.lamar.edu/ + # Classes/Alg/SolveRadicalEqns.aspx#Solve_Rad_Ex2_a + assert solve(Eq(x, sqrt(x + 6))) == [3] + assert solve(Eq(x + sqrt(x - 4), 4)) == [4] + assert solve(Eq(1, x + sqrt(2*x - 3))) == [] + assert set(solve(Eq(sqrt(5*x + 6) - 2, x))) == {-S.One, S(2)} + assert set(solve(Eq(sqrt(2*x - 1) - sqrt(x - 4), 2))) == {S(5), S(13)} + assert solve(Eq(sqrt(x + 7) + 2, sqrt(3 - x))) == [-6] + # http://www.purplemath.com/modules/solverad.htm + assert solve((2*x - 5)**Rational(1, 3) - 3) == [16] + assert set(solve(x + 1 - root(x**4 + 4*x**3 - x, 4))) == \ + {Rational(-1, 2), Rational(-1, 3)} + assert set(solve(sqrt(2*x**2 - 7) - (3 - x))) == {-S(8), S(2)} + assert solve(sqrt(2*x + 9) - sqrt(x + 1) - sqrt(x + 4)) == [0] + assert solve(sqrt(x + 4) + sqrt(2*x - 1) - 3*sqrt(x - 1)) == [5] + assert solve(sqrt(x)*sqrt(x - 7) - 12) == [16] + assert solve(sqrt(x - 3) + sqrt(x) - 3) == [4] + assert solve(sqrt(9*x**2 + 4) - (3*x + 2)) == [0] + assert solve(sqrt(x) - 2 - 5) == [49] + assert solve(sqrt(x - 3) - sqrt(x) - 3) == [] + assert solve(sqrt(x - 1) - x + 7) == [10] + assert solve(sqrt(x - 2) - 5) == [27] + 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 expression in unrad and do use _mexpand + z = sqrt(2*x + 1)/sqrt(x) - sqrt(2 + 1/x) + p = posify(z)[0] + assert solve(p) == [] + assert solve(z) == [] + assert solve(z + 6*I) == [Rational(-1, 11)] + assert solve(p + 6*I) == [] + # issue 8622 + assert unrad(root(x + 1, 5) - root(x, 3)) == ( + -(x**5 - x**3 - 3*x**2 - 3*x - 1), []) + # issue #8679 + assert check(unrad(x + root(x, 3) + root(x, 3)**2 + sqrt(y), x), + (s**3 + s**2 + s + sqrt(y), [s, s**3 - x])) + + # for coverage + assert check(unrad(sqrt(x) + root(x, 3) + y), + (s**3 + s**2 + y, [s, s**6 - x])) + assert solve(sqrt(x) + root(x, 3) - 2) == [1] + raises(NotImplementedError, lambda: + solve(sqrt(x) + root(x, 3) + root(x + 1, 5) - 2)) + # fails through a different code path + raises(NotImplementedError, lambda: solve(-sqrt(2) + cosh(x)/x)) + # unrad some + assert solve(sqrt(x + root(x, 3))+root(x - y, 5), y) == [ + x + (x**Rational(1, 3) + x)**Rational(5, 2)] + assert check(unrad(sqrt(x) - root(x + 1, 3)*sqrt(x + 2) + 2), + (s**10 + 8*s**8 + 24*s**6 - 12*s**5 - 22*s**4 - 160*s**3 - 212*s**2 - + 192*s - 56, [s, s**2 - x])) + e = root(x + 1, 3) + root(x, 3) + assert unrad(e) == (2*x + 1, []) + eq = (sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) + assert check(unrad(eq), + (15625*x**4 + 173000*x**3 + 355600*x**2 - 817920*x + 331776, [])) + assert check(unrad(root(x, 4) + root(x, 4)**3 - 1), + (s**3 + s - 1, [s, s**4 - x])) + assert check(unrad(root(x, 2) + root(x, 2)**3 - 1), + (x**3 + 2*x**2 + x - 1, [])) + assert unrad(x**0.5) is None + assert check(unrad(t + root(x + y, 5) + root(x + y, 5)**3), + (s**3 + s + t, [s, s**5 - x - y])) + assert check(unrad(x + root(x + y, 5) + root(x + y, 5)**3, y), + (s**3 + s + x, [s, s**5 - x - y])) + assert check(unrad(x + root(x + y, 5) + root(x + y, 5)**3, x), + (s**5 + s**3 + s - y, [s, s**5 - x - y])) + assert check(unrad(root(x - 1, 3) + root(x + 1, 5) + root(2, 5)), + (s**5 + 5*2**Rational(1, 5)*s**4 + s**3 + 10*2**Rational(2, 5)*s**3 + + 10*2**Rational(3, 5)*s**2 + 5*2**Rational(4, 5)*s + 4, [s, s**3 - x + 1])) + raises(NotImplementedError, lambda: + unrad((root(x, 2) + root(x, 3) + root(x, 4)).subs(x, x**5 - x + 1))) + + # the simplify flag should be reset to False for unrad results; + # if it's not then this next test will take a long time + assert solve(root(x, 3) + root(x, 5) - 2) == [1] + eq = (sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) + assert check(unrad(eq), + ((5*x - 4)*(3125*x**3 + 37100*x**2 + 100800*x - 82944), [])) + ans = S(''' + [4/5, -1484/375 + 172564/(140625*(114*sqrt(12657)/78125 + + 12459439/52734375)**(1/3)) + + 4*(114*sqrt(12657)/78125 + 12459439/52734375)**(1/3)]''') + assert solve(eq) == ans + # duplicate radical handling + assert check(unrad(sqrt(x + root(x + 1, 3)) - root(x + 1, 3) - 2), + (s**3 - s**2 - 3*s - 5, [s, s**3 - x - 1])) + # cov post-processing + e = root(x**2 + 1, 3) - root(x**2 - 1, 5) - 2 + assert check(unrad(e), + (s**5 - 10*s**4 + 39*s**3 - 80*s**2 + 80*s - 30, + [s, s**3 - x**2 - 1])) + + e = sqrt(x + root(x + 1, 2)) - root(x + 1, 3) - 2 + assert check(unrad(e), + (s**6 - 2*s**5 - 7*s**4 - 3*s**3 + 26*s**2 + 40*s + 25, + [s, s**3 - x - 1])) + assert check(unrad(e, _reverse=True), + (s**6 - 14*s**5 + 73*s**4 - 187*s**3 + 276*s**2 - 228*s + 89, + [s, s**2 - x - sqrt(x + 1)])) + # this one needs r0, r1 reversal to work + assert check(unrad(sqrt(x + sqrt(root(x, 3) - 1)) - root(x, 6) - 2), + (s**12 - 2*s**8 - 8*s**7 - 8*s**6 + s**4 + 8*s**3 + 23*s**2 + + 32*s + 17, [s, s**6 - x])) + + # why does this pass + assert unrad(root(cosh(x), 3)/x*root(x + 1, 5) - 1) == ( + -(x**15 - x**3*cosh(x)**5 - 3*x**2*cosh(x)**5 - 3*x*cosh(x)**5 + - cosh(x)**5), []) + # and this fail? + #assert unrad(sqrt(cosh(x)/x) + root(x + 1, 3)*sqrt(x) - 1) == ( + # -s**6 + 6*s**5 - 15*s**4 + 20*s**3 - 15*s**2 + 6*s + x**5 + + # 2*x**4 + x**3 - 1, [s, s**2 - cosh(x)/x]) + + # watch for symbols in exponents + assert unrad(S('(x+y)**(2*y/3) + (x+y)**(1/3) + 1')) is None + assert check(unrad(S('(x+y)**(2*y/3) + (x+y)**(1/3) + 1'), x), + (s**(2*y) + s + 1, [s, s**3 - x - y])) + # should _Q be so lenient? + assert unrad(x**(S.Half/y) + y, x) == (x**(1/y) - y**2, []) + + # This tests two things: that if full unrad is attempted and fails + # the solution should still be found; also it tests that the use of + # composite + assert len(solve(sqrt(y)*x + x**3 - 1, x)) == 3 + assert len(solve(-512*y**3 + 1344*(x + 2)**Rational(1, 3)*y**2 - + 1176*(x + 2)**Rational(2, 3)*y - 169*x + 686, y, _unrad=False)) == 3 + + # watch out for when the cov doesn't involve the symbol of interest + eq = S('-x + (7*y/8 - (27*x/2 + 27*sqrt(x**2)/2)**(1/3)/3)**3 - 1') + assert solve(eq, y) == [ + 2**(S(2)/3)*(27*x + 27*sqrt(x**2))**(S(1)/3)*S(4)/21 + (512*x/343 + + S(512)/343)**(S(1)/3)*(-S(1)/2 - sqrt(3)*I/2), 2**(S(2)/3)*(27*x + + 27*sqrt(x**2))**(S(1)/3)*S(4)/21 + (512*x/343 + + S(512)/343)**(S(1)/3)*(-S(1)/2 + sqrt(3)*I/2), 2**(S(2)/3)*(27*x + + 27*sqrt(x**2))**(S(1)/3)*S(4)/21 + (512*x/343 + S(512)/343)**(S(1)/3)] + + eq = root(x + 1, 3) - (root(x, 3) + root(x, 5)) + assert check(unrad(eq), + (3*s**13 + 3*s**11 + s**9 - 1, [s, s**15 - x])) + assert check(unrad(eq - 2), + (3*s**13 + 3*s**11 + 6*s**10 + s**9 + 12*s**8 + 6*s**6 + 12*s**5 + + 12*s**3 + 7, [s, s**15 - x])) + assert check(unrad(root(x, 3) - root(x + 1, 4)/2 + root(x + 2, 3)), + (s*(4096*s**9 + 960*s**8 + 48*s**7 - s**6 - 1728), + [s, s**4 - x - 1])) # orig expr has two real roots: -1, -.389 + assert check(unrad(root(x, 3) + root(x + 1, 4) - root(x + 2, 3)/2), + (343*s**13 + 2904*s**12 + 1344*s**11 + 512*s**10 - 1323*s**9 - + 3024*s**8 - 1728*s**7 + 1701*s**5 + 216*s**4 - 729*s, [s, s**4 - x - + 1])) # orig expr has one real root: -0.048 + assert check(unrad(root(x, 3)/2 - root(x + 1, 4) + root(x + 2, 3)), + (729*s**13 - 216*s**12 + 1728*s**11 - 512*s**10 + 1701*s**9 - + 3024*s**8 + 1344*s**7 + 1323*s**5 - 2904*s**4 + 343*s, [s, s**4 - x - + 1])) # orig expr has 2 real roots: -0.91, -0.15 + assert check(unrad(root(x, 3)/2 - root(x + 1, 4) + root(x + 2, 3) - 2), + (729*s**13 + 1242*s**12 + 18496*s**10 + 129701*s**9 + 388602*s**8 + + 453312*s**7 - 612864*s**6 - 3337173*s**5 - 6332418*s**4 - 7134912*s**3 + - 5064768*s**2 - 2111913*s - 398034, [s, s**4 - x - 1])) + # orig expr has 1 real root: 19.53 + + 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 + # https://github.com/sympy/sympy/issues/4793#issuecomment-36994519 + F = Symbol('F') + eq = F - (2*x + 2*y + sqrt(x**2 + y**2)) + ans = F*Rational(2, 7) - sqrt(2)*F/14 + X = solve(eq, x, check=False) + for xi in reversed(X): # reverse since currently, ans is the 2nd one + Y = solve((x*y).subs(x, xi).diff(y), y, simplify=False, check=False) + if any((a - ans).expand().is_zero for a in Y): + break + else: + assert None # no answer was found + assert solve(sqrt(x + 1) + root(x, 3) - 2) == S(''' + [(-11/(9*(47/54 + sqrt(93)/6)**(1/3)) + 1/3 + (47/54 + + sqrt(93)/6)**(1/3))**3]''') + assert solve(sqrt(sqrt(x + 1)) + x**Rational(1, 3) - 2) == S(''' + [(-sqrt(-2*(-1/16 + sqrt(6913)/16)**(1/3) + 6/(-1/16 + + sqrt(6913)/16)**(1/3) + 17/2 + 121/(4*sqrt(-6/(-1/16 + + sqrt(6913)/16)**(1/3) + 2*(-1/16 + sqrt(6913)/16)**(1/3) + 17/4)))/2 + + sqrt(-6/(-1/16 + sqrt(6913)/16)**(1/3) + 2*(-1/16 + + sqrt(6913)/16)**(1/3) + 17/4)/2 + 9/4)**3]''') + assert solve(sqrt(x) + root(sqrt(x) + 1, 3) - 2) == S(''' + [(-(81/2 + 3*sqrt(741)/2)**(1/3)/3 + (81/2 + 3*sqrt(741)/2)**(-1/3) + + 2)**2]''') + 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))''') + assert check(unrad(eq), + (s*-(-s**6 + sqrt(3)*s**6*I - 153*2**Rational(2, 3)*3**Rational(1, 3)*s**4 + + 51*12**Rational(1, 3)*s**4 - 102*2**Rational(2, 3)*3**Rational(5, 6)*s**4*I - 1620*s**3 + + 1620*sqrt(3)*s**3*I + 13872*18**Rational(1, 3)*s**2 - 471648 + + 471648*sqrt(3)*I), [s, s**3 - 306*x - sqrt(3)*sqrt(31212*x**2 - + 165240*x + 61484) + 810])) + + assert solve(eq) == [] # not other code errors + eq = root(x, 3) - root(y, 3) + root(x, 5) + assert check(unrad(eq), + (s**15 + 3*s**13 + 3*s**11 + s**9 - y, [s, s**15 - x])) + eq = root(x, 3) + root(y, 3) + root(x*y, 4) + assert check(unrad(eq), + (s*y*(-s**12 - 3*s**11*y - 3*s**10*y**2 - s**9*y**3 - + 3*s**8*y**2 + 21*s**7*y**3 - 3*s**6*y**4 - 3*s**4*y**4 - + 3*s**3*y**5 - y**6), [s, s**4 - x*y])) + raises(NotImplementedError, + lambda: unrad(root(x, 3) + root(y, 3) + root(x*y, 5))) + + # Test unrad with an Equality + eq = Eq(-x**(S(1)/5) + x**(S(1)/3), -3**(S(1)/3) - (-1)**(S(3)/5)*3**(S(1)/5)) + assert check(unrad(eq), + (-s**5 + s**3 - 3**(S(1)/3) - (-1)**(S(3)/5)*3**(S(1)/5), [s, s**15 - x])) + + # make sure buried radicals are exposed + s = sqrt(x) - 1 + assert unrad(s**2 - s**3) == (x**3 - 6*x**2 + 9*x - 4, []) + # make sure numerators which are already polynomial are rejected + assert unrad((x/(x + 1) + 3)**(-2), x) is None + + # https://github.com/sympy/sympy/issues/23707 + eq = sqrt(x - y)*exp(t*sqrt(x - y)) - exp(t*sqrt(x - y)) + assert solve(eq, y) == [x - 1] + assert unrad(eq) is None + + +@slow +def test_unrad_slow(): + # this has roots with multiplicity > 1; there should be no + # repeats in roots obtained, however + eq = (sqrt(1 + sqrt(1 - 4*x**2)) - x*(1 + sqrt(1 + 2*sqrt(1 - 4*x**2)))) + assert solve(eq) == [S.Half] + + +@XFAIL +def test_unrad_fail(): + # this only works if we check real_root(eq.subs(x, Rational(1, 3))) + # but checksol doesn't work like that + assert solve(root(x**3 - 3*x**2, 3) + 1 - x) == [Rational(1, 3)] + assert solve(root(x + 1, 3) + root(x**2 - 2, 5) + 1) == [ + -1, -1 + CRootOf(x**5 + x**4 + 5*x**3 + 8*x**2 + 10*x + 5, 0)**3] + + +def test_checksol(): + x, y, r, t = symbols('x, y, r, t') + eq = r - x**2 - y**2 + dict_var_soln = {y: - sqrt(r) / sqrt(tan(t)**2 + 1), + x: -sqrt(r)*tan(t)/sqrt(tan(t)**2 + 1)} + assert checksol(eq, dict_var_soln) == True + assert checksol(Eq(x, False), {x: False}) is True + assert checksol(Ne(x, False), {x: False}) is False + assert checksol(Eq(x < 1, True), {x: 0}) is True + assert checksol(Eq(x < 1, True), {x: 1}) is False + assert checksol(Eq(x < 1, False), {x: 1}) is True + assert checksol(Eq(x < 1, False), {x: 0}) is False + assert checksol(Eq(x + 1, x**2 + 1), {x: 1}) is True + assert checksol([x - 1, x**2 - 1], x, 1) is True + assert checksol([x - 1, x**2 - 2], x, 1) is False + assert checksol(Poly(x**2 - 1), x, 1) is True + assert checksol(0, {}) is True + assert checksol([1e-10, x - 2], x, 2) is False + assert checksol([0.5, 0, x], x, 0) is False + assert checksol(y, x, 2) is False + assert checksol(x+1e-10, x, 0, numerical=True) is True + assert checksol(x+1e-10, x, 0, numerical=False) is False + assert checksol(exp(92*x), {x: log(sqrt(2)/2)}) is False + assert checksol(exp(92*x), {x: log(sqrt(2)/2) + I*pi}) is False + assert checksol(1/x**5, x, 1000) is False + raises(ValueError, lambda: checksol(x, 1)) + raises(ValueError, lambda: checksol([], x, 1)) + + +def test__invert(): + assert _invert(x - 2) == (2, x) + assert _invert(2) == (2, 0) + assert _invert(exp(1/x) - 3, x) == (1/log(3), x) + assert _invert(exp(1/x + a/x) - 3, x) == ((a + 1)/log(3), x) + assert _invert(a, x) == (a, 0) + + +def test_issue_4463(): + assert solve(-a*x + 2*x*log(x), x) == [exp(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] + +@slow +def test_issue_5114_solvers(): + a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r = symbols('a:r') + + # there is no 'a' in the equation set but this is how the + # problem was originally posed + 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] + assert len(solve(eqs, syms, manual=True, check=False, simplify=False)) == 1 + + +def test_issue_5849(): + # + # XXX: This system does not have a solution for most values of the + # parameters. Generally solve returns the empty set for systems that are + # generically inconsistent. + # + 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 + ) + + ans = [{ + I1: I2 + I3, + dI1: -4*I2 - 8*I3 - 4*I5 - 6*I6 + 24, + I4: I3 - I5, + dQ4: I3 - I5, + Q4: -I3/2 + 3*I5/2 - dI4/2, + dQ2: I2, + Q2: 2*I3 + 2*I5 + 3*I6}] + + v = I1, I4, Q2, Q4, dI1, dI4, dQ2, dQ4 + assert solve(e, *v, manual=True, check=False, dict=True) == ans + assert solve(e, *v, manual=True, check=False) == [ + tuple([a.get(i, i) for i in v]) for a in ans] + assert solve(e, *v, manual=True) == [] + assert solve(e, *v) == [] + + # the matrix solver (tested below) doesn't like this because it produces + # a zero row in the matrix. Is this related to issue 4551? + assert [ei.subs( + ans[0]) for ei in e] == [0, 0, I3 - I6, -I3 + I6, 0, 0, 0, 0, 0] + + +def test_issue_5849_matrix(): + '''Same as test_issue_5849 but solved with the matrix solver. + + A solution only exists if I3 == I6 which is not generically true, + but `solve` does not return conditions under which the solution is + valid, only a solution that is canonical and consistent with the input. + ''' + # a simple example with the same issue + # assert solve([x+y+z, x+y], [x, y]) == {x: y} + # the longer example + 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 + ) + assert solve(e, I1, I4, Q2, Q4, dI1, dI4, dQ2, dQ4) == [] + + +def test_issue_21882(): + + a, b, c, d, f, g, k = unknowns = symbols('a, b, c, d, f, g, k') + + equations = [ + -k*a + b + 5*f/6 + 2*c/9 + 5*d/6 + 4*a/3, + -k*f + 4*f/3 + d/2, + -k*d + f/6 + d, + 13*b/18 + 13*c/18 + 13*a/18, + -k*c + b/2 + 20*c/9 + a, + -k*b + b + c/18 + a/6, + 5*b/3 + c/3 + a, + 2*b/3 + 2*c + 4*a/3, + -g, + ] + + answer = [ + {a: 0, f: 0, b: 0, d: 0, c: 0, g: 0}, + {a: 0, f: -d, b: 0, k: S(5)/6, c: 0, g: 0}, + {a: -2*c, f: 0, b: c, d: 0, k: S(13)/18, g: 0}] + # but not {a: 0, f: 0, b: 0, k: S(3)/2, c: 0, d: 0, g: 0} + # since this is already covered by the first solution + got = solve(equations, unknowns, dict=True) + assert got == answer, (got,answer) + + +def test_issue_5901(): + f, g, h = map(Function, 'fgh') + a = Symbol('a') + D = Derivative(f(x), x) + G = Derivative(g(a), a) + assert solve(f(x) + f(x).diff(x), f(x)) == \ + [-D] + assert solve(f(x) - 3, f(x)) == \ + [3] + assert solve(f(x) - 3*f(x).diff(x), f(x)) == \ + [3*D] + assert solve([f(x) - 3*f(x).diff(x)], f(x)) == \ + {f(x): 3*D} + assert solve([f(x) - 3*f(x).diff(x), f(x)**2 - y + 4], f(x), y) == \ + [(3*D, 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)], { + (-sqrt(f(a)**2*g(a)**2 - G)/f(a), g(a)), + (sqrt(f(a)**2*g(a)**2 - G)/f(a), g(a))}), solve(-f(a)**2*g(a)**2 + f(a)**2*h(a)**2 + g(a).diff(a), + h(a), g(a), set=True) + args = [[f(x).diff(x, 2)*(f(x) + g(x)), 2 - g(x)**2], f(x), g(x)] + assert solve(*args, set=True)[1] == \ + {(-sqrt(2), sqrt(2)), (sqrt(2), -sqrt(2))} + eqs = [f(x)**2 + g(x) - 2*f(x).diff(x), g(x)**2 - 4] + assert solve(eqs, f(x), g(x), set=True) == \ + ([f(x), g(x)], { + (-sqrt(2*D - 2), S(2)), + (sqrt(2*D - 2), S(2)), + (-sqrt(2*D + 2), -S(2)), + (sqrt(2*D + 2), -S(2))}) + + # the underlying problem was in solve_linear that was not masking off + # 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)])) + 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]) == \ + (f(x) + Integral(x, (x, y)), 1) + assert solve_linear(f(x) + Integral(x, (x, y)) + x, symbols=[x]) == \ + (x + f(x) + Integral(x, (x, y)), 1) + assert solve_linear(f(y) + Integral(x, (x, y)) + x, symbols=[x]) == \ + (x, -f(y) - Integral(x, (x, y))) + assert solve_linear(x - f(x)/a + (f(x) - 1)/a, symbols=[x]) == \ + (x, 1/a) + assert solve_linear(x + Derivative(2*x, x)) == \ + (x, -2) + assert solve_linear(x + Integral(x, y), symbols=[x]) == \ + (x, 0) + assert solve_linear(x + Integral(x, y) - 2, symbols=[x]) == \ + (x, 2/(y + 1)) + + assert set(solve(x + exp(x)**2, exp(x))) == \ + {-sqrt(-x), sqrt(-x)} + assert solve(x + exp(x), x, implicit=True) == \ + [-exp(x)] + assert solve(cos(x) - sin(x), x, implicit=True) == [] + assert solve(x - sin(x), x, implicit=True) == \ + [sin(x)] + assert solve(x**2 + x - 3, x, implicit=True) == \ + [-x**2 + 3] + assert solve(x**2 + x - 3, x**2, implicit=True) == \ + [-x + 3] + + +def test_issue_5912(): + assert set(solve(x**2 - x - 0.1, rational=True)) == \ + {S.Half + sqrt(35)/10, -sqrt(35)/10 + S.Half} + ans = solve(x**2 - x - 0.1, rational=False) + assert len(ans) == 2 and all(a.is_Number for a in ans) + 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)) + assert solve(x - 0.5, rational=True)[0].is_Rational + assert solve(x - 0.5, rational=False)[0].is_Float + assert solve(x - S.Half, rational=False)[0].is_Rational + assert solve(x - 0.5, rational=None)[0].is_Float + assert solve(x - S.Half, rational=None)[0].is_Rational + assert test(nfloat(1 + 2*x), 1.0 + 2.0*x) + for contain in [list, tuple, set]: + ans = nfloat(contain([1 + 2*x])) + assert type(ans) is contain and test(list(ans)[0], 1.0 + 2.0*x) + k, v = list(nfloat({2*x: [1 + 2*x]}).items())[0] + assert test(k, 2*x) and test(v[0], 1.0 + 2.0*x) + assert test(nfloat(cos(2*x)), cos(2.0*x)) + assert test(nfloat(3*x**2), 3.0*x**2) + assert test(nfloat(3*x**2, exponent=True), 3.0*x**2.0) + assert test(nfloat(exp(2*x)), exp(2.0*x)) + assert test(nfloat(x/3), x/3.0) + assert test(nfloat(x**4 + 2*x + cos(Rational(1, 3)) + 1), + x**4 + 2.0*x + 1.94495694631474) + # don't call nfloat if there is no solution + 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=True) + assert solve(x**2 - 1) == [1] + + +def test_issue_6056(): + assert solve(tanh(x + 3)*tanh(x - 3) - 1) == [] + assert solve(tanh(x - 1)*tanh(x + 1) + 1) == \ + [I*pi*Rational(-3, 4), -I*pi/4, I*pi/4, I*pi*Rational(3, 4)] + assert solve((tanh(x + 3)*tanh(x - 3) + 1)**2) == \ + [I*pi*Rational(-3, 4), -I*pi/4, I*pi/4, I*pi*Rational(3, 4)] + + +def test_issue_5673(): + eq = -x + exp(exp(LambertW(log(x)))*LambertW(log(x))) + 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 + 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: 2*Vplus + Vplus/(C*R*s), + Vout: C*R*Vplus*s + 3*Vplus + Vplus/(C*R*s)}, + { + Vplus: 0, + Vminus: 0, + V1: 0, + Vout: 0}, + ] + + # TODO: Investigate why currently solution [0] is preferred over [1]. + assert solve(eqs, exclude=[Vplus, s, C]) in [[{ + Vminus: Vplus, + V1: Vout/2 + Vplus/2 + sqrt((Vout - 5*Vplus)*(Vout - Vplus))/2, + R: (Vout - 3*Vplus - sqrt(Vout**2 - 6*Vout*Vplus + 5*Vplus**2))/(2*C*Vplus*s), + Rf: Ri*(Vout - Vplus)/Vplus, + }, { + Vminus: Vplus, + V1: Vout/2 + Vplus/2 - sqrt((Vout - 5*Vplus)*(Vout - Vplus))/2, + R: (Vout - 3*Vplus + sqrt(Vout**2 - 6*Vout*Vplus + 5*Vplus**2))/(2*C*Vplus*s), + Rf: Ri*(Vout - Vplus)/Vplus, + }], [{ + Vminus: Vplus, + Vout: (V1**2 - V1*Vplus - Vplus**2)/(V1 - 2*Vplus), + Rf: Ri*(V1 - Vplus)**2/(Vplus*(V1 - 2*Vplus)), + R: Vplus/(C*s*(V1 - 2*Vplus)), + }]] + + +def test_high_order_roots(): + s = x**5 + 4*x**3 + 3*x**2 + Rational(7, 4) + assert set(solve(s)) == set(Poly(s*4, domain='ZZ').all_roots()) + + +def test_minsolve_linear_system(): + pqt = {"quick": True, "particular": True} + pqf = {"quick": False, "particular": True} + assert solve([x + y - 5, 2*x - y - 1], **pqt) == {x: 2, y: 3} + assert solve([x + y - 5, 2*x - y - 1], **pqf) == {x: 2, y: 3} + def count(dic): + return len([x for x in dic.values() if x == 0]) + assert count(solve([x + y + z, y + z + a + t], **pqt)) == 3 + assert count(solve([x + y + z, y + z + a + t], **pqf)) == 3 + assert count(solve([x + y + z, y + z + a], **pqt)) == 1 + assert count(solve([x + y + z, y + z + a], **pqf)) == 2 + # issue 22718 + A = Matrix([ + [ 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0], + [ 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, -1, -1, 0, 0], + [-1, -1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 1, 0, 1], + [ 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, -1, 0, -1, 0], + [-1, 0, -1, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 1], + [-1, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1], + [ 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, -1, -1, 0], + [ 0, -1, -1, 0, 0, 0, 0, -1, 0, 0, 0, 1, 1, 1], + [ 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, 0, -1, 0, -1], + [ 0, 0, -1, -1, 0, 0, 0, 0, 0, -1, 0, 0, -1, -1], + [ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], + [ 0, 0, 0, 0, -1, -1, 0, -1, 0, 0, 0, 0, 0, 0]]) + v = Matrix(symbols("v:14", integer=True)) + B = Matrix([[2], [-2], [0], [0], [0], [0], [0], [0], [0], + [0], [0], [0]]) + eqs = A@v-B + assert solve(eqs) == [] + assert solve(eqs, particular=True) == [] # assumption violated + assert all(v for v in solve([x + y + z, y + z + a]).values()) + for _q in (True, False): + assert not all(v for v in solve( + [x + y + z, y + z + a], quick=_q, + particular=True).values()) + # raise error if quick used w/o particular=True + raises(ValueError, lambda: solve([x + 1], quick=_q)) + raises(ValueError, lambda: solve([x + 1], quick=_q, particular=False)) + # and give a good error message if someone tries to use + # particular with a single equation + raises(ValueError, lambda: solve(x + 1, particular=True)) + + +def test_real_roots(): + # cf. issue 6650 + x = Symbol('x', real=True) + assert len(solve(x**5 + x**3 + 1)) == 1 + + +def test_issue_6528(): + eqs = [ + 327600995*x**2 - 37869137*x + 1809975124*y**2 - 9998905626, + 895613949*x**2 - 273830224*x*y + 530506983*y**2 - 10000000000] + # two expressions encountered are > 1400 ops long so if this hangs + # it is likely because simplification is being done + assert len(solve(eqs, y, x, check=False)) == 4 + + +def test_overdetermined(): + x = symbols('x', real=True) + 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,), (S(3),)] + + +def test_issue_6605(): + x = symbols('x') + assert solve(4**(x/2) - 2**(x/3)) == [0, 3*I*pi/log(2)] + # 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_6644(): + eq = -sqrt((m - q)**2 + (-m/(2*q) + S.Half)**2) + sqrt((-m**2/2 - sqrt( + 4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2 + (m**2/2 - m - sqrt( + 4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2) + sol = solve(eq, q, simplify=False, check=False) + assert len(sol) == 5 + + +def test_issue_6752(): + 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_6792(): + assert solve(x*(x - 1)**2*(x + 1)*(x**6 - x + 1)) == [ + -1, 0, 1, CRootOf(x**6 - x + 1, 0), CRootOf(x**6 - x + 1, 1), + CRootOf(x**6 - x + 1, 2), CRootOf(x**6 - x + 1, 3), + CRootOf(x**6 - x + 1, 4), CRootOf(x**6 - x + 1, 5)] + + +def test_issues_6819_6820_6821_6248_8692_25777_25779(): + # issue 6821 + x, y = symbols('x y', real=True) + assert solve(abs(x + 3) - 2*abs(x - 3)) == [1, 9] + assert solve([abs(x) - 2, arg(x) - pi], x) == [(-2,)] + assert set(solve(abs(x - 7) - 8)) == {-S.One, S(15)} + + # issue 8692 + assert solve(Eq(Abs(x + 1) + Abs(x**2 - 7), 9), x) == [ + Rational(-1, 2) + sqrt(61)/2, -sqrt(69)/2 + S.Half] + + # issue 7145 + assert solve(2*abs(x) - abs(x - 1)) == [-1, Rational(1, 3)] + + # 25777 + assert solve(abs(x**3 + x + 2)/(x + 1)) == [] + + # 25779 + assert solve(abs(x)) == [0] + assert solve(Eq(abs(x**2 - 2*x), 4), x) == [ + 1 - sqrt(5), 1 + sqrt(5)] + nn = symbols('nn', nonnegative=True) + assert solve(abs(sqrt(nn))) == [0] + nz = symbols('nz', nonzero=True) + assert solve(Eq(Abs(4 + 1 / (4*nz)), 0)) == [-Rational(1, 16)] + + x = symbols('x') + assert solve([re(x) - 1, im(x) - 2], x) == [ + {x: 1 + 2*I, re(x): 1, im(x): 2}] + + # check for 'dict' handling of solution + eq = sqrt(re(x)**2 + im(x)**2) - 3 + assert solve(eq) == solve(eq, x) + + i = symbols('i', imaginary=True) + assert solve(abs(i) - 3) == [-3*I, 3*I] + raises(NotImplementedError, lambda: solve(abs(x) - 3)) + + 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} + # issue 2642 + assert solve(x*(1 + I)) == [0] + + 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 6248 + 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_17638(): + + assert solve(((2-exp(2*x))*exp(x))/(exp(2*x)+2)**2 > 0, x) == (-oo < x) & (x < log(2)/2) + assert solve(((2-exp(2*x)+2)*exp(x+2))/(exp(x)+2)**2 > 0, x) == (-oo < x) & (x < log(4)/2) + assert solve((exp(x)+2+x**2)*exp(2*x+2)/(exp(x)+2)**2 > 0, x) == (-oo < x) & (x < oo) + + + +def test_issue_14607(): + # issue 14607 + s, tau_c, tau_1, tau_2, phi, K = symbols( + 's, tau_c, tau_1, tau_2, phi, K') + + target = (s**2*tau_1*tau_2 + s*tau_1 + s*tau_2 + 1)/(K*s*(-phi + tau_c)) + + K_C, tau_I, tau_D = symbols('K_C, tau_I, tau_D', + positive=True, nonzero=True) + PID = K_C*(1 + 1/(tau_I*s) + tau_D*s) + + eq = (target - PID).together() + eq *= denom(eq).simplify() + eq = Poly(eq, s) + c = eq.coeffs() + + vars = [K_C, tau_I, tau_D] + s = solve(c, vars, dict=True) + + assert len(s) == 1 + + knownsolution = {K_C: -(tau_1 + tau_2)/(K*(phi - tau_c)), + tau_I: tau_1 + tau_2, + tau_D: tau_1*tau_2/(tau_1 + tau_2)} + + for var in vars: + assert s[0][var].simplify() == knownsolution[var].simplify() + + +def test_lambert_multivariate(): + from sympy.abc import x, y + assert _filtered_gens(Poly(x + 1/x + exp(x) + y), x) == {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(1 + sqrt(3)))/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)) + ans = [3, -3*LambertW(-log(3)/3)/log(3)] # 3 and 2.478... + assert solve(x**3 - 3**x, x) == ans + assert set(solve(3*log(x) - x*log(3))) == set(ans) + assert solve(LambertW(2*x) - y, x) == [y*exp(y)/2] + + +@XFAIL +def test_other_lambert(): + assert solve(3*sin(x) - x*sin(3), x) == [3] + assert set(solve(x**a - a**x), x) == { + a, -a*LambertW(-log(a)/a)/log(a)} + + +@slow +def test_lambert_bivariate(): + # tests passing current implementation + assert solve((x**2 + x)*exp(x**2 + x) - 1) == [ + Rational(-1, 2) + sqrt(1 + 4*LambertW(1))/2, + Rational(-1, 2) - sqrt(1 + 4*LambertW(1))/2] + assert solve((x**2 + x)*exp((x**2 + x)*2) - 1) == [ + Rational(-1, 2) + sqrt(1 + 2*LambertW(2))/2, + Rational(-1, 2) - sqrt(1 + 2*LambertW(2))/2] + assert solve(a/x + exp(x/2), x) == [2*LambertW(-a/2)] + assert solve((a/x + exp(x/2)).diff(x), x) == \ + [4*LambertW(-sqrt(2)*sqrt(a)/4), 4*LambertW(sqrt(2)*sqrt(a)/4)] + assert solve((1/x + exp(x/2)).diff(x), x) == \ + [4*LambertW(-sqrt(2)/4), + 4*LambertW(sqrt(2)/4), # nsimplifies as 2*2**(141/299)*3**(206/299)*5**(205/299)*7**(37/299)/21 + 4*LambertW(-sqrt(2)/4, -1)] + assert solve(x*log(x) + 3*x + 1, x) == \ + [exp(-3 + LambertW(-exp(3)))] + assert solve(-x**2 + 2**x, x) == [2, 4, -2*LambertW(log(2)/2)/log(2)] + assert solve(x**2 - 2**x, x) == [2, 4, -2*LambertW(log(2)/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*root(2, 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((log(x) + x).subs(x, x**2 + 1)) == [ + -I*sqrt(-LambertW(1) + 1), sqrt(-1 + LambertW(1))] + # check collection + ax = a**(3*x + 5) + ans = solve(3*log(ax) + b*log(ax) + ax, x) + x0 = 1/log(a) + x1 = sqrt(3)*I + x2 = b + 3 + x3 = x2*LambertW(1/x2)/a**5 + x4 = x3**Rational(1, 3)/2 + assert ans == [ + x0*log(x4*(-x1 - 1)), + x0*log(x4*(x1 - 1)), + x0*log(x3)/3] + x1 = LambertW(Rational(1, 3)) + x2 = a**(-5) + x3 = -3**Rational(1, 3) + x4 = 3**Rational(5, 6)*I + x5 = x1**Rational(1, 3)*x2**Rational(1, 3)/2 + ans = solve(3*log(ax) + ax, x) + assert ans == [ + x0*log(3*x1*x2)/3, + x0*log(x5*(x3 - x4)), + x0*log(x5*(x3 + x4))] + # coverage + p = symbols('p', positive=True) + eq = 4*2**(2*p + 3) - 2*p - 3 + assert _solve_lambert(eq, p, _filtered_gens(Poly(eq), p)) == [ + Rational(-3, 2) - LambertW(-4*log(2))/(2*log(2))] + assert set(solve(3**cos(x) - cos(x)**3)) == { + acos(3), acos(-3*LambertW(-log(3)/3)/log(3))} + # should give only one solution after using `uniq` + assert solve(2*log(x) - 2*log(z) + log(z + log(x) + log(z)), x) == [ + exp(-z + LambertW(2*z**4*exp(2*z))/2)/z] + # cases when p != S.One + # issue 4271 + ans = solve((a/x + exp(x/2)).diff(x, 2), x) + x0 = (-a)**Rational(1, 3) + x1 = sqrt(3)*I + x2 = x0/6 + assert ans == [ + 6*LambertW(x0/3), + 6*LambertW(x2*(-x1 - 1)), + 6*LambertW(x2*(x1 - 1))] + assert solve((1/x + exp(x/2)).diff(x, 2), x) == \ + [6*LambertW(Rational(-1, 3)), 6*LambertW(Rational(1, 6) - sqrt(3)*I/6), \ + 6*LambertW(Rational(1, 6) + sqrt(3)*I/6), 6*LambertW(Rational(-1, 3), -1)] + assert solve(x**2 - y**2/exp(x), x, y, dict=True) == \ + [{x: 2*LambertW(-y/2)}, {x: 2*LambertW(y/2)}] + # this is slow but not exceedingly slow + assert solve((x**3)**(x/2) + pi/2, x) == [ + exp(LambertW(-2*log(2)/3 + 2*log(pi)/3 + I*pi*Rational(2, 3)))] + + # issue 23253 + assert solve((1/log(sqrt(x) + 2)**2 - 1/x)) == [ + (LambertW(-exp(-2), -1) + 2)**2] + assert solve((1/log(1/sqrt(x) + 2)**2 - x)) == [ + (LambertW(-exp(-2), -1) + 2)**-2] + assert solve((1/log(x**2 + 2)**2 - x**-4)) == [ + -I*sqrt(2 - LambertW(exp(2))), + -I*sqrt(LambertW(-exp(-2)) + 2), + sqrt(-2 - LambertW(-exp(-2))), + sqrt(-2 + LambertW(exp(2))), + -sqrt(-2 - LambertW(-exp(-2), -1)), + sqrt(-2 - LambertW(-exp(-2), -1))] + + +def test_rewrite_trig(): + assert solve(sin(x) + tan(x)) == [0, -pi, pi, 2*pi] + assert solve(sin(x) + sec(x)) == [ + -2*atan(Rational(-1, 2) + sqrt(2)*sqrt(1 - sqrt(3)*I)/2 + sqrt(3)*I/2), + 2*atan(S.Half - sqrt(2)*sqrt(1 + sqrt(3)*I)/2 + sqrt(3)*I/2), 2*atan(S.Half + + sqrt(2)*sqrt(1 + sqrt(3)*I)/2 + sqrt(3)*I/2), 2*atan(S.Half - + sqrt(3)*I/2 + sqrt(2)*sqrt(1 - sqrt(3)*I)/2)] + assert solve(sinh(x) + tanh(x)) == [0, I*pi] + + # issue 6157 + assert solve(2*sin(x) - cos(x), x) == [atan(S.Half)] + + +@XFAIL +def test_rewrite_trigh(): + # if this import passes then the test below should also pass + from sympy.functions.elementary.hyperbolic import sech + assert solve(sinh(x) + sech(x)) == [ + 2*atanh(Rational(-1, 2) + sqrt(5)/2 - sqrt(-2*sqrt(5) + 2)/2), + 2*atanh(Rational(-1, 2) + 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) in [ + [-3 + sqrt(-12 + exp(3))*exp(Rational(3, 2))/2 + exp(3)/2, + -sqrt(-12 + exp(3))*exp(Rational(3, 2))/2 - 3 + exp(3)/2], + [-3 + sqrt(-36 + (-exp(3) + 6)**2)/2 + exp(3)/2, + -3 - sqrt(-36 + (-exp(3) + 6)**2)/2 + exp(3)/2], + ] + assert solve(log(exp(2*x) + 1) + log(-tanh(x) + 1) - log(2)) == [] + + +def test_atan2(): + assert solve(atan2(x, 2) - pi/3, x) == [2*sqrt(3)] + + +def test_errorinverses(): + assert solve(erf(x) - y, x) == [erfinv(y)] + assert solve(erfinv(x) - y, x) == [erf(y)] + assert solve(erfc(x) - y, x) == [erfcinv(y)] + assert solve(erfcinv(x) - y, x) == [erfc(y)] + + +def test_issue_2725(): + R = Symbol('R') + eq = sqrt(2)*R*sqrt(1/(R + 1)) + (R + 1)*(sqrt(2)*sqrt(1/(R + 1)) - 1) + sol = solve(eq, R, set=True)[1] + assert sol == {(Rational(5, 3) + (Rational(-1, 2) - sqrt(3)*I/2)*(Rational(251, 27) + + sqrt(111)*I/9)**Rational(1, 3) + 40/(9*((Rational(-1, 2) - sqrt(3)*I/2)*(Rational(251, 27) + + sqrt(111)*I/9)**Rational(1, 3))),), (Rational(5, 3) + 40/(9*(Rational(251, 27) + + sqrt(111)*I/9)**Rational(1, 3)) + (Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3),)} + + +def test_issue_5114_6611(): + # See that it doesn't hang; this solves in about 2 seconds. + # Also check that the solution is relatively small. + # Note: the system in issue 6611 solves in about 5 seconds and has + # an op-count of 138336 (with simplify=False). + b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r = symbols('b:r') + eqs = Matrix([ + [b - c/d + r/d], [c*(1/g + 1/e + 1/d) - f/g - r/d], + [-c/g + f*(1/j + 1/i + 1/g) - h/i], [-f/i + h*(1/m + 1/l + 1/i) - k/m], + [-h/m + k*(1/p + 1/o + 1/m) - n/p], [-k/p + n*(1/q + 1/p)]]) + v = Matrix([f, h, k, n, b, c]) + ans = solve(list(eqs), list(v), simplify=False) + # If time is taken to simplify then then 2617 below becomes + # 1168 and the time is about 50 seconds instead of 2. + assert sum(s.count_ops() for s in ans.values()) <= 3270 + + +def test_det_quick(): + m = Matrix(3, 3, symbols('a:9')) + assert m.det() == det_quick(m) # calls det_perm + m[0, 0] = 1 + assert m.det() == det_quick(m) # calls det_minor + m = Matrix(3, 3, list(range(9))) + assert m.det() == det_quick(m) # defaults to .det() + # make sure they work with Sparse + s = SparseMatrix(2, 2, (1, 2, 1, 4)) + assert det_perm(s) == det_minor(s) == s.det() + + +def test_real_imag_splitting(): + a, b = symbols('a b', real=True) + assert solve(sqrt(a**2 + b**2) - 3, a) == \ + [-sqrt(-b**2 + 9), sqrt(-b**2 + 9)] + a, b = symbols('a b', imaginary=True) + assert solve(sqrt(a**2 + b**2) - 3, a) == [] + + +def test_issue_7110(): + y = -2*x**3 + 4*x**2 - 2*x + 5 + assert any(ask(Q.real(i)) for i in solve(y)) + + +def test_units(): + assert solve(1/x - 1/(2*cm)) == [2*cm] + + +def test_issue_7547(): + A, B, V = symbols('A,B,V') + eq1 = Eq(630.26*(V - 39.0)*V*(V + 39) - A + B, 0) + eq2 = Eq(B, 1.36*10**8*(V - 39)) + eq3 = Eq(A, 5.75*10**5*V*(V + 39.0)) + sol = Matrix(nsolve(Tuple(eq1, eq2, eq3), [A, B, V], (0, 0, 0))) + assert str(sol) == str(Matrix( + [['4442890172.68209'], + ['4289299466.1432'], + ['70.5389666628177']])) + + +def test_issue_7895(): + r = symbols('r', real=True) + assert solve(sqrt(r) - 2) == [4] + + +def test_issue_2777(): + # the equations represent two circles + x, y = symbols('x y', real=True) + e1, e2 = sqrt(x**2 + y**2) - 10, sqrt(y**2 + (-x + 10)**2) - 3 + a, b = Rational(191, 20), 3*sqrt(391)/20 + ans = [(a, -b), (a, b)] + assert solve((e1, e2), (x, y)) == ans + assert solve((e1, e2/(x - a)), (x, y)) == [] + # make the 2nd circle's radius be -3 + e2 += 6 + assert solve((e1, e2), (x, y)) == [] + assert solve((e1, e2), (x, y), check=False) == ans + + +def test_issue_7322(): + number = 5.62527e-35 + assert solve(x - number, x)[0] == number + + +def test_nsolve(): + raises(ValueError, lambda: nsolve(x, (-1, 1), method='bisect')) + raises(TypeError, lambda: nsolve((x - y + 3,x + y,z - y),(x,y,z),(-50,50))) + raises(TypeError, lambda: nsolve((x + y, x - y), (0, 1))) + raises(TypeError, lambda: nsolve(x < 0.5, x, 1)) + + +@slow +def test_high_order_multivariate(): + assert len(solve(a*x**3 - x + 1, x)) == 3 + assert len(solve(a*x**4 - x + 1, x)) == 4 + assert solve(a*x**5 - x + 1, x) == [] # incomplete solution allowed + raises(NotImplementedError, lambda: + solve(a*x**5 - x + 1, x, incomplete=False)) + + # result checking must always consider the denominator and CRootOf + # must be checked, too + d = x**5 - x + 1 + assert solve(d*(1 + 1/d)) == [CRootOf(d + 1, i) for i in range(5)] + d = x - 1 + assert solve(d*(2 + 1/d)) == [S.Half] + + +def test_base_0_exp_0(): + assert solve(0**x - 1) == [0] + assert solve(0**(x - 2) - 1) == [2] + assert solve(S('x*(1/x**0 - x)', evaluate=False)) == \ + [0, 1] + + +def test__simple_dens(): + assert _simple_dens(1/x**0, [x]) == set() + assert _simple_dens(1/x**y, [x]) == {x**y} + assert _simple_dens(1/root(x, 3), [x]) == {x} + + +def test_issue_8755(): + # This tests two things: that if full unrad is attempted and fails + # the solution should still be found; also it tests the use of + # keyword `composite`. + assert len(solve(sqrt(y)*x + x**3 - 1, x)) == 3 + assert len(solve(-512*y**3 + 1344*(x + 2)**Rational(1, 3)*y**2 - + 1176*(x + 2)**Rational(2, 3)*y - 169*x + 686, y, _unrad=False)) == 3 + + +@slow +def test_issue_8828(): + x1 = 0 + y1 = -620 + r1 = 920 + x2 = 126 + y2 = 276 + x3 = 51 + y3 = 205 + r3 = 104 + v = x, y, z + + f1 = (x - x1)**2 + (y - y1)**2 - (r1 - z)**2 + f2 = (x - x2)**2 + (y - y2)**2 - z**2 + f3 = (x - x3)**2 + (y - y3)**2 - (r3 - z)**2 + F = f1,f2,f3 + + g1 = sqrt((x - x1)**2 + (y - y1)**2) + z - r1 + g2 = f2 + g3 = sqrt((x - x3)**2 + (y - y3)**2) + z - r3 + G = g1,g2,g3 + + A = solve(F, v) + B = solve(G, v) + C = solve(G, v, manual=True) + + p, q, r = [{tuple(i.evalf(2) for i in j) for j in R} for R in [A, B, C]] + assert p == q == r + + +def test_issue_2840_8155(): + # with parameter-free solutions (i.e. no `n`), we want to avoid + # excessive periodic solutions + assert solve(sin(3*x) + sin(6*x)) == [0, -2*pi/9, 2*pi/9] + assert solve(sin(300*x) + sin(600*x)) == [0, -pi/450, pi/450] + assert solve(2*sin(x) - 2*sin(2*x)) == [0, -pi/3, pi/3] + + +def test_issue_9567(): + assert solve(1 + 1/(x - 1)) == [0] + + +def test_issue_11538(): + assert solve(x + E) == [-E] + assert solve(x**2 + E) == [-I*sqrt(E), I*sqrt(E)] + assert solve(x**3 + 2*E) == [ + -cbrt(2 * E), + cbrt(2)*cbrt(E)/2 - cbrt(2)*sqrt(3)*I*cbrt(E)/2, + cbrt(2)*cbrt(E)/2 + cbrt(2)*sqrt(3)*I*cbrt(E)/2] + assert solve([x + 4, y + E], x, y) == {x: -4, y: -E} + assert solve([x**2 + 4, y + E], x, y) == [ + (-2*I, -E), (2*I, -E)] + + e1 = x - y**3 + 4 + e2 = x + y + 4 + 4 * E + assert len(solve([e1, e2], x, y)) == 3 + + +@slow +def test_issue_12114(): + a, b, c, d, e, f, g = symbols('a,b,c,d,e,f,g') + terms = [1 + a*b + d*e, 1 + a*c + d*f, 1 + b*c + e*f, + g - a**2 - d**2, g - b**2 - e**2, g - c**2 - f**2] + sol = solve(terms, [a, b, c, d, e, f, g], dict=True) + s = sqrt(-f**2 - 1) + s2 = sqrt(2 - f**2) + s3 = sqrt(6 - 3*f**2) + s4 = sqrt(3)*f + s5 = sqrt(3)*s2 + assert sol == [ + {a: -s, b: -s, c: -s, d: f, e: f, g: -1}, + {a: s, b: s, c: s, d: f, e: f, g: -1}, + {a: -s4/2 - s2/2, b: s4/2 - s2/2, c: s2, + d: -f/2 + s3/2, e: -f/2 - s5/2, g: 2}, + {a: -s4/2 + s2/2, b: s4/2 + s2/2, c: -s2, + d: -f/2 - s3/2, e: -f/2 + s5/2, g: 2}, + {a: s4/2 - s2/2, b: -s4/2 - s2/2, c: s2, + d: -f/2 - s3/2, e: -f/2 + s5/2, g: 2}, + {a: s4/2 + s2/2, b: -s4/2 + s2/2, c: -s2, + d: -f/2 + s3/2, e: -f/2 - s5/2, g: 2}] + + +def test_inf(): + assert solve(1 - oo*x) == [] + assert solve(oo*x, x) == [] + assert solve(oo*x - oo, x) == [] + + +def test_issue_12448(): + f = Function('f') + fun = [f(i) for i in range(15)] + sym = symbols('x:15') + reps = dict(zip(fun, sym)) + + (x, y, z), c = sym[:3], sym[3:] + ssym = solve([c[4*i]*x + c[4*i + 1]*y + c[4*i + 2]*z + c[4*i + 3] + for i in range(3)], (x, y, z)) + + (x, y, z), c = fun[:3], fun[3:] + sfun = solve([c[4*i]*x + c[4*i + 1]*y + c[4*i + 2]*z + c[4*i + 3] + for i in range(3)], (x, y, z)) + + assert sfun[fun[0]].xreplace(reps).count_ops() == \ + ssym[sym[0]].count_ops() + + +def test_denoms(): + assert denoms(x/2 + 1/y) == {2, y} + assert denoms(x/2 + 1/y, y) == {y} + assert denoms(x/2 + 1/y, [y]) == {y} + assert denoms(1/x + 1/y + 1/z, [x, y]) == {x, y} + assert denoms(1/x + 1/y + 1/z, x, y) == {x, y} + assert denoms(1/x + 1/y + 1/z, {x, y}) == {x, y} + + +def test_issue_12476(): + x0, x1, x2, x3, x4, x5 = symbols('x0 x1 x2 x3 x4 x5') + eqns = [x0**2 - x0, x0*x1 - x1, x0*x2 - x2, x0*x3 - x3, x0*x4 - x4, x0*x5 - x5, + x0*x1 - x1, -x0/3 + x1**2 - 2*x2/3, x1*x2 - x1/3 - x2/3 - x3/3, + x1*x3 - x2/3 - x3/3 - x4/3, x1*x4 - 2*x3/3 - x5/3, x1*x5 - x4, x0*x2 - x2, + x1*x2 - x1/3 - x2/3 - x3/3, -x0/6 - x1/6 + x2**2 - x2/6 - x3/3 - x4/6, + -x1/6 + x2*x3 - x2/3 - x3/6 - x4/6 - x5/6, x2*x4 - x2/3 - x3/3 - x4/3, + x2*x5 - x3, x0*x3 - x3, x1*x3 - x2/3 - x3/3 - x4/3, + -x1/6 + x2*x3 - x2/3 - x3/6 - x4/6 - x5/6, + -x0/6 - x1/6 - x2/6 + x3**2 - x3/3 - x4/6, -x1/3 - x2/3 + x3*x4 - x3/3, + -x2 + x3*x5, x0*x4 - x4, x1*x4 - 2*x3/3 - x5/3, x2*x4 - x2/3 - x3/3 - x4/3, + -x1/3 - x2/3 + x3*x4 - x3/3, -x0/3 - 2*x2/3 + x4**2, -x1 + x4*x5, x0*x5 - x5, + x1*x5 - x4, x2*x5 - x3, -x2 + x3*x5, -x1 + x4*x5, -x0 + x5**2, x0 - 1] + sols = [{x0: 1, x3: Rational(1, 6), x2: Rational(1, 6), x4: Rational(-2, 3), x1: Rational(-2, 3), x5: 1}, + {x0: 1, x3: S.Half, x2: Rational(-1, 2), x4: 0, x1: 0, x5: -1}, + {x0: 1, x3: Rational(-1, 3), x2: Rational(-1, 3), x4: Rational(1, 3), x1: Rational(1, 3), x5: 1}, + {x0: 1, x3: 1, x2: 1, x4: 1, x1: 1, x5: 1}, + {x0: 1, x3: Rational(-1, 3), x2: Rational(1, 3), x4: sqrt(5)/3, x1: -sqrt(5)/3, x5: -1}, + {x0: 1, x3: Rational(-1, 3), x2: Rational(1, 3), x4: -sqrt(5)/3, x1: sqrt(5)/3, x5: -1}] + + assert solve(eqns) == sols + + +def test_issue_13849(): + t = symbols('t') + assert solve((t*(sqrt(5) + sqrt(2)) - sqrt(2), t), t) == [] + + +def test_issue_14860(): + from sympy.physics.units import newton, kilo + assert solve(8*kilo*newton + x + y, x) == [-8000*newton - y] + + +def test_issue_14721(): + k, h, a, b = symbols(':4') + assert solve([ + -1 + (-k + 1)**2/b**2 + (-h - 1)**2/a**2, + -1 + (-k + 1)**2/b**2 + (-h + 1)**2/a**2, + h, k + 2], h, k, a, b) == [ + (0, -2, -b*sqrt(1/(b**2 - 9)), b), + (0, -2, b*sqrt(1/(b**2 - 9)), b)] + assert solve([ + h, h/a + 1/b**2 - 2, -h/2 + 1/b**2 - 2], a, h, b) == [ + (a, 0, -sqrt(2)/2), (a, 0, sqrt(2)/2)] + assert solve((a + b**2 - 1, a + b**2 - 2)) == [] + + +def test_issue_14779(): + x = symbols('x', real=True) + assert solve(sqrt(x**4 - 130*x**2 + 1089) + sqrt(x**4 - 130*x**2 + + 3969) - 96*Abs(x)/x,x) == [sqrt(130)] + + +def test_issue_15307(): + assert solve((y - 2, Mul(x + 3,x - 2, evaluate=False))) == \ + [{x: -3, y: 2}, {x: 2, y: 2}] + assert solve((y - 2, Mul(3, x - 2, evaluate=False))) == \ + {x: 2, y: 2} + assert solve((y - 2, Add(x + 4, x - 2, evaluate=False))) == \ + {x: -1, y: 2} + eq1 = Eq(12513*x + 2*y - 219093, -5726*x - y) + eq2 = Eq(-2*x + 8, 2*x - 40) + assert solve([eq1, eq2]) == {x:12, y:75} + + +def test_issue_15415(): + assert solve(x - 3, x) == [3] + assert solve([x - 3], x) == {x:3} + assert solve(Eq(y + 3*x**2/2, y + 3*x), y) == [] + assert solve([Eq(y + 3*x**2/2, y + 3*x)], y) == [] + assert solve([Eq(y + 3*x**2/2, y + 3*x), Eq(x, 1)], y) == [] + + +@slow +def test_issue_15731(): + # f(x)**g(x)=c + assert solve(Eq((x**2 - 7*x + 11)**(x**2 - 13*x + 42), 1)) == [2, 3, 4, 5, 6, 7] + assert solve((x)**(x + 4) - 4) == [-2] + assert solve((-x)**(-x + 4) - 4) == [2] + assert solve((x**2 - 6)**(x**2 - 2) - 4) == [-2, 2] + assert solve((x**2 - 2*x - 1)**(x**2 - 3) - 1/(1 - 2*sqrt(2))) == [sqrt(2)] + assert solve(x**(x + S.Half) - 4*sqrt(2)) == [S(2)] + assert solve((x**2 + 1)**x - 25) == [2] + assert solve(x**(2/x) - 2) == [2, 4] + assert solve((x/2)**(2/x) - sqrt(2)) == [4, 8] + assert solve(x**(x + S.Half) - Rational(9, 4)) == [Rational(3, 2)] + # a**g(x)=c + assert solve((-sqrt(sqrt(2)))**x - 2) == [4, log(2)/(log(2**Rational(1, 4)) + I*pi)] + assert solve((sqrt(2))**x - sqrt(sqrt(2))) == [S.Half] + assert solve((-sqrt(2))**x + 2*(sqrt(2))) == [3, + (3*log(2)**2 + 4*pi**2 - 4*I*pi*log(2))/(log(2)**2 + 4*pi**2)] + assert solve((sqrt(2))**x - 2*(sqrt(2))) == [3] + assert solve(I**x + 1) == [2] + assert solve((1 + I)**x - 2*I) == [2] + assert solve((sqrt(2) + sqrt(3))**x - (2*sqrt(6) + 5)**Rational(1, 3)) == [Rational(2, 3)] + # bases of both sides are equal + b = Symbol('b') + assert solve(b**x - b**2, x) == [2] + assert solve(b**x - 1/b, x) == [-1] + assert solve(b**x - b, x) == [1] + b = Symbol('b', positive=True) + assert solve(b**x - b**2, x) == [2] + assert solve(b**x - 1/b, x) == [-1] + + +def test_issue_10933(): + assert solve(x**4 + y*(x + 0.1), x) # doesn't fail + assert solve(I*x**4 + x**3 + x**2 + 1.) # doesn't fail + + +def test_Abs_handling(): + x = symbols('x', real=True) + assert solve(abs(x/y), x) == [0] + + +def test_issue_7982(): + x = Symbol('x') + # Test that no exception happens + assert solve([2*x**2 + 5*x + 20 <= 0, x >= 1.5], x) is S.false + # From #8040 + assert solve([x**3 - 8.08*x**2 - 56.48*x/5 - 106 >= 0, x - 1 <= 0], [x]) is S.false + + +def test_issue_14645(): + x, y = symbols('x y') + assert solve([x*y - x - y, x*y - x - y], [x, y]) == [(y/(y - 1), y)] + + +def test_issue_12024(): + x, y = symbols('x y') + assert solve(Piecewise((0.0, x < 0.1), (x, x >= 0.1)) - y) == \ + [{y: Piecewise((0.0, x < 0.1), (x, True))}] + + +def test_issue_17452(): + assert solve((7**x)**x + pi, x) == [-sqrt(log(pi) + I*pi)/sqrt(log(7)), + sqrt(log(pi) + I*pi)/sqrt(log(7))] + assert solve(x**(x/11) + pi/11, x) == [exp(LambertW(-11*log(11) + 11*log(pi) + 11*I*pi))] + + +def test_issue_17799(): + assert solve(-erf(x**(S(1)/3))**pi + I, x) == [] + + +def test_issue_17650(): + x = Symbol('x', real=True) + assert solve(abs(abs(x**2 - 1) - x) - x) == [1, -1 + sqrt(2), 1 + sqrt(2)] + + +def test_issue_17882(): + eq = -8*x**2/(9*(x**2 - 1)**(S(4)/3)) + 4/(3*(x**2 - 1)**(S(1)/3)) + assert unrad(eq) is None + + +def test_issue_17949(): + assert solve(exp(+x+x**2), x) == [] + assert solve(exp(-x+x**2), x) == [] + assert solve(exp(+x-x**2), x) == [] + assert solve(exp(-x-x**2), x) == [] + + +def test_issue_10993(): + assert solve(Eq(binomial(x, 2), 3)) == [-2, 3] + assert solve(Eq(pow(x, 2) + binomial(x, 3), x)) == [-4, 0, 1] + assert solve(Eq(binomial(x, 2), 0)) == [0, 1] + assert solve(a+binomial(x, 3), a) == [-binomial(x, 3)] + assert solve(x-binomial(a, 3) + binomial(y, 2) + sin(a), x) == [-sin(a) + binomial(a, 3) - binomial(y, 2)] + assert solve((x+1)-binomial(x+1, 3), x) == [-2, -1, 3] + + +def test_issue_11553(): + eq1 = x + y + 1 + eq2 = x + GoldenRatio + assert solve([eq1, eq2], x, y) == {x: -GoldenRatio, y: -1 + GoldenRatio} + eq3 = x + 2 + TribonacciConstant + assert solve([eq1, eq3], x, y) == {x: -2 - TribonacciConstant, y: 1 + TribonacciConstant} + + +def test_issue_19113_19102(): + t = S(1)/3 + solve(cos(x)**5-sin(x)**5) + assert solve(4*cos(x)**3 - 2*sin(x)**3) == [ + atan(2**(t)), -atan(2**(t)*(1 - sqrt(3)*I)/2), + -atan(2**(t)*(1 + sqrt(3)*I)/2)] + h = S.Half + assert solve(cos(x)**2 + sin(x)) == [ + 2*atan(-h + sqrt(5)/2 + sqrt(2)*sqrt(1 - sqrt(5))/2), + -2*atan(h + sqrt(5)/2 + sqrt(2)*sqrt(1 + sqrt(5))/2), + -2*atan(-sqrt(5)/2 + h + sqrt(2)*sqrt(1 - sqrt(5))/2), + -2*atan(-sqrt(2)*sqrt(1 + sqrt(5))/2 + h + sqrt(5)/2)] + assert solve(3*cos(x) - sin(x)) == [atan(3)] + + +def test_issue_19509(): + a = S(3)/4 + b = S(5)/8 + c = sqrt(5)/8 + d = sqrt(5)/4 + assert solve(1/(x -1)**5 - 1) == [2, + -d + a - sqrt(-b + c), + -d + a + sqrt(-b + c), + d + a - sqrt(-b - c), + d + a + sqrt(-b - c)] + +def test_issue_20747(): + THT, HT, DBH, dib, c0, c1, c2, c3, c4 = symbols('THT HT DBH dib c0 c1 c2 c3 c4') + f = DBH*c3 + THT*c4 + c2 + rhs = 1 - ((HT - 1)/(THT - 1))**c1*(1 - exp(c0/f)) + eq = dib - DBH*(c0 - f*log(rhs)) + term = ((1 - exp((DBH*c0 - dib)/(DBH*(DBH*c3 + THT*c4 + c2)))) + / (1 - exp(c0/(DBH*c3 + THT*c4 + c2)))) + sol = [THT*term**(1/c1) - term**(1/c1) + 1] + assert solve(eq, HT) == sol + + +def test_issue_27001(): + assert solve((x, x**2), (x, y, z), dict=True) == [{x: 0}] + s = a1, a2, a3, a4, a5 = symbols('a1:6') + eqs = [8*a1**4*a2 + 4*a1**2*a2**3 - 8*a1**2*a2*a4 + a2**5/2 - 2*a2**3*a4 + + 8*a2*a3**2 + 2*a2*a4**2 + 8*a2*a5, 12*a1**4 + 6*a1**2*a2**2 - + 8*a1**2*a4 + 3*a2**4/4 - 2*a2**2*a4 + 4*a3**2 + a4**2 + 4*a5, 16*a1**3 + + 4*a1*a2**2 - 8*a1*a4, -8*a1**2*a2 - 2*a2**3 + 4*a2*a4] + sol = [{a4: 2*a1**2 + a2**2/2, a5: -a3**2}, {a1: 0, a2: 0, a5: -a3**2 - a4**2/4}] + assert solve(eqs, s, dict=True) == sol + assert (g:=solve(groebner(eqs, s), dict=True)) == sol, g + + +def test_issue_20902(): + f = (t / ((1 + t) ** 2)) + assert solve(f.subs({t: 3 * x + 2}).diff(x) > 0, x) == (S(-1) < x) & (x < S(-1)/3) + assert solve(f.subs({t: 3 * x + 3}).diff(x) > 0, x) == (S(-4)/3 < x) & (x < S(-2)/3) + assert solve(f.subs({t: 3 * x + 4}).diff(x) > 0, x) == (S(-5)/3 < x) & (x < S(-1)) + assert solve(f.subs({t: 3 * x + 2}).diff(x) > 0, x) == (S(-1) < x) & (x < S(-1)/3) + + +def test_issue_21034(): + a = symbols('a', real=True) + system = [x - cosh(cos(4)), y - sinh(cos(a)), z - tanh(x)] + # constants inside hyperbolic functions should not be rewritten in terms of exp + assert solve(system, x, y, z) == [(cosh(cos(4)), sinh(cos(a)), tanh(cosh(cos(4))))] + # but if the variable of interest is present in a hyperbolic function, + # then it should be rewritten in terms of exp and solved further + newsystem = [(exp(x) - exp(-x)) - tanh(x)*(exp(x) + exp(-x)) + x - 5] + assert solve(newsystem, x) == {x: 5} + + +def test_issue_4886(): + z = a*sqrt(R**2*a**2 + R**2*b**2 - c**2)/(a**2 + b**2) + t = b*c/(a**2 + b**2) + sol = [((b*(t - z) - c)/(-a), t - z), ((b*(t + z) - c)/(-a), t + z)] + assert solve([x**2 + y**2 - R**2, a*x + b*y - c], x, y) == sol + + +def test_issue_6819(): + a, b, c, d = symbols('a b c d', positive=True) + assert solve(a*b**x - c*d**x, x) == [log(c/a)/log(b/d)] + + +def test_issue_17454(): + x = Symbol('x') + assert solve((1 - x - I)**4, x) == [1 - I] + + +def test_issue_21852(): + solution = [21 - 21*sqrt(2)/2] + assert solve(2*x + sqrt(2*x**2) - 21) == solution + + +def test_issue_21942(): + eq = -d + (a*c**(1 - e) + b**(1 - e)*(1 - a))**(1/(1 - e)) + sol = solve(eq, c, simplify=False, check=False) + assert sol == [((a*b**(1 - e) - b**(1 - e) + + d**(1 - e))/a)**(1/(1 - e))] + + +def test_solver_flags(): + root = solve(x**5 + x**2 - x - 1, cubics=False) + rad = solve(x**5 + x**2 - x - 1, cubics=True) + assert root != rad + + +def test_issue_22768(): + eq = 2*x**3 - 16*(y - 1)**6*z**3 + assert solve(eq.expand(), x, simplify=False + ) == [2*z*(y - 1)**2, z*(-1 + sqrt(3)*I)*(y - 1)**2, + -z*(1 + sqrt(3)*I)*(y - 1)**2] + + +def test_issue_22717(): + assert solve((-y**2 + log(y**2/x) + 2, -2*x*y + 2*x/y)) == [ + {y: -1, x: E}, {y: 1, x: E}] + + +def test_issue_25176(): + eq = (x - 5)**-8 - 3 + sol = solve(eq) + assert not any(eq.subs(x, i) for i in sol) + + +def test_issue_10169(): + eq = S(-8*a - x**5*(a + b + c + e) - x**4*(4*a - 2**Rational(3,4)*c + 4*c + + d + 2**Rational(3,4)*e + 4*e + k) - x**3*(-4*2**Rational(3,4)*c + sqrt(2)*c - + 2**Rational(3,4)*d + 4*d + sqrt(2)*e + 4*2**Rational(3,4)*e + 2**Rational(3,4)*k + 4*k) - + x**2*(4*sqrt(2)*c - 4*2**Rational(3,4)*d + sqrt(2)*d + 4*sqrt(2)*e + + sqrt(2)*k + 4*2**Rational(3,4)*k) - x*(2*a + 2*b + 4*sqrt(2)*d + + 4*sqrt(2)*k) + 5) + assert solve_undetermined_coeffs(eq, [a, b, c, d, e, k], x) == { + a: Rational(5,8), + b: Rational(-5,1032), + c: Rational(-40,129) - 5*2**Rational(3,4)/129 + 5*2**Rational(1,4)/1032, + d: -20*2**Rational(3,4)/129 - 10*sqrt(2)/129 - 5*2**Rational(1,4)/258, + e: Rational(-40,129) - 5*2**Rational(1,4)/1032 + 5*2**Rational(3,4)/129, + k: -10*sqrt(2)/129 + 5*2**Rational(1,4)/258 + 20*2**Rational(3,4)/129 + } + + +def test_solve_undetermined_coeffs_issue_23927(): + A, B, r, phi = symbols('A, B, r, phi') + e = Eq(A*sin(t) + B*cos(t), r*sin(t - phi)) + eq = (e.lhs - e.rhs).expand(trig=True) + soln = solve_undetermined_coeffs(eq, (r, phi), t) + assert soln == [{ + phi: 2*atan((A - sqrt(A**2 + B**2))/B), + r: (-A**2 + A*sqrt(A**2 + B**2) - B**2)/(A - sqrt(A**2 + B**2)) + }, { + phi: 2*atan((A + sqrt(A**2 + B**2))/B), + r: (A**2 + A*sqrt(A**2 + B**2) + B**2)/(A + sqrt(A**2 + B**2))/-1 + }] + +def test_issue_24368(): + # Ideally these would produce a solution, but for now just check that they + # don't fail with a RuntimeError + raises(NotImplementedError, lambda: solve(Mod(x**2, 49), x)) + s2 = Symbol('s2', integer=True, positive=True) + f = floor(s2/2 - S(1)/2) + raises(NotImplementedError, lambda: solve((Mod(f**2/(f + 1) + 2*f/(f + 1) + 1/(f + 1), 1))*f + Mod(f**2/(f + 1) + 2*f/(f + 1) + 1/(f + 1), 1), s2)) + + +def test_solve_Piecewise(): + assert [S(10)/3] == solve(3*Piecewise( + (S.NaN, x <= 0), + (20*x - 3*(x - 6)**2/2 - 176, (x >= 0) & (x >= 2) & (x>= 4) & (x >= 6) & (x < 10)), + (100 - 26*x, (x >= 0) & (x >= 2) & (x >= 4) & (x < 10)), + (16*x - 3*(x - 6)**2/2 - 176, (x >= 2) & (x >= 4) & (x >= 6) & (x < 10)), + (100 - 30*x, (x >= 2) & (x >= 4) & (x < 10)), + (30*x - 3*(x - 6)**2/2 - 196, (x>= 0) & (x >= 4) & (x >= 6) & (x < 10)), + (80 - 16*x, (x >= 0) & (x >= 4) & (x < 10)), + (26*x - 3*(x - 6)**2/2 - 196, (x >= 4) & (x >= 6) & (x < 10)), + (80 - 20*x, (x >= 4) & (x < 10)), + (40*x - 3*(x - 6)**2/2 - 256, (x >= 0) & (x >= 2) & (x >= 6) & (x < 10)), + (20 - 6*x, (x >= 0) & (x >= 2) & (x < 10)), + (36*x - 3*(x - 6)**2/2 - 256, (x >= 2) & (x >= 6) & (x < 10)), + (20 - 10*x, (x >= 2) & (x < 10)), + (50*x - 3*(x - 6)**2/2 - 276, (x >= 0) & (x >= 6) & (x < 10)), + (4*x, (x >= 0) & (x < 10)), + (46*x - 3*(x - 6)**2/2 - 276, (x >= 6) & (x < 10)), + (0, x < 10), # this will simplify away + (S.NaN,True))) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_solveset.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_solveset.py new file mode 100644 index 0000000000000000000000000000000000000000..a1ba7a11e68ed518c4d83c050947b78756ade181 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/solvers/tests/test_solveset.py @@ -0,0 +1,3548 @@ +from math import isclose + +from sympy.calculus.util import stationary_points +from sympy.core.containers import Tuple +from sympy.core.function import (Function, Lambda, nfloat, diff) +from sympy.core.mod import Mod +from sympy.core.numbers import (E, I, Rational, oo, pi, Integer, all_close) +from sympy.core.relational import (Eq, Gt, Ne, Ge) +from sympy.core.singleton import S +from sympy.core.sorting import ordered +from sympy.core.symbol import (Dummy, Symbol, symbols) +from sympy.core.sympify import sympify +from sympy.functions.elementary.complexes import (Abs, arg, im, re, sign, conjugate) +from sympy.functions.elementary.exponential import (LambertW, exp, log) +from sympy.functions.elementary.hyperbolic import (HyperbolicFunction, + sinh, cosh, tanh, coth, sech, csch, asinh, acosh, atanh, acoth, asech, acsch) +from sympy.functions.elementary.miscellaneous import sqrt, Min, Max +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import ( + TrigonometricFunction, acos, acot, acsc, asec, asin, atan, atan2, + cos, cot, csc, sec, sin, tan) +from sympy.functions.special.error_functions import (erf, erfc, + erfcinv, erfinv) +from sympy.logic.boolalg import And +from sympy.matrices.dense import MutableDenseMatrix as Matrix +from sympy.matrices.immutable import ImmutableDenseMatrix +from sympy.polys.polytools import Poly +from sympy.polys.rootoftools import CRootOf +from sympy.sets.contains import Contains +from sympy.sets.conditionset import ConditionSet +from sympy.sets.fancysets import ImageSet, Range +from sympy.sets.sets import (Complement, FiniteSet, + Intersection, Interval, Union, imageset, ProductSet) +from sympy.simplify import simplify +from sympy.tensor.indexed import Indexed +from sympy.utilities.iterables import numbered_symbols + +from sympy.testing.pytest import (XFAIL, raises, skip, slow, SKIP, _both_exp_pow) +from sympy.core.random import verify_numerically as tn +from sympy.physics.units import cm + +from sympy.solvers import solve +from sympy.solvers.solveset import ( + solveset_real, domain_check, solveset_complex, linear_eq_to_matrix, + linsolve, _is_function_class_equation, invert_real, invert_complex, + _invert_trig_hyp_real, solveset, solve_decomposition, substitution, + nonlinsolve, solvify, + _is_finite_with_finite_vars, _transolve, _is_exponential, + _solve_exponential, _is_logarithmic, _is_lambert, + _solve_logarithm, _term_factors, _is_modular, NonlinearError) + +from sympy.abc import (a, b, c, d, e, f, g, h, i, j, k, l, m, n, q, r, + t, w, x, y, z) + + +def dumeq(i, j): + if type(i) in (list, tuple): + return all(dumeq(i, j) for i, j in zip(i, j)) + return i == j or i.dummy_eq(j) + + +def assert_close_ss(sol1, sol2): + """Test solutions with floats from solveset are close""" + sol1 = sympify(sol1) + sol2 = sympify(sol2) + assert isinstance(sol1, FiniteSet) + assert isinstance(sol2, FiniteSet) + assert len(sol1) == len(sol2) + assert all(isclose(v1, v2) for v1, v2 in zip(sol1, sol2)) + + +def assert_close_nl(sol1, sol2): + """Test solutions with floats from nonlinsolve are close""" + sol1 = sympify(sol1) + sol2 = sympify(sol2) + assert isinstance(sol1, FiniteSet) + assert isinstance(sol2, FiniteSet) + assert len(sol1) == len(sol2) + for s1, s2 in zip(sol1, sol2): + assert len(s1) == len(s2) + assert all(isclose(v1, v2) for v1, v2 in zip(s1, s2)) + + +@_both_exp_pow +def test_invert_real(): + x = Symbol('x', real=True) + + def ireal(x, s=S.Reals): + return Intersection(s, x) + + assert invert_real(exp(x), z, x) == (x, ireal(FiniteSet(log(z)))) + + y = Symbol('y', positive=True) + n = Symbol('n', real=True) + assert invert_real(x + 3, y, x) == (x, FiniteSet(y - 3)) + assert invert_real(x*3, y, x) == (x, FiniteSet(y / 3)) + + assert invert_real(exp(x), y, x) == (x, FiniteSet(log(y))) + assert invert_real(exp(3*x), y, x) == (x, FiniteSet(log(y) / 3)) + assert invert_real(exp(x + 3), y, x) == (x, FiniteSet(log(y) - 3)) + + assert invert_real(exp(x) + 3, y, x) == (x, ireal(FiniteSet(log(y - 3)))) + assert invert_real(exp(x)*3, y, x) == (x, FiniteSet(log(y / 3))) + + assert invert_real(log(x), y, x) == (x, FiniteSet(exp(y))) + assert invert_real(log(3*x), y, x) == (x, FiniteSet(exp(y) / 3)) + assert invert_real(log(x + 3), y, x) == (x, FiniteSet(exp(y) - 3)) + + assert invert_real(Abs(x), y, x) == (x, FiniteSet(y, -y)) + + assert invert_real(2**x, y, x) == (x, FiniteSet(log(y)/log(2))) + assert invert_real(2**exp(x), y, x) == (x, ireal(FiniteSet(log(log(y)/log(2))))) + + assert invert_real(x**2, y, x) == (x, FiniteSet(sqrt(y), -sqrt(y))) + assert invert_real(x**S.Half, y, x) == (x, FiniteSet(y**2)) + + raises(ValueError, lambda: invert_real(x, x, x)) + + # issue 21236 + assert invert_real(x**pi, y, x) == (x, FiniteSet(y**(1/pi))) + assert invert_real(x**pi, -E, x) == (x, S.EmptySet) + assert invert_real(x**Rational(3/2), 1000, x) == (x, FiniteSet(100)) + assert invert_real(x**1.0, 1, x) == (x**1.0, FiniteSet(1)) + + raises(ValueError, lambda: invert_real(S.One, y, x)) + + assert invert_real(x**31 + x, y, x) == (x**31 + x, FiniteSet(y)) + + lhs = x**31 + x + base_values = FiniteSet(y - 1, -y - 1) + assert invert_real(Abs(x**31 + x + 1), y, x) == (lhs, base_values) + + assert dumeq(invert_real(sin(x), y, x), (x, + ConditionSet(x, (S(-1) <= y) & (y <= S(1)), Union( + ImageSet(Lambda(n, 2*n*pi + asin(y)), S.Integers), + ImageSet(Lambda(n, pi*2*n + pi - asin(y)), S.Integers))))) + + assert dumeq(invert_real(sin(exp(x)), y, x), (x, + ConditionSet(x, (S(-1) <= y) & (y <= S(1)), Union( + ImageSet(Lambda(n, log(2*n*pi + asin(y))), S.Integers), + ImageSet(Lambda(n, log(pi*2*n + pi - asin(y))), S.Integers))))) + + assert dumeq(invert_real(csc(x), y, x), (x, + ConditionSet(x, ((S(1) <= y) & (y < oo)) | ((-oo < y) & (y <= S(-1))), + Union(ImageSet(Lambda(n, 2*n*pi + acsc(y)), S.Integers), + ImageSet(Lambda(n, 2*n*pi - acsc(y) + pi), S.Integers))))) + + assert dumeq(invert_real(csc(exp(x)), y, x), (x, + ConditionSet(x, ((S(1) <= y) & (y < oo)) | ((-oo < y) & (y <= S(-1))), + Union(ImageSet(Lambda(n, log(2*n*pi + acsc(y))), S.Integers), + ImageSet(Lambda(n, log(2*n*pi - acsc(y) + pi)), S.Integers))))) + + assert dumeq(invert_real(cos(x), y, x), (x, + ConditionSet(x, (S(-1) <= y) & (y <= S(1)), Union( + ImageSet(Lambda(n, 2*n*pi + acos(y)), S.Integers), + ImageSet(Lambda(n, 2*n*pi - acos(y)), S.Integers))))) + + assert dumeq(invert_real(cos(exp(x)), y, x), (x, + ConditionSet(x, (S(-1) <= y) & (y <= S(1)), Union( + ImageSet(Lambda(n, log(2*n*pi + acos(y))), S.Integers), + ImageSet(Lambda(n, log(2*n*pi - acos(y))), S.Integers))))) + + assert dumeq(invert_real(sec(x), y, x), (x, + ConditionSet(x, ((S(1) <= y) & (y < oo)) | ((-oo < y) & (y <= S(-1))), + Union(ImageSet(Lambda(n, 2*n*pi + asec(y)), S.Integers), \ + ImageSet(Lambda(n, 2*n*pi - asec(y)), S.Integers))))) + + assert dumeq(invert_real(sec(exp(x)), y, x), (x, + ConditionSet(x, ((S(1) <= y) & (y < oo)) | ((-oo < y) & (y <= S(-1))), + Union(ImageSet(Lambda(n, log(2*n*pi - asec(y))), S.Integers), + ImageSet(Lambda(n, log(2*n*pi + asec(y))), S.Integers))))) + + assert dumeq(invert_real(tan(x), y, x), (x, + ConditionSet(x, (-oo < y) & (y < oo), + ImageSet(Lambda(n, n*pi + atan(y)), S.Integers)))) + + assert dumeq(invert_real(tan(exp(x)), y, x), (x, + ConditionSet(x, (-oo < y) & (y < oo), + ImageSet(Lambda(n, log(n*pi + atan(y))), S.Integers)))) + + assert dumeq(invert_real(cot(x), y, x), (x, + ConditionSet(x, (-oo < y) & (y < oo), + ImageSet(Lambda(n, n*pi + acot(y)), S.Integers)))) + + assert dumeq(invert_real(cot(exp(x)), y, x), (x, + ConditionSet(x, (-oo < y) & (y < oo), + ImageSet(Lambda(n, log(n*pi + acot(y))), S.Integers)))) + + assert dumeq(invert_real(tan(tan(x)), y, x), + (x, ConditionSet(x, Eq(tan(tan(x)), y), S.Reals))) + # slight regression compared to previous result: + # (tan(x), imageset(Lambda(n, n*pi + atan(y)), S.Integers))) + + x = Symbol('x', positive=True) + assert invert_real(x**pi, y, x) == (x, FiniteSet(y**(1/pi))) + + r = Symbol('r', real=True) + p = Symbol('p', positive=True) + assert invert_real(sinh(x), r, x) == (x, FiniteSet(asinh(r))) + assert invert_real(sinh(log(x)), p, x) == (x, FiniteSet(exp(asinh(p)))) + + assert invert_real(cosh(x), r, x) == (x, Intersection( + FiniteSet(-acosh(r), acosh(r)), S.Reals)) + assert invert_real(cosh(x), p + 1, x) == (x, + FiniteSet(-acosh(p + 1), acosh(p + 1))) + + assert invert_real(tanh(x), r, x) == (x, Intersection(FiniteSet(atanh(r)), S.Reals)) + assert invert_real(coth(x), p+1, x) == (x, FiniteSet(acoth(p+1))) + assert invert_real(sech(x), r, x) == (x, Intersection( + FiniteSet(-asech(r), asech(r)), S.Reals)) + assert invert_real(csch(x), p, x) == (x, FiniteSet(acsch(p))) + + assert dumeq(invert_real(tanh(sin(x)), r, x), (x, + ConditionSet(x, (S(-1) <= atanh(r)) & (atanh(r) <= S(1)), Union( + ImageSet(Lambda(n, 2*n*pi + asin(atanh(r))), S.Integers), + ImageSet(Lambda(n, 2*n*pi - asin(atanh(r)) + pi), S.Integers))))) + + +def test_invert_trig_hyp_real(): + # check some codepaths that are not as easily reached otherwise + n = Dummy('n') + assert _invert_trig_hyp_real(cosh(x), Range(-5, 10, 1), x)[1].dummy_eq(Union( + ImageSet(Lambda(n, -acosh(n)), Range(1, 10, 1)), + ImageSet(Lambda(n, acosh(n)), Range(1, 10, 1)))) + assert _invert_trig_hyp_real(coth(x), Interval(-3, 2), x) == (x, Union( + Interval(-oo, -acoth(3)), Interval(acoth(2), oo))) + assert _invert_trig_hyp_real(tanh(x), Interval(-S.Half, 1), x) == (x, + Interval(-atanh(S.Half), oo)) + assert _invert_trig_hyp_real(sech(x), imageset(n, S.Half + n/3, S.Naturals0), x) == \ + (x, FiniteSet(-asech(S(1)/2), asech(S(1)/2), -asech(S(5)/6), asech(S(5)/6))) + assert _invert_trig_hyp_real(csch(x), S.Reals, x) == (x, + Union(Interval.open(-oo, 0), Interval.open(0, oo))) + + +def test_invert_complex(): + assert invert_complex(x + 3, y, x) == (x, FiniteSet(y - 3)) + assert invert_complex(x*3, y, x) == (x, FiniteSet(y / 3)) + assert invert_complex((x - 1)**3, 0, x) == (x, FiniteSet(1)) + + assert dumeq(invert_complex(exp(x), y, x), + (x, imageset(Lambda(n, I*(2*pi*n + arg(y)) + log(Abs(y))), S.Integers))) + + assert invert_complex(log(x), y, x) == (x, FiniteSet(exp(y))) + + raises(ValueError, lambda: invert_real(1, y, x)) + raises(ValueError, lambda: invert_complex(x, x, x)) + raises(ValueError, lambda: invert_complex(x, x, 1)) + + assert dumeq(invert_complex(sin(x), I, x), (x, Union( + ImageSet(Lambda(n, 2*n*pi + I*log(1 + sqrt(2))), S.Integers), + ImageSet(Lambda(n, 2*n*pi + pi - I*log(1 + sqrt(2))), S.Integers)))) + assert dumeq(invert_complex(cos(x), 1+I, x), (x, Union( + ImageSet(Lambda(n, 2*n*pi - acos(1 + I)), S.Integers), + ImageSet(Lambda(n, 2*n*pi + acos(1 + I)), S.Integers)))) + assert dumeq(invert_complex(tan(2*x), 1, x), (x, + ImageSet(Lambda(n, n*pi/2 + pi/8), S.Integers))) + assert dumeq(invert_complex(cot(x), 2*I, x), (x, + ImageSet(Lambda(n, n*pi - I*acoth(2)), S.Integers))) + + assert dumeq(invert_complex(sinh(x), 0, x), (x, Union( + ImageSet(Lambda(n, 2*n*I*pi), S.Integers), + ImageSet(Lambda(n, 2*n*I*pi + I*pi), S.Integers)))) + assert dumeq(invert_complex(cosh(x), 0, x), (x, Union( + ImageSet(Lambda(n, 2*n*I*pi + I*pi/2), S.Integers), + ImageSet(Lambda(n, 2*n*I*pi + 3*I*pi/2), S.Integers)))) + assert invert_complex(tanh(x), 1, x) == (x, S.EmptySet) + assert dumeq(invert_complex(tanh(x), a, x), (x, + ConditionSet(x, Ne(a, -1) & Ne(a, 1), + ImageSet(Lambda(n, n*I*pi + atanh(a)), S.Integers)))) + assert invert_complex(coth(x), 1, x) == (x, S.EmptySet) + assert dumeq(invert_complex(coth(x), a, x), (x, + ConditionSet(x, Ne(a, -1) & Ne(a, 1), + ImageSet(Lambda(n, n*I*pi + acoth(a)), S.Integers)))) + assert dumeq(invert_complex(sech(x), 2, x), (x, Union( + ImageSet(Lambda(n, 2*n*I*pi + I*pi/3), S.Integers), + ImageSet(Lambda(n, 2*n*I*pi + 5*I*pi/3), S.Integers)))) + + +def test_domain_check(): + assert domain_check(1/(1 + (1/(x+1))**2), x, -1) is False + assert domain_check(x**2, x, 0) is True + assert domain_check(x, x, oo) is False + assert domain_check(0, x, oo) is False + + +def test_issue_11536(): + assert solveset(0**x - 100, x, S.Reals) == S.EmptySet + assert solveset(0**x - 1, x, S.Reals) == FiniteSet(0) + + +def test_issue_17479(): + f = (x**2 + y**2)**2 + (x**2 + z**2)**2 - 2*(2*x**2 + y**2 + z**2) + fx = f.diff(x) + fy = f.diff(y) + fz = f.diff(z) + sol = nonlinsolve([fx, fy, fz], [x, y, z]) + assert len(sol) >= 4 and len(sol) <= 20 + # nonlinsolve has been giving a varying number of solutions + # (originally 18, then 20, now 19) due to various internal changes. + # Unfortunately not all the solutions are actually valid and some are + # redundant. Since the original issue was that an exception was raised, + # this first test only checks that nonlinsolve returns a "plausible" + # solution set. The next test checks the result for correctness. + + +@XFAIL +def test_issue_18449(): + x, y, z = symbols("x, y, z") + f = (x**2 + y**2)**2 + (x**2 + z**2)**2 - 2*(2*x**2 + y**2 + z**2) + fx = diff(f, x) + fy = diff(f, y) + fz = diff(f, z) + sol = nonlinsolve([fx, fy, fz], [x, y, z]) + for (xs, ys, zs) in sol: + d = {x: xs, y: ys, z: zs} + assert tuple(_.subs(d).simplify() for _ in (fx, fy, fz)) == (0, 0, 0) + # After simplification and removal of duplicate elements, there should + # only be 4 parametric solutions left: + # simplifiedsolutions = FiniteSet((sqrt(1 - z**2), z, z), + # (-sqrt(1 - z**2), z, z), + # (sqrt(1 - z**2), -z, z), + # (-sqrt(1 - z**2), -z, z)) + # TODO: Is the above solution set definitely complete? + + +def test_issue_21047(): + f = (2 - x)**2 + (sqrt(x - 1) - 1)**6 + assert solveset(f, x, S.Reals) == FiniteSet(2) + + f = (sqrt(x)-1)**2 + (sqrt(x)+1)**2 -2*x**2 + sqrt(2) + assert solveset(f, x, S.Reals) == FiniteSet( + S.Half - sqrt(2*sqrt(2) + 5)/2, S.Half + sqrt(2*sqrt(2) + 5)/2) + + +def test_is_function_class_equation(): + assert _is_function_class_equation(TrigonometricFunction, + tan(x), x) is True + assert _is_function_class_equation(TrigonometricFunction, + tan(x) - 1, x) is True + assert _is_function_class_equation(TrigonometricFunction, + tan(x) + sin(x), x) is True + assert _is_function_class_equation(TrigonometricFunction, + tan(x) + sin(x) - a, x) is True + assert _is_function_class_equation(TrigonometricFunction, + sin(x)*tan(x) + sin(x), x) is True + assert _is_function_class_equation(TrigonometricFunction, + sin(x)*tan(x + a) + sin(x), x) is True + assert _is_function_class_equation(TrigonometricFunction, + sin(x)*tan(x*a) + sin(x), x) is True + assert _is_function_class_equation(TrigonometricFunction, + a*tan(x) - 1, x) is True + assert _is_function_class_equation(TrigonometricFunction, + tan(x)**2 + sin(x) - 1, x) is True + assert _is_function_class_equation(TrigonometricFunction, + tan(x) + x, x) is False + assert _is_function_class_equation(TrigonometricFunction, + tan(x**2), x) is False + assert _is_function_class_equation(TrigonometricFunction, + tan(x**2) + sin(x), x) is False + assert _is_function_class_equation(TrigonometricFunction, + tan(x)**sin(x), x) is False + assert _is_function_class_equation(TrigonometricFunction, + tan(sin(x)) + sin(x), x) is False + assert _is_function_class_equation(HyperbolicFunction, + tanh(x), x) is True + assert _is_function_class_equation(HyperbolicFunction, + tanh(x) - 1, x) is True + assert _is_function_class_equation(HyperbolicFunction, + tanh(x) + sinh(x), x) is True + assert _is_function_class_equation(HyperbolicFunction, + tanh(x) + sinh(x) - a, x) is True + assert _is_function_class_equation(HyperbolicFunction, + sinh(x)*tanh(x) + sinh(x), x) is True + assert _is_function_class_equation(HyperbolicFunction, + sinh(x)*tanh(x + a) + sinh(x), x) is True + assert _is_function_class_equation(HyperbolicFunction, + sinh(x)*tanh(x*a) + sinh(x), x) is True + assert _is_function_class_equation(HyperbolicFunction, + a*tanh(x) - 1, x) is True + assert _is_function_class_equation(HyperbolicFunction, + tanh(x)**2 + sinh(x) - 1, x) is True + assert _is_function_class_equation(HyperbolicFunction, + tanh(x) + x, x) is False + assert _is_function_class_equation(HyperbolicFunction, + tanh(x**2), x) is False + assert _is_function_class_equation(HyperbolicFunction, + tanh(x**2) + sinh(x), x) is False + assert _is_function_class_equation(HyperbolicFunction, + tanh(x)**sinh(x), x) is False + assert _is_function_class_equation(HyperbolicFunction, + tanh(sinh(x)) + sinh(x), x) is False + + +def test_garbage_input(): + raises(ValueError, lambda: solveset_real([y], y)) + x = Symbol('x', real=True) + assert solveset_real(x, 1) == S.EmptySet + assert solveset_real(x - 1, 1) == FiniteSet(x) + assert solveset_real(x, pi) == S.EmptySet + assert solveset_real(x, x**2) == S.EmptySet + + raises(ValueError, lambda: solveset_complex([x], x)) + assert solveset_complex(x, pi) == S.EmptySet + + raises(ValueError, lambda: solveset((x, y), x)) + raises(ValueError, lambda: solveset(x + 1, S.Reals)) + raises(ValueError, lambda: solveset(x + 1, x, 2)) + + +def test_solve_mul(): + assert solveset_real((a*x + b)*(exp(x) - 3), x) == \ + Union({log(3)}, Intersection({-b/a}, S.Reals)) + anz = Symbol('anz', nonzero=True) + bb = Symbol('bb', real=True) + assert solveset_real((anz*x + bb)*(exp(x) - 3), x) == \ + FiniteSet(-bb/anz, log(3)) + assert solveset_real((2*x + 8)*(8 + exp(x)), x) == FiniteSet(S(-4)) + assert solveset_real(x/log(x), x) is S.EmptySet + + +def test_solve_invert(): + assert solveset_real(exp(x) - 3, x) == FiniteSet(log(3)) + assert solveset_real(log(x) - 3, x) == FiniteSet(exp(3)) + + assert solveset_real(3**(x + 2), x) == FiniteSet() + assert solveset_real(3**(2 - x), x) == FiniteSet() + + assert solveset_real(y - b*exp(a/x), x) == Intersection( + S.Reals, FiniteSet(a/log(y/b))) + + # issue 4504 + assert solveset_real(2**x - 10, x) == FiniteSet(1 + log(5)/log(2)) + + +def test_issue_25768(): + assert dumeq(solveset_real(sin(x) - S.Half, x), Union( + ImageSet(Lambda(n, pi*2*n + pi/6), S.Integers), + ImageSet(Lambda(n, pi*2*n + pi*5/6), S.Integers))) + n1 = solveset_real(sin(x) - 0.5, x).n(5) + n2 = solveset_real(sin(x) - S.Half, x).n(5) + # help pass despite fp differences + eq = [i.replace( + lambda x:x.is_Float, + lambda x:Rational(x).limit_denominator(1000)) for i in (n1, n2)] + assert dumeq(*eq),(n1,n2) + + +def test_errorinverses(): + assert solveset_real(erf(x) - S.Half, x) == \ + FiniteSet(erfinv(S.Half)) + assert solveset_real(erfinv(x) - 2, x) == \ + FiniteSet(erf(2)) + assert solveset_real(erfc(x) - S.One, x) == \ + FiniteSet(erfcinv(S.One)) + assert solveset_real(erfcinv(x) - 2, x) == FiniteSet(erfc(2)) + + +def test_solve_polynomial(): + x = Symbol('x', real=True) + y = Symbol('y', real=True) + assert solveset_real(3*x - 2, x) == FiniteSet(Rational(2, 3)) + + assert solveset_real(x**2 - 1, x) == FiniteSet(-S.One, S.One) + assert solveset_real(x - y**3, x) == FiniteSet(y ** 3) + + assert solveset_real(x**3 - 15*x - 4, x) == FiniteSet( + -2 + 3 ** S.Half, + S(4), + -2 - 3 ** S.Half) + + assert solveset_real(sqrt(x) - 1, x) == FiniteSet(1) + assert solveset_real(sqrt(x) - 2, x) == FiniteSet(4) + assert solveset_real(x**Rational(1, 4) - 2, x) == FiniteSet(16) + assert solveset_real(x**Rational(1, 3) - 3, x) == FiniteSet(27) + assert len(solveset_real(x**5 + x**3 + 1, x)) == 1 + assert len(solveset_real(-2*x**3 + 4*x**2 - 2*x + 6, x)) > 0 + assert solveset_real(x**6 + x**4 + I, x) is S.EmptySet + + +def test_return_root_of(): + f = x**5 - 15*x**3 - 5*x**2 + 10*x + 20 + s = list(solveset_complex(f, x)) + for root in s: + assert root.func == CRootOf + + # if one uses solve to get the roots of a polynomial that has a CRootOf + # solution, make sure that the use of nfloat during the solve process + # doesn't fail. Note: if you want numerical solutions to a polynomial + # it is *much* faster to use nroots to get them than to solve the + # equation only to get CRootOf solutions which are then numerically + # evaluated. So for eq = x**5 + 3*x + 7 do Poly(eq).nroots() rather + # than [i.n() for i in solve(eq)] to get the numerical roots of eq. + assert nfloat(list(solveset_complex(x**5 + 3*x**3 + 7, x))[0], + exponent=False) == CRootOf(x**5 + 3*x**3 + 7, 0).n() + + sol = list(solveset_complex(x**6 - 2*x + 2, x)) + assert all(isinstance(i, CRootOf) for i in sol) and len(sol) == 6 + + f = x**5 - 15*x**3 - 5*x**2 + 10*x + 20 + s = list(solveset_complex(f, x)) + for root in s: + assert root.func == CRootOf + + s = x**5 + 4*x**3 + 3*x**2 + Rational(7, 4) + assert solveset_complex(s, x) == \ + FiniteSet(*Poly(s*4, domain='ZZ').all_roots()) + + # Refer issue #7876 + eq = x*(x - 1)**2*(x + 1)*(x**6 - x + 1) + assert solveset_complex(eq, x) == \ + FiniteSet(-1, 0, 1, CRootOf(x**6 - x + 1, 0), + CRootOf(x**6 - x + 1, 1), + CRootOf(x**6 - x + 1, 2), + CRootOf(x**6 - x + 1, 3), + CRootOf(x**6 - x + 1, 4), + CRootOf(x**6 - x + 1, 5)) + + +def test_solveset_sqrt_1(): + assert solveset_real(sqrt(5*x + 6) - 2 - x, x) == \ + FiniteSet(-S.One, S(2)) + assert solveset_real(sqrt(x - 1) - x + 7, x) == FiniteSet(10) + assert solveset_real(sqrt(x - 2) - 5, x) == FiniteSet(27) + assert solveset_real(sqrt(x) - 2 - 5, x) == FiniteSet(49) + assert solveset_real(sqrt(x**3), x) == FiniteSet(0) + assert solveset_real(sqrt(x - 1), x) == FiniteSet(1) + assert solveset_real(sqrt((x-3)/x), x) == FiniteSet(3) + assert solveset_real(sqrt((x-3)/x)-Rational(1, 2), x) == \ + FiniteSet(4) + +def test_solveset_sqrt_2(): + x = Symbol('x', real=True) + y = Symbol('y', real=True) + # http://tutorial.math.lamar.edu/Classes/Alg/SolveRadicalEqns.aspx#Solve_Rad_Ex2_a + assert solveset_real(sqrt(2*x - 1) - sqrt(x - 4) - 2, x) == \ + FiniteSet(S(5), S(13)) + assert solveset_real(sqrt(x + 7) + 2 - sqrt(3 - x), x) == \ + FiniteSet(-6) + + # http://www.purplemath.com/modules/solverad.htm + assert solveset_real(sqrt(17*x - sqrt(x**2 - 5)) - 7, x) == \ + FiniteSet(3) + + eq = x + 1 - (x**4 + 4*x**3 - x)**Rational(1, 4) + assert solveset_real(eq, x) == FiniteSet(Rational(-1, 2), Rational(-1, 3)) + + eq = sqrt(2*x + 9) - sqrt(x + 1) - sqrt(x + 4) + assert solveset_real(eq, x) == FiniteSet(0) + + eq = sqrt(x + 4) + sqrt(2*x - 1) - 3*sqrt(x - 1) + assert solveset_real(eq, x) == FiniteSet(5) + + eq = sqrt(x)*sqrt(x - 7) - 12 + assert solveset_real(eq, x) == FiniteSet(16) + + eq = sqrt(x - 3) + sqrt(x) - 3 + assert solveset_real(eq, x) == FiniteSet(4) + + eq = sqrt(2*x**2 - 7) - (3 - x) + assert solveset_real(eq, x) == FiniteSet(-S(8), S(2)) + + # others + eq = sqrt(9*x**2 + 4) - (3*x + 2) + assert solveset_real(eq, x) == FiniteSet(0) + + assert solveset_real(sqrt(x - 3) - sqrt(x) - 3, x) == FiniteSet() + + eq = (2*x - 5)**Rational(1, 3) - 3 + assert solveset_real(eq, x) == FiniteSet(16) + + assert solveset_real(sqrt(x) + sqrt(sqrt(x)) - 4, x) == \ + FiniteSet((Rational(-1, 2) + sqrt(17)/2)**4) + + eq = sqrt(x) - sqrt(x - 1) + sqrt(sqrt(x)) + assert solveset_real(eq, x) == FiniteSet() + + eq = (x - 4)**2 + (sqrt(x) - 2)**4 + assert solveset_real(eq, x) == FiniteSet(-4, 4) + + eq = (sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) + ans = solveset_real(eq, x) + ra = S('''-1484/375 - 4*(-S(1)/2 + sqrt(3)*I/2)*(-12459439/52734375 + + 114*sqrt(12657)/78125)**(S(1)/3) - 172564/(140625*(-S(1)/2 + + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(S(1)/3))''') + rb = Rational(4, 5) + assert all(abs(eq.subs(x, i).n()) < 1e-10 for i in (ra, rb)) and \ + len(ans) == 2 and \ + {i.n(chop=True) for i in ans} == \ + {i.n(chop=True) for i in (ra, rb)} + + assert solveset_real(sqrt(x) + x**Rational(1, 3) + + x**Rational(1, 4), x) == FiniteSet(0) + + assert solveset_real(x/sqrt(x**2 + 1), x) == FiniteSet(0) + + eq = (x - y**3)/((y**2)*sqrt(1 - y**2)) + assert solveset_real(eq, x) == FiniteSet(y**3) + + # issue 4497 + assert solveset_real(1/(5 + x)**Rational(1, 5) - 9, x) == \ + FiniteSet(Rational(-295244, 59049)) + + +@XFAIL +def test_solve_sqrt_fail(): + # this only works if we check real_root(eq.subs(x, Rational(1, 3))) + # but checksol doesn't work like that + eq = (x**3 - 3*x**2)**Rational(1, 3) + 1 - x + assert solveset_real(eq, x) == FiniteSet(Rational(1, 3)) + + +@slow +def test_solve_sqrt_3(): + R = Symbol('R') + eq = sqrt(2)*R*sqrt(1/(R + 1)) + (R + 1)*(sqrt(2)*sqrt(1/(R + 1)) - 1) + sol = solveset_complex(eq, R) + fset = [Rational(5, 3) + 4*sqrt(10)*cos(atan(3*sqrt(111)/251)/3)/3, + -sqrt(10)*cos(atan(3*sqrt(111)/251)/3)/3 + + 40*re(1/((Rational(-1, 2) - sqrt(3)*I/2)*(Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3)))/9 + + sqrt(30)*sin(atan(3*sqrt(111)/251)/3)/3 + Rational(5, 3) + + I*(-sqrt(30)*cos(atan(3*sqrt(111)/251)/3)/3 - + sqrt(10)*sin(atan(3*sqrt(111)/251)/3)/3 + + 40*im(1/((Rational(-1, 2) - sqrt(3)*I/2)*(Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3)))/9)] + cset = [40*re(1/((Rational(-1, 2) + sqrt(3)*I/2)*(Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3)))/9 - + sqrt(10)*cos(atan(3*sqrt(111)/251)/3)/3 - sqrt(30)*sin(atan(3*sqrt(111)/251)/3)/3 + + Rational(5, 3) + + I*(40*im(1/((Rational(-1, 2) + sqrt(3)*I/2)*(Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3)))/9 - + sqrt(10)*sin(atan(3*sqrt(111)/251)/3)/3 + + sqrt(30)*cos(atan(3*sqrt(111)/251)/3)/3)] + + fs = FiniteSet(*fset) + cs = ConditionSet(R, Eq(eq, 0), FiniteSet(*cset)) + assert sol == (fs - {-1}) | (cs - {-1}) + + # the number of real roots will depend on the value of m: for m=1 there are 4 + # and for m=-1 there are none. + eq = -sqrt((m - q)**2 + (-m/(2*q) + S.Half)**2) + sqrt((-m**2/2 - sqrt( + 4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2 + (m**2/2 - m - sqrt( + 4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2) + unsolved_object = ConditionSet(q, Eq(sqrt((m - q)**2 + (-m/(2*q) + S.Half)**2) - + sqrt((-m**2/2 - sqrt(4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2 + (m**2/2 - m - + sqrt(4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2), 0), S.Reals) + assert solveset_real(eq, q) == unsolved_object + + +def test_solve_polynomial_symbolic_param(): + assert solveset_complex((x**2 - 1)**2 - a, x) == \ + FiniteSet(sqrt(1 + sqrt(a)), -sqrt(1 + sqrt(a)), + sqrt(1 - sqrt(a)), -sqrt(1 - sqrt(a))) + + # issue 4507 + assert solveset_complex(y - b/(1 + a*x), x) == \ + FiniteSet((b/y - 1)/a) - FiniteSet(-1/a) + + # issue 4508 + assert solveset_complex(y - b*x/(a + x), x) == \ + FiniteSet(-a*y/(y - b)) - FiniteSet(-a) + + +def test_solve_rational(): + assert solveset_real(1/x + 1, x) == FiniteSet(-S.One) + assert solveset_real(1/exp(x) - 1, x) == FiniteSet(0) + assert solveset_real(x*(1 - 5/x), x) == FiniteSet(5) + assert solveset_real(2*x/(x + 2) - 1, x) == FiniteSet(2) + assert solveset_real((x**2/(7 - x)).diff(x), x) == \ + FiniteSet(S.Zero, S(14)) + + +def test_solveset_real_gen_is_pow(): + assert solveset_real(sqrt(1) + 1, x) is S.EmptySet + + +def test_no_sol(): + assert solveset(1 - oo*x) is S.EmptySet + assert solveset(oo*x, x) is S.EmptySet + assert solveset(oo*x - oo, x) is S.EmptySet + assert solveset_real(4, x) is S.EmptySet + assert solveset_real(exp(x), x) is S.EmptySet + assert solveset_real(x**2 + 1, x) is S.EmptySet + assert solveset_real(-3*a/sqrt(x), x) is S.EmptySet + assert solveset_real(1/x, x) is S.EmptySet + assert solveset_real(-(1 + x)/(2 + x)**2 + 1/(2 + x), x + ) is S.EmptySet + + +def test_sol_zero_real(): + assert solveset_real(0, x) == S.Reals + assert solveset(0, x, Interval(1, 2)) == Interval(1, 2) + assert solveset_real(-x**2 - 2*x + (x + 1)**2 - 1, x) == S.Reals + + +def test_no_sol_rational_extragenous(): + assert solveset_real((x/(x + 1) + 3)**(-2), x) is S.EmptySet + assert solveset_real((x - 1)/(1 + 1/(x - 1)), x) is S.EmptySet + + +def test_solve_polynomial_cv_1a(): + """ + Test for solving on equations that can be converted to + a polynomial equation using the change of variable y -> x**Rational(p, q) + """ + assert solveset_real(sqrt(x) - 1, x) == FiniteSet(1) + assert solveset_real(sqrt(x) - 2, x) == FiniteSet(4) + assert solveset_real(x**Rational(1, 4) - 2, x) == FiniteSet(16) + assert solveset_real(x**Rational(1, 3) - 3, x) == FiniteSet(27) + assert solveset_real(x*(x**(S.One / 3) - 3), x) == \ + FiniteSet(S.Zero, S(27)) + + +def test_solveset_real_rational(): + """Test solveset_real for rational functions""" + x = Symbol('x', real=True) + y = Symbol('y', real=True) + assert solveset_real((x - y**3) / ((y**2)*sqrt(1 - y**2)), x) \ + == FiniteSet(y**3) + # issue 4486 + assert solveset_real(2*x/(x + 2) - 1, x) == FiniteSet(2) + + +def test_solveset_real_log(): + assert solveset_real(log((x-1)*(x+1)), x) == \ + FiniteSet(sqrt(2), -sqrt(2)) + + +def test_poly_gens(): + assert solveset_real(4**(2*(x**2) + 2*x) - 8, x) == \ + FiniteSet(Rational(-3, 2), S.Half) + + +def test_solve_abs(): + n = Dummy('n') + raises(ValueError, lambda: solveset(Abs(x) - 1, x)) + assert solveset(Abs(x) - n, x, S.Reals).dummy_eq( + ConditionSet(x, Contains(n, Interval(0, oo)), {-n, n})) + assert solveset_real(Abs(x) - 2, x) == FiniteSet(-2, 2) + assert solveset_real(Abs(x) + 2, x) is S.EmptySet + assert solveset_real(Abs(x + 3) - 2*Abs(x - 3), x) == \ + FiniteSet(1, 9) + assert solveset_real(2*Abs(x) - Abs(x - 1), x) == \ + FiniteSet(-1, Rational(1, 3)) + + sol = ConditionSet( + x, + And( + Contains(b, Interval(0, oo)), + Contains(a + b, Interval(0, oo)), + Contains(a - b, Interval(0, oo))), + FiniteSet(-a - b - 3, -a + b - 3, a - b - 3, a + b - 3)) + eq = Abs(Abs(x + 3) - a) - b + assert invert_real(eq, 0, x)[1] == sol + reps = {a: 3, b: 1} + eqab = eq.subs(reps) + for si in sol.subs(reps): + assert not eqab.subs(x, si) + assert dumeq(solveset(Eq(sin(Abs(x)), 1), x, domain=S.Reals), Union( + Intersection(Interval(0, oo), Union( + Intersection(ImageSet(Lambda(n, 2*n*pi + 3*pi/2), S.Integers), + Interval(-oo, 0)), + Intersection(ImageSet(Lambda(n, 2*n*pi + pi/2), S.Integers), + Interval(0, oo)))))) + + +def test_issue_9824(): + assert dumeq(solveset(sin(x)**2 - 2*sin(x) + 1, x), ImageSet(Lambda(n, 2*n*pi + pi/2), S.Integers)) + assert dumeq(solveset(cos(x)**2 - 2*cos(x) + 1, x), ImageSet(Lambda(n, 2*n*pi), S.Integers)) + + +def test_issue_9565(): + assert solveset_real(Abs((x - 1)/(x - 5)) <= Rational(1, 3), x) == Interval(-1, 2) + + +def test_issue_10069(): + eq = abs(1/(x - 1)) - 1 > 0 + assert solveset_real(eq, x) == Union( + Interval.open(0, 1), Interval.open(1, 2)) + + +def test_real_imag_splitting(): + a, b = symbols('a b', real=True) + assert solveset_real(sqrt(a**2 - b**2) - 3, a) == \ + FiniteSet(-sqrt(b**2 + 9), sqrt(b**2 + 9)) + assert solveset_real(sqrt(a**2 + b**2) - 3, a) != \ + S.EmptySet + + +def test_units(): + assert solveset_real(1/x - 1/(2*cm), x) == FiniteSet(2*cm) + + +def test_solve_only_exp_1(): + y = Symbol('y', positive=True) + assert solveset_real(exp(x) - y, x) == FiniteSet(log(y)) + assert solveset_real(exp(x) + exp(-x) - 4, x) == \ + FiniteSet(log(-sqrt(3) + 2), log(sqrt(3) + 2)) + assert solveset_real(exp(x) + exp(-x) - y, x) != S.EmptySet + + +def test_atan2(): + # The .inverse() method on atan2 works only if x.is_real is True and the + # second argument is a real constant + assert solveset_real(atan2(x, 2) - pi/3, x) == FiniteSet(2*sqrt(3)) + + +def test_piecewise_solveset(): + eq = Piecewise((x - 2, Gt(x, 2)), (2 - x, True)) - 3 + assert set(solveset_real(eq, x)) == set(FiniteSet(-1, 5)) + + absxm3 = Piecewise( + (x - 3, 0 <= x - 3), + (3 - x, 0 > x - 3)) + y = Symbol('y', positive=True) + assert solveset_real(absxm3 - y, x) == FiniteSet(-y + 3, y + 3) + + f = Piecewise(((x - 2)**2, x >= 0), (0, True)) + assert solveset(f, x, domain=S.Reals) == Union(FiniteSet(2), Interval(-oo, 0, True, True)) + + assert solveset( + Piecewise((x + 1, x > 0), (I, True)) - I, x, S.Reals + ) == Interval(-oo, 0) + + assert solveset(Piecewise((x - 1, Ne(x, I)), (x, True)), x) == FiniteSet(1) + + # issue 19718 + g = Piecewise((1, x > 10), (0, True)) + assert solveset(g > 0, x, S.Reals) == Interval.open(10, oo) + + from sympy.logic.boolalg import BooleanTrue + f = BooleanTrue() + assert solveset(f, x, domain=Interval(-3, 10)) == Interval(-3, 10) + + # issue 20552 + f = Piecewise((0, Eq(x, 0)), (x**2/Abs(x), True)) + g = Piecewise((0, Eq(x, pi)), ((x - pi)/sin(x), True)) + assert solveset(f, x, domain=S.Reals) == FiniteSet(0) + assert solveset(g) == FiniteSet(pi) + + +def test_solveset_complex_polynomial(): + assert solveset_complex(a*x**2 + b*x + c, x) == \ + FiniteSet(-b/(2*a) - sqrt(-4*a*c + b**2)/(2*a), + -b/(2*a) + sqrt(-4*a*c + b**2)/(2*a)) + + assert solveset_complex(x - y**3, y) == FiniteSet( + (-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) + + assert solveset_complex(x + 1/x - 1, x) == \ + FiniteSet(S.Half + I*sqrt(3)/2, S.Half - I*sqrt(3)/2) + + +def test_sol_zero_complex(): + assert solveset_complex(0, x) is S.Complexes + + +def test_solveset_complex_rational(): + assert solveset_complex((x - 1)*(x - I)/(x - 3), x) == \ + FiniteSet(1, I) + + assert solveset_complex((x - y**3)/((y**2)*sqrt(1 - y**2)), x) == \ + FiniteSet(y**3) + assert solveset_complex(-x**2 - I, x) == \ + FiniteSet(-sqrt(2)/2 + sqrt(2)*I/2, sqrt(2)/2 - sqrt(2)*I/2) + + +def test_solve_quintics(): + skip("This test is too slow") + f = x**5 - 110*x**3 - 55*x**2 + 2310*x + 979 + s = solveset_complex(f, x) + for root in s: + res = f.subs(x, root.n()).n() + assert tn(res, 0) + + f = x**5 + 15*x + 12 + s = solveset_complex(f, x) + for root in s: + res = f.subs(x, root.n()).n() + assert tn(res, 0) + + +def test_solveset_complex_exp(): + assert dumeq(solveset_complex(exp(x) - 1, x), + imageset(Lambda(n, I*2*n*pi), S.Integers)) + assert dumeq(solveset_complex(exp(x) - I, x), + imageset(Lambda(n, I*(2*n*pi + pi/2)), S.Integers)) + assert solveset_complex(1/exp(x), x) == S.EmptySet + assert dumeq(solveset_complex(sinh(x).rewrite(exp), x), + imageset(Lambda(n, n*pi*I), S.Integers)) + + +def test_solveset_real_exp(): + assert solveset(Eq((-2)**x, 4), x, S.Reals) == FiniteSet(2) + assert solveset(Eq(-2**x, 4), x, S.Reals) == S.EmptySet + assert solveset(Eq((-3)**x, 27), x, S.Reals) == S.EmptySet + assert solveset(Eq((-5)**(x+1), 625), x, S.Reals) == FiniteSet(3) + assert solveset(Eq(2**(x-3), -16), x, S.Reals) == S.EmptySet + assert solveset(Eq((-3)**(x - 3), -3**39), x, S.Reals) == FiniteSet(42) + assert solveset(Eq(2**x, y), x, S.Reals) == Intersection(S.Reals, FiniteSet(log(y)/log(2))) + + assert invert_real((-2)**(2*x) - 16, 0, x) == (x, FiniteSet(2)) + + +def test_solve_complex_log(): + assert solveset_complex(log(x), x) == FiniteSet(1) + assert solveset_complex(1 - log(a + 4*x**2), x) == \ + FiniteSet(-sqrt(-a + E)/2, sqrt(-a + E)/2) + + +def test_solve_complex_sqrt(): + assert solveset_complex(sqrt(5*x + 6) - 2 - x, x) == \ + FiniteSet(-S.One, S(2)) + assert solveset_complex(sqrt(5*x + 6) - (2 + 2*I) - x, x) == \ + FiniteSet(-S(2), 3 - 4*I) + assert solveset_complex(4*x*(1 - a * sqrt(x)), x) == \ + FiniteSet(S.Zero, 1 / a ** 2) + + +def test_solveset_complex_tan(): + s = solveset_complex(tan(x).rewrite(exp), x) + assert dumeq(s, imageset(Lambda(n, pi*n), S.Integers) - \ + imageset(Lambda(n, pi*n + pi/2), S.Integers)) + + +@_both_exp_pow +def test_solve_trig(): + assert dumeq(solveset_real(sin(x), x), + Union(imageset(Lambda(n, 2*pi*n), S.Integers), + imageset(Lambda(n, 2*pi*n + pi), S.Integers))) + + assert dumeq(solveset_real(sin(x) - 1, x), + imageset(Lambda(n, 2*pi*n + pi/2), S.Integers)) + + assert dumeq(solveset_real(cos(x), x), + Union(imageset(Lambda(n, 2*pi*n + pi/2), S.Integers), + imageset(Lambda(n, 2*pi*n + pi*Rational(3, 2)), S.Integers))) + + assert dumeq(solveset_real(sin(x) + cos(x), x), + Union(imageset(Lambda(n, 2*n*pi + pi*Rational(3, 4)), S.Integers), + imageset(Lambda(n, 2*n*pi + pi*Rational(7, 4)), S.Integers))) + + assert solveset_real(sin(x)**2 + cos(x)**2, x) == S.EmptySet + + assert dumeq(solveset_complex(cos(x) - S.Half, x), + Union(imageset(Lambda(n, 2*n*pi + pi*Rational(5, 3)), S.Integers), + imageset(Lambda(n, 2*n*pi + pi/3), S.Integers))) + + assert dumeq(solveset(sin(y + a) - sin(y), a, domain=S.Reals), + ConditionSet(a, (S(-1) <= sin(y)) & (sin(y) <= S(1)), Union( + ImageSet(Lambda(n, 2*n*pi - y + asin(sin(y))), S.Integers), + ImageSet(Lambda(n, 2*n*pi - y - asin(sin(y)) + pi), S.Integers)))) + + assert dumeq(solveset_real(sin(2*x)*cos(x) + cos(2*x)*sin(x)-1, x), + ImageSet(Lambda(n, n*pi*Rational(2, 3) + pi/6), S.Integers)) + + assert dumeq(solveset_real(2*tan(x)*sin(x) + 1, x), Union( + ImageSet(Lambda(n, 2*n*pi + atan(sqrt(2)*sqrt(-1 + sqrt(17))/ + (1 - sqrt(17))) + pi), S.Integers), + ImageSet(Lambda(n, 2*n*pi - atan(sqrt(2)*sqrt(-1 + sqrt(17))/ + (1 - sqrt(17))) + pi), S.Integers))) + + assert dumeq(solveset_real(cos(2*x)*cos(4*x) - 1, x), + ImageSet(Lambda(n, n*pi), S.Integers)) + + assert dumeq(solveset(sin(x/10) + Rational(3, 4)), Union( + ImageSet(Lambda(n, 20*n*pi - 10*asin(S(3)/4) + 20*pi), S.Integers), + ImageSet(Lambda(n, 20*n*pi + 10*asin(S(3)/4) + 10*pi), S.Integers))) + + assert dumeq(solveset(cos(x/15) + cos(x/5)), Union( + ImageSet(Lambda(n, 30*n*pi + 15*pi/2), S.Integers), + ImageSet(Lambda(n, 30*n*pi + 45*pi/2), S.Integers), + ImageSet(Lambda(n, 30*n*pi + 75*pi/4), S.Integers), + ImageSet(Lambda(n, 30*n*pi + 45*pi/4), S.Integers), + ImageSet(Lambda(n, 30*n*pi + 105*pi/4), S.Integers), + ImageSet(Lambda(n, 30*n*pi + 15*pi/4), S.Integers))) + + assert dumeq(solveset(sec(sqrt(2)*x/3) + 5), Union( + ImageSet(Lambda(n, 3*sqrt(2)*(2*n*pi - asec(-5))/2), S.Integers), + ImageSet(Lambda(n, 3*sqrt(2)*(2*n*pi + asec(-5))/2), S.Integers))) + + assert dumeq(simplify(solveset(tan(pi*x) - cot(pi/2*x))), Union( + ImageSet(Lambda(n, 4*n + 1), S.Integers), + ImageSet(Lambda(n, 4*n + 3), S.Integers), + ImageSet(Lambda(n, 4*n + Rational(7, 3)), S.Integers), + ImageSet(Lambda(n, 4*n + Rational(5, 3)), S.Integers), + ImageSet(Lambda(n, 4*n + Rational(11, 3)), S.Integers), + ImageSet(Lambda(n, 4*n + Rational(1, 3)), S.Integers))) + + assert dumeq(solveset(cos(9*x)), Union( + ImageSet(Lambda(n, 2*n*pi/9 + pi/18), S.Integers), + ImageSet(Lambda(n, 2*n*pi/9 + pi/6), S.Integers))) + + assert dumeq(solveset(sin(8*x) + cot(12*x), x, S.Reals), Union( + ImageSet(Lambda(n, n*pi/2 + pi/8), S.Integers), + ImageSet(Lambda(n, n*pi/2 + 3*pi/8), S.Integers), + ImageSet(Lambda(n, n*pi/2 + 5*pi/16), S.Integers), + ImageSet(Lambda(n, n*pi/2 + 3*pi/16), S.Integers), + ImageSet(Lambda(n, n*pi/2 + 7*pi/16), S.Integers), + ImageSet(Lambda(n, n*pi/2 + pi/16), S.Integers))) + + # This is the only remaining solveset test that actually ends up being solved + # by _solve_trig2(). All others are handled by the improved _solve_trig1. + assert dumeq(solveset_real(2*cos(x)*cos(2*x) - 1, x), + Union(ImageSet(Lambda(n, 2*n*pi + 2*atan(sqrt(-2*2**Rational(1, 3)*(67 + + 9*sqrt(57))**Rational(2, 3) + 8*2**Rational(2, 3) + 11*(67 + + 9*sqrt(57))**Rational(1, 3))/(3*(67 + 9*sqrt(57))**Rational(1, 6)))), S.Integers), + ImageSet(Lambda(n, 2*n*pi - 2*atan(sqrt(-2*2**Rational(1, 3)*(67 + + 9*sqrt(57))**Rational(2, 3) + 8*2**Rational(2, 3) + 11*(67 + + 9*sqrt(57))**Rational(1, 3))/(3*(67 + 9*sqrt(57))**Rational(1, 6))) + + 2*pi), S.Integers))) + + # issue #16870 + assert dumeq(simplify(solveset(sin(x/180*pi) - S.Half, x, S.Reals)), Union( + ImageSet(Lambda(n, 360*n + 150), S.Integers), + ImageSet(Lambda(n, 360*n + 30), S.Integers))) + + +def test_solve_trig_hyp_by_inversion(): + n = Dummy('n') + assert solveset_real(sin(2*x + 3) - S(1)/2, x).dummy_eq(Union( + ImageSet(Lambda(n, n*pi - S(3)/2 + 13*pi/12), S.Integers), + ImageSet(Lambda(n, n*pi - S(3)/2 + 17*pi/12), S.Integers))) + assert solveset_complex(sin(2*x + 3) - S(1)/2, x).dummy_eq(Union( + ImageSet(Lambda(n, n*pi - S(3)/2 + 13*pi/12), S.Integers), + ImageSet(Lambda(n, n*pi - S(3)/2 + 17*pi/12), S.Integers))) + assert solveset_real(tan(x) - tan(pi/10), x).dummy_eq( + ImageSet(Lambda(n, n*pi + pi/10), S.Integers)) + assert solveset_complex(tan(x) - tan(pi/10), x).dummy_eq( + ImageSet(Lambda(n, n*pi + pi/10), S.Integers)) + + assert solveset_real(3*cosh(2*x) - 5, x) == FiniteSet( + -acosh(S(5)/3)/2, acosh(S(5)/3)/2) + assert solveset_complex(3*cosh(2*x) - 5, x).dummy_eq(Union( + ImageSet(Lambda(n, n*I*pi - acosh(S(5)/3)/2), S.Integers), + ImageSet(Lambda(n, n*I*pi + acosh(S(5)/3)/2), S.Integers))) + assert solveset_real(sinh(x - 3) - 2, x) == FiniteSet( + asinh(2) + 3) + assert solveset_complex(sinh(x - 3) - 2, x).dummy_eq(Union( + ImageSet(Lambda(n, 2*n*I*pi + asinh(2) + 3), S.Integers), + ImageSet(Lambda(n, 2*n*I*pi - asinh(2) + 3 + I*pi), S.Integers))) + + assert solveset_real(cos(sinh(x))-cos(pi/12), x).dummy_eq(Union( + ImageSet(Lambda(n, asinh(2*n*pi + pi/12)), S.Integers), + ImageSet(Lambda(n, asinh(2*n*pi + 23*pi/12)), S.Integers))) + assert solveset(cos(sinh(x))-cos(pi/12), x, Interval(2,3)) == \ + FiniteSet(asinh(23*pi/12), asinh(25*pi/12)) + assert solveset_real(cosh(x**2-1)-2, x) == FiniteSet( + -sqrt(1 + acosh(2)), sqrt(1 + acosh(2))) + + assert solveset_real(sin(x) - 2, x) == S.EmptySet # issue #17334 + assert solveset_real(cos(x) + 2, x) == S.EmptySet + assert solveset_real(sec(x), x) == S.EmptySet + assert solveset_real(csc(x), x) == S.EmptySet + assert solveset_real(cosh(x) + 1, x) == S.EmptySet + assert solveset_real(coth(x), x) == S.EmptySet + assert solveset_real(sech(x) - 2, x) == S.EmptySet + assert solveset_real(sech(x), x) == S.EmptySet + assert solveset_real(tanh(x) + 1, x) == S.EmptySet + assert solveset_complex(tanh(x), 1) == S.EmptySet + assert solveset_complex(coth(x), -1) == S.EmptySet + assert solveset_complex(sech(x), 0) == S.EmptySet + assert solveset_complex(csch(x), 0) == S.EmptySet + + assert solveset_real(abs(csch(x)) - 3, x) == FiniteSet(-acsch(3), acsch(3)) + + assert solveset_real(tanh(x**2 - 1) - exp(-9), x) == FiniteSet( + -sqrt(atanh(exp(-9)) + 1), sqrt(atanh(exp(-9)) + 1)) + + assert solveset_real(coth(log(x)) + 2, x) == FiniteSet(exp(-acoth(2))) + assert solveset_real(coth(exp(x)) + 2, x) == S.EmptySet + + assert solveset_complex(sinh(x) - I/2, x).dummy_eq(Union( + ImageSet(Lambda(n, 2*I*pi*n + 5*I*pi/6), S.Integers), + ImageSet(Lambda(n, 2*I*pi*n + I*pi/6), S.Integers))) + assert solveset_complex(sinh(x/10) + Rational(3, 4), x).dummy_eq(Union( + ImageSet(Lambda(n, 20*n*I*pi - 10*asinh(S(3)/4)), S.Integers), + ImageSet(Lambda(n, 20*n*I*pi + 10*asinh(S(3)/4) + 10*I*pi), S.Integers))) + assert solveset_complex(sech(sqrt(2)*x/3) + 5, x).dummy_eq(Union( + ImageSet(Lambda(n, 3*sqrt(2)*(2*n*I*pi - asech(-5))/2), S.Integers), + ImageSet(Lambda(n, 3*sqrt(2)*(2*n*I*pi + asech(-5))/2), S.Integers))) + assert solveset_complex(cosh(9*x), x).dummy_eq(Union( + ImageSet(Lambda(n, 2*n*I*pi/9 + I*pi/18), S.Integers), + ImageSet(Lambda(n, 2*n*I*pi/9 + I*pi/6), S.Integers))) + + eq = (x**5 -4*x + 1).subs(x, coth(z)) + assert solveset(eq, z, S.Complexes).dummy_eq(Union( + ImageSet(Lambda(n, n*I*pi + acoth(CRootOf(x**5 -4*x + 1, 0))), S.Integers), + ImageSet(Lambda(n, n*I*pi + acoth(CRootOf(x**5 -4*x + 1, 1))), S.Integers), + ImageSet(Lambda(n, n*I*pi + acoth(CRootOf(x**5 -4*x + 1, 2))), S.Integers), + ImageSet(Lambda(n, n*I*pi + acoth(CRootOf(x**5 -4*x + 1, 3))), S.Integers), + ImageSet(Lambda(n, n*I*pi + acoth(CRootOf(x**5 -4*x + 1, 4))), S.Integers))) + assert solveset(eq, z, S.Reals) == FiniteSet( + acoth(CRootOf(x**5 - 4*x + 1, 0)), acoth(CRootOf(x**5 - 4*x + 1, 2))) + + eq = ((x-sqrt(3)/2)*(x+2)).expand().subs(x, cos(x)) + assert solveset(eq, x, S.Complexes).dummy_eq(Union( + ImageSet(Lambda(n, 2*n*pi - acos(-2)), S.Integers), + ImageSet(Lambda(n, 2*n*pi + acos(-2)), S.Integers), + ImageSet(Lambda(n, 2*n*pi + pi/6), S.Integers), + ImageSet(Lambda(n, 2*n*pi + 11*pi/6), S.Integers))) + assert solveset(eq, x, S.Reals).dummy_eq(Union( + ImageSet(Lambda(n, 2*n*pi + pi/6), S.Integers), + ImageSet(Lambda(n, 2*n*pi + 11*pi/6), S.Integers))) + + assert solveset((1+sec(sqrt(3)*x+4)**2)/(1-sec(sqrt(3)*x+4))).dummy_eq(Union( + ImageSet(Lambda(n, sqrt(3)*(2*n*pi - 4 - asec(I))/3), S.Integers), + ImageSet(Lambda(n, sqrt(3)*(2*n*pi - 4 + asec(I))/3), S.Integers), + ImageSet(Lambda(n, sqrt(3)*(2*n*pi - 4 - asec(-I))/3), S.Integers), + ImageSet(Lambda(n, sqrt(3)*(2*n*pi - 4 + asec(-I))/3), S.Integers))) + + assert all_close(solveset(tan(3.14*x)**(S(3)/2)-5.678, x, Interval(0, 3)), + FiniteSet(0.403301114561067, 0.403301114561067 + 0.318471337579618*pi, + 0.403301114561067 + 0.636942675159236*pi)) + + +def test_old_trig_issues(): + # issues #9606 / #9531: + assert solveset(sinh(x), x, S.Reals) == FiniteSet(0) + assert solveset(sinh(x), x, S.Complexes).dummy_eq(Union( + ImageSet(Lambda(n, 2*n*I*pi), S.Integers), + ImageSet(Lambda(n, 2*n*I*pi + I*pi), S.Integers))) + + # issues #11218 / #18427 + assert solveset(sin(pi*x), x, S.Reals).dummy_eq(Union( + ImageSet(Lambda(n, (2*n*pi + pi)/pi), S.Integers), + ImageSet(Lambda(n, 2*n), S.Integers))) + assert solveset(sin(pi*x), x).dummy_eq(Union( + ImageSet(Lambda(n, (2*n*pi + pi)/pi), S.Integers), + ImageSet(Lambda(n, 2*n), S.Integers))) + + # issue #17543 + assert solveset(I*cot(8*x - 8*E), x).dummy_eq( + ImageSet(Lambda(n, pi*n/8 - 13*pi/16 + E), S.Integers)) + + # issue #20798 + assert all_close(solveset(cos(2*x) - 0.5, x, Interval(0, 2*pi)), FiniteSet( + 0.523598775598299, -0.523598775598299 + pi, + -0.523598775598299 + 2*pi, 0.523598775598299 + pi)) + sol = Union(ImageSet(Lambda(n, n*pi - 0.523598775598299), S.Integers), + ImageSet(Lambda(n, n*pi + 0.523598775598299), S.Integers)) + ret = solveset(cos(2*x) - 0.5, x, S.Reals) + # replace Dummy n by the regular Symbol n to allow all_close comparison. + ret = ret.subs(ret.atoms(Dummy).pop(), n) + assert all_close(ret, sol) + ret = solveset(cos(2*x) - 0.5, x, S.Complexes) + ret = ret.subs(ret.atoms(Dummy).pop(), n) + assert all_close(ret, sol) + + # issue #21296 / #17667 + assert solveset(tan(x)-sqrt(2), x, Interval(0, pi/2)) == FiniteSet(atan(sqrt(2))) + assert solveset(tan(x)-pi, x, Interval(0, pi/2)) == FiniteSet(atan(pi)) + + # issue #17667 + # not yet working properly: + # solveset(cos(x)-y, x, Interval(0, pi)) + assert solveset(cos(x)-y, x, S.Reals).dummy_eq( + ConditionSet(x,(S(-1) <= y) & (y <= S(1)), Union( + ImageSet(Lambda(n, 2*n*pi - acos(y)), S.Integers), + ImageSet(Lambda(n, 2*n*pi + acos(y)), S.Integers)))) + + # issue #17579 + # Valid result, but the intersection could potentially be simplified. + assert solveset(sin(log(x)), x, Interval(0,1, True, False)).dummy_eq( + Union(Intersection(ImageSet(Lambda(n, exp(2*n*pi)), S.Integers), Interval.Lopen(0, 1)), + Intersection(ImageSet(Lambda(n, exp(2*n*pi + pi)), S.Integers), Interval.Lopen(0, 1)))) + + # issue #17334 + assert solveset(sin(x) - sin(1), x, S.Reals).dummy_eq(Union( + ImageSet(Lambda(n, 2*n*pi + 1), S.Integers), + ImageSet(Lambda(n, 2*n*pi - 1 + pi), S.Integers))) + assert solveset(sin(x) - sqrt(5)/3, x, S.Reals).dummy_eq(Union( + ImageSet(Lambda(n, 2*n*pi + asin(sqrt(5)/3)), S.Integers), + ImageSet(Lambda(n, 2*n*pi - asin(sqrt(5)/3) + pi), S.Integers))) + assert solveset(sinh(x)-cosh(2), x, S.Reals) == FiniteSet(asinh(cosh(2))) + + # issue 9825 + assert solveset(Eq(tan(x), y), x, domain=S.Reals).dummy_eq( + ConditionSet(x, (-oo < y) & (y < oo), + ImageSet(Lambda(n, n*pi + atan(y)), S.Integers))) + r = Symbol('r', real=True) + assert solveset(Eq(tan(x), r), x, domain=S.Reals).dummy_eq( + ImageSet(Lambda(n, n*pi + atan(r)), S.Integers)) + + +def test_solve_hyperbolic(): + # actual solver: _solve_trig1 + n = Dummy('n') + assert solveset(sinh(x) + cosh(x), x) == S.EmptySet + assert solveset(sinh(x) + cos(x), x) == ConditionSet(x, + Eq(cos(x) + sinh(x), 0), S.Complexes) + assert solveset_real(sinh(x) + sech(x), x) == FiniteSet( + log(sqrt(sqrt(5) - 2))) + assert solveset_real(cosh(2*x) + 2*sinh(x) - 5, x) == FiniteSet( + log(-2 + sqrt(5)), log(1 + sqrt(2))) + assert solveset_real((coth(x) + sinh(2*x))/cosh(x) - 3, x) == FiniteSet( + log(S.Half + sqrt(5)/2), log(1 + sqrt(2))) + assert solveset_real(cosh(x)*sinh(x) - 2, x) == FiniteSet( + log(4 + sqrt(17))/2) + assert solveset_real(sinh(x) + tanh(x) - 1, x) == FiniteSet( + log(sqrt(2)/2 + sqrt(-S(1)/2 + sqrt(2)))) + + assert dumeq(solveset_complex(sinh(x) + sech(x), x), Union( + ImageSet(Lambda(n, 2*n*I*pi + log(sqrt(-2 + sqrt(5)))), S.Integers), + ImageSet(Lambda(n, I*(2*n*pi + pi/2) + log(sqrt(2 + sqrt(5)))), S.Integers), + ImageSet(Lambda(n, I*(2*n*pi + pi) + log(sqrt(-2 + sqrt(5)))), S.Integers), + ImageSet(Lambda(n, I*(2*n*pi - pi/2) + log(sqrt(2 + sqrt(5)))), S.Integers))) + + assert dumeq(solveset(cosh(x/15) + cosh(x/5)), Union( + ImageSet(Lambda(n, 15*I*(2*n*pi + pi/2)), S.Integers), + ImageSet(Lambda(n, 15*I*(2*n*pi - pi/2)), S.Integers), + ImageSet(Lambda(n, 15*I*(2*n*pi - 3*pi/4)), S.Integers), + ImageSet(Lambda(n, 15*I*(2*n*pi + 3*pi/4)), S.Integers), + ImageSet(Lambda(n, 15*I*(2*n*pi - pi/4)), S.Integers), + ImageSet(Lambda(n, 15*I*(2*n*pi + pi/4)), S.Integers))) + + assert dumeq(solveset(tanh(pi*x) - coth(pi/2*x)), Union( + ImageSet(Lambda(n, 2*I*(2*n*pi + pi/2)/pi), S.Integers), + ImageSet(Lambda(n, 2*I*(2*n*pi - pi/2)/pi), S.Integers))) + + # issues #18490 / #19489 + assert solveset(cosh(x) + cosh(3*x) - cosh(5*x), x, S.Reals + ).dummy_eq(ConditionSet(x, + Eq(cosh(x) + cosh(3*x) - cosh(5*x), 0), S.Reals)) + assert solveset(sinh(8*x) + coth(12*x)).dummy_eq( + ConditionSet(x, Eq(sinh(8*x) + coth(12*x), 0), S.Complexes)) + + +def test_solve_trig_hyp_symbolic(): + # actual solver: invert_trig_hyp + assert dumeq(solveset(sin(a*x), x), ConditionSet(x, Ne(a, 0), Union( + ImageSet(Lambda(n, (2*n*pi + pi)/a), S.Integers), + ImageSet(Lambda(n, 2*n*pi/a), S.Integers)))) + + assert dumeq(solveset(cosh(x/a), x), ConditionSet(x, Ne(a, 0), Union( + ImageSet(Lambda(n, a*(2*n*I*pi + I*pi/2)), S.Integers), + ImageSet(Lambda(n, a*(2*n*I*pi + 3*I*pi/2)), S.Integers)))) + + assert dumeq(solveset(sin(2*sqrt(3)/3*a**2/(b*pi)*x) + + cos(4*sqrt(3)/3*a**2/(b*pi)*x), x), + ConditionSet(x, Ne(b, 0) & Ne(a**2, 0), Union( + ImageSet(Lambda(n, sqrt(3)*pi*b*(2*n*pi + pi/2)/(2*a**2)), S.Integers), + ImageSet(Lambda(n, sqrt(3)*pi*b*(2*n*pi - 5*pi/6)/(2*a**2)), S.Integers), + ImageSet(Lambda(n, sqrt(3)*pi*b*(2*n*pi - pi/6)/(2*a**2)), S.Integers)))) + + assert dumeq(solveset(cosh((a**2 + 1)*x) - 3, x), ConditionSet( + x, Ne(a**2 + 1, 0), Union( + ImageSet(Lambda(n, (2*n*I*pi - acosh(3))/(a**2 + 1)), S.Integers), + ImageSet(Lambda(n, (2*n*I*pi + acosh(3))/(a**2 + 1)), S.Integers)))) + + ar = Symbol('ar', real=True) + assert solveset(cosh((ar**2 + 1)*x) - 2, x, S.Reals) == FiniteSet( + -acosh(2)/(ar**2 + 1), acosh(2)/(ar**2 + 1)) + + # actual solver: _solve_trig1 + assert dumeq(simplify(solveset(cot((1 + I)*x) - cot((3 + 3*I)*x), x)), Union( + ImageSet(Lambda(n, pi*(1 - I)*(4*n + 1)/4), S.Integers), + ImageSet(Lambda(n, pi*(1 - I)*(4*n - 1)/4), S.Integers))) + + +def test_issue_9616(): + assert dumeq(solveset(sinh(x) + tanh(x) - 1, x), Union( + ImageSet(Lambda(n, 2*n*I*pi + log(sqrt(2)/2 + sqrt(-S.Half + sqrt(2)))), S.Integers), + ImageSet(Lambda(n, I*(2*n*pi - atan(sqrt(2)*sqrt(S.Half + sqrt(2))) + pi) + + log(sqrt(1 + sqrt(2)))), S.Integers), + ImageSet(Lambda(n, I*(2*n*pi + pi) + log(-sqrt(2)/2 + sqrt(-S.Half + sqrt(2)))), S.Integers), + ImageSet(Lambda(n, I*(2*n*pi - pi + atan(sqrt(2)*sqrt(S.Half + sqrt(2)))) + + log(sqrt(1 + sqrt(2)))), S.Integers))) + f1 = (sinh(x)).rewrite(exp) + f2 = (tanh(x)).rewrite(exp) + assert dumeq(solveset(f1 + f2 - 1, x), Union( + Complement(ImageSet( + Lambda(n, I*(2*n*pi + pi) + log(-sqrt(2)/2 + sqrt(-S.Half + sqrt(2)))), S.Integers), + ImageSet(Lambda(n, I*(2*n*pi + pi)/2), S.Integers)), + Complement(ImageSet(Lambda(n, I*(2*n*pi - pi + atan(sqrt(2)*sqrt(S.Half + sqrt(2)))) + + log(sqrt(1 + sqrt(2)))), S.Integers), + ImageSet(Lambda(n, I*(2*n*pi + pi)/2), S.Integers)), + Complement(ImageSet(Lambda(n, I*(2*n*pi - atan(sqrt(2)*sqrt(S.Half + sqrt(2))) + pi) + + log(sqrt(1 + sqrt(2)))), S.Integers), + ImageSet(Lambda(n, I*(2*n*pi + pi)/2), S.Integers)), + Complement( + ImageSet(Lambda(n, 2*n*I*pi + log(sqrt(2)/2 + sqrt(-S.Half + sqrt(2)))), S.Integers), + ImageSet(Lambda(n, I*(2*n*pi + pi)/2), S.Integers)))) + + +def test_solve_invalid_sol(): + assert 0 not in solveset_real(sin(x)/x, x) + assert 0 not in solveset_complex((exp(x) - 1)/x, x) + + +@XFAIL +def test_solve_trig_simplified(): + n = Dummy('n') + assert dumeq(solveset_real(sin(x), x), + imageset(Lambda(n, n*pi), S.Integers)) + + assert dumeq(solveset_real(cos(x), x), + imageset(Lambda(n, n*pi + pi/2), S.Integers)) + + assert dumeq(solveset_real(cos(x) + sin(x), x), + imageset(Lambda(n, n*pi - pi/4), S.Integers)) + + +@XFAIL +def test_solve_lambert(): + assert solveset_real(x*exp(x) - 1, x) == FiniteSet(LambertW(1)) + assert solveset_real(exp(x) + x, x) == FiniteSet(-LambertW(1)) + assert solveset_real(x + 2**x, x) == \ + FiniteSet(-LambertW(log(2))/log(2)) + + # issue 4739 + ans = solveset_real(3*x + 5 + 2**(-5*x + 3), x) + assert ans == FiniteSet(Rational(-5, 3) + + LambertW(-10240*2**Rational(1, 3)*log(2)/3)/(5*log(2))) + + eq = 2*(3*x + 4)**5 - 6*7**(3*x + 9) + result = solveset_real(eq, x) + ans = FiniteSet((log(2401) + + 5*LambertW(-log(7**(7*3**Rational(1, 5)/5))))/(3*log(7))/-1) + assert result == ans + assert solveset_real(eq.expand(), x) == result + + assert solveset_real(5*x - 1 + 3*exp(2 - 7*x), x) == \ + FiniteSet(Rational(1, 5) + LambertW(-21*exp(Rational(3, 5))/5)/7) + + assert solveset_real(2*x + 5 + log(3*x - 2), x) == \ + FiniteSet(Rational(2, 3) + LambertW(2*exp(Rational(-19, 3))/3)/2) + + assert solveset_real(3*x + log(4*x), x) == \ + FiniteSet(LambertW(Rational(3, 4))/3) + + assert solveset_real(x**x - 2) == FiniteSet(exp(LambertW(log(2)))) + + a = Symbol('a') + assert solveset_real(-a*x + 2*x*log(x), x) == FiniteSet(exp(a/2)) + a = Symbol('a', real=True) + assert solveset_real(a/x + exp(x/2), x) == \ + FiniteSet(2*LambertW(-a/2)) + assert solveset_real((a/x + exp(x/2)).diff(x), x) == \ + FiniteSet(4*LambertW(sqrt(2)*sqrt(a)/4)) + + # coverage test + assert solveset_real(tanh(x + 3)*tanh(x - 3) - 1, x) is S.EmptySet + + assert solveset_real((x**2 - 2*x + 1).subs(x, log(x) + 3*x), x) == \ + FiniteSet(LambertW(3*S.Exp1)/3) + assert solveset_real((x**2 - 2*x + 1).subs(x, (log(x) + 3*x)**2 - 1), x) == \ + FiniteSet(LambertW(3*exp(-sqrt(2)))/3, LambertW(3*exp(sqrt(2)))/3) + assert solveset_real((x**2 - 2*x - 2).subs(x, log(x) + 3*x), x) == \ + FiniteSet(LambertW(3*exp(1 + sqrt(3)))/3, LambertW(3*exp(-sqrt(3) + 1))/3) + assert solveset_real(x*log(x) + 3*x + 1, x) == \ + FiniteSet(exp(-3 + LambertW(-exp(3)))) + eq = (x*exp(x) - 3).subs(x, x*exp(x)) + assert solveset_real(eq, x) == \ + FiniteSet(LambertW(3*exp(-LambertW(3)))) + + assert solveset_real(3*log(a**(3*x + 5)) + a**(3*x + 5), x) == \ + FiniteSet(-((log(a**5) + LambertW(Rational(1, 3)))/(3*log(a)))) + p = symbols('p', positive=True) + assert solveset_real(3*log(p**(3*x + 5)) + p**(3*x + 5), x) == \ + FiniteSet( + log((-3**Rational(1, 3) - 3**Rational(5, 6)*I)*LambertW(Rational(1, 3))**Rational(1, 3)/(2*p**Rational(5, 3)))/log(p), + log((-3**Rational(1, 3) + 3**Rational(5, 6)*I)*LambertW(Rational(1, 3))**Rational(1, 3)/(2*p**Rational(5, 3)))/log(p), + log((3*LambertW(Rational(1, 3))/p**5)**(1/(3*log(p)))),) # checked numerically + # check collection + b = Symbol('b') + eq = 3*log(a**(3*x + 5)) + b*log(a**(3*x + 5)) + a**(3*x + 5) + assert solveset_real(eq, x) == FiniteSet( + -((log(a**5) + LambertW(1/(b + 3)))/(3*log(a)))) + + # issue 4271 + assert solveset_real((a/x + exp(x/2)).diff(x, 2), x) == FiniteSet( + 6*LambertW((-1)**Rational(1, 3)*a**Rational(1, 3)/3)) + + assert solveset_real(x**3 - 3**x, x) == \ + FiniteSet(-3/log(3)*LambertW(-log(3)/3)) + assert solveset_real(3**cos(x) - cos(x)**3) == FiniteSet( + acos(-3*LambertW(-log(3)/3)/log(3))) + + assert solveset_real(x**2 - 2**x, x) == \ + solveset_real(-x**2 + 2**x, x) + + assert solveset_real(3*log(x) - x*log(3)) == FiniteSet( + -3*LambertW(-log(3)/3)/log(3), + -3*LambertW(-log(3)/3, -1)/log(3)) + + assert solveset_real(LambertW(2*x) - y) == FiniteSet( + y*exp(y)/2) + + +@XFAIL +def test_other_lambert(): + a = Rational(6, 5) + assert solveset_real(x**a - a**x, x) == FiniteSet( + a, -a*LambertW(-log(a)/a)/log(a)) + + +@_both_exp_pow +def test_solveset(): + f = Function('f') + raises(ValueError, lambda: solveset(x + y)) + assert solveset(x, 1) == S.EmptySet + assert solveset(f(1)**2 + y + 1, f(1) + ) == FiniteSet(-sqrt(-y - 1), sqrt(-y - 1)) + assert solveset(f(1)**2 - 1, f(1), S.Reals) == FiniteSet(-1, 1) + assert solveset(f(1)**2 + 1, f(1)) == FiniteSet(-I, I) + assert solveset(x - 1, 1) == FiniteSet(x) + assert solveset(sin(x) - cos(x), sin(x)) == FiniteSet(cos(x)) + + assert solveset(0, domain=S.Reals) == S.Reals + assert solveset(1) == S.EmptySet + assert solveset(True, domain=S.Reals) == S.Reals # issue 10197 + assert solveset(False, domain=S.Reals) == S.EmptySet + + assert solveset(exp(x) - 1, domain=S.Reals) == FiniteSet(0) + assert solveset(exp(x) - 1, x, S.Reals) == FiniteSet(0) + assert solveset(Eq(exp(x), 1), x, S.Reals) == FiniteSet(0) + assert solveset(exp(x) - 1, exp(x), S.Reals) == FiniteSet(1) + A = Indexed('A', x) + assert solveset(A - 1, A, S.Reals) == FiniteSet(1) + + assert solveset(x - 1 >= 0, x, S.Reals) == Interval(1, oo) + assert solveset(exp(x) - 1 >= 0, x, S.Reals) == Interval(0, oo) + + assert dumeq(solveset(exp(x) - 1, x), imageset(Lambda(n, 2*I*pi*n), S.Integers)) + assert dumeq(solveset(Eq(exp(x), 1), x), imageset(Lambda(n, 2*I*pi*n), + S.Integers)) + # issue 13825 + assert solveset(x**2 + f(0) + 1, x) == {-sqrt(-f(0) - 1), sqrt(-f(0) - 1)} + + # issue 19977 + assert solveset(atan(log(x)) > 0, x, domain=Interval.open(0, oo)) == Interval.open(1, oo) + + +@_both_exp_pow +def test_multi_exp(): + k1, k2, k3 = symbols('k1, k2, k3') + assert dumeq(solveset(exp(exp(x)) - 5, x),\ + imageset(Lambda(((k1, n),), I*(2*k1*pi + arg(2*n*I*pi + log(5))) + log(Abs(2*n*I*pi + log(5)))),\ + ProductSet(S.Integers, S.Integers))) + assert dumeq(solveset((d*exp(exp(a*x + b)) + c), x),\ + imageset(Lambda(x, (-b + x)/a), ImageSet(Lambda(((k1, n),), \ + I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))) + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d))))), \ + ProductSet(S.Integers, S.Integers)))) + + assert dumeq(solveset((d*exp(exp(exp(a*x + b))) + c), x),\ + imageset(Lambda(x, (-b + x)/a), ImageSet(Lambda(((k2, k1, n),), \ + I*(2*k2*pi + arg(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))) + \ + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))))) + log(Abs(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + \ + log(Abs(c/d)))) + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d))))))), \ + ProductSet(S.Integers, S.Integers, S.Integers)))) + + assert dumeq(solveset((d*exp(exp(exp(exp(a*x + b)))) + c), x),\ + ImageSet(Lambda(x, (-b + x)/a), ImageSet(Lambda(((k3, k2, k1, n),), \ + I*(2*k3*pi + arg(I*(2*k2*pi + arg(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))) + \ + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))))) + log(Abs(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + \ + log(Abs(c/d)))) + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))))))) + log(Abs(I*(2*k2*pi + \ + arg(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))) + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))))) + \ + log(Abs(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))) + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d))))))))), \ + ProductSet(S.Integers, S.Integers, S.Integers, S.Integers)))) + + +def test__solveset_multi(): + from sympy.solvers.solveset import _solveset_multi + from sympy.sets import Reals + + # Basic univariate case: + assert _solveset_multi([x**2-1], [x], [S.Reals]) == FiniteSet((1,), (-1,)) + + # Linear systems of two equations + assert _solveset_multi([x+y, x+1], [x, y], [Reals, Reals]) == FiniteSet((-1, 1)) + assert _solveset_multi([x+y, x+1], [y, x], [Reals, Reals]) == FiniteSet((1, -1)) + assert _solveset_multi([x+y, x-y-1], [x, y], [Reals, Reals]) == FiniteSet((S(1)/2, -S(1)/2)) + assert _solveset_multi([x-1, y-2], [x, y], [Reals, Reals]) == FiniteSet((1, 2)) + # assert dumeq(_solveset_multi([x+y], [x, y], [Reals, Reals]), ImageSet(Lambda(x, (x, -x)), Reals)) + assert dumeq(_solveset_multi([x+y], [x, y], [Reals, Reals]), Union( + ImageSet(Lambda(((x,),), (x, -x)), ProductSet(Reals)), + ImageSet(Lambda(((y,),), (-y, y)), ProductSet(Reals)))) + assert _solveset_multi([x+y, x+y+1], [x, y], [Reals, Reals]) == S.EmptySet + assert _solveset_multi([x+y, x-y, x-1], [x, y], [Reals, Reals]) == S.EmptySet + assert _solveset_multi([x+y, x-y, x-1], [y, x], [Reals, Reals]) == S.EmptySet + + # Systems of three equations: + assert _solveset_multi([x+y+z-1, x+y-z-2, x-y-z-3], [x, y, z], [Reals, + Reals, Reals]) == FiniteSet((2, -S.Half, -S.Half)) + + # Nonlinear systems: + from sympy.abc import theta + assert _solveset_multi([x**2+y**2-2, x+y], [x, y], [Reals, Reals]) == FiniteSet((-1, 1), (1, -1)) + assert _solveset_multi([x**2-1, y], [x, y], [Reals, Reals]) == FiniteSet((1, 0), (-1, 0)) + #assert _solveset_multi([x**2-y**2], [x, y], [Reals, Reals]) == Union( + # ImageSet(Lambda(x, (x, -x)), Reals), ImageSet(Lambda(x, (x, x)), Reals)) + assert dumeq(_solveset_multi([x**2-y**2], [x, y], [Reals, Reals]), Union( + ImageSet(Lambda(((x,),), (x, -Abs(x))), ProductSet(Reals)), + ImageSet(Lambda(((x,),), (x, Abs(x))), ProductSet(Reals)), + ImageSet(Lambda(((y,),), (-Abs(y), y)), ProductSet(Reals)), + ImageSet(Lambda(((y,),), (Abs(y), y)), ProductSet(Reals)))) + assert _solveset_multi([r*cos(theta)-1, r*sin(theta)], [theta, r], + [Interval(0, pi), Interval(-1, 1)]) == FiniteSet((0, 1), (pi, -1)) + assert _solveset_multi([r*cos(theta)-1, r*sin(theta)], [r, theta], + [Interval(0, 1), Interval(0, pi)]) == FiniteSet((1, 0)) + assert _solveset_multi([r*cos(theta)-r, r*sin(theta)], [r, theta], + [Interval(0, 1), Interval(0, pi)]) == Union( + ImageSet(Lambda(((r,),), (r, 0)), + ImageSet(Lambda(r, (r,)), Interval(0, 1))), + ImageSet(Lambda(((theta,),), (0, theta)), + ImageSet(Lambda(theta, (theta,)), Interval(0, pi)))) + + +def test_conditionset(): + assert solveset(Eq(sin(x)**2 + cos(x)**2, 1), x, domain=S.Reals + ) is S.Reals + + assert solveset(Eq(x**2 + x*sin(x), 1), x, domain=S.Reals + ).dummy_eq(ConditionSet(x, Eq(x**2 + x*sin(x) - 1, 0), S.Reals)) + + assert dumeq(solveset(Eq(-I*(exp(I*x) - exp(-I*x))/2, 1), x + ), imageset(Lambda(n, 2*n*pi + pi/2), S.Integers)) + + assert solveset(x + sin(x) > 1, x, domain=S.Reals + ).dummy_eq(ConditionSet(x, x + sin(x) > 1, S.Reals)) + + assert solveset(Eq(sin(Abs(x)), x), x, domain=S.Reals + ).dummy_eq(ConditionSet(x, Eq(-x + sin(Abs(x)), 0), S.Reals)) + + assert solveset(y**x-z, x, S.Reals + ).dummy_eq(ConditionSet(x, Eq(y**x - z, 0), S.Reals)) + + +@XFAIL +def test_conditionset_equality(): + ''' Checking equality of different representations of ConditionSet''' + assert solveset(Eq(tan(x), y), x) == ConditionSet(x, Eq(tan(x), y), S.Complexes) + + +def test_solveset_domain(): + assert solveset(x**2 - x - 6, x, Interval(0, oo)) == FiniteSet(3) + assert solveset(x**2 - 1, x, Interval(0, oo)) == FiniteSet(1) + assert solveset(x**4 - 16, x, Interval(0, 10)) == FiniteSet(2) + + +def test_improve_coverage(): + solution = solveset(exp(x) + sin(x), x, S.Reals) + unsolved_object = ConditionSet(x, Eq(exp(x) + sin(x), 0), S.Reals) + assert solution.dummy_eq(unsolved_object) + + +def test_issue_9522(): + expr1 = Eq(1/(x**2 - 4) + x, 1/(x**2 - 4) + 2) + expr2 = Eq(1/x + x, 1/x) + + assert solveset(expr1, x, S.Reals) is S.EmptySet + assert solveset(expr2, x, S.Reals) is S.EmptySet + + +def test_solvify(): + assert solvify(x**2 + 10, x, S.Reals) == [] + assert solvify(x**3 + 1, x, S.Complexes) == [-1, S.Half - sqrt(3)*I/2, + S.Half + sqrt(3)*I/2] + assert solvify(log(x), x, S.Reals) == [1] + assert solvify(cos(x), x, S.Reals) == [pi/2, pi*Rational(3, 2)] + assert solvify(sin(x) + 1, x, S.Reals) == [pi*Rational(3, 2)] + raises(NotImplementedError, lambda: solvify(sin(exp(x)), x, S.Complexes)) + + +def test_solvify_piecewise(): + p1 = Piecewise((0, x < -1), (x**2, x <= 1), (log(x), True)) + p2 = Piecewise((0, x < -10), (x**2 + 5*x - 6, x >= -9)) + p3 = Piecewise((0, Eq(x, 0)), (x**2/Abs(x), True)) + p4 = Piecewise((0, Eq(x, pi)), ((x - pi)/sin(x), True)) + + # issue 21079 + assert solvify(p1, x, S.Reals) == [0] + assert solvify(p2, x, S.Reals) == [-6, 1] + assert solvify(p3, x, S.Reals) == [0] + assert solvify(p4, x, S.Reals) == [pi] + + +def test_abs_invert_solvify(): + + x = Symbol('x',positive=True) + assert solvify(sin(Abs(x)), x, S.Reals) == [0, pi] + x = Symbol('x') + assert solvify(sin(Abs(x)), x, S.Reals) is None + + +def test_linear_eq_to_matrix(): + assert linear_eq_to_matrix(0, x) == (Matrix([[0]]), Matrix([[0]])) + assert linear_eq_to_matrix(1, x) == (Matrix([[0]]), Matrix([[-1]])) + + # integer coefficients + eqns1 = [2*x + y - 2*z - 3, x - y - z, x + y + 3*z - 12] + eqns2 = [Eq(3*x + 2*y - z, 1), Eq(2*x - 2*y + 4*z, -2), -2*x + y - 2*z] + + A, B = linear_eq_to_matrix(eqns1, x, y, z) + assert A == Matrix([[2, 1, -2], [1, -1, -1], [1, 1, 3]]) + assert B == Matrix([[3], [0], [12]]) + + A, B = linear_eq_to_matrix(eqns2, x, y, z) + assert A == Matrix([[3, 2, -1], [2, -2, 4], [-2, 1, -2]]) + assert B == Matrix([[1], [-2], [0]]) + + # Pure symbolic coefficients + eqns3 = [a*b*x + b*y + c*z - d, e*x + d*x + f*y + g*z - h, i*x + j*y + k*z - l] + A, B = linear_eq_to_matrix(eqns3, x, y, z) + assert A == Matrix([[a*b, b, c], [d + e, f, g], [i, j, k]]) + assert B == Matrix([[d], [h], [l]]) + + # raise Errors if + # 1) no symbols are given + raises(ValueError, lambda: linear_eq_to_matrix(eqns3)) + # 2) there are duplicates + raises(ValueError, lambda: linear_eq_to_matrix(eqns3, [x, x, y])) + # 3) a nonlinear term is detected in the original expression + raises(NonlinearError, lambda: linear_eq_to_matrix(Eq(1/x + x, 1/x), [x])) + raises(NonlinearError, lambda: linear_eq_to_matrix([x**2], [x])) + raises(NonlinearError, lambda: linear_eq_to_matrix([x*y], [x, y])) + # 4) Eq being used to represent equations autoevaluates + # (use unevaluated Eq instead) + raises(ValueError, lambda: linear_eq_to_matrix(Eq(x, x), x)) + raises(ValueError, lambda: linear_eq_to_matrix(Eq(x, x + 1), x)) + + + # if non-symbols are passed, the user is responsible for interpreting + assert linear_eq_to_matrix([x], [1/x]) == (Matrix([[0]]), Matrix([[-x]])) + + # issue 15195 + assert linear_eq_to_matrix(x + y*(z*(3*x + 2) + 3), x) == ( + Matrix([[3*y*z + 1]]), Matrix([[-y*(2*z + 3)]])) + assert linear_eq_to_matrix(Matrix( + [[a*x + b*y - 7], [5*x + 6*y - c]]), x, y) == ( + Matrix([[a, b], [5, 6]]), Matrix([[7], [c]])) + + # issue 15312 + assert linear_eq_to_matrix(Eq(x + 2, 1), x) == ( + Matrix([[1]]), Matrix([[-1]])) + + # issue 25423 + raises(TypeError, lambda: linear_eq_to_matrix([], {x, y})) + raises(TypeError, lambda: linear_eq_to_matrix([x + y], {x, y})) + raises(ValueError, lambda: linear_eq_to_matrix({x + y}, (x, y))) + + +def test_issue_16577(): + assert linear_eq_to_matrix(Eq(a*(2*x + 3*y) + 4*y, 5), x, y) == ( + Matrix([[2*a, 3*a + 4]]), Matrix([[5]])) + + +def test_issue_10085(): + assert invert_real(exp(x),0,x) == (x, S.EmptySet) + + +def test_linsolve(): + x1, x2, x3, x4 = symbols('x1, x2, x3, x4') + + # Test for different input forms + + M = Matrix([[1, 2, 1, 1, 7], [1, 2, 2, -1, 12], [2, 4, 0, 6, 4]]) + system1 = A, B = M[:, :-1], M[:, -1] + Eqns = [x1 + 2*x2 + x3 + x4 - 7, x1 + 2*x2 + 2*x3 - x4 - 12, + 2*x1 + 4*x2 + 6*x4 - 4] + + sol = FiniteSet((-2*x2 - 3*x4 + 2, x2, 2*x4 + 5, x4)) + assert linsolve(Eqns, (x1, x2, x3, x4)) == sol + assert linsolve(Eqns, *(x1, x2, x3, x4)) == sol + assert linsolve(system1, (x1, x2, x3, x4)) == sol + assert linsolve(system1, *(x1, x2, x3, x4)) == sol + # issue 9667 - symbols can be Dummy symbols + x1, x2, x3, x4 = symbols('x:4', cls=Dummy) + assert linsolve(system1, x1, x2, x3, x4) == FiniteSet( + (-2*x2 - 3*x4 + 2, x2, 2*x4 + 5, x4)) + + # raise ValueError for garbage value + raises(ValueError, lambda: linsolve(Eqns)) + raises(ValueError, lambda: linsolve(x1)) + raises(ValueError, lambda: linsolve(x1, x2)) + raises(ValueError, lambda: linsolve((A,), x1, x2)) + raises(ValueError, lambda: linsolve(A, B, x1, x2)) + raises(ValueError, lambda: linsolve([x1], x1, x1)) + raises(ValueError, lambda: linsolve([x1], (i for i in (x1, x1)))) + + #raise ValueError if equations are non-linear in given variables + raises(NonlinearError, lambda: linsolve([x + y - 1, x ** 2 + y - 3], [x, y])) + raises(NonlinearError, lambda: linsolve([cos(x) + y, x + y], [x, y])) + assert linsolve([x + z - 1, x ** 2 + y - 3], [z, y]) == {(-x + 1, -x**2 + 3)} + + # Fully symbolic test + A = Matrix([[a, b], [c, d]]) + B = Matrix([[e], [g]]) + system2 = (A, B) + sol = FiniteSet(((-b*g + d*e)/(a*d - b*c), (a*g - c*e)/(a*d - b*c))) + assert linsolve(system2, [x, y]) == sol + + # No solution + A = Matrix([[1, 2, 3], [2, 4, 6], [3, 6, 9]]) + B = Matrix([0, 0, 1]) + assert linsolve((A, B), (x, y, z)) is S.EmptySet + + # Issue #10056 + A, B, J1, J2 = symbols('A B J1 J2') + Augmatrix = Matrix([ + [2*I*J1, 2*I*J2, -2/J1], + [-2*I*J2, -2*I*J1, 2/J2], + [0, 2, 2*I/(J1*J2)], + [2, 0, 0], + ]) + + assert linsolve(Augmatrix, A, B) == FiniteSet((0, I/(J1*J2))) + + # Issue #10121 - Assignment of free variables + Augmatrix = Matrix([[0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0]]) + assert linsolve(Augmatrix, a, b, c, d, e) == FiniteSet((a, 0, c, 0, e)) + #raises(IndexError, lambda: linsolve(Augmatrix, a, b, c)) + + x0, x1, x2, _x0 = symbols('tau0 tau1 tau2 _tau0') + assert linsolve(Matrix([[0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, _x0]]) + ) == FiniteSet((x0, 0, x1, _x0, x2)) + x0, x1, x2, _x0 = symbols('tau00 tau01 tau02 tau0') + assert linsolve(Matrix([[0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, _x0]]) + ) == FiniteSet((x0, 0, x1, _x0, x2)) + x0, x1, x2, _x0 = symbols('tau00 tau01 tau02 tau1') + assert linsolve(Matrix([[0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, _x0]]) + ) == FiniteSet((x0, 0, x1, _x0, x2)) + # symbols can be given as generators + x0, x2, x4 = symbols('x0, x2, x4') + assert linsolve(Augmatrix, numbered_symbols('x') + ) == FiniteSet((x0, 0, x2, 0, x4)) + Augmatrix[-1, -1] = x0 + # use Dummy to avoid clash; the names may clash but the symbols + # will not + Augmatrix[-1, -1] = symbols('_x0') + assert len(linsolve( + Augmatrix, numbered_symbols('x', cls=Dummy)).free_symbols) == 4 + + # Issue #12604 + f = Function('f') + assert linsolve([f(x) - 5], f(x)) == FiniteSet((5,)) + + # Issue #14860 + from sympy.physics.units import meter, newton, kilo + kN = kilo*newton + Eqns = [8*kN + x + y, 28*kN*meter + 3*x*meter] + assert linsolve(Eqns, x, y) == { + (kilo*newton*Rational(-28, 3), kN*Rational(4, 3))} + + # linsolve does not allow expansion (real or implemented) + # to remove singularities, but it will cancel linear terms + assert linsolve([Eq(x, x + y)], [x, y]) == {(x, 0)} + assert linsolve([Eq(x + x*y, 1 + y)], [x]) == {(1,)} + assert linsolve([Eq(1 + y, x + x*y)], [x]) == {(1,)} + raises(NonlinearError, lambda: + linsolve([Eq(x**2, x**2 + y)], [x, y])) + + # corner cases + # + # XXX: The case below should give the same as for [0] + # assert linsolve([], [x]) == {(x,)} + assert linsolve([], [x]) is S.EmptySet + assert linsolve([0], [x]) == {(x,)} + assert linsolve([x], [x, y]) == {(0, y)} + assert linsolve([x, 0], [x, y]) == {(0, y)} + + +def test_linsolve_large_sparse(): + # + # This is mainly a performance test + # + + def _mk_eqs_sol(n): + xs = symbols('x:{}'.format(n)) + ys = symbols('y:{}'.format(n)) + syms = xs + ys + eqs = [] + sol = (-S.Half,) * n + (S.Half,) * n + for xi, yi in zip(xs, ys): + eqs.extend([xi + yi, xi - yi + 1]) + return eqs, syms, FiniteSet(sol) + + n = 500 + eqs, syms, sol = _mk_eqs_sol(n) + assert linsolve(eqs, syms) == sol + + +def test_linsolve_immutable(): + A = ImmutableDenseMatrix([[1, 1, 2], [0, 1, 2], [0, 0, 1]]) + B = ImmutableDenseMatrix([2, 1, -1]) + assert linsolve([A, B], (x, y, z)) == FiniteSet((1, 3, -1)) + + A = ImmutableDenseMatrix([[1, 1, 7], [1, -1, 3]]) + assert linsolve(A) == FiniteSet((5, 2)) + + +def test_solve_decomposition(): + n = Dummy('n') + + f1 = exp(3*x) - 6*exp(2*x) + 11*exp(x) - 6 + f2 = sin(x)**2 - 2*sin(x) + 1 + f3 = sin(x)**2 - sin(x) + f4 = sin(x + 1) + f5 = exp(x + 2) - 1 + f6 = 1/log(x) + f7 = 1/x + + s1 = ImageSet(Lambda(n, 2*n*pi), S.Integers) + s2 = ImageSet(Lambda(n, 2*n*pi + pi), S.Integers) + s3 = ImageSet(Lambda(n, 2*n*pi + pi/2), S.Integers) + s4 = ImageSet(Lambda(n, 2*n*pi - 1), S.Integers) + s5 = ImageSet(Lambda(n, 2*n*pi - 1 + pi), S.Integers) + + assert solve_decomposition(f1, x, S.Reals) == FiniteSet(0, log(2), log(3)) + assert dumeq(solve_decomposition(f2, x, S.Reals), s3) + assert dumeq(solve_decomposition(f3, x, S.Reals), Union(s1, s2, s3)) + assert dumeq(solve_decomposition(f4, x, S.Reals), Union(s4, s5)) + assert solve_decomposition(f5, x, S.Reals) == FiniteSet(-2) + assert solve_decomposition(f6, x, S.Reals) == S.EmptySet + assert solve_decomposition(f7, x, S.Reals) == S.EmptySet + assert solve_decomposition(x, x, Interval(1, 2)) == S.EmptySet + + +# nonlinsolve testcases +def test_nonlinsolve_basic(): + assert nonlinsolve([],[]) == S.EmptySet + assert nonlinsolve([],[x, y]) == S.EmptySet + + system = [x, y - x - 5] + assert nonlinsolve([x],[x, y]) == FiniteSet((0, y)) + assert nonlinsolve(system, [y]) == S.EmptySet + soln = (ImageSet(Lambda(n, 2*n*pi + pi/2), S.Integers),) + assert dumeq(nonlinsolve([sin(x) - 1], [x]), FiniteSet(tuple(soln))) + soln = ((ImageSet(Lambda(n, 2*n*pi + pi), S.Integers), 1), + (ImageSet(Lambda(n, 2*n*pi), S.Integers), 1)) + assert dumeq(nonlinsolve([sin(x), y - 1], [x, y]), FiniteSet(*soln)) + assert nonlinsolve([x**2 - 1], [x]) == FiniteSet((-1,), (1,)) + + soln = FiniteSet((y, y)) + assert nonlinsolve([x - y, 0], x, y) == soln + assert nonlinsolve([0, x - y], x, y) == soln + assert nonlinsolve([x - y, x - y], x, y) == soln + assert nonlinsolve([x, 0], x, y) == FiniteSet((0, y)) + f = Function('f') + assert nonlinsolve([f(x), 0], f(x), y) == FiniteSet((0, y)) + assert nonlinsolve([f(x), 0], f(x), f(y)) == FiniteSet((0, f(y))) + A = Indexed('A', x) + assert nonlinsolve([A, 0], A, y) == FiniteSet((0, y)) + assert nonlinsolve([x**2 -1], [sin(x)]) == FiniteSet((S.EmptySet,)) + assert nonlinsolve([x**2 -1], sin(x)) == FiniteSet((S.EmptySet,)) + assert nonlinsolve([x**2 -1], 1) == FiniteSet((x**2,)) + assert nonlinsolve([x**2 -1], x + y) == FiniteSet((S.EmptySet,)) + assert nonlinsolve([Eq(1, x + y), Eq(1, -x + y - 1), Eq(1, -x + y - 1)], x, y) == FiniteSet( + (-S.Half, 3*S.Half)) + + +def test_nonlinsolve_abs(): + soln = FiniteSet((y, y), (-y, y)) + assert nonlinsolve([Abs(x) - y], x, y) == soln + + +def test_raise_exception_nonlinsolve(): + raises(IndexError, lambda: nonlinsolve([x**2 -1], [])) + raises(ValueError, lambda: nonlinsolve([x**2 -1])) + + +def test_trig_system(): + # TODO: add more simple testcases when solveset returns + # simplified soln for Trig eq + assert nonlinsolve([sin(x) - 1, cos(x) -1 ], x) == S.EmptySet + soln1 = (ImageSet(Lambda(n, 2*n*pi + pi/2), S.Integers),) + soln = FiniteSet(soln1) + assert dumeq(nonlinsolve([sin(x) - 1, cos(x)], x), soln) + + +@XFAIL +def test_trig_system_fail(): + # fails because solveset trig solver is not much smart. + sys = [x + y - pi/2, sin(x) + sin(y) - 1] + # solveset returns conditionset for sin(x) + sin(y) - 1 + soln_1 = (ImageSet(Lambda(n, n*pi + pi/2), S.Integers), + ImageSet(Lambda(n, n*pi), S.Integers)) + soln_1 = FiniteSet(soln_1) + soln_2 = (ImageSet(Lambda(n, n*pi), S.Integers), + ImageSet(Lambda(n, n*pi+ pi/2), S.Integers)) + soln_2 = FiniteSet(soln_2) + soln = soln_1 + soln_2 + assert dumeq(nonlinsolve(sys, [x, y]), soln) + + # Add more cases from here + # http://www.vitutor.com/geometry/trigonometry/equations_systems.html#uno + sys = [sin(x) + sin(y) - (sqrt(3)+1)/2, sin(x) - sin(y) - (sqrt(3) - 1)/2] + soln_x = Union(ImageSet(Lambda(n, 2*n*pi + pi/3), S.Integers), + ImageSet(Lambda(n, 2*n*pi + pi*Rational(2, 3)), S.Integers)) + soln_y = Union(ImageSet(Lambda(n, 2*n*pi + pi/6), S.Integers), + ImageSet(Lambda(n, 2*n*pi + pi*Rational(5, 6)), S.Integers)) + assert dumeq(nonlinsolve(sys, [x, y]), FiniteSet((soln_x, soln_y))) + + +def test_nonlinsolve_positive_dimensional(): + x, y, a, b, c, d = symbols('x, y, a, b, c, d', extended_real=True) + assert nonlinsolve([x*y, x*y - x], [x, y]) == FiniteSet((0, y)) + + system = [a**2 + a*c, a - b] + assert nonlinsolve(system, [a, b]) == FiniteSet((0, 0), (-c, -c)) + # here (a= 0, b = 0) is independent soln so both is printed. + # if symbols = [a, b, c] then only {a : -c ,b : -c} + + eq1 = a + b + c + d + eq2 = a*b + b*c + c*d + d*a + eq3 = a*b*c + b*c*d + c*d*a + d*a*b + eq4 = a*b*c*d - 1 + system = [eq1, eq2, eq3, eq4] + sol1 = (-1/d, -d, 1/d, FiniteSet(d) - FiniteSet(0)) + sol2 = (1/d, -d, -1/d, FiniteSet(d) - FiniteSet(0)) + soln = FiniteSet(sol1, sol2) + assert nonlinsolve(system, [a, b, c, d]) == soln + + assert nonlinsolve([x**4 - 3*x**2 + y*x, x*z**2, y*z - 1], [x, y, z]) == \ + {(0, 1/z, z)} + + +def test_nonlinsolve_polysys(): + x, y, z = symbols('x, y, z', real=True) + assert nonlinsolve([x**2 + y - 2, x**2 + y], [x, y]) == S.EmptySet + + s = (-y + 2, y) + assert nonlinsolve([(x + y)**2 - 4, x + y - 2], [x, y]) == FiniteSet(s) + + system = [x**2 - y**2] + soln_real = FiniteSet((-y, y), (y, y)) + soln_complex = FiniteSet((-Abs(y), y), (Abs(y), y)) + soln =soln_real + soln_complex + assert nonlinsolve(system, [x, y]) == soln + + system = [x**2 - y**2] + soln_real= FiniteSet((y, -y), (y, y)) + soln_complex = FiniteSet((y, -Abs(y)), (y, Abs(y))) + soln = soln_real + soln_complex + assert nonlinsolve(system, [y, x]) == soln + + system = [x**2 + y - 3, x - y - 4] + assert nonlinsolve(system, (x, y)) != nonlinsolve(system, (y, x)) + + assert nonlinsolve([-x**2 - y**2 + z, -2*x, -2*y, S.One], [x, y, z]) == S.EmptySet + assert nonlinsolve([x + y + z, S.One, S.One, S.One], [x, y, z]) == S.EmptySet + + system = [-x**2*z**2 + x*y*z + y**4, -2*x*z**2 + y*z, x*z + 4*y**3, -2*x**2*z + x*y] + assert nonlinsolve(system, [x, y, z]) == FiniteSet((0, 0, z), (x, 0, 0)) + + +def test_nonlinsolve_using_substitution(): + x, y, z, n = symbols('x, y, z, n', real = True) + system = [(x + y)*n - y**2 + 2] + s_x = (n*y - y**2 + 2)/n + soln = (-s_x, y) + assert nonlinsolve(system, [x, y]) == FiniteSet(soln) + + system = [z**2*x**2 - z**2*y**2/exp(x)] + soln_real_1 = (y, x, 0) + soln_real_2 = (-exp(x/2)*Abs(x), x, z) + soln_real_3 = (exp(x/2)*Abs(x), x, z) + soln_complex_1 = (-x*exp(x/2), x, z) + soln_complex_2 = (x*exp(x/2), x, z) + syms = [y, x, z] + soln = FiniteSet(soln_real_1, soln_complex_1, soln_complex_2,\ + soln_real_2, soln_real_3) + assert nonlinsolve(system,syms) == soln + + +def test_nonlinsolve_complex(): + n = Dummy('n') + assert dumeq(nonlinsolve([exp(x) - sin(y), 1/y - 3], [x, y]), { + (ImageSet(Lambda(n, 2*n*I*pi + log(sin(Rational(1, 3)))), S.Integers), Rational(1, 3))}) + + system = [exp(x) - sin(y), 1/exp(y) - 3] + assert dumeq(nonlinsolve(system, [x, y]), { + (ImageSet(Lambda(n, I*(2*n*pi + pi) + + log(sin(log(3)))), S.Integers), -log(3)), + (ImageSet(Lambda(n, I*(2*n*pi + arg(sin(2*n*I*pi - log(3)))) + + log(Abs(sin(2*n*I*pi - log(3))))), S.Integers), + ImageSet(Lambda(n, 2*n*I*pi - log(3)), S.Integers))}) + + system = [exp(x) - sin(y), y**2 - 4] + assert dumeq(nonlinsolve(system, [x, y]), { + (ImageSet(Lambda(n, I*(2*n*pi + pi) + log(sin(2))), S.Integers), -2), + (ImageSet(Lambda(n, 2*n*I*pi + log(sin(2))), S.Integers), 2)}) + + system = [exp(x) - 2, y ** 2 - 2] + assert dumeq(nonlinsolve(system, [x, y]), { + (log(2), -sqrt(2)), (log(2), sqrt(2)), + (ImageSet(Lambda(n, 2*n*I*pi + log(2)), S.Integers), -sqrt(2)), + (ImageSet(Lambda(n, 2 * n * I * pi + log(2)), S.Integers), sqrt(2))}) + + +def test_nonlinsolve_radical(): + assert nonlinsolve([sqrt(y) - x - z, y - 1], [x, y, z]) == {(1 - z, 1, z)} + + +def test_nonlinsolve_inexact(): + sol = [(-1.625, -1.375), (1.625, 1.375)] + res = nonlinsolve([(x + y)**2 - 9, x**2 - y**2 - 0.75], [x, y]) + assert all(abs(res.args[i][j]-sol[i][j]) < 1e-9 + for i in range(2) for j in range(2)) + + assert nonlinsolve([(x + y)**2 - 9, (x + y)**2 - 0.75], [x, y]) == S.EmptySet + + assert nonlinsolve([y**2 + (x - 0.5)**2 - 0.0625, 2*x - 1.0, 2*y], [x, y]) == \ + S.EmptySet + + res = nonlinsolve([x**2 + y - 0.5, (x + y)**2, log(z)], [x, y, z]) + sol = [(-0.366025403784439, 0.366025403784439, 1), + (-0.366025403784439, 0.366025403784439, 1), + (1.36602540378444, -1.36602540378444, 1)] + assert all(abs(res.args[i][j]-sol[i][j]) < 1e-9 + for i in range(3) for j in range(3)) + + res = nonlinsolve([y - x**2, x**5 - x + 1.0], [x, y]) + sol = [(-1.16730397826142, 1.36259857766493), + (-0.181232444469876 - 1.08395410131771*I, + -1.14211129483496 + 0.392895302949911*I), + (-0.181232444469876 + 1.08395410131771*I, + -1.14211129483496 - 0.392895302949911*I), + (0.764884433600585 - 0.352471546031726*I, + 0.460812006002492 - 0.539199997693599*I), + (0.764884433600585 + 0.352471546031726*I, + 0.460812006002492 + 0.539199997693599*I)] + assert all(abs(res.args[i][j] - sol[i][j]) < 1e-9 + for i in range(5) for j in range(2)) + +@XFAIL +def test_solve_nonlinear_trans(): + # After the transcendental equation solver these will work + x, y = symbols('x, y', real=True) + soln1 = FiniteSet((2*LambertW(y/2), y)) + soln2 = FiniteSet((-x*sqrt(exp(x)), y), (x*sqrt(exp(x)), y)) + soln3 = FiniteSet((x*exp(x/2), x)) + soln4 = FiniteSet(2*LambertW(y/2), y) + assert nonlinsolve([x**2 - y**2/exp(x)], [x, y]) == soln1 + assert nonlinsolve([x**2 - y**2/exp(x)], [y, x]) == soln2 + assert nonlinsolve([x**2 - y**2/exp(x)], [y, x]) == soln3 + assert nonlinsolve([x**2 - y**2/exp(x)], [x, y]) == soln4 + + +def test_nonlinsolve_issue_25182(): + a1, b1, c1, ca, cb, cg = symbols('a1, b1, c1, ca, cb, cg') + eq1 = a1*a1 + b1*b1 - 2.*a1*b1*cg - c1*c1 + eq2 = a1*a1 + c1*c1 - 2.*a1*c1*cb - b1*b1 + eq3 = b1*b1 + c1*c1 - 2.*b1*c1*ca - a1*a1 + assert nonlinsolve([eq1, eq2, eq3], [c1, cb, cg]) == FiniteSet( + (1.0*b1*ca - 1.0*sqrt(a1**2 + b1**2*ca**2 - b1**2), + -1.0*sqrt(a1**2 + b1**2*ca**2 - b1**2)/a1, + -1.0*b1*(ca - 1)*(ca + 1)/a1 + 1.0*ca*sqrt(a1**2 + b1**2*ca**2 - b1**2)/a1), + (1.0*b1*ca + 1.0*sqrt(a1**2 + b1**2*ca**2 - b1**2), + 1.0*sqrt(a1**2 + b1**2*ca**2 - b1**2)/a1, + -1.0*b1*(ca - 1)*(ca + 1)/a1 - 1.0*ca*sqrt(a1**2 + b1**2*ca**2 - b1**2)/a1)) + + +def test_issue_14642(): + x = Symbol('x') + n1 = 0.5*x**3+x**2+0.5+I #add I in the Polynomials + solution = solveset(n1, x) + assert abs(solution.args[0] - (-2.28267560928153 - 0.312325580497716*I)) <= 1e-9 + assert abs(solution.args[1] - (-0.297354141679308 + 1.01904778618762*I)) <= 1e-9 + assert abs(solution.args[2] - (0.580029750960839 - 0.706722205689907*I)) <= 1e-9 + + # Symbolic + n1 = S.Half*x**3+x**2+S.Half+I + res = FiniteSet(-((3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + + S(43)/2)**2 + (27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan(S(172)/49) + /2)/2)**2)**(S(1)/6)*cos(atan((27 + 3*sqrt(3)*31985**(S(1)/4)* + cos(atan(S(172)/49)/2)/2)/(3*sqrt(3)*31985**(S(1)/4)*sin(atan( + S(172)/49)/2)/2 + S(43)/2))/3)/3 - S(2)/3 - 4*cos(atan((27 + + 3*sqrt(3)*31985**(S(1)/4)*cos(atan(S(172)/49)/2)/2)/(3*sqrt(3)* + 31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + S(43)/2))/3)/(3*((3* + sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + S(43)/2)**2 + + (27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan(S(172)/49)/2)/2)**2)**(S(1)/ + 6)) + I*(-((3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + + S(43)/2)**2 + (27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan(S(172)/49)/ + 2)/2)**2)**(S(1)/6)*sin(atan((27 + 3*sqrt(3)*31985**(S(1)/4)*cos( + atan(S(172)/49)/2)/2)/(3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49) + /2)/2 + S(43)/2))/3)/3 + 4*sin(atan((27 + 3*sqrt(3)*31985**(S(1)/4)* + cos(atan(S(172)/49)/2)/2)/(3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172) + /49)/2)/2 + S(43)/2))/3)/(3*((3*sqrt(3)*31985**(S(1)/4)*sin(atan( + S(172)/49)/2)/2 + S(43)/2)**2 + (27 + 3*sqrt(3)*31985**(S(1)/4)* + cos(atan(S(172)/49)/2)/2)**2)**(S(1)/6))), -S(2)/3 - sqrt(3)*((3* + sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + S(43)/2)**2 + + (27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan(S(172)/49)/2)/2)**2)**(S(1) + /6)*sin(atan((27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan(S(172)/49)/2) + /2)/(3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + S(43)/2)) + /3)/6 - 4*re(1/((-S(1)/2 - sqrt(3)*I/2)*(S(43)/2 + 27*I + sqrt(-256 + + (43 + 54*I)**2)/2)**(S(1)/3)))/3 + ((3*sqrt(3)*31985**(S(1)/4)*sin( + atan(S(172)/49)/2)/2 + S(43)/2)**2 + (27 + 3*sqrt(3)*31985**(S(1)/4)* + cos(atan(S(172)/49)/2)/2)**2)**(S(1)/6)*cos(atan((27 + 3*sqrt(3)* + 31985**(S(1)/4)*cos(atan(S(172)/49)/2)/2)/(3*sqrt(3)*31985**(S(1)/4)* + sin(atan(S(172)/49)/2)/2 + S(43)/2))/3)/6 + I*(-4*im(1/((-S(1)/2 - + sqrt(3)*I/2)*(S(43)/2 + 27*I + sqrt(-256 + (43 + 54*I)**2)/2)**(S(1)/ + 3)))/3 + ((3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + + S(43)/2)**2 + (27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan(S(172)/49)/2) + /2)**2)**(S(1)/6)*sin(atan((27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan( + S(172)/49)/2)/2)/(3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + + S(43)/2))/3)/6 + sqrt(3)*((3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/ + 49)/2)/2 + S(43)/2)**2 + (27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan( + S(172)/49)/2)/2)**2)**(S(1)/6)*cos(atan((27 + 3*sqrt(3)*31985**(S(1)/ + 4)*cos(atan(S(172)/49)/2)/2)/(3*sqrt(3)*31985**(S(1)/4)*sin(atan( + S(172)/49)/2)/2 + S(43)/2))/3)/6), -S(2)/3 - 4*re(1/((-S(1)/2 + + sqrt(3)*I/2)*(S(43)/2 + 27*I + sqrt(-256 + (43 + 54*I)**2)/2)**(S(1) + /3)))/3 + sqrt(3)*((3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + + S(43)/2)**2 + (27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan(S(172)/49)/2) + /2)**2)**(S(1)/6)*sin(atan((27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan( + S(172)/49)/2)/2)/(3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + + S(43)/2))/3)/6 + ((3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + + S(43)/2)**2 + (27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan(S(172)/49)/2) + /2)**2)**(S(1)/6)*cos(atan((27 + 3*sqrt(3)*31985**(S(1)/4)*cos(atan( + S(172)/49)/2)/2)/(3*sqrt(3)*31985**(S(1)/4)*sin(atan(S(172)/49)/2)/2 + + S(43)/2))/3)/6 + I*(-sqrt(3)*((3*sqrt(3)*31985**(S(1)/4)*sin(atan( + S(172)/49)/2)/2 + S(43)/2)**2 + (27 + 3*sqrt(3)*31985**(S(1)/4)*cos( + atan(S(172)/49)/2)/2)**2)**(S(1)/6)*cos(atan((27 + 3*sqrt(3)*31985**( + S(1)/4)*cos(atan(S(172)/49)/2)/2)/(3*sqrt(3)*31985**(S(1)/4)*sin( + atan(S(172)/49)/2)/2 + S(43)/2))/3)/6 + ((3*sqrt(3)*31985**(S(1)/4)* + sin(atan(S(172)/49)/2)/2 + S(43)/2)**2 + (27 + 3*sqrt(3)*31985**(S(1)/4)* + cos(atan(S(172)/49)/2)/2)**2)**(S(1)/6)*sin(atan((27 + 3*sqrt(3)*31985**( + S(1)/4)*cos(atan(S(172)/49)/2)/2)/(3*sqrt(3)*31985**(S(1)/4)*sin( + atan(S(172)/49)/2)/2 + S(43)/2))/3)/6 - 4*im(1/((-S(1)/2 + sqrt(3)*I/2)* + (S(43)/2 + 27*I + sqrt(-256 + (43 + 54*I)**2)/2)**(S(1)/3)))/3)) + + assert solveset(n1, x) == res + + +def test_issue_13961(): + V = (ax, bx, cx, gx, jx, lx, mx, nx, q) = symbols('ax bx cx gx jx lx mx nx q') + S = (ax*q - lx*q - mx, ax - gx*q - lx, bx*q**2 + cx*q - jx*q - nx, q*(-ax*q + lx*q + mx), q*(-ax + gx*q + lx)) + + sol = FiniteSet((lx + mx/q, (-cx*q + jx*q + nx)/q**2, cx, mx/q**2, jx, lx, mx, nx, Complement({q}, {0})), + (lx + mx/q, (cx*q - jx*q - nx)/q**2*-1, cx, mx/q**2, jx, lx, mx, nx, Complement({q}, {0}))) + assert nonlinsolve(S, *V) == sol + # The two solutions are in fact identical, so even better if only one is returned + + +def test_issue_14541(): + solutions = solveset(sqrt(-x**2 - 2.0), x) + assert abs(solutions.args[0]+1.4142135623731*I) <= 1e-9 + assert abs(solutions.args[1]-1.4142135623731*I) <= 1e-9 + + +def test_issue_13396(): + expr = -2*y*exp(-x**2 - y**2)*Abs(x) + sol = FiniteSet(0) + + assert solveset(expr, y, domain=S.Reals) == sol + + # Related type of equation also solved here + assert solveset(atan(x**2 - y**2)-pi/2, y, S.Reals) is S.EmptySet + + +def test_issue_12032(): + sol = FiniteSet(-sqrt(-2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) + + 2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3)))/2 + + sqrt(Abs(-2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3)) + + 2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) + + 2/sqrt(-2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) + + 2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3)))))/2, + -sqrt(Abs(-2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3)) + + 2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) + + 2/sqrt(-2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) + + 2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3)))))/2 - + sqrt(-2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) + + 2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3)))/2, + sqrt(-2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) + + 2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3)))/2 - + I*sqrt(Abs(-2/sqrt(-2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) + + 2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) - + 2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3)) + + 2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3)))))/2, + sqrt(-2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) + + 2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3)))/2 + + I*sqrt(Abs(-2/sqrt(-2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) + + 2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3))) - + 2*(Rational(1, 16) + sqrt(849)/144)**(Rational(1, 3)) + + 2/(3*(Rational(1, 16) + sqrt(849)/144)**(Rational(1,3)))))/2) + assert solveset(x**4 + x - 1, x) == sol + + +def test_issue_10876(): + assert solveset(1/sqrt(x), x) == S.EmptySet + + +def test_issue_19050(): + # test_issue_19050 --> TypeError removed + assert dumeq(nonlinsolve([x + y, sin(y)], [x, y]), + FiniteSet((ImageSet(Lambda(n, -2*n*pi), S.Integers), ImageSet(Lambda(n, 2*n*pi), S.Integers)),\ + (ImageSet(Lambda(n, -2*n*pi - pi), S.Integers), ImageSet(Lambda(n, 2*n*pi + pi), S.Integers)))) + assert dumeq(nonlinsolve([x + y, sin(y) + cos(y)], [x, y]), + FiniteSet((ImageSet(Lambda(n, -2*n*pi - 3*pi/4), S.Integers), ImageSet(Lambda(n, 2*n*pi + 3*pi/4), S.Integers)), \ + (ImageSet(Lambda(n, -2*n*pi - 7*pi/4), S.Integers), ImageSet(Lambda(n, 2*n*pi + 7*pi/4), S.Integers)))) + + +def test_issue_16618(): + eqn = [sin(x)*sin(y), cos(x)*cos(y) - 1] + # nonlinsolve's answer is still suspicious since it contains only three + # distinct Dummys instead of 4. (Both 'x' ImageSets share the same Dummy.) + ans = FiniteSet((ImageSet(Lambda(n, 2*n*pi), S.Integers), ImageSet(Lambda(n, 2*n*pi), S.Integers)), + (ImageSet(Lambda(n, 2*n*pi + pi), S.Integers), ImageSet(Lambda(n, 2*n*pi + pi), S.Integers))) + sol = nonlinsolve(eqn, [x, y]) + + for i0, j0 in zip(ordered(sol), ordered(ans)): + assert len(i0) == len(j0) == 2 + assert all(a.dummy_eq(b) for a, b in zip(i0, j0)) + assert len(sol) == len(ans) + + +def test_issue_17566(): + assert nonlinsolve([32*(2**x)/2**(-y) - 4**y, 27*(3**x) - S(1)/3**y], x, y) ==\ + FiniteSet((-log(81)/log(3), 1)) + + +def test_issue_16643(): + n = Dummy('n') + assert solveset(x**2*sin(x), x).dummy_eq(Union(ImageSet(Lambda(n, 2*n*pi + pi), S.Integers), + ImageSet(Lambda(n, 2*n*pi), S.Integers))) + + +def test_issue_19587(): + n,m = symbols('n m') + assert nonlinsolve([32*2**m*2**n - 4**n, 27*3**m - 3**(-n)], m, n) ==\ + FiniteSet((-log(81)/log(3), 1)) + + +def test_issue_5132_1(): + system = [sqrt(x**2 + y**2) - sqrt(10), x + y - 4] + assert nonlinsolve(system, [x, y]) == FiniteSet((1, 3), (3, 1)) + + n = Dummy('n') + eqs = [exp(x)**2 - sin(y) + z**2, 1/exp(y) - 3] + s_real_y = -log(3) + s_real_z = sqrt(-exp(2*x) - sin(log(3))) + soln_real = FiniteSet((s_real_y, s_real_z), (s_real_y, -s_real_z)) + lam = Lambda(n, 2*n*I*pi + -log(3)) + s_complex_y = ImageSet(lam, S.Integers) + lam = Lambda(n, sqrt(-exp(2*x) + sin(2*n*I*pi + -log(3)))) + s_complex_z_1 = ImageSet(lam, S.Integers) + lam = Lambda(n, -sqrt(-exp(2*x) + sin(2*n*I*pi + -log(3)))) + s_complex_z_2 = ImageSet(lam, S.Integers) + soln_complex = FiniteSet( + (s_complex_y, s_complex_z_1), + (s_complex_y, s_complex_z_2) + ) + soln = soln_real + soln_complex + assert dumeq(nonlinsolve(eqs, [y, z]), soln) + + +def test_issue_5132_2(): + x, y = symbols('x, y', real=True) + eqs = [exp(x)**2 - sin(y) + z**2] + n = Dummy('n') + soln_real = (log(-z**2 + sin(y))/2, z) + lam = Lambda( n, I*(2*n*pi + arg(-z**2 + sin(y)))/2 + log(Abs(z**2 - sin(y)))/2) + img = ImageSet(lam, S.Integers) + # not sure about the complex soln. But it looks correct. + soln_complex = (img, z) + soln = FiniteSet(soln_real, soln_complex) + assert dumeq(nonlinsolve(eqs, [x, z]), soln) + + system = [r - x**2 - y**2, tan(t) - y/x] + s_x = sqrt(r/(tan(t)**2 + 1)) + s_y = sqrt(r/(tan(t)**2 + 1))*tan(t) + soln = FiniteSet((s_x, s_y), (-s_x, -s_y)) + assert nonlinsolve(system, [x, y]) == soln + + +def test_issue_6752(): + a, b = symbols('a, b', real=True) + assert nonlinsolve([a**2 + a, a - b], [a, b]) == {(-1, -1), (0, 0)} + + +@SKIP("slow") +def test_issue_5114_solveset(): + # slow testcase + from sympy.abc import o, p + + # there is no 'a' in the equation set but this is how the + # problem was originally posed + 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] + assert len(nonlinsolve(eqs, syms)) == 1 + + +@SKIP("Hangs") +def _test_issue_5335(): + # Not able to check zero dimensional system. + # is_zero_dimensional Hangs + lam, a0, conc = symbols('lam a0 conc') + eqs = [lam + 2*y - a0*(1 - x/2)*x - 0.005*x/2*x, + a0*(1 - x/2)*x - 1*y - 0.743436700916726*y, + x + y - conc] + sym = [x, y, a0] + # there are 4 solutions but only two are valid + assert len(nonlinsolve(eqs, sym)) == 2 + # float + eqs = [lam + 2*y - a0*(1 - x/2)*x - 0.005*x/2*x, + a0*(1 - x/2)*x - 1*y - 0.743436700916726*y, + x + y - conc] + sym = [x, y, a0] + assert len(nonlinsolve(eqs, sym)) == 2 + + +def test_issue_2777(): + # the equations represent two circles + x, y = symbols('x y', real=True) + e1, e2 = sqrt(x**2 + y**2) - 10, sqrt(y**2 + (-x + 10)**2) - 3 + a, b = Rational(191, 20), 3*sqrt(391)/20 + ans = {(a, -b), (a, b)} + assert nonlinsolve((e1, e2), (x, y)) == ans + assert nonlinsolve((e1, e2/(x - a)), (x, y)) == S.EmptySet + # make the 2nd circle's radius be -3 + e2 += 6 + assert nonlinsolve((e1, e2), (x, y)) == S.EmptySet + + +def test_issue_8828(): + x1 = 0 + y1 = -620 + r1 = 920 + x2 = 126 + y2 = 276 + x3 = 51 + y3 = 205 + r3 = 104 + v = [x, y, z] + + f1 = (x - x1)**2 + (y - y1)**2 - (r1 - z)**2 + f2 = (x2 - x)**2 + (y2 - y)**2 - z**2 + f3 = (x - x3)**2 + (y - y3)**2 - (r3 - z)**2 + F = [f1, f2, f3] + + g1 = sqrt((x - x1)**2 + (y - y1)**2) + z - r1 + g2 = f2 + g3 = sqrt((x - x3)**2 + (y - y3)**2) + z - r3 + G = [g1, g2, g3] + + # both soln same + A = nonlinsolve(F, v) + B = nonlinsolve(G, v) + assert A == B + + +def test_nonlinsolve_conditionset(): + # when solveset failed to solve all the eq + # return conditionset + f = Function('f') + f1 = f(x) - pi/2 + f2 = f(y) - pi*Rational(3, 2) + intermediate_system = Eq(2*f(x) - pi, 0) & Eq(2*f(y) - 3*pi, 0) + syms = Tuple(x, y) + soln = ConditionSet( + syms, + intermediate_system, + S.Complexes**2) + assert nonlinsolve([f1, f2], [x, y]) == soln + + +def test_substitution_basic(): + assert substitution([], [x, y]) == S.EmptySet + assert substitution([], []) == S.EmptySet + system = [2*x**2 + 3*y**2 - 30, 3*x**2 - 2*y**2 - 19] + soln = FiniteSet((-3, -2), (-3, 2), (3, -2), (3, 2)) + assert substitution(system, [x, y]) == soln + + soln = FiniteSet((-1, 1)) + assert substitution([x + y], [x], [{y: 1}], [y], set(), [x, y]) == soln + assert substitution( + [x + y], [x], [{y: 1}], [y], + {x + 1}, [y, x]) == S.EmptySet + + +def test_substitution_incorrect(): + # the solutions in the following two tests are incorrect. The + # correct result is EmptySet in both cases. + assert substitution([h - 1, k - 1, f - 2, f - 4, -2 * k], + [h, k, f]) == {(1, 1, f)} + assert substitution([x + y + z, S.One, S.One, S.One], [x, y, z]) == \ + {(-y - z, y, z)} + + # the correct result in the test below is {(-I, I, I, -I), + # (I, -I, -I, I)} + assert substitution([a - d, b + d, c + d, d**2 + 1], [a, b, c, d]) == \ + {(d, -d, -d, d)} + + # the result in the test below is incomplete. The complete result + # is {(0, b), (log(2), 2)} + assert substitution([a*(a - log(b)), a*(b - 2)], [a, b]) == \ + {(0, b)} + + # The system in the test below is zero-dimensional, so the result + # should have no free symbols + assert substitution([-k*y + 6*x - 4*y, -81*k + 49*y**2 - 270, + -3*k*z + k + z**3, k**2 - 2*k + 4], + [x, y, z, k]).free_symbols == {z} + + +def test_substitution_redundant(): + # the third and fourth solutions are redundant in the test below + assert substitution([x**2 - y**2, z - 1], [x, z]) == \ + {(-y, 1), (y, 1), (-sqrt(y**2), 1), (sqrt(y**2), 1)} + + # the system below has three solutions. Two of the solutions + # returned by substitution are redundant. + res = substitution([x - y, y**3 - 3*y**2 + 1], [x, y]) + assert len(res) == 5 + + +def test_issue_5132_substitution(): + x, y, z, r, t = symbols('x, y, z, r, t', real=True) + system = [r - x**2 - y**2, tan(t) - y/x] + s_x_1 = Complement(FiniteSet(-sqrt(r/(tan(t)**2 + 1))), FiniteSet(0)) + s_x_2 = Complement(FiniteSet(sqrt(r/(tan(t)**2 + 1))), FiniteSet(0)) + s_y = sqrt(r/(tan(t)**2 + 1))*tan(t) + soln = FiniteSet((s_x_2, s_y)) + FiniteSet((s_x_1, -s_y)) + assert substitution(system, [x, y]) == soln + + n = Dummy('n') + eqs = [exp(x)**2 - sin(y) + z**2, 1/exp(y) - 3] + s_real_y = -log(3) + s_real_z = sqrt(-exp(2*x) - sin(log(3))) + soln_real = FiniteSet((s_real_y, s_real_z), (s_real_y, -s_real_z)) + lam = Lambda(n, 2*n*I*pi + -log(3)) + s_complex_y = ImageSet(lam, S.Integers) + lam = Lambda(n, sqrt(-exp(2*x) + sin(2*n*I*pi + -log(3)))) + s_complex_z_1 = ImageSet(lam, S.Integers) + lam = Lambda(n, -sqrt(-exp(2*x) + sin(2*n*I*pi + -log(3)))) + s_complex_z_2 = ImageSet(lam, S.Integers) + soln_complex = FiniteSet( + (s_complex_y, s_complex_z_1), + (s_complex_y, s_complex_z_2)) + soln = soln_real + soln_complex + assert dumeq(substitution(eqs, [y, z]), soln) + + +def test_raises_substitution(): + raises(ValueError, lambda: substitution([x**2 -1], [])) + raises(TypeError, lambda: substitution([x**2 -1])) + raises(ValueError, lambda: substitution([x**2 -1], [sin(x)])) + raises(TypeError, lambda: substitution([x**2 -1], x)) + raises(TypeError, lambda: substitution([x**2 -1], 1)) + + +def test_issue_21022(): + from sympy.core.sympify import sympify + + eqs = [ + 'k-16', + 'p-8', + 'y*y+z*z-x*x', + 'd - x + p', + 'd*d+k*k-y*y', + 'z*z-p*p-k*k', + 'abc-efg', + ] + efg = Symbol('efg') + eqs = [sympify(x) for x in eqs] + + syb = list(ordered(set.union(*[x.free_symbols for x in eqs]))) + res = nonlinsolve(eqs, syb) + + ans = FiniteSet( + (efg, 32, efg, 16, 8, 40, -16*sqrt(5), -8*sqrt(5)), + (efg, 32, efg, 16, 8, 40, -16*sqrt(5), 8*sqrt(5)), + (efg, 32, efg, 16, 8, 40, 16*sqrt(5), -8*sqrt(5)), + (efg, 32, efg, 16, 8, 40, 16*sqrt(5), 8*sqrt(5)), + ) + assert len(res) == len(ans) == 4 + assert res == ans + for result in res.args: + assert len(result) == 8 + + +def test_issue_17940(): + n = Dummy('n') + k1 = Dummy('k1') + sol = ImageSet(Lambda(((k1, n),), I*(2*k1*pi + arg(2*n*I*pi + log(5))) + + log(Abs(2*n*I*pi + log(5)))), + ProductSet(S.Integers, S.Integers)) + assert solveset(exp(exp(x)) - 5, x).dummy_eq(sol) + + +def test_issue_17906(): + assert solveset(7**(x**2 - 80) - 49**x, x) == FiniteSet(-8, 10) + + +@XFAIL +def test_issue_17933(): + eq1 = x*sin(45) - y*cos(q) + eq2 = x*cos(45) - y*sin(q) + eq3 = 9*x*sin(45)/10 + y*cos(q) + eq4 = 9*x*cos(45)/10 + y*sin(z) - z + assert nonlinsolve([eq1, eq2, eq3, eq4], x, y, z, q) ==\ + FiniteSet((0, 0, 0, q)) + +def test_issue_17933_bis(): + # nonlinsolve's result depends on the 'default_sort_key' ordering of + # the unknowns. + eq1 = x*sin(45) - y*cos(q) + eq2 = x*cos(45) - y*sin(q) + eq3 = 9*x*sin(45)/10 + y*cos(q) + eq4 = 9*x*cos(45)/10 + y*sin(z) - z + zz = Symbol('zz') + eqs = [e.subs(q, zz) for e in (eq1, eq2, eq3, eq4)] + assert nonlinsolve(eqs, x, y, z, zz) == FiniteSet((0, 0, 0, zz)) + + +def test_issue_14565(): + # removed redundancy + assert dumeq(nonlinsolve([k + m, k + m*exp(-2*pi*k)], [k, m]) , + FiniteSet((-n*I, ImageSet(Lambda(n, n*I), S.Integers)))) + + +# end of tests for nonlinsolve + + +def test_issue_9556(): + b = Symbol('b', positive=True) + + assert solveset(Abs(x) + 1, x, S.Reals) is S.EmptySet + assert solveset(Abs(x) + b, x, S.Reals) is S.EmptySet + assert solveset(Eq(b, -1), b, S.Reals) is S.EmptySet + + +def test_issue_9611(): + assert solveset(Eq(x - x + a, a), x, S.Reals) == S.Reals + assert solveset(Eq(y - y + a, a), y) == S.Complexes + + +def test_issue_9557(): + assert solveset(x**2 + a, x, S.Reals) == Intersection(S.Reals, + FiniteSet(-sqrt(-a), sqrt(-a))) + + +def test_issue_9778(): + x = Symbol('x', real=True) + y = Symbol('y', real=True) + assert solveset(x**3 + 1, x, S.Reals) == FiniteSet(-1) + assert solveset(x**Rational(3, 5) + 1, x, S.Reals) == S.EmptySet + assert solveset(x**3 + y, x, S.Reals) == \ + FiniteSet(-Abs(y)**Rational(1, 3)*sign(y)) + + +def test_issue_10214(): + assert solveset(x**Rational(3, 2) + 4, x, S.Reals) == S.EmptySet + assert solveset(x**(Rational(-3, 2)) + 4, x, S.Reals) == S.EmptySet + + ans = FiniteSet(-2**Rational(2, 3)) + assert solveset(x**(S(3)) + 4, x, S.Reals) == ans + assert (x**(S(3)) + 4).subs(x,list(ans)[0]) == 0 # substituting ans and verifying the result. + assert (x**(S(3)) + 4).subs(x,-(-2)**Rational(2, 3)) == 0 + + +def test_issue_9849(): + assert solveset(Abs(sin(x)) + 1, x, S.Reals) == S.EmptySet + + +def test_issue_9953(): + assert linsolve([ ], x) == S.EmptySet + + +def test_issue_9913(): + assert solveset(2*x + 1/(x - 10)**2, x, S.Reals) == \ + FiniteSet(-(3*sqrt(24081)/4 + Rational(4027, 4))**Rational(1, 3)/3 - 100/ + (3*(3*sqrt(24081)/4 + Rational(4027, 4))**Rational(1, 3)) + Rational(20, 3)) + + +def test_issue_10397(): + assert solveset(sqrt(x), x, S.Complexes) == FiniteSet(0) + + +def test_issue_14987(): + raises(ValueError, lambda: linear_eq_to_matrix( + [x**2], x)) + raises(ValueError, lambda: linear_eq_to_matrix( + [x*(-3/x + 1) + 2*y - a], [x, y])) + raises(ValueError, lambda: linear_eq_to_matrix( + [(x**2 - 3*x)/(x - 3) - 3], x)) + raises(ValueError, lambda: linear_eq_to_matrix( + [(x + 1)**3 - x**3 - 3*x**2 + 7], x)) + raises(ValueError, lambda: linear_eq_to_matrix( + [x*(1/x + 1) + y], [x, y])) + raises(ValueError, lambda: linear_eq_to_matrix( + [(x + 1)*y], [x, y])) + raises(ValueError, lambda: linear_eq_to_matrix( + [Eq(1/x, 1/x + y)], [x, y])) + raises(ValueError, lambda: linear_eq_to_matrix( + [Eq(y/x, y/x + y)], [x, y])) + raises(ValueError, lambda: linear_eq_to_matrix( + [Eq(x*(x + 1), x**2 + y)], [x, y])) + + +def test_simplification(): + eq = x + (a - b)/(-2*a + 2*b) + assert solveset(eq, x) == FiniteSet(S.Half) + assert solveset(eq, x, S.Reals) == Intersection({-((a - b)/(-2*a + 2*b))}, S.Reals) + # So that ap - bn is not zero: + ap = Symbol('ap', positive=True) + bn = Symbol('bn', negative=True) + eq = x + (ap - bn)/(-2*ap + 2*bn) + assert solveset(eq, x) == FiniteSet(S.Half) + assert solveset(eq, x, S.Reals) == FiniteSet(S.Half) + + +def test_integer_domain_relational(): + eq1 = 2*x + 3 > 0 + eq2 = x**2 + 3*x - 2 >= 0 + eq3 = x + 1/x > -2 + 1/x + eq4 = x + sqrt(x**2 - 5) > 0 + eq = x + 1/x > -2 + 1/x + eq5 = eq.subs(x,log(x)) + eq6 = log(x)/x <= 0 + eq7 = log(x)/x < 0 + eq8 = x/(x-3) < 3 + eq9 = x/(x**2-3) < 3 + + assert solveset(eq1, x, S.Integers) == Range(-1, oo, 1) + assert solveset(eq2, x, S.Integers) == Union(Range(-oo, -3, 1), Range(1, oo, 1)) + assert solveset(eq3, x, S.Integers) == Union(Range(-1, 0, 1), Range(1, oo, 1)) + assert solveset(eq4, x, S.Integers) == Range(3, oo, 1) + assert solveset(eq5, x, S.Integers) == Range(2, oo, 1) + assert solveset(eq6, x, S.Integers) == Range(1, 2, 1) + assert solveset(eq7, x, S.Integers) == S.EmptySet + assert solveset(eq8, x, domain=Range(0,5)) == Range(0, 3, 1) + assert solveset(eq9, x, domain=Range(0,5)) == Union(Range(0, 2, 1), Range(2, 5, 1)) + + # test_issue_19794 + assert solveset(x + 2 < 0, x, S.Integers) == Range(-oo, -2, 1) + + +def test_issue_10555(): + f = Function('f') + g = Function('g') + assert solveset(f(x) - pi/2, x, S.Reals).dummy_eq( + ConditionSet(x, Eq(f(x) - pi/2, 0), S.Reals)) + assert solveset(f(g(x)) - pi/2, g(x), S.Reals).dummy_eq( + ConditionSet(g(x), Eq(f(g(x)) - pi/2, 0), S.Reals)) + + +def test_issue_8715(): + eq = x + 1/x > -2 + 1/x + assert solveset(eq, x, S.Reals) == \ + (Interval.open(-2, oo) - FiniteSet(0)) + assert solveset(eq.subs(x,log(x)), x, S.Reals) == \ + Interval.open(exp(-2), oo) - FiniteSet(1) + + +def test_issue_11174(): + eq = z**2 + exp(2*x) - sin(y) + soln = Intersection(S.Reals, FiniteSet(log(-z**2 + sin(y))/2)) + assert solveset(eq, x, S.Reals) == soln + + eq = sqrt(r)*Abs(tan(t))/sqrt(tan(t)**2 + 1) + x*tan(t) + s = -sqrt(r)*Abs(tan(t))/(sqrt(tan(t)**2 + 1)*tan(t)) + soln = Intersection(S.Reals, FiniteSet(s)) + assert solveset(eq, x, S.Reals) == soln + + +def test_issue_11534(): + # eq1 and eq2 should not have the same solutions because squaring both + # sides of the radical equation introduces a spurious solution branch. + # The equations have a symbolic parameter y and it is easy to see that for + # y != 0 the solution s1 will not be valid for eq1. + x = Symbol('x', real=True) + y = Symbol('y', real=True) + eq1 = -y + x/sqrt(-x**2 + 1) + eq2 = -y**2 + x**2/(-x**2 + 1) + + # We get a ConditionSet here because s1 works in eq1 if y is equal to zero + # although not for any other value of y. That case is redundant though + # because if y=0 then s1=s2 so the solution for eq1 could just be returned + # as s2 - {-1, 1}. In fact we have + # |y/sqrt(y**2 + 1)| < 1 + # So the complements are not needed either. The ideal output here would be + # sol1 = s2 + # sol2 = s1 | s2. + s1, s2 = FiniteSet(-y/sqrt(y**2 + 1)), FiniteSet(y/sqrt(y**2 + 1)) + cset = ConditionSet(x, Eq(eq1, 0), s1) + sol1 = (s2 - {-1, 1}) | (cset - {-1, 1}) + sol2 = (s1 | s2) - {-1, 1} + + assert solveset(eq1, x, S.Reals) == sol1 + assert solveset(eq2, x, S.Reals) == sol2 + + +def test_issue_10477(): + assert solveset((x**2 + 4*x - 3)/x < 2, x, S.Reals) == \ + Union(Interval.open(-oo, -3), Interval.open(0, 1)) + + +def test_issue_10671(): + assert solveset(sin(y), y, Interval(0, pi)) == FiniteSet(0, pi) + i = Interval(1, 10) + assert solveset((1/x).diff(x) < 0, x, i) == i + + +def test_issue_11064(): + eq = x + sqrt(x**2 - 5) + assert solveset(eq > 0, x, S.Reals) == \ + Interval(sqrt(5), oo) + assert solveset(eq < 0, x, S.Reals) == \ + Interval(-oo, -sqrt(5)) + assert solveset(eq > sqrt(5), x, S.Reals) == \ + Interval.Lopen(sqrt(5), oo) + + +def test_issue_12478(): + eq = sqrt(x - 2) + 2 + soln = solveset_real(eq, x) + assert soln is S.EmptySet + assert solveset(eq < 0, x, S.Reals) is S.EmptySet + assert solveset(eq > 0, x, S.Reals) == Interval(2, oo) + + +def test_issue_12429(): + eq = solveset(log(x)/x <= 0, x, S.Reals) + sol = Interval.Lopen(0, 1) + assert eq == sol + + +def test_issue_19506(): + eq = arg(x + I) + C = Dummy('C') + assert solveset(eq).dummy_eq(Intersection(ConditionSet(C, Eq(im(C) + 1, 0), S.Complexes), + ConditionSet(C, re(C) > 0, S.Complexes))) + + +def test_solveset_arg(): + assert solveset(arg(x), x, S.Reals) == Interval.open(0, oo) + assert solveset(arg(4*x -3), x, S.Reals) == Interval.open(Rational(3, 4), oo) + + +def test__is_finite_with_finite_vars(): + f = _is_finite_with_finite_vars + # issue 12482 + assert all(f(1/x) is None for x in ( + Dummy(), Dummy(real=True), Dummy(complex=True))) + assert f(1/Dummy(real=False)) is True # b/c it's finite but not 0 + + +def test_issue_13550(): + assert solveset(x**2 - 2*x - 15, symbol = x, domain = Interval(-oo, 0)) == FiniteSet(-3) + + +def test_issue_13849(): + assert nonlinsolve((t*(sqrt(5) + sqrt(2)) - sqrt(2), t), t) is S.EmptySet + + +def test_issue_14223(): + assert solveset((Abs(x + Min(x, 2)) - 2).rewrite(Piecewise), x, + S.Reals) == FiniteSet(-1, 1) + assert solveset((Abs(x + Min(x, 2)) - 2).rewrite(Piecewise), x, + Interval(0, 2)) == FiniteSet(1) + assert solveset(x, x, FiniteSet(1, 2)) is S.EmptySet + + +def test_issue_10158(): + dom = S.Reals + assert solveset(x*Max(x, 15) - 10, x, dom) == FiniteSet(Rational(2, 3)) + assert solveset(x*Min(x, 15) - 10, x, dom) == FiniteSet(-sqrt(10), sqrt(10)) + assert solveset(Max(Abs(x - 3) - 1, x + 2) - 3, x, dom) == FiniteSet(-1, 1) + assert solveset(Abs(x - 1) - Abs(y), x, dom) == FiniteSet(-Abs(y) + 1, Abs(y) + 1) + assert solveset(Abs(x + 4*Abs(x + 1)), x, dom) == FiniteSet(Rational(-4, 3), Rational(-4, 5)) + assert solveset(2*Abs(x + Abs(x + Max(3, x))) - 2, x, S.Reals) == FiniteSet(-1, -2) + dom = S.Complexes + raises(ValueError, lambda: solveset(x*Max(x, 15) - 10, x, dom)) + raises(ValueError, lambda: solveset(x*Min(x, 15) - 10, x, dom)) + raises(ValueError, lambda: solveset(Max(Abs(x - 3) - 1, x + 2) - 3, x, dom)) + raises(ValueError, lambda: solveset(Abs(x - 1) - Abs(y), x, dom)) + raises(ValueError, lambda: solveset(Abs(x + 4*Abs(x + 1)), x, dom)) + + +def test_issue_14300(): + f = 1 - exp(-18000000*x) - y + a1 = FiniteSet(-log(-y + 1)/18000000) + + assert solveset(f, x, S.Reals) == \ + Intersection(S.Reals, a1) + assert dumeq(solveset(f, x), + ImageSet(Lambda(n, -I*(2*n*pi + arg(-y + 1))/18000000 - + log(Abs(y - 1))/18000000), S.Integers)) + + +def test_issue_14454(): + number = CRootOf(x**4 + x - 1, 2) + raises(ValueError, lambda: invert_real(number, 0, x)) + assert invert_real(x**2, number, x) # no error + + +def test_issue_17882(): + assert solveset(-8*x**2/(9*(x**2 - 1)**(S(4)/3)) + 4/(3*(x**2 - 1)**(S(1)/3)), x, S.Complexes) == \ + FiniteSet(sqrt(3), -sqrt(3)) + + +def test_term_factors(): + assert list(_term_factors(3**x - 2)) == [-2, 3**x] + expr = 4**(x + 1) + 4**(x + 2) + 4**(x - 1) - 3**(x + 2) - 3**(x + 3) + assert set(_term_factors(expr)) == { + 3**(x + 2), 4**(x + 2), 3**(x + 3), 4**(x - 1), -1, 4**(x + 1)} + + +#################### tests for transolve and its helpers ############### + +def test_transolve(): + + assert _transolve(3**x, x, S.Reals) == S.EmptySet + assert _transolve(3**x - 9**(x + 5), x, S.Reals) == FiniteSet(-10) + + +def test_issue_21276(): + eq = (2*x*(y - z) - y*erf(y - z) - y + z*erf(y - z) + z)**2 + assert solveset(eq.expand(), y) == FiniteSet(z, z + erfinv(2*x - 1)) + + +# exponential tests +def test_exponential_real(): + from sympy.abc import y + + e1 = 3**(2*x) - 2**(x + 3) + e2 = 4**(5 - 9*x) - 8**(2 - x) + e3 = 2**x + 4**x + e4 = exp(log(5)*x) - 2**x + e5 = exp(x/y)*exp(-z/y) - 2 + e6 = 5**(x/2) - 2**(x/3) + e7 = 4**(x + 1) + 4**(x + 2) + 4**(x - 1) - 3**(x + 2) - 3**(x + 3) + e8 = -9*exp(-2*x + 5) + 4*exp(3*x + 1) + e9 = 2**x + 4**x + 8**x - 84 + e10 = 29*2**(x + 1)*615**(x) - 123*2726**(x) + + assert solveset(e1, x, S.Reals) == FiniteSet( + -3*log(2)/(-2*log(3) + log(2))) + assert solveset(e2, x, S.Reals) == FiniteSet(Rational(4, 15)) + assert solveset(e3, x, S.Reals) == S.EmptySet + assert solveset(e4, x, S.Reals) == FiniteSet(0) + assert solveset(e5, x, S.Reals) == Intersection( + S.Reals, FiniteSet(y*log(2*exp(z/y)))) + assert solveset(e6, x, S.Reals) == FiniteSet(0) + assert solveset(e7, x, S.Reals) == FiniteSet(2) + assert solveset(e8, x, S.Reals) == FiniteSet(-2*log(2)/5 + 2*log(3)/5 + Rational(4, 5)) + assert solveset(e9, x, S.Reals) == FiniteSet(2) + assert solveset(e10,x, S.Reals) == FiniteSet((-log(29) - log(2) + log(123))/(-log(2726) + log(2) + log(615))) + + assert solveset_real(-9*exp(-2*x + 5) + 2**(x + 1), x) == FiniteSet( + -((-5 - 2*log(3) + log(2))/(log(2) + 2))) + assert solveset_real(4**(x/2) - 2**(x/3), x) == FiniteSet(0) + b = sqrt(6)*sqrt(log(2))/sqrt(log(5)) + assert solveset_real(5**(x/2) - 2**(3/x), x) == FiniteSet(-b, b) + + # coverage test + C1, C2 = symbols('C1 C2') + f = Function('f') + assert solveset_real(C1 + C2/x**2 - exp(-f(x)), f(x)) == Intersection( + S.Reals, FiniteSet(-log(C1 + C2/x**2))) + y = symbols('y', positive=True) + assert solveset_real(x**2 - y**2/exp(x), y) == Intersection( + S.Reals, FiniteSet(-sqrt(x**2*exp(x)), sqrt(x**2*exp(x)))) + p = Symbol('p', positive=True) + assert solveset_real((1/p + 1)**(p + 1), p).dummy_eq( + ConditionSet(x, Eq((1 + 1/x)**(x + 1), 0), S.Reals)) + assert solveset(2**x - 4**x + 12, x, S.Reals) == {2} + assert solveset(2**x - 2**(2*x) + 12, x, S.Reals) == {2} + + +@XFAIL +def test_exponential_complex(): + n = Dummy('n') + + assert dumeq(solveset_complex(2**x + 4**x, x),imageset( + Lambda(n, I*(2*n*pi + pi)/log(2)), S.Integers)) + assert solveset_complex(x**z*y**z - 2, z) == FiniteSet( + log(2)/(log(x) + log(y))) + assert dumeq(solveset_complex(4**(x/2) - 2**(x/3), x), imageset( + Lambda(n, 3*n*I*pi/log(2)), S.Integers)) + assert dumeq(solveset(2**x + 32, x), imageset( + Lambda(n, (I*(2*n*pi + pi) + 5*log(2))/log(2)), S.Integers)) + + eq = (2**exp(y**2/x) + 2)/(x**2 + 15) + a = sqrt(x)*sqrt(-log(log(2)) + log(log(2) + 2*n*I*pi)) + assert solveset_complex(eq, y) == FiniteSet(-a, a) + + union1 = imageset(Lambda(n, I*(2*n*pi - pi*Rational(2, 3))/log(2)), S.Integers) + union2 = imageset(Lambda(n, I*(2*n*pi + pi*Rational(2, 3))/log(2)), S.Integers) + assert dumeq(solveset(2**x + 4**x + 8**x, x), Union(union1, union2)) + + eq = 4**(x + 1) + 4**(x + 2) + 4**(x - 1) - 3**(x + 2) - 3**(x + 3) + res = solveset(eq, x) + num = 2*n*I*pi - 4*log(2) + 2*log(3) + den = -2*log(2) + log(3) + ans = imageset(Lambda(n, num/den), S.Integers) + assert dumeq(res, ans) + + +def test_expo_conditionset(): + + f1 = (exp(x) + 1)**x - 2 + f2 = (x + 2)**y*x - 3 + f3 = 2**x - exp(x) - 3 + f4 = log(x) - exp(x) + f5 = 2**x + 3**x - 5**x + + assert solveset(f1, x, S.Reals).dummy_eq(ConditionSet( + x, Eq((exp(x) + 1)**x - 2, 0), S.Reals)) + assert solveset(f2, x, S.Reals).dummy_eq(ConditionSet( + x, Eq(x*(x + 2)**y - 3, 0), S.Reals)) + assert solveset(f3, x, S.Reals).dummy_eq(ConditionSet( + x, Eq(2**x - exp(x) - 3, 0), S.Reals)) + assert solveset(f4, x, S.Reals).dummy_eq(ConditionSet( + x, Eq(-exp(x) + log(x), 0), S.Reals)) + assert solveset(f5, x, S.Reals).dummy_eq(ConditionSet( + x, Eq(2**x + 3**x - 5**x, 0), S.Reals)) + + +def test_exponential_symbols(): + x, y, z = symbols('x y z', positive=True) + xr, zr = symbols('xr, zr', real=True) + + assert solveset(z**x - y, x, S.Reals) == Intersection( + S.Reals, FiniteSet(log(y)/log(z))) + + f1 = 2*x**w - 4*y**w + f2 = (x/y)**w - 2 + sol1 = Intersection({log(2)/(log(x) - log(y))}, S.Reals) + sol2 = Intersection({log(2)/log(x/y)}, S.Reals) + assert solveset(f1, w, S.Reals) == sol1, solveset(f1, w, S.Reals) + assert solveset(f2, w, S.Reals) == sol2, solveset(f2, w, S.Reals) + + assert solveset(x**x, x, Interval.Lopen(0,oo)).dummy_eq( + ConditionSet(w, Eq(w**w, 0), Interval.open(0, oo))) + assert solveset(x**y - 1, y, S.Reals) == FiniteSet(0) + assert solveset(exp(x/y)*exp(-z/y) - 2, y, S.Reals) == \ + Complement(ConditionSet(y, Eq(im(x)/y, 0) & Eq(im(z)/y, 0), \ + Complement(Intersection(FiniteSet((x - z)/log(2)), S.Reals), FiniteSet(0))), FiniteSet(0)) + assert solveset(exp(xr/y)*exp(-zr/y) - 2, y, S.Reals) == \ + Complement(FiniteSet((xr - zr)/log(2)), FiniteSet(0)) + + assert solveset(a**x - b**x, x).dummy_eq(ConditionSet( + w, Ne(a, 0) & Ne(b, 0), FiniteSet(0))) + + +def test_ignore_assumptions(): + # make sure assumptions are ignored + xpos = symbols('x', positive=True) + x = symbols('x') + assert solveset_complex(xpos**2 - 4, xpos + ) == solveset_complex(x**2 - 4, x) + + +@XFAIL +def test_issue_10864(): + assert solveset(x**(y*z) - x, x, S.Reals) == FiniteSet(1) + + +@XFAIL +def test_solve_only_exp_2(): + assert solveset_real(sqrt(exp(x)) + sqrt(exp(-x)) - 4, x) == \ + FiniteSet(2*log(-sqrt(3) + 2), 2*log(sqrt(3) + 2)) + + +def test_is_exponential(): + assert _is_exponential(y, x) is False + assert _is_exponential(3**x - 2, x) is True + assert _is_exponential(5**x - 7**(2 - x), x) is True + assert _is_exponential(sin(2**x) - 4*x, x) is False + assert _is_exponential(x**y - z, y) is True + assert _is_exponential(x**y - z, x) is False + assert _is_exponential(2**x + 4**x - 1, x) is True + assert _is_exponential(x**(y*z) - x, x) is False + assert _is_exponential(x**(2*x) - 3**x, x) is False + assert _is_exponential(x**y - y*z, y) is False + assert _is_exponential(x**y - x*z, y) is True + + +def test_solve_exponential(): + assert _solve_exponential(3**(2*x) - 2**(x + 3), 0, x, S.Reals) == \ + FiniteSet(-3*log(2)/(-2*log(3) + log(2))) + assert _solve_exponential(2**y + 4**y, 1, y, S.Reals) == \ + FiniteSet(log(Rational(-1, 2) + sqrt(5)/2)/log(2)) + assert _solve_exponential(2**y + 4**y, 0, y, S.Reals) == \ + S.EmptySet + assert _solve_exponential(2**x + 3**x - 5**x, 0, x, S.Reals) == \ + ConditionSet(x, Eq(2**x + 3**x - 5**x, 0), S.Reals) + +# end of exponential tests + + +# logarithmic tests +def test_logarithmic(): + assert solveset_real(log(x - 3) + log(x + 3), x) == FiniteSet( + -sqrt(10), sqrt(10)) + assert solveset_real(log(x + 1) - log(2*x - 1), x) == FiniteSet(2) + assert solveset_real(log(x + 3) + log(1 + 3/x) - 3, x) == FiniteSet( + -3 + sqrt(-12 + exp(3))*exp(Rational(3, 2))/2 + exp(3)/2, + -sqrt(-12 + exp(3))*exp(Rational(3, 2))/2 - 3 + exp(3)/2) + + eq = z - log(x) + log(y/(x*(-1 + y**2/x**2))) + assert solveset_real(eq, x) == \ + Intersection(S.Reals, FiniteSet(-sqrt(y**2 - y*exp(z)), + sqrt(y**2 - y*exp(z)))) - \ + Intersection(S.Reals, FiniteSet(-sqrt(y**2), sqrt(y**2))) + assert solveset_real( + log(3*x) - log(-x + 1) - log(4*x + 1), x) == FiniteSet(Rational(-1, 2), S.Half) + assert solveset(log(x**y) - y*log(x), x, S.Reals) == S.Reals + +@XFAIL +def test_uselogcombine_2(): + eq = log(exp(2*x) + 1) + log(-tanh(x) + 1) - log(2) + assert solveset_real(eq, x) is S.EmptySet + eq = log(8*x) - log(sqrt(x) + 1) - 2 + assert solveset_real(eq, x) is S.EmptySet + + +def test_is_logarithmic(): + assert _is_logarithmic(y, x) is False + assert _is_logarithmic(log(x), x) is True + assert _is_logarithmic(log(x) - 3, x) is True + assert _is_logarithmic(log(x)*log(y), x) is True + assert _is_logarithmic(log(x)**2, x) is False + assert _is_logarithmic(log(x - 3) + log(x + 3), x) is True + assert _is_logarithmic(log(x**y) - y*log(x), x) is True + assert _is_logarithmic(sin(log(x)), x) is False + assert _is_logarithmic(x + y, x) is False + assert _is_logarithmic(log(3*x) - log(1 - x) + 4, x) is True + assert _is_logarithmic(log(x) + log(y) + x, x) is False + assert _is_logarithmic(log(log(x - 3)) + log(x - 3), x) is True + assert _is_logarithmic(log(log(3) + x) + log(x), x) is True + assert _is_logarithmic(log(x)*(y + 3) + log(x), y) is False + + +def test_solve_logarithm(): + y = Symbol('y') + assert _solve_logarithm(log(x**y) - y*log(x), 0, x, S.Reals) == S.Reals + y = Symbol('y', positive=True) + assert _solve_logarithm(log(x)*log(y), 0, x, S.Reals) == FiniteSet(1) + +# end of logarithmic tests + + +# lambert tests +def test_is_lambert(): + a, b, c = symbols('a,b,c') + assert _is_lambert(x**2, x) is False + assert _is_lambert(a**x**2+b*x+c, x) is True + assert _is_lambert(E**2, x) is False + assert _is_lambert(x*E**2, x) is False + assert _is_lambert(3*log(x) - x*log(3), x) is True + assert _is_lambert(log(log(x - 3)) + log(x-3), x) is True + assert _is_lambert(5*x - 1 + 3*exp(2 - 7*x), x) is True + assert _is_lambert((a/x + exp(x/2)).diff(x, 2), x) is True + assert _is_lambert((x**2 - 2*x + 1).subs(x, (log(x) + 3*x)**2 - 1), x) is True + assert _is_lambert(x*sinh(x) - 1, x) is True + assert _is_lambert(x*cos(x) - 5, x) is True + assert _is_lambert(tanh(x) - 5*x, x) is True + assert _is_lambert(cosh(x) - sinh(x), x) is False + +# end of lambert tests + + +def test_linear_coeffs(): + from sympy.solvers.solveset import linear_coeffs + assert linear_coeffs(0, x) == [0, 0] + assert all(i is S.Zero for i in linear_coeffs(0, x)) + assert linear_coeffs(x + 2*y + 3, x, y) == [1, 2, 3] + assert linear_coeffs(x + 2*y + 3, y, x) == [2, 1, 3] + assert linear_coeffs(x + 2*x**2 + 3, x, x**2) == [1, 2, 3] + raises(ValueError, lambda: + linear_coeffs(x + 2*x**2 + x**3, x, x**2)) + raises(ValueError, lambda: + linear_coeffs(1/x*(x - 1) + 1/x, x)) + raises(ValueError, lambda: + linear_coeffs(x, x, x)) + assert linear_coeffs(a*(x + y), x, y) == [a, a, 0] + assert linear_coeffs(1.0, x, y) == [0, 0, 1.0] + # don't include coefficients of 0 + assert linear_coeffs(Eq(x, x + y), x, y, dict=True) == {y: -1} + assert linear_coeffs(0, x, y, dict=True) == {} + + +def test_is_modular(): + assert _is_modular(y, x) is False + assert _is_modular(Mod(x, 3) - 1, x) is True + assert _is_modular(Mod(x**3 - 3*x**2 - x + 1, 3) - 1, x) is True + assert _is_modular(Mod(exp(x + y), 3) - 2, x) is True + assert _is_modular(Mod(exp(x + y), 3) - log(x), x) is True + assert _is_modular(Mod(x, 3) - 1, y) is False + assert _is_modular(Mod(x, 3)**2 - 5, x) is False + assert _is_modular(Mod(x, 3)**2 - y, x) is False + assert _is_modular(exp(Mod(x, 3)) - 1, x) is False + assert _is_modular(Mod(3, y) - 1, y) is False + + +def test_invert_modular(): + n = Dummy('n', integer=True) + from sympy.solvers.solveset import _invert_modular as invert_modular + + # no solutions + assert invert_modular(Mod(x, 12), S(1)/2, n, x) == (x, S.EmptySet) + # non invertible cases + assert invert_modular(Mod(sin(x), 7), S(5), n, x) == (Mod(sin(x), 7), 5) + assert invert_modular(Mod(exp(x), 7), S(5), n, x) == (Mod(exp(x), 7), 5) + assert invert_modular(Mod(log(x), 7), S(5), n, x) == (Mod(log(x), 7), 5) + # a is symbol + assert dumeq(invert_modular(Mod(x, 7), S(5), n, x), + (x, ImageSet(Lambda(n, 7*n + 5), S.Integers))) + # a.is_Add + assert dumeq(invert_modular(Mod(x + 8, 7), S(5), n, x), + (x, ImageSet(Lambda(n, 7*n + 4), S.Integers))) + assert invert_modular(Mod(x**2 + x, 7), S(5), n, x) == \ + (Mod(x**2 + x, 7), 5) + # a.is_Mul + assert dumeq(invert_modular(Mod(3*x, 7), S(5), n, x), + (x, ImageSet(Lambda(n, 7*n + 4), S.Integers))) + assert invert_modular(Mod((x + 1)*(x + 2), 7), S(5), n, x) == \ + (Mod((x + 1)*(x + 2), 7), 5) + # a.is_Pow + assert invert_modular(Mod(x**4, 7), S(5), n, x) == \ + (x, S.EmptySet) + assert dumeq(invert_modular(Mod(3**x, 4), S(3), n, x), + (x, ImageSet(Lambda(n, 2*n + 1), S.Naturals0))) + assert dumeq(invert_modular(Mod(2**(x**2 + x + 1), 7), S(2), n, x), + (x**2 + x + 1, ImageSet(Lambda(n, 3*n + 1), S.Naturals0))) + assert invert_modular(Mod(sin(x)**4, 7), S(5), n, x) == (x, S.EmptySet) + + +def test_solve_modular(): + n = Dummy('n', integer=True) + # if rhs has symbol (need to be implemented in future). + assert solveset(Mod(x, 4) - x, x, S.Integers + ).dummy_eq( + ConditionSet(x, Eq(-x + Mod(x, 4), 0), + S.Integers)) + # when _invert_modular fails to invert + assert solveset(3 - Mod(sin(x), 7), x, S.Integers + ).dummy_eq( + ConditionSet(x, Eq(Mod(sin(x), 7) - 3, 0), S.Integers)) + assert solveset(3 - Mod(log(x), 7), x, S.Integers + ).dummy_eq( + ConditionSet(x, Eq(Mod(log(x), 7) - 3, 0), S.Integers)) + assert solveset(3 - Mod(exp(x), 7), x, S.Integers + ).dummy_eq(ConditionSet(x, Eq(Mod(exp(x), 7) - 3, 0), + S.Integers)) + # EmptySet solution definitely + assert solveset(7 - Mod(x, 5), x, S.Integers) is S.EmptySet + assert solveset(5 - Mod(x, 5), x, S.Integers) is S.EmptySet + # Negative m + assert dumeq(solveset(2 + Mod(x, -3), x, S.Integers), + ImageSet(Lambda(n, -3*n - 2), S.Integers)) + assert solveset(4 + Mod(x, -3), x, S.Integers) is S.EmptySet + # linear expression in Mod + assert dumeq(solveset(3 - Mod(x, 5), x, S.Integers), + ImageSet(Lambda(n, 5*n + 3), S.Integers)) + assert dumeq(solveset(3 - Mod(5*x - 8, 7), x, S.Integers), + ImageSet(Lambda(n, 7*n + 5), S.Integers)) + assert dumeq(solveset(3 - Mod(5*x, 7), x, S.Integers), + ImageSet(Lambda(n, 7*n + 2), S.Integers)) + # higher degree expression in Mod + assert dumeq(solveset(Mod(x**2, 160) - 9, x, S.Integers), + Union(ImageSet(Lambda(n, 160*n + 3), S.Integers), + ImageSet(Lambda(n, 160*n + 13), S.Integers), + ImageSet(Lambda(n, 160*n + 67), S.Integers), + ImageSet(Lambda(n, 160*n + 77), S.Integers), + ImageSet(Lambda(n, 160*n + 83), S.Integers), + ImageSet(Lambda(n, 160*n + 93), S.Integers), + ImageSet(Lambda(n, 160*n + 147), S.Integers), + ImageSet(Lambda(n, 160*n + 157), S.Integers))) + assert solveset(3 - Mod(x**4, 7), x, S.Integers) is S.EmptySet + assert dumeq(solveset(Mod(x**4, 17) - 13, x, S.Integers), + Union(ImageSet(Lambda(n, 17*n + 3), S.Integers), + ImageSet(Lambda(n, 17*n + 5), S.Integers), + ImageSet(Lambda(n, 17*n + 12), S.Integers), + ImageSet(Lambda(n, 17*n + 14), S.Integers))) + # a.is_Pow tests + assert dumeq(solveset(Mod(7**x, 41) - 15, x, S.Integers), + ImageSet(Lambda(n, 40*n + 3), S.Naturals0)) + assert dumeq(solveset(Mod(12**x, 21) - 18, x, S.Integers), + ImageSet(Lambda(n, 6*n + 2), S.Naturals0)) + assert dumeq(solveset(Mod(3**x, 4) - 3, x, S.Integers), + ImageSet(Lambda(n, 2*n + 1), S.Naturals0)) + assert dumeq(solveset(Mod(2**x, 7) - 2 , x, S.Integers), + ImageSet(Lambda(n, 3*n + 1), S.Naturals0)) + assert dumeq(solveset(Mod(3**(3**x), 4) - 3, x, S.Integers), + Intersection(ImageSet(Lambda(n, Intersection({log(2*n + 1)/log(3)}, + S.Integers)), S.Naturals0), S.Integers)) + # Implemented for m without primitive root + assert solveset(Mod(x**3, 7) - 2, x, S.Integers) is S.EmptySet + assert dumeq(solveset(Mod(x**3, 8) - 1, x, S.Integers), + ImageSet(Lambda(n, 8*n + 1), S.Integers)) + assert dumeq(solveset(Mod(x**4, 9) - 4, x, S.Integers), + Union(ImageSet(Lambda(n, 9*n + 4), S.Integers), + ImageSet(Lambda(n, 9*n + 5), S.Integers))) + # domain intersection + assert dumeq(solveset(3 - Mod(5*x - 8, 7), x, S.Naturals0), + Intersection(ImageSet(Lambda(n, 7*n + 5), S.Integers), S.Naturals0)) + # Complex args + assert solveset(Mod(x, 3) - I, x, S.Integers) == \ + S.EmptySet + assert solveset(Mod(I*x, 3) - 2, x, S.Integers + ).dummy_eq( + ConditionSet(x, Eq(Mod(I*x, 3) - 2, 0), S.Integers)) + assert solveset(Mod(I + x, 3) - 2, x, S.Integers + ).dummy_eq( + ConditionSet(x, Eq(Mod(x + I, 3) - 2, 0), S.Integers)) + + # issue 17373 (https://github.com/sympy/sympy/issues/17373) + assert dumeq(solveset(Mod(x**4, 14) - 11, x, S.Integers), + Union(ImageSet(Lambda(n, 14*n + 3), S.Integers), + ImageSet(Lambda(n, 14*n + 11), S.Integers))) + assert dumeq(solveset(Mod(x**31, 74) - 43, x, S.Integers), + ImageSet(Lambda(n, 74*n + 31), S.Integers)) + + # issue 13178 + n = symbols('n', integer=True) + a = 742938285 + b = 1898888478 + m = 2**31 - 1 + c = 20170816 + assert dumeq(solveset(c - Mod(a**n*b, m), n, S.Integers), + ImageSet(Lambda(n, 2147483646*n + 100), S.Naturals0)) + assert dumeq(solveset(c - Mod(a**n*b, m), n, S.Naturals0), + Intersection(ImageSet(Lambda(n, 2147483646*n + 100), S.Naturals0), + S.Naturals0)) + assert dumeq(solveset(c - Mod(a**(2*n)*b, m), n, S.Integers), + Intersection(ImageSet(Lambda(n, 1073741823*n + 50), S.Naturals0), + S.Integers)) + assert solveset(c - Mod(a**(2*n + 7)*b, m), n, S.Integers) is S.EmptySet + assert dumeq(solveset(c - Mod(a**(n - 4)*b, m), n, S.Integers), + Intersection(ImageSet(Lambda(n, 2147483646*n + 104), S.Naturals0), + S.Integers)) + +# end of modular tests + +def test_issue_17276(): + assert nonlinsolve([Eq(x, 5**(S(1)/5)), Eq(x*y, 25*sqrt(5))], x, y) == \ + FiniteSet((5**(S(1)/5), 25*5**(S(3)/10))) + + +def test_issue_10426(): + x = Dummy('x') + a = Symbol('a') + n = Dummy('n') + assert (solveset(sin(x + a) - sin(x), a)).dummy_eq(Dummy('x')) == (Union( + ImageSet(Lambda(n, 2*n*pi), S.Integers), + Intersection(S.Complexes, ImageSet(Lambda(n, -I*(I*(2*n*pi + arg(-exp(-2*I*x))) + 2*im(x))), + S.Integers)))).dummy_eq(Dummy('x,n')) + + +def test_solveset_conjugate(): + """Test solveset for simple conjugate functions""" + assert solveset(conjugate(x) -3 + I) == FiniteSet(3 + I) + + +def test_issue_18208(): + variables = symbols('x0:16') + symbols('y0:12') + x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15,\ + y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11 = variables + + eqs = [x0 + x1 + x2 + x3 - 51, + x0 + x1 + x4 + x5 - 46, + x2 + x3 + x6 + x7 - 39, + x0 + x3 + x4 + x7 - 50, + x1 + x2 + x5 + x6 - 35, + x4 + x5 + x6 + x7 - 34, + x4 + x5 + x8 + x9 - 46, + x10 + x11 + x6 + x7 - 23, + x11 + x4 + x7 + x8 - 25, + x10 + x5 + x6 + x9 - 44, + x10 + x11 + x8 + x9 - 35, + x12 + x13 + x8 + x9 - 35, + x10 + x11 + x14 + x15 - 29, + x11 + x12 + x15 + x8 - 35, + x10 + x13 + x14 + x9 - 29, + x12 + x13 + x14 + x15 - 29, + y0 + y1 + y2 + y3 - 55, + y0 + y1 + y4 + y5 - 53, + y2 + y3 + y6 + y7 - 56, + y0 + y3 + y4 + y7 - 57, + y1 + y2 + y5 + y6 - 52, + y4 + y5 + y6 + y7 - 54, + y4 + y5 + y8 + y9 - 48, + y10 + y11 + y6 + y7 - 60, + y11 + y4 + y7 + y8 - 51, + y10 + y5 + y6 + y9 - 57, + y10 + y11 + y8 + y9 - 54, + x10 - 2, + x11 - 5, + x12 - 1, + x13 - 6, + x14 - 1, + x15 - 21, + y0 - 12, + y1 - 20] + + expected = [38 - x3, x3 - 10, 23 - x3, x3, 12 - x7, x7 + 6, 16 - x7, x7, + 8, 20, 2, 5, 1, 6, 1, 21, 12, 20, -y11 + y9 + 2, y11 - y9 + 21, + -y11 - y7 + y9 + 24, y11 + y7 - y9 - 3, 33 - y7, y7, 27 - y9, y9, + 27 - y11, y11] + + A, b = linear_eq_to_matrix(eqs, variables) + + # solve + solve_expected = {v:eq for v, eq in zip(variables, expected) if v != eq} + + assert solve(eqs, variables) == solve_expected + + # linsolve + linsolve_expected = FiniteSet(Tuple(*expected)) + + assert linsolve(eqs, variables) == linsolve_expected + assert linsolve((A, b), variables) == linsolve_expected + + # gauss_jordan_solve + gj_solve, new_vars = A.gauss_jordan_solve(b) + gj_solve = list(gj_solve) + + gj_expected = linsolve_expected.subs(zip([x3, x7, y7, y9, y11], new_vars)) + + assert FiniteSet(Tuple(*gj_solve)) == gj_expected + + # nonlinsolve + # The solution set of nonlinsolve is currently equivalent to linsolve and is + # also correct. However, we would prefer to use the same symbols as parameters + # for the solution to the underdetermined system in all cases if possible. + # We want a solution that is not just equivalent but also given in the same form. + # This test may be changed should nonlinsolve be modified in this way. + + nonlinsolve_expected = FiniteSet((38 - x3, x3 - 10, 23 - x3, x3, 12 - x7, x7 + 6, + 16 - x7, x7, 8, 20, 2, 5, 1, 6, 1, 21, 12, 20, + -y5 + y7 - 1, y5 - y7 + 24, 21 - y5, y5, 33 - y7, + y7, 27 - y9, y9, -y5 + y7 - y9 + 24, y5 - y7 + y9 + 3)) + + assert nonlinsolve(eqs, variables) == nonlinsolve_expected + + +def test_substitution_with_infeasible_solution(): + a00, a01, a10, a11, l0, l1, l2, l3, m0, m1, m2, m3, m4, m5, m6, m7, c00, c01, c10, c11, p00, p01, p10, p11 = symbols( + 'a00, a01, a10, a11, l0, l1, l2, l3, m0, m1, m2, m3, m4, m5, m6, m7, c00, c01, c10, c11, p00, p01, p10, p11' + ) + solvefor = [p00, p01, p10, p11, c00, c01, c10, c11, m0, m1, m3, l0, l1, l2, l3] + system = [ + -l0 * c00 - l1 * c01 + m0 + c00 + c01, + -l0 * c10 - l1 * c11 + m1, + -l2 * c00 - l3 * c01 + c00 + c01, + -l2 * c10 - l3 * c11 + m3, + -l0 * p00 - l2 * p10 + p00 + p10, + -l1 * p00 - l3 * p10 + p00 + p10, + -l0 * p01 - l2 * p11, + -l1 * p01 - l3 * p11, + -a00 + c00 * p00 + c10 * p01, + -a01 + c01 * p00 + c11 * p01, + -a10 + c00 * p10 + c10 * p11, + -a11 + c01 * p10 + c11 * p11, + -m0 * p00, + -m1 * p01, + -m2 * p10, + -m3 * p11, + -m4 * c00, + -m5 * c01, + -m6 * c10, + -m7 * c11, + m2, + m4, + m5, + m6, + m7 + ] + sol = FiniteSet( + (0, Complement(FiniteSet(p01), FiniteSet(0)), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, l2, l3), + (p00, Complement(FiniteSet(p01), FiniteSet(0)), 0, p11, 0, 0, 0, 0, 0, 0, 0, 1, 1, -p01/p11, -p01/p11), + (0, Complement(FiniteSet(p01), FiniteSet(0)), 0, p11, 0, 0, 0, 0, 0, 0, 0, 1, -l3*p11/p01, -p01/p11, l3), + (0, Complement(FiniteSet(p01), FiniteSet(0)), 0, p11, 0, 0, 0, 0, 0, 0, 0, -l2*p11/p01, -l3*p11/p01, l2, l3), + ) + assert sol != nonlinsolve(system, solvefor) + + +def test_issue_20097(): + assert solveset(1/sqrt(x)) is S.EmptySet + + +def test_issue_15350(): + assert solveset(diff(sqrt(1/x+x))) == FiniteSet(-1, 1) + + +def test_issue_18359(): + c1 = Piecewise((0, x < 0), (Min(1, x)/2 - Min(2, x)/2 + Min(3, x)/2, True)) + c2 = Piecewise((Piecewise((0, x < 0), (Min(1, x)/2 - Min(2, x)/2 + Min(3, x)/2, True)), x >= 0), (0, True)) + correct_result = Interval(1, 2) + result1 = solveset(c1 - Rational(1, 2), x, Interval(0, 3)) + result2 = solveset(c2 - Rational(1, 2), x, Interval(0, 3)) + assert result1 == correct_result + assert result2 == correct_result + + +def test_issue_17604(): + lhs = -2**(3*x/11)*exp(x/11) + pi**(x/11) + assert _is_exponential(lhs, x) + assert _solve_exponential(lhs, 0, x, S.Complexes) == FiniteSet(0) + + +def test_issue_17580(): + assert solveset(1/(1 - x**3)**2, x, S.Reals) is S.EmptySet + + +def test_issue_17566_actual(): + sys = [2**x + 2**y - 3, 4**x + 9**y - 5] + # Not clear this is the correct result, but at least no recursion error + assert nonlinsolve(sys, x, y) == FiniteSet((log(3 - 2**y)/log(2), y)) + + +def test_issue_17565(): + eq = Ge(2*(x - 2)**2/(3*(x + 1)**(Integer(1)/3)) + 2*(x - 2)*(x + 1)**(Integer(2)/3), 0) + res = Union(Interval.Lopen(-1, -Rational(1, 4)), Interval(2, oo)) + assert solveset(eq, x, S.Reals) == res + + +def test_issue_15024(): + function = (x + 5)/sqrt(-x**2 - 10*x) + assert solveset(function, x, S.Reals) == FiniteSet(Integer(-5)) + + +def test_issue_16877(): + assert dumeq(nonlinsolve([x - 1, sin(y)], x, y), + FiniteSet((1, ImageSet(Lambda(n, 2*n*pi), S.Integers)), + (1, ImageSet(Lambda(n, 2*n*pi + pi), S.Integers)))) + # Even better if (1, ImageSet(Lambda(n, n*pi), S.Integers)) is obtained + + +def test_issue_16876(): + assert dumeq(nonlinsolve([sin(x), 2*x - 4*y], x, y), + FiniteSet((ImageSet(Lambda(n, 2*n*pi), S.Integers), + ImageSet(Lambda(n, n*pi), S.Integers)), + (ImageSet(Lambda(n, 2*n*pi + pi), S.Integers), + ImageSet(Lambda(n, n*pi + pi/2), S.Integers)))) + # Even better if (ImageSet(Lambda(n, n*pi), S.Integers), + # ImageSet(Lambda(n, n*pi/2), S.Integers)) is obtained + +def test_issue_21236(): + x, z = symbols("x z") + y = symbols('y', rational=True) + assert solveset(x**y - z, x, S.Reals) == ConditionSet(x, Eq(x**y - z, 0), S.Reals) + e1, e2 = symbols('e1 e2', even=True) + y = e1/e2 # don't know if num or den will be odd and the other even + assert solveset(x**y - z, x, S.Reals) == ConditionSet(x, Eq(x**y - z, 0), S.Reals) + + +def test_issue_21908(): + assert nonlinsolve([(x**2 + 2*x - y**2)*exp(x), -2*y*exp(x)], x, y + ) == {(-2, 0), (0, 0)} + + +def test_issue_19144(): + # test case 1 + expr1 = [x + y - 1, y**2 + 1] + eq1 = [Eq(i, 0) for i in expr1] + soln1 = {(1 - I, I), (1 + I, -I)} + soln_expr1 = nonlinsolve(expr1, [x, y]) + soln_eq1 = nonlinsolve(eq1, [x, y]) + assert soln_eq1 == soln_expr1 == soln1 + # test case 2 - with denoms + expr2 = [x/y - 1, y**2 + 1] + eq2 = [Eq(i, 0) for i in expr2] + soln2 = {(-I, -I), (I, I)} + soln_expr2 = nonlinsolve(expr2, [x, y]) + soln_eq2 = nonlinsolve(eq2, [x, y]) + assert soln_eq2 == soln_expr2 == soln2 + # denominators that cancel in expression + assert nonlinsolve([Eq(x + 1/x, 1/x)], [x]) == FiniteSet((S.EmptySet,)) + + +def test_issue_22413(): + res = nonlinsolve((4*y*(2*x + 2*exp(y) + 1)*exp(2*x), + 4*x*exp(2*x) + 4*y*exp(2*x + y) + 4*exp(2*x + y) + 1), + x, y) + # First solution is not correct, but the issue was an exception + sols = FiniteSet((x, S.Zero), (-exp(y) - S.Half, y)) + assert res == sols + + +def test_issue_23318(): + eqs_eq = [ + Eq(53.5780461486929, x * log(y / (5.0 - y) + 1) / y), + Eq(x, 0.0015 * z), + Eq(0.0015, 7845.32 * y / z), + ] + eqs_expr = [eq.lhs - eq.rhs for eq in eqs_eq] + + sol = {(266.97755814852, 0.0340301680681629, 177985.03876568)} + + assert_close_nl(nonlinsolve(eqs_eq, [x, y, z]), sol) + assert_close_nl(nonlinsolve(eqs_expr, [x, y, z]), sol) + + logterm = log(1.91196789933362e-7*z/(5.0 - 1.91196789933362e-7*z) + 1) + eq = -0.0015*z*logterm + 1.02439504345316e-5*z + assert_close_ss(solveset(eq, z), {0, 177985.038765679}) + + +def test_issue_19814(): + assert nonlinsolve([ 2**m - 2**(2*n), 4*2**m - 2**(4*n)], m, n + ) == FiniteSet((log(2**(2*n))/log(2), S.Complexes)) + + +def test_issue_22058(): + sol = solveset(-sqrt(t)*x**2 + 2*x + sqrt(t), x, S.Reals) + # doesn't fail (and following numerical check) + assert sol.xreplace({t: 1}) == {1 - sqrt(2), 1 + sqrt(2)}, sol.xreplace({t: 1}) + + +def test_issue_11184(): + assert solveset(20*sqrt(y**2 + (sqrt(-(y - 10)*(y + 10)) + 10)**2) - 60, y, S.Reals) is S.EmptySet + + +def test_issue_21890(): + e = S(2)/3 + assert nonlinsolve([4*x**3*y**4 - 2*y, 4*x**4*y**3 - 2*x], x, y) == { + (2**e/(2*y), y), ((-2**e/4 - 2**e*sqrt(3)*I/4)/y, y), + ((-2**e/4 + 2**e*sqrt(3)*I/4)/y, y)} + assert nonlinsolve([(1 - 4*x**2)*exp(-2*x**2 - 2*y**2), + -4*x*y*exp(-2*x**2)*exp(-2*y**2)], x, y) == {(-S(1)/2, 0), (S(1)/2, 0)} + rx, ry = symbols('x y', real=True) + sol = nonlinsolve([4*rx**3*ry**4 - 2*ry, 4*rx**4*ry**3 - 2*rx], rx, ry) + ans = {(2**(S(2)/3)/(2*ry), ry), + ((-2**(S(2)/3)/4 - 2**(S(2)/3)*sqrt(3)*I/4)/ry, ry), + ((-2**(S(2)/3)/4 + 2**(S(2)/3)*sqrt(3)*I/4)/ry, ry)} + assert sol == ans + + +def test_issue_22628(): + assert nonlinsolve([h - 1, k - 1, f - 2, f - 4, -2*k], h, k, f) == S.EmptySet + assert nonlinsolve([x**3 - 1, x + y, x**2 - 4], [x, y]) == S.EmptySet + + +def test_issue_25781(): + assert solve(sqrt(x/2) - x) == [0, S.Half] + + +def test_issue_26077(): + _n = Symbol('_n') + function = x*cot(5*x) + critical_points = stationary_points(function, x, S.Reals) + excluded_points = Union( + ImageSet(Lambda(_n, 2*_n*pi/5), S.Integers), + ImageSet(Lambda(_n, 2*_n*pi/5 + pi/5), S.Integers) + ) + solution = ConditionSet(x, + Eq(x*(-5*cot(5*x)**2 - 5) + cot(5*x), 0), + Complement(S.Reals, excluded_points) + ) + assert solution.as_dummy() == critical_points.as_dummy() diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a3ff0c96d2c7245b581b28b0e6c3810c888152d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/compound_rv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/compound_rv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22d42c2565f1d329dcfefd91fa69144b2e490551 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/compound_rv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/crv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/crv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f587e1cba909d9c6b8cf9c9343eeaaac8a53f73 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/crv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/drv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/drv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..851d8617cb614906f4e928cf2c91ff984e612f61 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/drv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/drv_types.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/drv_types.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b4a5f4c223e5580311334b7d35326fb47c3a87aa Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/drv_types.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/error_prop.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/error_prop.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11c2197e2363f7d909ca8c4c5e05319b810ce543 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/error_prop.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/frv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/frv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f3afb9b165389b27fe6616b347900a39365edd3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/frv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/frv_types.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/frv_types.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..610eef52b162997528d7c692cf33cf1cf7e399a3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/frv_types.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/joint_rv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/joint_rv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b68be8c011cefd4da02209e2b3d58319f95daaad Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/joint_rv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/joint_rv_types.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/joint_rv_types.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..411eedd704861dafae6d8e4bbe75b05f6718c5c0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/joint_rv_types.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/matrix_distributions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/matrix_distributions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..56275624332c67439328f3d1c5a19c8e82d5511d Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/matrix_distributions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/random_matrix.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/random_matrix.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7da0d9ac7b9d4322928b312c50654bb39699b584 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/random_matrix.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/random_matrix_models.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/random_matrix_models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c87292a1b6747cc6cd6c2b7bc8e753ca6d154b45 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/random_matrix_models.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/rv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/rv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d61bdb4a7fedb95c56b817329aca2f6dc81b0ef Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/rv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/rv_interface.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/rv_interface.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2f6fa24171feaf9ead9a84b2432814ccd04dcee Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/rv_interface.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/stochastic_process.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/stochastic_process.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9447b7cd1715107c6e879a98f0a4a4dbb6d4526 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/stochastic_process.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/symbolic_multivariate_probability.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/symbolic_multivariate_probability.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a245e0138394448b0132246c6bb89e65400603d0 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/symbolic_multivariate_probability.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/symbolic_probability.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/symbolic_probability.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..442a9744b0eb404a3df7ea0f720ea4b376c9fdad Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/__pycache__/symbolic_probability.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b450213945c50bdd570f8e192ab13cc6e6619470 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/sample_numpy.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/sample_numpy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad5a0b2187ce7d8f2fcc4fc7f2b228e49aa2ee51 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/sample_numpy.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/sample_pymc.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/sample_pymc.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2038fe3216ad162b092d70733b096ae43564be32 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/sample_pymc.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/sample_scipy.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/sample_scipy.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f29ce44b18245788d7667681ad660926ff3cc79a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/__pycache__/sample_scipy.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/sample_numpy.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/sample_numpy.py new file mode 100644 index 0000000000000000000000000000000000000000..d65417945449ed8b62d2547215d8908f84820a9b --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/sample_numpy.py @@ -0,0 +1,105 @@ +from functools import singledispatch + +from sympy.external import import_module +from sympy.stats.crv_types import BetaDistribution, ChiSquaredDistribution, ExponentialDistribution, GammaDistribution, \ + LogNormalDistribution, NormalDistribution, ParetoDistribution, UniformDistribution, FDistributionDistribution, GumbelDistribution, LaplaceDistribution, \ + LogisticDistribution, RayleighDistribution, TriangularDistribution +from sympy.stats.drv_types import GeometricDistribution, PoissonDistribution, ZetaDistribution +from sympy.stats.frv_types import BinomialDistribution, HypergeometricDistribution + + +numpy = import_module('numpy') + + +@singledispatch +def do_sample_numpy(dist, size, rand_state): + return None + + +# CRV: + +@do_sample_numpy.register(BetaDistribution) +def _(dist: BetaDistribution, size, rand_state): + return rand_state.beta(a=float(dist.alpha), b=float(dist.beta), size=size) + + +@do_sample_numpy.register(ChiSquaredDistribution) +def _(dist: ChiSquaredDistribution, size, rand_state): + return rand_state.chisquare(df=float(dist.k), size=size) + + +@do_sample_numpy.register(ExponentialDistribution) +def _(dist: ExponentialDistribution, size, rand_state): + return rand_state.exponential(1 / float(dist.rate), size=size) + +@do_sample_numpy.register(FDistributionDistribution) +def _(dist: FDistributionDistribution, size, rand_state): + return rand_state.f(dfnum = float(dist.d1), dfden = float(dist.d2), size=size) + +@do_sample_numpy.register(GammaDistribution) +def _(dist: GammaDistribution, size, rand_state): + return rand_state.gamma(shape = float(dist.k), scale = float(dist.theta), size=size) + +@do_sample_numpy.register(GumbelDistribution) +def _(dist: GumbelDistribution, size, rand_state): + return rand_state.gumbel(loc = float(dist.mu), scale = float(dist.beta), size=size) + +@do_sample_numpy.register(LaplaceDistribution) +def _(dist: LaplaceDistribution, size, rand_state): + return rand_state.laplace(loc = float(dist.mu), scale = float(dist.b), size=size) + +@do_sample_numpy.register(LogisticDistribution) +def _(dist: LogisticDistribution, size, rand_state): + return rand_state.logistic(loc = float(dist.mu), scale = float(dist.s), size=size) + +@do_sample_numpy.register(LogNormalDistribution) +def _(dist: LogNormalDistribution, size, rand_state): + return rand_state.lognormal(mean = float(dist.mean), sigma = float(dist.std), size=size) + +@do_sample_numpy.register(NormalDistribution) +def _(dist: NormalDistribution, size, rand_state): + return rand_state.normal(loc = float(dist.mean), scale = float(dist.std), size=size) + +@do_sample_numpy.register(RayleighDistribution) +def _(dist: RayleighDistribution, size, rand_state): + return rand_state.rayleigh(scale = float(dist.sigma), size=size) + +@do_sample_numpy.register(ParetoDistribution) +def _(dist: ParetoDistribution, size, rand_state): + return (numpy.random.pareto(a=float(dist.alpha), size=size) + 1) * float(dist.xm) + +@do_sample_numpy.register(TriangularDistribution) +def _(dist: TriangularDistribution, size, rand_state): + return rand_state.triangular(left = float(dist.a), mode = float(dist.b), right = float(dist.c), size=size) + +@do_sample_numpy.register(UniformDistribution) +def _(dist: UniformDistribution, size, rand_state): + return rand_state.uniform(low=float(dist.left), high=float(dist.right), size=size) + + +# DRV: + +@do_sample_numpy.register(GeometricDistribution) +def _(dist: GeometricDistribution, size, rand_state): + return rand_state.geometric(p=float(dist.p), size=size) + + +@do_sample_numpy.register(PoissonDistribution) +def _(dist: PoissonDistribution, size, rand_state): + return rand_state.poisson(lam=float(dist.lamda), size=size) + + +@do_sample_numpy.register(ZetaDistribution) +def _(dist: ZetaDistribution, size, rand_state): + return rand_state.zipf(a=float(dist.s), size=size) + + +# FRV: + +@do_sample_numpy.register(BinomialDistribution) +def _(dist: BinomialDistribution, size, rand_state): + return rand_state.binomial(n=int(dist.n), p=float(dist.p), size=size) + +@do_sample_numpy.register(HypergeometricDistribution) +def _(dist: HypergeometricDistribution, size, rand_state): + return rand_state.hypergeometric(ngood = int(dist.N), nbad = int(dist.m), nsample = int(dist.n), size=size) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/sample_pymc.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/sample_pymc.py new file mode 100644 index 0000000000000000000000000000000000000000..546f02a3092815af2e54b4a164463f62ece7a024 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/sample_pymc.py @@ -0,0 +1,99 @@ +from functools import singledispatch +from sympy.external import import_module +from sympy.stats.crv_types import BetaDistribution, CauchyDistribution, ChiSquaredDistribution, ExponentialDistribution, \ + GammaDistribution, LogNormalDistribution, NormalDistribution, ParetoDistribution, UniformDistribution, \ + GaussianInverseDistribution +from sympy.stats.drv_types import PoissonDistribution, GeometricDistribution, NegativeBinomialDistribution +from sympy.stats.frv_types import BinomialDistribution, BernoulliDistribution + + +try: + import pymc +except ImportError: + pymc = import_module('pymc3') + +@singledispatch +def do_sample_pymc(dist): + return None + + +# CRV: + +@do_sample_pymc.register(BetaDistribution) +def _(dist: BetaDistribution): + return pymc.Beta('X', alpha=float(dist.alpha), beta=float(dist.beta)) + + +@do_sample_pymc.register(CauchyDistribution) +def _(dist: CauchyDistribution): + return pymc.Cauchy('X', alpha=float(dist.x0), beta=float(dist.gamma)) + + +@do_sample_pymc.register(ChiSquaredDistribution) +def _(dist: ChiSquaredDistribution): + return pymc.ChiSquared('X', nu=float(dist.k)) + + +@do_sample_pymc.register(ExponentialDistribution) +def _(dist: ExponentialDistribution): + return pymc.Exponential('X', lam=float(dist.rate)) + + +@do_sample_pymc.register(GammaDistribution) +def _(dist: GammaDistribution): + return pymc.Gamma('X', alpha=float(dist.k), beta=1 / float(dist.theta)) + + +@do_sample_pymc.register(LogNormalDistribution) +def _(dist: LogNormalDistribution): + return pymc.Lognormal('X', mu=float(dist.mean), sigma=float(dist.std)) + + +@do_sample_pymc.register(NormalDistribution) +def _(dist: NormalDistribution): + return pymc.Normal('X', float(dist.mean), float(dist.std)) + + +@do_sample_pymc.register(GaussianInverseDistribution) +def _(dist: GaussianInverseDistribution): + return pymc.Wald('X', mu=float(dist.mean), lam=float(dist.shape)) + + +@do_sample_pymc.register(ParetoDistribution) +def _(dist: ParetoDistribution): + return pymc.Pareto('X', alpha=float(dist.alpha), m=float(dist.xm)) + + +@do_sample_pymc.register(UniformDistribution) +def _(dist: UniformDistribution): + return pymc.Uniform('X', lower=float(dist.left), upper=float(dist.right)) + + +# DRV: + +@do_sample_pymc.register(GeometricDistribution) +def _(dist: GeometricDistribution): + return pymc.Geometric('X', p=float(dist.p)) + + +@do_sample_pymc.register(NegativeBinomialDistribution) +def _(dist: NegativeBinomialDistribution): + return pymc.NegativeBinomial('X', mu=float((dist.p * dist.r) / (1 - dist.p)), + alpha=float(dist.r)) + + +@do_sample_pymc.register(PoissonDistribution) +def _(dist: PoissonDistribution): + return pymc.Poisson('X', mu=float(dist.lamda)) + + +# FRV: + +@do_sample_pymc.register(BernoulliDistribution) +def _(dist: BernoulliDistribution): + return pymc.Bernoulli('X', p=float(dist.p)) + + +@do_sample_pymc.register(BinomialDistribution) +def _(dist: BinomialDistribution): + return pymc.Binomial('X', n=int(dist.n), p=float(dist.p)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/sample_scipy.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/sample_scipy.py new file mode 100644 index 0000000000000000000000000000000000000000..f12508f68844488e9a14b1476005164eb422796e --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/sample_scipy.py @@ -0,0 +1,167 @@ +from functools import singledispatch + +from sympy.core.symbol import Dummy +from sympy.functions.elementary.exponential import exp +from sympy.utilities.lambdify import lambdify +from sympy.external import import_module +from sympy.stats import DiscreteDistributionHandmade +from sympy.stats.crv import SingleContinuousDistribution +from sympy.stats.crv_types import ChiSquaredDistribution, ExponentialDistribution, GammaDistribution, \ + LogNormalDistribution, NormalDistribution, ParetoDistribution, UniformDistribution, BetaDistribution, \ + StudentTDistribution, CauchyDistribution +from sympy.stats.drv_types import GeometricDistribution, LogarithmicDistribution, NegativeBinomialDistribution, \ + PoissonDistribution, SkellamDistribution, YuleSimonDistribution, ZetaDistribution +from sympy.stats.frv import SingleFiniteDistribution + + +scipy = import_module("scipy", import_kwargs={'fromlist':['stats']}) + + +@singledispatch +def do_sample_scipy(dist, size, seed): + return None + + +# CRV + +@do_sample_scipy.register(SingleContinuousDistribution) +def _(dist: SingleContinuousDistribution, size, seed): + # if we don't need to make a handmade pdf, we won't + import scipy.stats + + z = Dummy('z') + handmade_pdf = lambdify(z, dist.pdf(z), ['numpy', 'scipy']) + + class scipy_pdf(scipy.stats.rv_continuous): + def _pdf(dist, x): + return handmade_pdf(x) + + scipy_rv = scipy_pdf(a=float(dist.set._inf), + b=float(dist.set._sup), name='scipy_pdf') + return scipy_rv.rvs(size=size, random_state=seed) + + +@do_sample_scipy.register(ChiSquaredDistribution) +def _(dist: ChiSquaredDistribution, size, seed): + # same parametrisation + return scipy.stats.chi2.rvs(df=float(dist.k), size=size, random_state=seed) + + +@do_sample_scipy.register(ExponentialDistribution) +def _(dist: ExponentialDistribution, size, seed): + # https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.expon.html#scipy.stats.expon + return scipy.stats.expon.rvs(scale=1 / float(dist.rate), size=size, random_state=seed) + + +@do_sample_scipy.register(GammaDistribution) +def _(dist: GammaDistribution, size, seed): + # https://stackoverflow.com/questions/42150965/how-to-plot-gamma-distribution-with-alpha-and-beta-parameters-in-python + return scipy.stats.gamma.rvs(a=float(dist.k), scale=float(dist.theta), size=size, random_state=seed) + + +@do_sample_scipy.register(LogNormalDistribution) +def _(dist: LogNormalDistribution, size, seed): + # https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.lognorm.html + return scipy.stats.lognorm.rvs(scale=float(exp(dist.mean)), s=float(dist.std), size=size, random_state=seed) + + +@do_sample_scipy.register(NormalDistribution) +def _(dist: NormalDistribution, size, seed): + return scipy.stats.norm.rvs(loc=float(dist.mean), scale=float(dist.std), size=size, random_state=seed) + + +@do_sample_scipy.register(ParetoDistribution) +def _(dist: ParetoDistribution, size, seed): + # https://stackoverflow.com/questions/42260519/defining-pareto-distribution-in-python-scipy + return scipy.stats.pareto.rvs(b=float(dist.alpha), scale=float(dist.xm), size=size, random_state=seed) + + +@do_sample_scipy.register(StudentTDistribution) +def _(dist: StudentTDistribution, size, seed): + return scipy.stats.t.rvs(df=float(dist.nu), size=size, random_state=seed) + + +@do_sample_scipy.register(UniformDistribution) +def _(dist: UniformDistribution, size, seed): + # https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.uniform.html + return scipy.stats.uniform.rvs(loc=float(dist.left), scale=float(dist.right - dist.left), size=size, random_state=seed) + + +@do_sample_scipy.register(BetaDistribution) +def _(dist: BetaDistribution, size, seed): + # same parametrisation + return scipy.stats.beta.rvs(a=float(dist.alpha), b=float(dist.beta), size=size, random_state=seed) + + +@do_sample_scipy.register(CauchyDistribution) +def _(dist: CauchyDistribution, size, seed): + return scipy.stats.cauchy.rvs(loc=float(dist.x0), scale=float(dist.gamma), size=size, random_state=seed) + + +# DRV: + +@do_sample_scipy.register(DiscreteDistributionHandmade) +def _(dist: DiscreteDistributionHandmade, size, seed): + from scipy.stats import rv_discrete + + z = Dummy('z') + handmade_pmf = lambdify(z, dist.pdf(z), ['numpy', 'scipy']) + + class scipy_pmf(rv_discrete): + def _pmf(dist, x): + return handmade_pmf(x) + + scipy_rv = scipy_pmf(a=float(dist.set._inf), b=float(dist.set._sup), + name='scipy_pmf') + return scipy_rv.rvs(size=size, random_state=seed) + + +@do_sample_scipy.register(GeometricDistribution) +def _(dist: GeometricDistribution, size, seed): + return scipy.stats.geom.rvs(p=float(dist.p), size=size, random_state=seed) + + +@do_sample_scipy.register(LogarithmicDistribution) +def _(dist: LogarithmicDistribution, size, seed): + return scipy.stats.logser.rvs(p=float(dist.p), size=size, random_state=seed) + + +@do_sample_scipy.register(NegativeBinomialDistribution) +def _(dist: NegativeBinomialDistribution, size, seed): + return scipy.stats.nbinom.rvs(n=float(dist.r), p=float(dist.p), size=size, random_state=seed) + + +@do_sample_scipy.register(PoissonDistribution) +def _(dist: PoissonDistribution, size, seed): + return scipy.stats.poisson.rvs(mu=float(dist.lamda), size=size, random_state=seed) + + +@do_sample_scipy.register(SkellamDistribution) +def _(dist: SkellamDistribution, size, seed): + return scipy.stats.skellam.rvs(mu1=float(dist.mu1), mu2=float(dist.mu2), size=size, random_state=seed) + + +@do_sample_scipy.register(YuleSimonDistribution) +def _(dist: YuleSimonDistribution, size, seed): + return scipy.stats.yulesimon.rvs(alpha=float(dist.rho), size=size, random_state=seed) + + +@do_sample_scipy.register(ZetaDistribution) +def _(dist: ZetaDistribution, size, seed): + return scipy.stats.zipf.rvs(a=float(dist.s), size=size, random_state=seed) + + +# FRV: + +@do_sample_scipy.register(SingleFiniteDistribution) +def _(dist: SingleFiniteDistribution, size, seed): + # scipy can handle with custom distributions + + from scipy.stats import rv_discrete + density_ = dist.dict + x, y = [], [] + for k, v in density_.items(): + x.append(int(k)) + y.append(float(v)) + scipy_rv = rv_discrete(name='scipy_rv', values=(x, y)) + return scipy_rv.rvs(size=size, random_state=seed) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..51abce2b54c1eb87dfda2e73b1c0fc0f58fb3e11 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/test_sample_continuous_rv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/test_sample_continuous_rv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..317480984d0e27706edbc5d81a225d836d4f8c7a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/test_sample_continuous_rv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/test_sample_discrete_rv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/test_sample_discrete_rv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b5300ea8dc33e311a1c3893b5a5ed0bb1a231ce3 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/test_sample_discrete_rv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/test_sample_finite_rv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/test_sample_finite_rv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a60cf7fe1bd2ef6d3e00b3d93907a2f291e43b64 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/__pycache__/test_sample_finite_rv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/test_sample_continuous_rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/test_sample_continuous_rv.py new file mode 100644 index 0000000000000000000000000000000000000000..953bb602df5e63da2882ee118de9dbf24b6f7804 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/test_sample_continuous_rv.py @@ -0,0 +1,181 @@ +from sympy.core.numbers import oo +from sympy.core.symbol import Symbol +from sympy.functions.elementary.exponential import exp +from sympy.sets.sets import Interval +from sympy.external import import_module +from sympy.stats import Beta, Chi, Normal, Gamma, Exponential, LogNormal, Pareto, ChiSquared, Uniform, sample, \ + BetaPrime, Cauchy, GammaInverse, GaussianInverse, StudentT, Weibull, density, ContinuousRV, FDistribution, \ + Gumbel, Laplace, Logistic, Rayleigh, Triangular +from sympy.testing.pytest import skip, raises + + +def test_sample_numpy(): + distribs_numpy = [ + Beta("B", 1, 1), + Normal("N", 0, 1), + Gamma("G", 2, 7), + Exponential("E", 2), + LogNormal("LN", 0, 1), + Pareto("P", 1, 1), + ChiSquared("CS", 2), + Uniform("U", 0, 1), + FDistribution("FD", 1, 2), + Gumbel("GB", 1, 2), + Laplace("L", 1, 2), + Logistic("LO", 1, 2), + Rayleigh("R", 1), + Triangular("T", 1, 2, 2), + ] + size = 3 + numpy = import_module('numpy') + if not numpy: + skip('Numpy is not installed. Abort tests for _sample_numpy.') + else: + for X in distribs_numpy: + samps = sample(X, size=size, library='numpy') + for sam in samps: + assert sam in X.pspace.domain.set + raises(NotImplementedError, + lambda: sample(Chi("C", 1), library='numpy')) + raises(NotImplementedError, + lambda: Chi("C", 1).pspace.distribution.sample(library='tensorflow')) + + +def test_sample_scipy(): + distribs_scipy = [ + Beta("B", 1, 1), + BetaPrime("BP", 1, 1), + Cauchy("C", 1, 1), + Chi("C", 1), + Normal("N", 0, 1), + Gamma("G", 2, 7), + GammaInverse("GI", 1, 1), + GaussianInverse("GUI", 1, 1), + Exponential("E", 2), + LogNormal("LN", 0, 1), + Pareto("P", 1, 1), + StudentT("S", 2), + ChiSquared("CS", 2), + Uniform("U", 0, 1) + ] + size = 3 + scipy = import_module('scipy') + if not scipy: + skip('Scipy is not installed. Abort tests for _sample_scipy.') + else: + for X in distribs_scipy: + samps = sample(X, size=size, library='scipy') + samps2 = sample(X, size=(2, 2), library='scipy') + for sam in samps: + assert sam in X.pspace.domain.set + for i in range(2): + for j in range(2): + assert samps2[i][j] in X.pspace.domain.set + + +def test_sample_pymc(): + distribs_pymc = [ + Beta("B", 1, 1), + Cauchy("C", 1, 1), + Normal("N", 0, 1), + Gamma("G", 2, 7), + GaussianInverse("GI", 1, 1), + Exponential("E", 2), + LogNormal("LN", 0, 1), + Pareto("P", 1, 1), + ChiSquared("CS", 2), + Uniform("U", 0, 1) + ] + size = 3 + pymc = import_module('pymc') + if not pymc: + skip('PyMC is not installed. Abort tests for _sample_pymc.') + else: + for X in distribs_pymc: + samps = sample(X, size=size, library='pymc') + for sam in samps: + assert sam in X.pspace.domain.set + raises(NotImplementedError, + lambda: sample(Chi("C", 1), library='pymc')) + + +def test_sampling_gamma_inverse(): + scipy = import_module('scipy') + if not scipy: + skip('Scipy not installed. Abort tests for sampling of gamma inverse.') + X = GammaInverse("x", 1, 1) + assert sample(X) in X.pspace.domain.set + + +def test_lognormal_sampling(): + # Right now, only density function and sampling works + scipy = import_module('scipy') + if not scipy: + skip('Scipy is not installed. Abort tests') + for i in range(3): + X = LogNormal('x', i, 1) + assert sample(X) in X.pspace.domain.set + + size = 5 + samps = sample(X, size=size) + for samp in samps: + assert samp in X.pspace.domain.set + + +def test_sampling_gaussian_inverse(): + scipy = import_module('scipy') + if not scipy: + skip('Scipy not installed. Abort tests for sampling of Gaussian inverse.') + X = GaussianInverse("x", 1, 1) + assert sample(X, library='scipy') in X.pspace.domain.set + + +def test_prefab_sampling(): + scipy = import_module('scipy') + if not scipy: + skip('Scipy is not installed. Abort tests') + N = Normal('X', 0, 1) + L = LogNormal('L', 0, 1) + E = Exponential('Ex', 1) + P = Pareto('P', 1, 3) + W = Weibull('W', 1, 1) + U = Uniform('U', 0, 1) + B = Beta('B', 2, 5) + G = Gamma('G', 1, 3) + + variables = [N, L, E, P, W, U, B, G] + niter = 10 + size = 5 + for var in variables: + for _ in range(niter): + assert sample(var) in var.pspace.domain.set + samps = sample(var, size=size) + for samp in samps: + assert samp in var.pspace.domain.set + + +def test_sample_continuous(): + z = Symbol('z') + Z = ContinuousRV(z, exp(-z), set=Interval(0, oo)) + assert density(Z)(-1) == 0 + + scipy = import_module('scipy') + if not scipy: + skip('Scipy is not installed. Abort tests') + 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) + + libraries = ['scipy', 'numpy', 'pymc'] + for lib in libraries: + try: + imported_lib = import_module(lib) + if imported_lib: + s0, s1, s2 = [], [], [] + s0 = sample(Z, size=10, library=lib, seed=0) + s1 = sample(Z, size=10, library=lib, seed=0) + s2 = sample(Z, size=10, library=lib, seed=1) + assert all(s0 == s1) + assert all(s1 != s2) + except NotImplementedError: + continue diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/test_sample_discrete_rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/test_sample_discrete_rv.py new file mode 100644 index 0000000000000000000000000000000000000000..90d385cd599222fd7da7c1559b619bafbeb01831 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/test_sample_discrete_rv.py @@ -0,0 +1,109 @@ +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.external import import_module +from sympy.stats import ( + Geometric, + Poisson, + Zeta, + sample, + Skellam, + Logarithmic, + NegativeBinomial, + YuleSimon, + DiscreteRV, +) +from sympy.testing.pytest import skip, raises, slow + + +def test_sample_numpy(): + distribs_numpy = [ + Geometric('G', 0.5), + Poisson('P', 1), + Zeta('Z', 2) + ] + size = 3 + numpy = import_module('numpy') + if not numpy: + skip('Numpy is not installed. Abort tests for _sample_numpy.') + else: + for X in distribs_numpy: + samps = sample(X, size=size, library='numpy') + for sam in samps: + assert sam in X.pspace.domain.set + raises(NotImplementedError, + lambda: sample(Skellam('S', 1, 1), library='numpy')) + raises(NotImplementedError, + lambda: Skellam('S', 1, 1).pspace.distribution.sample(library='tensorflow')) + + +def test_sample_scipy(): + p = S(2)/3 + x = Symbol('x', integer=True, positive=True) + pdf = p*(1 - p)**(x - 1) # pdf of Geometric Distribution + distribs_scipy = [ + DiscreteRV(x, pdf, set=S.Naturals), + Geometric('G', 0.5), + Logarithmic('L', 0.5), + NegativeBinomial('N', 5, 0.4), + Poisson('P', 1), + Skellam('S', 1, 1), + YuleSimon('Y', 1), + Zeta('Z', 2) + ] + size = 3 + scipy = import_module('scipy') + if not scipy: + skip('Scipy is not installed. Abort tests for _sample_scipy.') + else: + for X in distribs_scipy: + samps = sample(X, size=size, library='scipy') + samps2 = sample(X, size=(2, 2), library='scipy') + for sam in samps: + assert sam in X.pspace.domain.set + for i in range(2): + for j in range(2): + assert samps2[i][j] in X.pspace.domain.set + + +def test_sample_pymc(): + distribs_pymc = [ + Geometric('G', 0.5), + Poisson('P', 1), + NegativeBinomial('N', 5, 0.4) + ] + size = 3 + pymc = import_module('pymc') + if not pymc: + skip('PyMC is not installed. Abort tests for _sample_pymc.') + else: + for X in distribs_pymc: + samps = sample(X, size=size, library='pymc') + for sam in samps: + assert sam in X.pspace.domain.set + raises(NotImplementedError, + lambda: sample(Skellam('S', 1, 1), library='pymc')) + +@slow +def test_sample_discrete(): + X = Geometric('X', S.Half) + scipy = import_module('scipy') + if not scipy: + skip('Scipy not installed. Abort tests') + assert sample(X) in X.pspace.domain.set + samps = sample(X, size=2) # This takes long time if ran without scipy + for samp in samps: + assert samp in X.pspace.domain.set + + libraries = ['scipy', 'numpy', 'pymc'] + for lib in libraries: + try: + imported_lib = import_module(lib) + if imported_lib: + s0, s1, s2 = [], [], [] + s0 = sample(X, size=10, library=lib, seed=0) + s1 = sample(X, size=10, library=lib, seed=0) + s2 = sample(X, size=10, library=lib, seed=1) + assert all(s0 == s1) + assert not all(s1 == s2) + except NotImplementedError: + continue diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/test_sample_finite_rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/test_sample_finite_rv.py new file mode 100644 index 0000000000000000000000000000000000000000..96cabe0ff4aaa5977e16600217fbbdeb08b962ae --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/sampling/tests/test_sample_finite_rv.py @@ -0,0 +1,94 @@ +from sympy.core.numbers import Rational +from sympy.core.singleton import S +from sympy.external import import_module +from sympy.stats import Binomial, sample, Die, FiniteRV, DiscreteUniform, Bernoulli, BetaBinomial, Hypergeometric, \ + Rademacher +from sympy.testing.pytest import skip, raises + +def test_given_sample(): + X = Die('X', 6) + scipy = import_module('scipy') + if not scipy: + skip('Scipy is not installed. Abort tests') + assert sample(X, X > 5) == 6 + +def test_sample_numpy(): + distribs_numpy = [ + Binomial("B", 5, 0.4), + Hypergeometric("H", 2, 1, 1) + ] + size = 3 + numpy = import_module('numpy') + if not numpy: + skip('Numpy is not installed. Abort tests for _sample_numpy.') + else: + for X in distribs_numpy: + samps = sample(X, size=size, library='numpy') + for sam in samps: + assert sam in X.pspace.domain.set + raises(NotImplementedError, + lambda: sample(Die("D"), library='numpy')) + raises(NotImplementedError, + lambda: Die("D").pspace.sample(library='tensorflow')) + + +def test_sample_scipy(): + distribs_scipy = [ + FiniteRV('F', {1: S.Half, 2: Rational(1, 4), 3: Rational(1, 4)}), + DiscreteUniform("Y", list(range(5))), + Die("D"), + Bernoulli("Be", 0.3), + Binomial("Bi", 5, 0.4), + BetaBinomial("Bb", 2, 1, 1), + Hypergeometric("H", 1, 1, 1), + Rademacher("R") + ] + + size = 3 + scipy = import_module('scipy') + if not scipy: + skip('Scipy not installed. Abort tests for _sample_scipy.') + else: + for X in distribs_scipy: + samps = sample(X, size=size) + samps2 = sample(X, size=(2, 2)) + for sam in samps: + assert sam in X.pspace.domain.set + for i in range(2): + for j in range(2): + assert samps2[i][j] in X.pspace.domain.set + + +def test_sample_pymc(): + distribs_pymc = [ + Bernoulli('B', 0.2), + Binomial('N', 5, 0.4) + ] + size = 3 + pymc = import_module('pymc') + if not pymc: + skip('PyMC is not installed. Abort tests for _sample_pymc.') + else: + for X in distribs_pymc: + samps = sample(X, size=size, library='pymc') + for sam in samps: + assert sam in X.pspace.domain.set + raises(NotImplementedError, + lambda: (sample(Die("D"), library='pymc'))) + + +def test_sample_seed(): + F = FiniteRV('F', {1: S.Half, 2: Rational(1, 4), 3: Rational(1, 4)}) + size = 10 + libraries = ['scipy', 'numpy', 'pymc'] + for lib in libraries: + try: + imported_lib = import_module(lib) + if imported_lib: + s0 = sample(F, size=size, library=lib, seed=0) + s1 = sample(F, size=size, library=lib, seed=0) + s2 = sample(F, size=size, library=lib, seed=1) + assert all(s0 == s1) + assert not all(s1 == s2) + except NotImplementedError: + continue diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__init__.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/__init__.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c30d5e298d3bf32e3d2c4b32c222d52fa39214bb Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_compound_rv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_compound_rv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f0392952186e5c4244f4eae6dd1f788391bff47 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_compound_rv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_discrete_rv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_discrete_rv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65590b5d87d797f2dc9f1666650032e375b90766 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_discrete_rv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_error_prop.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_error_prop.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..081754f14215ab168fdebb6bbeda2fbf900ed7c5 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_error_prop.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_finite_rv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_finite_rv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc5673b642458d82ed3540a3e7c8bad5ce7b4259 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_finite_rv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_joint_rv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_joint_rv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c79388b3e55ec8bcc6f3920ab63a20049fe4789 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_joint_rv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_matrix_distributions.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_matrix_distributions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d31f8bf275fe5784123f6fb24e816ae8fca02ff Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_matrix_distributions.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_mix.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_mix.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d8372c43748452f4048ad01c004c10c3e93e15a Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_mix.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_random_matrix.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_random_matrix.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..67f755ac0cc6c804517558e74a7b3bd6d0ddbd85 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_random_matrix.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_rv.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_rv.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d3730a14c84e88c98ed52abfe963ede750067b9 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_rv.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_stochastic_process.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_stochastic_process.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7115446a79d04a589d596a9954ab6230e1e7a803 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_stochastic_process.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_symbolic_multivariate.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_symbolic_multivariate.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ea1229208201372c2f926fa3b0c95d14e3c47c7 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_symbolic_multivariate.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_symbolic_probability.cpython-312.pyc b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_symbolic_probability.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..310a231fa5d3e49cc69abe80a344c27ada593261 Binary files /dev/null and b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/__pycache__/test_symbolic_probability.cpython-312.pyc differ diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_compound_rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_compound_rv.py new file mode 100644 index 0000000000000000000000000000000000000000..573ba364b686738e56bb1c4615acd2a9bc8bf3ae --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_compound_rv.py @@ -0,0 +1,159 @@ +from sympy.concrete.summations import Sum +from sympy.core.numbers import (oo, pi) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.special.beta_functions import beta +from sympy.functions.special.error_functions import erf +from sympy.functions.special.gamma_functions import gamma +from sympy.integrals.integrals import Integral +from sympy.sets.sets import Interval +from sympy.stats import (Normal, P, E, density, Gamma, Poisson, Rayleigh, + variance, Bernoulli, Beta, Uniform, cdf) +from sympy.stats.compound_rv import CompoundDistribution, CompoundPSpace +from sympy.stats.crv_types import NormalDistribution +from sympy.stats.drv_types import PoissonDistribution +from sympy.stats.frv_types import BernoulliDistribution +from sympy.testing.pytest import raises, ignore_warnings +from sympy.stats.joint_rv_types import MultivariateNormalDistribution + +from sympy.abc import x + + +# helpers for testing troublesome unevaluated expressions +flat = lambda s: ''.join(str(s).split()) +streq = lambda *a: len(set(map(flat, a))) == 1 +assert streq(x, x) +assert streq(x, 'x') +assert not streq(x, x + 1) + + +def test_normal_CompoundDist(): + X = Normal('X', 1, 2) + Y = Normal('X', X, 4) + assert density(Y)(x).simplify() == sqrt(10)*exp(-x**2/40 + x/20 - S(1)/40)/(20*sqrt(pi)) + assert E(Y) == 1 # it is always equal to mean of X + assert P(Y > 1) == S(1)/2 # as 1 is the mean + assert P(Y > 5).simplify() == S(1)/2 - erf(sqrt(10)/5)/2 + assert variance(Y) == variance(X) + 4**2 # 2**2 + 4**2 + # https://math.stackexchange.com/questions/1484451/ + # (Contains proof of E and variance computation) + + +def test_poisson_CompoundDist(): + k, t, y = symbols('k t y', positive=True, real=True) + G = Gamma('G', k, t) + D = Poisson('P', G) + assert density(D)(y).simplify() == t**y*(t + 1)**(-k - y)*gamma(k + y)/(gamma(k)*gamma(y + 1)) + # https://en.wikipedia.org/wiki/Negative_binomial_distribution#Gamma%E2%80%93Poisson_mixture + assert E(D).simplify() == k*t # mean of NegativeBinomialDistribution + + +def test_bernoulli_CompoundDist(): + X = Beta('X', 1, 2) + Y = Bernoulli('Y', X) + assert density(Y).dict == {0: S(2)/3, 1: S(1)/3} + assert E(Y) == P(Eq(Y, 1)) == S(1)/3 + assert variance(Y) == S(2)/9 + assert cdf(Y) == {0: S(2)/3, 1: 1} + + # test issue 8128 + a = Bernoulli('a', S(1)/2) + b = Bernoulli('b', a) + assert density(b).dict == {0: S(1)/2, 1: S(1)/2} + assert P(b > 0.5) == S(1)/2 + + X = Uniform('X', 0, 1) + Y = Bernoulli('Y', X) + assert E(Y) == S(1)/2 + assert P(Eq(Y, 1)) == E(Y) + + +def test_unevaluated_CompoundDist(): + # these tests need to be removed once they work with evaluation as they are currently not + # evaluated completely in sympy. + R = Rayleigh('R', 4) + X = Normal('X', 3, R) + ans = ''' + Piecewise(((-sqrt(pi)*sinh(x/4 - 3/4) + sqrt(pi)*cosh(x/4 - 3/4))/( + 8*sqrt(pi)), Abs(arg(x - 3)) <= pi/4), (Integral(sqrt(2)*exp(-(x - 3) + **2/(2*R**2))*exp(-R**2/32)/(32*sqrt(pi)), (R, 0, oo)), True))''' + assert streq(density(X)(x), ans) + + expre = ''' + Integral(X*Integral(sqrt(2)*exp(-(X-3)**2/(2*R**2))*exp(-R**2/32)/(32* + sqrt(pi)),(R,0,oo)),(X,-oo,oo))''' + with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed + assert streq(E(X, evaluate=False).rewrite(Integral), expre) + + X = Poisson('X', 1) + Y = Poisson('Y', X) + Z = Poisson('Z', Y) + exprd = Sum(exp(-Y)*Y**x*Sum(exp(-1)*exp(-X)*X**Y/(factorial(X)*factorial(Y) + ), (X, 0, oo))/factorial(x), (Y, 0, oo)) + assert density(Z)(x) == exprd + + N = Normal('N', 1, 2) + M = Normal('M', 3, 4) + D = Normal('D', M, N) + exprd = ''' + Integral(sqrt(2)*exp(-(N-1)**2/8)*Integral(exp(-(x-M)**2/(2*N**2))*exp + (-(M-3)**2/32)/(8*pi*N),(M,-oo,oo))/(4*sqrt(pi)),(N,-oo,oo))''' + assert streq(density(D, evaluate=False)(x), exprd) + + +def test_Compound_Distribution(): + X = Normal('X', 2, 4) + N = NormalDistribution(X, 4) + C = CompoundDistribution(N) + assert C.is_Continuous + assert C.set == Interval(-oo, oo) + assert C.pdf(x, evaluate=True).simplify() == exp(-x**2/64 + x/16 - S(1)/16)/(8*sqrt(pi)) + + assert not isinstance(CompoundDistribution(NormalDistribution(2, 3)), + CompoundDistribution) + M = MultivariateNormalDistribution([1, 2], [[2, 1], [1, 2]]) + raises(NotImplementedError, lambda: CompoundDistribution(M)) + + X = Beta('X', 2, 4) + B = BernoulliDistribution(X, 1, 0) + C = CompoundDistribution(B) + assert C.is_Finite + assert C.set == {0, 1} + y = symbols('y', negative=False, integer=True) + assert C.pdf(y, evaluate=True) == Piecewise((S(1)/(30*beta(2, 4)), Eq(y, 0)), + (S(1)/(60*beta(2, 4)), Eq(y, 1)), (0, True)) + + k, t, z = symbols('k t z', positive=True, real=True) + G = Gamma('G', k, t) + X = PoissonDistribution(G) + C = CompoundDistribution(X) + assert C.is_Discrete + assert C.set == S.Naturals0 + assert C.pdf(z, evaluate=True).simplify() == t**z*(t + 1)**(-k - z)*gamma(k \ + + z)/(gamma(k)*gamma(z + 1)) + + +def test_compound_pspace(): + X = Normal('X', 2, 4) + Y = Normal('Y', 3, 6) + assert not isinstance(Y.pspace, CompoundPSpace) + N = NormalDistribution(1, 2) + D = PoissonDistribution(3) + B = BernoulliDistribution(0.2, 1, 0) + pspace1 = CompoundPSpace('N', N) + pspace2 = CompoundPSpace('D', D) + pspace3 = CompoundPSpace('B', B) + assert not isinstance(pspace1, CompoundPSpace) + assert not isinstance(pspace2, CompoundPSpace) + assert not isinstance(pspace3, CompoundPSpace) + M = MultivariateNormalDistribution([1, 2], [[2, 1], [1, 2]]) + raises(ValueError, lambda: CompoundPSpace('M', M)) + Y = Normal('Y', X, 6) + assert isinstance(Y.pspace, CompoundPSpace) + assert Y.pspace.distribution == CompoundDistribution(NormalDistribution(X, 6)) + assert Y.pspace.domain.set == Interval(-oo, oo) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_continuous_rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_continuous_rv.py new file mode 100644 index 0000000000000000000000000000000000000000..b2c4206b5c29ffd3194d1ae05e57c51c9c1b6d78 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_continuous_rv.py @@ -0,0 +1,1583 @@ +from sympy.concrete.summations import Sum +from sympy.core.function import (Lambda, diff, expand_func) +from sympy.core.mul import Mul +from sympy.core import EulerGamma +from sympy.core.numbers import (E as e, I, Rational, pi) +from sympy.core.relational import (Eq, Ne) +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol, symbols) +from sympy.functions.combinatorial.factorials import (binomial, factorial) +from sympy.functions.elementary.complexes import (Abs, im, re, sign) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.hyperbolic import (cosh, sinh) +from sympy.functions.elementary.integers import floor +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import (asin, atan, cos, sin, tan) +from sympy.functions.special.bessel import (besseli, besselj, besselk) +from sympy.functions.special.beta_functions import beta +from sympy.functions.special.error_functions import (erf, erfc, erfi, expint) +from sympy.functions.special.gamma_functions import (gamma, lowergamma, uppergamma) +from sympy.functions.special.zeta_functions import zeta +from sympy.functions.special.hyper import hyper +from sympy.integrals.integrals import Integral +from sympy.logic.boolalg import (And, Or) +from sympy.sets.sets import Interval +from sympy.simplify.simplify import simplify +from sympy.utilities.lambdify import lambdify +from sympy.functions.special.error_functions import erfinv +from sympy.functions.special.hyper import meijerg +from sympy.sets.sets import FiniteSet, Complement, Intersection +from sympy.stats import (P, E, where, density, variance, covariance, skewness, kurtosis, median, + given, pspace, cdf, characteristic_function, moment_generating_function, + ContinuousRV, Arcsin, Benini, Beta, BetaNoncentral, BetaPrime, + Cauchy, Chi, ChiSquared, ChiNoncentral, Dagum, Davis, Erlang, ExGaussian, + Exponential, ExponentialPower, FDistribution, FisherZ, Frechet, Gamma, + GammaInverse, Gompertz, Gumbel, Kumaraswamy, Laplace, Levy, Logistic, LogCauchy, + LogLogistic, LogitNormal, LogNormal, Maxwell, Moyal, Nakagami, Normal, GaussianInverse, + Pareto, PowerFunction, QuadraticU, RaisedCosine, Rayleigh, Reciprocal, ShiftedGompertz, StudentT, + Trapezoidal, Triangular, Uniform, UniformSum, VonMises, Weibull, coskewness, + WignerSemicircle, Wald, correlation, moment, cmoment, smoment, quantile, + Lomax, BoundedPareto) + +from sympy.stats.crv_types import NormalDistribution, ExponentialDistribution, ContinuousDistributionHandmade +from sympy.stats.joint_rv_types import MultivariateLaplaceDistribution, MultivariateNormalDistribution +from sympy.stats.crv import SingleContinuousPSpace, SingleContinuousDomain +from sympy.stats.compound_rv import CompoundPSpace +from sympy.stats.symbolic_probability import Probability +from sympy.testing.pytest import raises, XFAIL, slow, ignore_warnings +from sympy.core.random import verify_numerically as tn + +oo = S.Infinity + +x, y, z = map(Symbol, 'xyz') + +def test_single_normal(): + mu = Symbol('mu', real=True) + sigma = Symbol('sigma', positive=True) + X = Normal('x', 0, 1) + Y = X*sigma + mu + + assert E(Y) == mu + assert variance(Y) == sigma**2 + pdf = density(Y) + x = Symbol('x', real=True) + assert (pdf(x) == + 2**S.Half*exp(-(x - mu)**2/(2*sigma**2))/(2*pi**S.Half*sigma)) + + assert P(X**2 < 1) == erf(2**S.Half/2) + ans = quantile(Y)(x) + assert ans == Complement(Intersection(FiniteSet( + sqrt(2)*sigma*(sqrt(2)*mu/(2*sigma)+ erfinv(2*x - 1))), + Interval(-oo, oo)), FiniteSet(mu)) + assert E(X, Eq(X, mu)) == mu + + assert median(X) == FiniteSet(0) + # issue 8248 + assert X.pspace.compute_expectation(1).doit() == 1 + + +def test_conditional_1d(): + X = Normal('x', 0, 1) + Y = given(X, X >= 0) + z = Symbol('z') + + assert density(Y)(z) == 2 * density(X)(z) + + assert Y.pspace.domain.set == Interval(0, oo) + assert E(Y) == sqrt(2) / sqrt(pi) + + 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 + assert where(And(X**2 <= 1, X >= 0)).set == Interval(0, 1) + raises(ValueError, lambda: where(sin(X) > 1)) + + 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) + p = Symbol("p", positive=True) + + 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 kurtosis(X) == 3 + assert kurtosis(X+Y) == 3 + 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 smoment(X + Y, 4) == kurtosis(X + Y) + assert E(X, Eq(X + Y, 0)) == 0 + assert variance(X, Eq(X + Y, 0)) == S.Half + assert quantile(X)(p) == sqrt(2)*erfinv(2*p - S.One) + + +def test_symbolic(): + mu1, mu2 = symbols('mu1 mu2', real=True) + s1, s2 = symbols('sigma1 sigma2', positive=True) + rate = Symbol('lambda', positive=True) + X = Normal('x', mu1, s1) + Y = Normal('y', mu2, s2) + Z = Exponential('z', rate) + a, b, c = symbols('a b c', real=True) + + assert E(X) == mu1 + assert E(X + Y) == mu1 + mu2 + assert E(a*X + b) == a*E(X) + b + assert variance(X) == s1**2 + assert 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 median(X) == FiniteSet(mu1) + + +def test_cdf(): + X = Normal('x', 0, 1) + + d = cdf(X) + assert P(X < 1) == d(1).rewrite(erfc) + assert d(0) == S.Half + + d = cdf(X, X > 0) # given X>0 + assert d(0) == 0 + + Y = Exponential('y', 10) + d = cdf(Y) + assert d(-5) == 0 + assert P(Y > 3) == 1 - d(3) + + raises(ValueError, lambda: cdf(X + Y)) + + Z = Exponential('z', 1) + f = cdf(Z) + assert f(z) == Piecewise((1 - exp(-z), z >= 0), (0, True)) + + +def test_characteristic_function(): + X = Uniform('x', 0, 1) + + cf = characteristic_function(X) + assert cf(1) == -I*(-1 + exp(I)) + + Y = Normal('y', 1, 1) + cf = characteristic_function(Y) + assert cf(0) == 1 + assert cf(1) == exp(I - S.Half) + + Z = Exponential('z', 5) + cf = characteristic_function(Z) + assert cf(0) == 1 + assert cf(1).expand() == Rational(25, 26) + I*5/26 + + X = GaussianInverse('x', 1, 1) + cf = characteristic_function(X) + assert cf(0) == 1 + assert cf(1) == exp(1 - sqrt(1 - 2*I)) + + X = ExGaussian('x', 0, 1, 1) + cf = characteristic_function(X) + assert cf(0) == 1 + assert cf(1) == (1 + I)*exp(Rational(-1, 2))/2 + + L = Levy('x', 0, 1) + cf = characteristic_function(L) + assert cf(0) == 1 + assert cf(1) == exp(-sqrt(2)*sqrt(-I)) + + +def test_moment_generating_function(): + t = symbols('t', positive=True) + + # Symbolic tests + a, b, c = symbols('a b c') + + mgf = moment_generating_function(Beta('x', a, b))(t) + assert mgf == hyper((a,), (a + b,), t) + + mgf = moment_generating_function(Chi('x', a))(t) + assert mgf == sqrt(2)*t*gamma(a/2 + S.Half)*\ + hyper((a/2 + S.Half,), (Rational(3, 2),), t**2/2)/gamma(a/2) +\ + hyper((a/2,), (S.Half,), t**2/2) + + mgf = moment_generating_function(ChiSquared('x', a))(t) + assert mgf == (1 - 2*t)**(-a/2) + + mgf = moment_generating_function(Erlang('x', a, b))(t) + assert mgf == (1 - t/b)**(-a) + + mgf = moment_generating_function(ExGaussian("x", a, b, c))(t) + assert mgf == exp(a*t + b**2*t**2/2)/(1 - t/c) + + mgf = moment_generating_function(Exponential('x', a))(t) + assert mgf == a/(a - t) + + mgf = moment_generating_function(Gamma('x', a, b))(t) + assert mgf == (-b*t + 1)**(-a) + + mgf = moment_generating_function(Gumbel('x', a, b))(t) + assert mgf == exp(b*t)*gamma(-a*t + 1) + + mgf = moment_generating_function(Gompertz('x', a, b))(t) + assert mgf == b*exp(b)*expint(t/a, b) + + mgf = moment_generating_function(Laplace('x', a, b))(t) + assert mgf == exp(a*t)/(-b**2*t**2 + 1) + + mgf = moment_generating_function(Logistic('x', a, b))(t) + assert mgf == exp(a*t)*beta(-b*t + 1, b*t + 1) + + mgf = moment_generating_function(Normal('x', a, b))(t) + assert mgf == exp(a*t + b**2*t**2/2) + + mgf = moment_generating_function(Pareto('x', a, b))(t) + assert mgf == b*(-a*t)**b*uppergamma(-b, -a*t) + + mgf = moment_generating_function(QuadraticU('x', a, b))(t) + assert str(mgf) == ("(3*(t*(-4*b + (a + b)**2) + 4)*exp(b*t) - " + "3*(t*(a**2 + 2*a*(b - 2) + b**2) + 4)*exp(a*t))/(t**2*(a - b)**3)") + + mgf = moment_generating_function(RaisedCosine('x', a, b))(t) + assert mgf == pi**2*exp(a*t)*sinh(b*t)/(b*t*(b**2*t**2 + pi**2)) + + mgf = moment_generating_function(Rayleigh('x', a))(t) + assert mgf == sqrt(2)*sqrt(pi)*a*t*(erf(sqrt(2)*a*t/2) + 1)\ + *exp(a**2*t**2/2)/2 + 1 + + mgf = moment_generating_function(Triangular('x', a, b, c))(t) + assert str(mgf) == ("(-2*(-a + b)*exp(c*t) + 2*(-a + c)*exp(b*t) + " + "2*(b - c)*exp(a*t))/(t**2*(-a + b)*(-a + c)*(b - c))") + + mgf = moment_generating_function(Uniform('x', a, b))(t) + assert mgf == (-exp(a*t) + exp(b*t))/(t*(-a + b)) + + mgf = moment_generating_function(UniformSum('x', a))(t) + assert mgf == ((exp(t) - 1)/t)**a + + mgf = moment_generating_function(WignerSemicircle('x', a))(t) + assert mgf == 2*besseli(1, a*t)/(a*t) + + # Numeric tests + + mgf = moment_generating_function(Beta('x', 1, 1))(t) + assert mgf.diff(t).subs(t, 1) == hyper((2,), (3,), 1)/2 + + mgf = moment_generating_function(Chi('x', 1))(t) + assert mgf.diff(t).subs(t, 1) == sqrt(2)*hyper((1,), (Rational(3, 2),), S.Half + )/sqrt(pi) + hyper((Rational(3, 2),), (Rational(3, 2),), S.Half) + 2*sqrt(2)*hyper((2,), + (Rational(5, 2),), S.Half)/(3*sqrt(pi)) + + mgf = moment_generating_function(ChiSquared('x', 1))(t) + assert mgf.diff(t).subs(t, 1) == I + + mgf = moment_generating_function(Erlang('x', 1, 1))(t) + assert mgf.diff(t).subs(t, 0) == 1 + + mgf = moment_generating_function(ExGaussian("x", 0, 1, 1))(t) + assert mgf.diff(t).subs(t, 2) == -exp(2) + + mgf = moment_generating_function(Exponential('x', 1))(t) + assert mgf.diff(t).subs(t, 0) == 1 + + mgf = moment_generating_function(Gamma('x', 1, 1))(t) + assert mgf.diff(t).subs(t, 0) == 1 + + mgf = moment_generating_function(Gumbel('x', 1, 1))(t) + assert mgf.diff(t).subs(t, 0) == EulerGamma + 1 + + mgf = moment_generating_function(Gompertz('x', 1, 1))(t) + assert mgf.diff(t).subs(t, 1) == -e*meijerg(((), (1, 1)), + ((0, 0, 0), ()), 1) + + mgf = moment_generating_function(Laplace('x', 1, 1))(t) + assert mgf.diff(t).subs(t, 0) == 1 + + mgf = moment_generating_function(Logistic('x', 1, 1))(t) + assert mgf.diff(t).subs(t, 0) == beta(1, 1) + + mgf = moment_generating_function(Normal('x', 0, 1))(t) + assert mgf.diff(t).subs(t, 1) == exp(S.Half) + + mgf = moment_generating_function(Pareto('x', 1, 1))(t) + assert mgf.diff(t).subs(t, 0) == expint(1, 0) + + mgf = moment_generating_function(QuadraticU('x', 1, 2))(t) + assert mgf.diff(t).subs(t, 1) == -12*e - 3*exp(2) + + mgf = moment_generating_function(RaisedCosine('x', 1, 1))(t) + assert mgf.diff(t).subs(t, 1) == -2*e*pi**2*sinh(1)/\ + (1 + pi**2)**2 + e*pi**2*cosh(1)/(1 + pi**2) + + mgf = moment_generating_function(Rayleigh('x', 1))(t) + assert mgf.diff(t).subs(t, 0) == sqrt(2)*sqrt(pi)/2 + + mgf = moment_generating_function(Triangular('x', 1, 3, 2))(t) + assert mgf.diff(t).subs(t, 1) == -e + exp(3) + + mgf = moment_generating_function(Uniform('x', 0, 1))(t) + assert mgf.diff(t).subs(t, 1) == 1 + + mgf = moment_generating_function(UniformSum('x', 1))(t) + assert mgf.diff(t).subs(t, 1) == 1 + + mgf = moment_generating_function(WignerSemicircle('x', 1))(t) + assert mgf.diff(t).subs(t, 1) == -2*besseli(1, 1) + besseli(2, 1) +\ + besseli(0, 1) + + +def test_ContinuousRV(): + pdf = sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)) # Normal distribution + # X and Y should be equivalent + X = ContinuousRV(x, pdf, check=True) + Y = Normal('y', 0, 1) + + assert variance(X) == variance(Y) + assert P(X > 0) == P(Y > 0) + Z = ContinuousRV(z, exp(-z), set=Interval(0, oo)) + assert Z.pspace.domain.set == Interval(0, oo) + assert E(Z) == 1 + assert P(Z > 5) == exp(-5) + raises(ValueError, lambda: ContinuousRV(z, exp(-z), set=Interval(0, 10), check=True)) + + # the correct pdf for Gamma(k, theta) but the integral in `check` + # integrates to something equivalent to 1 and not to 1 exactly + _x, k, theta = symbols("x k theta", positive=True) + pdf = 1/(gamma(k)*theta**k)*_x**(k-1)*exp(-_x/theta) + X = ContinuousRV(_x, pdf, set=Interval(0, oo)) + Y = Gamma('y', k, theta) + assert (E(X) - E(Y)).simplify() == 0 + assert (variance(X) - variance(Y)).simplify() == 0 + + +def test_arcsin(): + + a = Symbol("a", real=True) + b = Symbol("b", real=True) + + X = Arcsin('x', a, b) + assert density(X)(x) == 1/(pi*sqrt((-x + b)*(x - a))) + assert cdf(X)(x) == Piecewise((0, a > x), + (2*asin(sqrt((-a + x)/(-a + b)))/pi, b >= x), + (1, True)) + assert pspace(X).domain.set == Interval(a, b) + +def test_benini(): + alpha = Symbol("alpha", positive=True) + beta = Symbol("beta", positive=True) + sigma = Symbol("sigma", positive=True) + X = Benini('x', alpha, beta, sigma) + + assert density(X)(x) == ((alpha/x + 2*beta*log(x/sigma)/x) + *exp(-alpha*log(x/sigma) - beta*log(x/sigma)**2)) + + assert pspace(X).domain.set == Interval(sigma, oo) + raises(NotImplementedError, lambda: moment_generating_function(X)) + alpha = Symbol("alpha", nonpositive=True) + raises(ValueError, lambda: Benini('x', alpha, beta, sigma)) + + beta = Symbol("beta", nonpositive=True) + raises(ValueError, lambda: Benini('x', alpha, beta, sigma)) + + alpha = Symbol("alpha", positive=True) + raises(ValueError, lambda: Benini('x', alpha, beta, sigma)) + + beta = Symbol("beta", positive=True) + sigma = Symbol("sigma", nonpositive=True) + raises(ValueError, lambda: Benini('x', alpha, beta, sigma)) + +def test_beta(): + a, b = symbols('alpha beta', positive=True) + B = Beta('x', a, b) + + assert pspace(B).domain.set == Interval(0, 1) + assert characteristic_function(B)(x) == hyper((a,), (a + b,), I*x) + assert density(B)(x) == x**(a - 1)*(1 - x)**(b - 1)/beta(a, b) + + assert simplify(E(B)) == a / (a + b) + assert simplify(variance(B)) == a*b / (a**3 + 3*a**2*b + a**2 + 3*a*b**2 + 2*a*b + b**3 + b**2) + + # Full symbolic solution is too much, test with numeric version + a, b = 1, 2 + B = Beta('x', a, b) + assert expand_func(E(B)) == a / S(a + b) + assert expand_func(variance(B)) == (a*b) / S((a + b)**2 * (a + b + 1)) + assert median(B) == FiniteSet(1 - 1/sqrt(2)) + +def test_beta_noncentral(): + a, b = symbols('a b', positive=True) + c = Symbol('c', nonnegative=True) + _k = Dummy('k') + + X = BetaNoncentral('x', a, b, c) + + assert pspace(X).domain.set == Interval(0, 1) + + dens = density(X) + z = Symbol('z') + + res = Sum( z**(_k + a - 1)*(c/2)**_k*(1 - z)**(b - 1)*exp(-c/2)/ + (beta(_k + a, b)*factorial(_k)), (_k, 0, oo)) + assert dens(z).dummy_eq(res) + + # BetaCentral should not raise if the assumptions + # on the symbols can not be determined + a, b, c = symbols('a b c') + assert BetaNoncentral('x', a, b, c) + + a = Symbol('a', positive=False, real=True) + raises(ValueError, lambda: BetaNoncentral('x', a, b, c)) + + a = Symbol('a', positive=True) + b = Symbol('b', positive=False, real=True) + raises(ValueError, lambda: BetaNoncentral('x', a, b, c)) + + a = Symbol('a', positive=True) + b = Symbol('b', positive=True) + c = Symbol('c', nonnegative=False, real=True) + raises(ValueError, lambda: BetaNoncentral('x', a, b, c)) + +def test_betaprime(): + alpha = Symbol("alpha", positive=True) + + betap = Symbol("beta", positive=True) + + X = BetaPrime('x', alpha, betap) + assert density(X)(x) == x**(alpha - 1)*(x + 1)**(-alpha - betap)/beta(alpha, betap) + + alpha = Symbol("alpha", nonpositive=True) + raises(ValueError, lambda: BetaPrime('x', alpha, betap)) + + alpha = Symbol("alpha", positive=True) + betap = Symbol("beta", nonpositive=True) + raises(ValueError, lambda: BetaPrime('x', alpha, betap)) + X = BetaPrime('x', 1, 1) + assert median(X) == FiniteSet(1) + + +def test_BoundedPareto(): + L, H = symbols('L, H', negative=True) + raises(ValueError, lambda: BoundedPareto('X', 1, L, H)) + L, H = symbols('L, H', real=False) + raises(ValueError, lambda: BoundedPareto('X', 1, L, H)) + L, H = symbols('L, H', positive=True) + raises(ValueError, lambda: BoundedPareto('X', -1, L, H)) + + X = BoundedPareto('X', 2, L, H) + assert X.pspace.domain.set == Interval(L, H) + assert density(X)(x) == 2*L**2/(x**3*(1 - L**2/H**2)) + assert cdf(X)(x) == Piecewise((-H**2*L**2/(x**2*(H**2 - L**2)) \ + + H**2/(H**2 - L**2), L <= x), (0, True)) + assert E(X).simplify() == 2*H*L/(H + L) + X = BoundedPareto('X', 1, 2, 4) + assert E(X).simplify() == log(16) + assert median(X) == FiniteSet(Rational(8, 3)) + assert variance(X).simplify() == 8 - 16*log(2)**2 + + +def test_cauchy(): + x0 = Symbol("x0", real=True) + gamma = Symbol("gamma", positive=True) + p = Symbol("p", positive=True) + + X = Cauchy('x', x0, gamma) + # Tests the characteristic function + assert characteristic_function(X)(x) == exp(-gamma*Abs(x) + I*x*x0) + raises(NotImplementedError, lambda: moment_generating_function(X)) + assert density(X)(x) == 1/(pi*gamma*(1 + (x - x0)**2/gamma**2)) + assert diff(cdf(X)(x), x) == density(X)(x) + assert quantile(X)(p) == gamma*tan(pi*(p - S.Half)) + x0 + + x1 = Symbol("x1", real=False) + raises(ValueError, lambda: Cauchy('x', x1, gamma)) + gamma = Symbol("gamma", nonpositive=True) + raises(ValueError, lambda: Cauchy('x', x0, gamma)) + assert median(X) == FiniteSet(x0) + +def test_chi(): + from sympy.core.numbers import I + k = Symbol("k", integer=True) + + X = Chi('x', k) + assert density(X)(x) == 2**(-k/2 + 1)*x**(k - 1)*exp(-x**2/2)/gamma(k/2) + + # Tests the characteristic function + assert characteristic_function(X)(x) == sqrt(2)*I*x*gamma(k/2 + S(1)/2)*hyper((k/2 + S(1)/2,), + (S(3)/2,), -x**2/2)/gamma(k/2) + hyper((k/2,), (S(1)/2,), -x**2/2) + + # Tests the moment generating function + assert moment_generating_function(X)(x) == sqrt(2)*x*gamma(k/2 + S(1)/2)*hyper((k/2 + S(1)/2,), + (S(3)/2,), x**2/2)/gamma(k/2) + hyper((k/2,), (S(1)/2,), x**2/2) + + k = Symbol("k", integer=True, positive=False) + raises(ValueError, lambda: Chi('x', k)) + + k = Symbol("k", integer=False, positive=True) + raises(ValueError, lambda: Chi('x', k)) + +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)) + + k = Symbol("k", integer=True, positive=False) + raises(ValueError, lambda: ChiNoncentral('x', k, l)) + + k = Symbol("k", integer=True, positive=True) + l = Symbol("l", nonpositive=True) + raises(ValueError, lambda: ChiNoncentral('x', k, l)) + + k = Symbol("k", integer=False) + l = Symbol("l", positive=True) + raises(ValueError, lambda: ChiNoncentral('x', k, l)) + + +def test_chi_squared(): + k = Symbol("k", integer=True) + X = ChiSquared('x', k) + + # Tests the characteristic function + assert characteristic_function(X)(x) == ((-2*I*x + 1)**(-k/2)) + + assert density(X)(x) == 2**(-k/2)*x**(k/2 - 1)*exp(-x/2)/gamma(k/2) + assert cdf(X)(x) == Piecewise((lowergamma(k/2, x/2)/gamma(k/2), x >= 0), (0, True)) + assert E(X) == k + assert variance(X) == 2*k + + X = ChiSquared('x', 15) + assert cdf(X)(3) == -14873*sqrt(6)*exp(Rational(-3, 2))/(5005*sqrt(pi)) + erf(sqrt(6)/2) + + k = Symbol("k", integer=True, positive=False) + raises(ValueError, lambda: ChiSquared('x', k)) + + k = Symbol("k", integer=False, positive=True) + raises(ValueError, lambda: ChiSquared('x', k)) + + +def test_dagum(): + p = Symbol("p", positive=True) + b = Symbol("b", positive=True) + a = Symbol("a", positive=True) + + X = Dagum('x', p, a, b) + assert density(X)(x) == a*p*(x/b)**(a*p)*((x/b)**a + 1)**(-p - 1)/x + assert cdf(X)(x) == Piecewise(((1 + (x/b)**(-a))**(-p), x >= 0), + (0, True)) + + p = Symbol("p", nonpositive=True) + raises(ValueError, lambda: Dagum('x', p, a, b)) + + p = Symbol("p", positive=True) + b = Symbol("b", nonpositive=True) + raises(ValueError, lambda: Dagum('x', p, a, b)) + + b = Symbol("b", positive=True) + a = Symbol("a", nonpositive=True) + raises(ValueError, lambda: Dagum('x', p, a, b)) + X = Dagum('x', 1, 1, 1) + assert median(X) == FiniteSet(1) + +def test_davis(): + b = Symbol("b", positive=True) + n = Symbol("n", positive=True) + mu = Symbol("mu", positive=True) + + X = Davis('x', b, n, mu) + dividend = b**n*(x - mu)**(-1-n) + divisor = (exp(b/(x-mu))-1)*(gamma(n)*zeta(n)) + assert density(X)(x) == dividend/divisor + + +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) + assert cdf(X)(x) == Piecewise((lowergamma(k, l*x)/gamma(k), x > 0), + (0, True)) + + +def test_exgaussian(): + m, z = symbols("m, z") + s, l = symbols("s, l", positive=True) + X = ExGaussian("x", m, s, l) + + assert density(X)(z) == l*exp(l*(l*s**2 + 2*m - 2*z)/2) *\ + erfc(sqrt(2)*(l*s**2 + m - z)/(2*s))/2 + + # Note: actual_output simplifies to expected_output. + # Ideally cdf(X)(z) would return expected_output + # expected_output = (erf(sqrt(2)*(l*s**2 + m - z)/(2*s)) - 1)*exp(l*(l*s**2 + 2*m - 2*z)/2)/2 - erf(sqrt(2)*(m - z)/(2*s))/2 + S.Half + u = l*(z - m) + v = l*s + GaussianCDF1 = cdf(Normal('x', 0, v))(u) + GaussianCDF2 = cdf(Normal('x', v**2, v))(u) + actual_output = GaussianCDF1 - exp(-u + (v**2/2) + log(GaussianCDF2)) + assert cdf(X)(z) == actual_output + # assert simplify(actual_output) == expected_output + + assert variance(X).expand() == s**2 + l**(-2) + + assert skewness(X).expand() == 2/(l**3*s**2*sqrt(s**2 + l**(-2)) + l * + sqrt(s**2 + l**(-2))) + + +@slow +def test_exponential(): + rate = Symbol('lambda', positive=True) + X = Exponential('x', rate) + p = Symbol("p", positive=True, real=True) + + assert E(X) == 1/rate + assert variance(X) == 1/rate**2 + assert skewness(X) == 2 + assert skewness(X) == smoment(X, 3) + assert kurtosis(X) == 9 + assert kurtosis(X) == smoment(X, 4) + assert smoment(2*X, 4) == smoment(X, 4) + assert moment(X, 3) == 3*2*1/rate**3 + assert P(X > 0) is S.One + assert P(X > 1) == exp(-rate) + assert P(X > 10) == exp(-10*rate) + assert quantile(X)(p) == -log(1-p)/rate + + assert where(X <= 1).set == Interval(0, 1) + Y = Exponential('y', 1) + assert median(Y) == FiniteSet(log(2)) + #Test issue 9970 + z = Dummy('z') + assert P(X > z) == exp(-z*rate) + assert P(X < z) == 0 + #Test issue 10076 (Distribution with interval(0,oo)) + x = Symbol('x') + _z = Dummy('_z') + b = SingleContinuousPSpace(x, ExponentialDistribution(2)) + + with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed + expected1 = Integral(2*exp(-2*_z), (_z, 3, oo)) + assert b.probability(x > 3, evaluate=False).rewrite(Integral).dummy_eq(expected1) + + expected2 = Integral(2*exp(-2*_z), (_z, 0, 4)) + assert b.probability(x < 4, evaluate=False).rewrite(Integral).dummy_eq(expected2) + Y = Exponential('y', 2*rate) + assert coskewness(X, X, X) == skewness(X) + assert coskewness(X, Y + rate*X, Y + 2*rate*X) == \ + 4/(sqrt(1 + 1/(4*rate**2))*sqrt(4 + 1/(4*rate**2))) + assert coskewness(X + 2*Y, Y + X, Y + 2*X, X > 3) == \ + sqrt(170)*Rational(9, 85) + +def test_exponential_power(): + mu = Symbol('mu') + z = Symbol('z') + alpha = Symbol('alpha', positive=True) + beta = Symbol('beta', positive=True) + + X = ExponentialPower('x', mu, alpha, beta) + + assert density(X)(z) == beta*exp(-(Abs(mu - z)/alpha) + ** beta)/(2*alpha*gamma(1/beta)) + assert cdf(X)(z) == S.Half + lowergamma(1/beta, + (Abs(mu - z)/alpha)**beta)*sign(-mu + z)/\ + (2*gamma(1/beta)) + + +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((d1*x)**d1*(d1*x + d2)**(-d1 - d2)) + /(x*beta(d1/2, d2/2))) + + raises(NotImplementedError, lambda: moment_generating_function(X)) + d1 = Symbol("d1", nonpositive=True) + raises(ValueError, lambda: FDistribution('x', d1, d1)) + + d1 = Symbol("d1", positive=True, integer=False) + raises(ValueError, lambda: FDistribution('x', d1, d1)) + + d1 = Symbol("d1", positive=True) + d2 = Symbol("d2", nonpositive=True) + raises(ValueError, lambda: FDistribution('x', d1, d2)) + + d2 = Symbol("d2", positive=True, integer=False) + raises(ValueError, lambda: FDistribution('x', d1, d2)) + + +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(d1*x)/beta(d1/2, d2/2)) + +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 + assert cdf(X)(x) == Piecewise((exp(-((-m + x)/s)**(-a)), m <= x), (0, True)) + +@slow +def test_gamma(): + k = Symbol("k", positive=True) + theta = Symbol("theta", positive=True) + + X = Gamma('x', k, theta) + + # Tests characteristic function + assert characteristic_function(X)(x) == ((-I*theta*x + 1)**(-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', positive=True) + X = Gamma('x', k, theta) + assert E(X) == k*theta + assert variance(X) == k*theta**2 + assert skewness(X).expand() == 2/sqrt(k) + assert kurtosis(X).expand() == 3 + 6/k + + Y = Gamma('y', 2*k, 3*theta) + assert coskewness(X, theta*X + Y, k*X + Y).simplify() == \ + 2*531441**(-k)*sqrt(k)*theta*(3*3**(12*k) - 2*531441**k) \ + /(sqrt(k**2 + 18)*sqrt(theta**2 + 18)) + +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) + assert cdf(X)(x) == Piecewise((uppergamma(a, b/x)/gamma(a), x > 0), (0, True)) + assert characteristic_function(X)(x) == 2 * (-I*b*x)**(a/2) \ + * besselk(a, 2*sqrt(b)*sqrt(-I*x))/gamma(a) + raises(NotImplementedError, lambda: moment_generating_function(X)) + +def test_gompertz(): + b = Symbol("b", positive=True) + eta = Symbol("eta", positive=True) + + X = Gompertz("x", b, eta) + + assert density(X)(x) == b*eta*exp(eta)*exp(b*x)*exp(-eta*exp(b*x)) + assert cdf(X)(x) == 1 - exp(eta)*exp(-eta*exp(b*x)) + assert diff(cdf(X)(x), x) == density(X)(x) + + +def test_gumbel(): + beta = Symbol("beta", positive=True) + mu = Symbol("mu") + x = Symbol("x") + y = Symbol("y") + X = Gumbel("x", beta, mu) + Y = Gumbel("y", beta, mu, minimum=True) + assert density(X)(x).expand() == \ + exp(mu/beta)*exp(-x/beta)*exp(-exp(mu/beta)*exp(-x/beta))/beta + assert density(Y)(y).expand() == \ + exp(-mu/beta)*exp(y/beta)*exp(-exp(-mu/beta)*exp(y/beta))/beta + assert cdf(X)(x).expand() == \ + exp(-exp(mu/beta)*exp(-x/beta)) + assert characteristic_function(X)(x) == exp(I*mu*x)*gamma(-I*beta*x + 1) + +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) + assert cdf(X)(x) == Piecewise((0, x < 0), + (-(-x**a + 1)**b + 1, x <= 1), + (1, True)) + + +def test_laplace(): + mu = Symbol("mu") + b = Symbol("b", positive=True) + + X = Laplace('x', mu, b) + + #Tests characteristic_function + assert characteristic_function(X)(x) == (exp(I*mu*x)/(b**2*x**2 + 1)) + + assert density(X)(x) == exp(-Abs(x - mu)/b)/(2*b) + assert cdf(X)(x) == Piecewise((exp((-mu + x)/b)/2, mu > x), + (-exp((mu - x)/b)/2 + 1, True)) + X = Laplace('x', [1, 2], [[1, 0], [0, 1]]) + assert isinstance(pspace(X).distribution, MultivariateLaplaceDistribution) + +def test_levy(): + mu = Symbol("mu", real=True) + c = Symbol("c", positive=True) + + X = Levy('x', mu, c) + assert X.pspace.domain.set == Interval(mu, oo) + assert density(X)(x) == sqrt(c/(2*pi))*exp(-c/(2*(x - mu)))/((x - mu)**(S.One + S.Half)) + assert cdf(X)(x) == erfc(sqrt(c/(2*(x - mu)))) + + raises(NotImplementedError, lambda: moment_generating_function(X)) + mu = Symbol("mu", real=False) + raises(ValueError, lambda: Levy('x',mu,c)) + + c = Symbol("c", nonpositive=True) + raises(ValueError, lambda: Levy('x',mu,c)) + + mu = Symbol("mu", real=True) + raises(ValueError, lambda: Levy('x',mu,c)) + +def test_logcauchy(): + mu = Symbol("mu", positive=True) + sigma = Symbol("sigma", positive=True) + + X = LogCauchy("x", mu, sigma) + + assert density(X)(x) == sigma/(x*pi*(sigma**2 + (-mu + log(x))**2)) + assert cdf(X)(x) == atan((log(x) - mu)/sigma)/pi + S.Half + + +def test_logistic(): + mu = Symbol("mu", real=True) + s = Symbol("s", positive=True) + p = Symbol("p", positive=True) + + X = Logistic('x', mu, s) + + #Tests characteristics_function + assert characteristic_function(X)(x) == \ + (Piecewise((pi*s*x*exp(I*mu*x)/sinh(pi*s*x), Ne(x, 0)), (1, True))) + + assert density(X)(x) == exp((-x + mu)/s)/(s*(exp((-x + mu)/s) + 1)**2) + assert cdf(X)(x) == 1/(exp((mu - x)/s) + 1) + assert quantile(X)(p) == mu - s*log(-S.One + 1/p) + +def test_loglogistic(): + a, b = symbols('a b') + assert LogLogistic('x', a, b) + + a = Symbol('a', negative=True) + b = Symbol('b', positive=True) + raises(ValueError, lambda: LogLogistic('x', a, b)) + + a = Symbol('a', positive=True) + b = Symbol('b', negative=True) + raises(ValueError, lambda: LogLogistic('x', a, b)) + + a, b, z, p = symbols('a b z p', positive=True) + X = LogLogistic('x', a, b) + assert density(X)(z) == b*(z/a)**(b - 1)/(a*((z/a)**b + 1)**2) + assert cdf(X)(z) == 1/(1 + (z/a)**(-b)) + assert quantile(X)(p) == a*(p/(1 - p))**(1/b) + + # Expectation + assert E(X) == Piecewise((S.NaN, b <= 1), (pi*a/(b*sin(pi/b)), True)) + b = symbols('b', prime=True) # b > 1 + X = LogLogistic('x', a, b) + assert E(X) == pi*a/(b*sin(pi/b)) + X = LogLogistic('x', 1, 2) + assert median(X) == FiniteSet(1) + +def test_logitnormal(): + mu = Symbol('mu', real=True) + s = Symbol('s', positive=True) + X = LogitNormal('x', mu, s) + x = Symbol('x') + + assert density(X)(x) == sqrt(2)*exp(-(-mu + log(x/(1 - x)))**2/(2*s**2))/(2*sqrt(pi)*s*x*(1 - x)) + assert cdf(X)(x) == erf(sqrt(2)*(-mu + log(x/(1 - x)))/(2*s))/2 + S(1)/2 + +def test_lognormal(): + mean = Symbol('mu', real=True) + std = Symbol('sigma', positive=True) + X = LogNormal('x', mean, std) + # The sympy integrator can't do this too well + #assert E(X) == exp(mean+std**2/2) + #assert variance(X) == (exp(std**2)-1) * exp(2*mean + std**2) + + # The sympy integrator can't do this too well + #assert E(X) == + raises(NotImplementedError, lambda: moment_generating_function(X)) + mu = Symbol("mu", real=True) + sigma = Symbol("sigma", positive=True) + + X = LogNormal('x', mu, sigma) + assert density(X)(x) == (sqrt(2)*exp(-(-mu + log(x))**2 + /(2*sigma**2))/(2*x*sqrt(pi)*sigma)) + # Tests cdf + assert cdf(X)(x) == Piecewise( + (erf(sqrt(2)*(-mu + log(x))/(2*sigma))/2 + + S(1)/2, x > 0), (0, True)) + + 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_Lomax(): + a, l = symbols('a, l', negative=True) + raises(ValueError, lambda: Lomax('X', a, l)) + a, l = symbols('a, l', real=False) + raises(ValueError, lambda: Lomax('X', a, l)) + + a, l = symbols('a, l', positive=True) + X = Lomax('X', a, l) + assert X.pspace.domain.set == Interval(0, oo) + assert density(X)(x) == a*(1 + x/l)**(-a - 1)/l + assert cdf(X)(x) == Piecewise((1 - (1 + x/l)**(-a), x >= 0), (0, True)) + a = 3 + X = Lomax('X', a, l) + assert E(X) == l/2 + assert median(X) == FiniteSet(l*(-1 + 2**Rational(1, 3))) + assert variance(X) == 3*l**2/4 + + +def test_maxwell(): + a = Symbol("a", positive=True) + + X = Maxwell('x', a) + + 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 variance(X) == -8*a**2/pi + 3*a**2 + assert cdf(X)(x) == erf(sqrt(2)*x/(2*a)) - sqrt(2)*x*exp(-x**2/(2*a**2))/(sqrt(pi)*a) + assert diff(cdf(X)(x), x) == density(X)(x) + + +@slow +def test_Moyal(): + mu = Symbol('mu',real=False) + sigma = Symbol('sigma', positive=True) + raises(ValueError, lambda: Moyal('M',mu, sigma)) + + mu = Symbol('mu', real=True) + sigma = Symbol('sigma', negative=True) + raises(ValueError, lambda: Moyal('M',mu, sigma)) + + sigma = Symbol('sigma', positive=True) + M = Moyal('M', mu, sigma) + assert density(M)(z) == sqrt(2)*exp(-exp((mu - z)/sigma)/2 + - (-mu + z)/(2*sigma))/(2*sqrt(pi)*sigma) + assert cdf(M)(z).simplify() == 1 - erf(sqrt(2)*exp((mu - z)/(2*sigma))/2) + assert characteristic_function(M)(z) == 2**(-I*sigma*z)*exp(I*mu*z) \ + *gamma(-I*sigma*z + Rational(1, 2))/sqrt(pi) + assert E(M) == mu + EulerGamma*sigma + sigma*log(2) + assert moment_generating_function(M)(z) == 2**(-sigma*z)*exp(mu*z) \ + *gamma(-sigma*z + Rational(1, 2))/sqrt(pi) + + +def test_nakagami(): + mu = Symbol("mu", positive=True) + omega = Symbol("omega", positive=True) + + X = Nakagami('x', mu, omega) + assert density(X)(x) == (2*x**(2*mu - 1)*mu**mu*omega**(-mu) + *exp(-x**2*mu/omega)/gamma(mu)) + assert simplify(E(X)) == (sqrt(mu)*sqrt(omega) + *gamma(mu + S.Half)/gamma(mu + 1)) + assert simplify(variance(X)) == ( + omega - omega*gamma(mu + S.Half)**2/(gamma(mu)*gamma(mu + 1))) + assert cdf(X)(x) == Piecewise( + (lowergamma(mu, mu*x**2/omega)/gamma(mu), x > 0), + (0, True)) + X = Nakagami('x', 1, 1) + assert median(X) == FiniteSet(sqrt(log(2))) + +def test_gaussian_inverse(): + # test for symbolic parameters + a, b = symbols('a b') + assert GaussianInverse('x', a, b) + + # Inverse Gaussian distribution is also known as Wald distribution + # `GaussianInverse` can also be referred by the name `Wald` + a, b, z = symbols('a b z') + X = Wald('x', a, b) + assert density(X)(z) == sqrt(2)*sqrt(b/z**3)*exp(-b*(-a + z)**2/(2*a**2*z))/(2*sqrt(pi)) + + a, b = symbols('a b', positive=True) + z = Symbol('z', positive=True) + + X = GaussianInverse('x', a, b) + assert density(X)(z) == sqrt(2)*sqrt(b)*sqrt(z**(-3))*exp(-b*(-a + z)**2/(2*a**2*z))/(2*sqrt(pi)) + assert E(X) == a + assert variance(X).expand() == a**3/b + assert cdf(X)(z) == (S.Half - erf(sqrt(2)*sqrt(b)*(1 + z/a)/(2*sqrt(z)))/2)*exp(2*b/a) +\ + erf(sqrt(2)*sqrt(b)*(-1 + z/a)/(2*sqrt(z)))/2 + S.Half + + a = symbols('a', nonpositive=True) + raises(ValueError, lambda: GaussianInverse('x', a, b)) + + a = symbols('a', positive=True) + b = symbols('b', nonpositive=True) + raises(ValueError, lambda: GaussianInverse('x', a, b)) + +def test_pareto(): + xm, beta = symbols('xm beta', positive=True) + alpha = beta + 5 + X = Pareto('x', xm, alpha) + + dens = density(X) + + #Tests cdf function + assert cdf(X)(x) == \ + Piecewise((-x**(-beta - 5)*xm**(beta + 5) + 1, x >= xm), (0, True)) + + #Tests characteristic_function + assert characteristic_function(X)(x) == \ + ((-I*x*xm)**(beta + 5)*(beta + 5)*uppergamma(-beta - 5, -I*x*xm)) + + assert dens(x) == x**(-(alpha + 1))*xm**(alpha)*(alpha) + + assert simplify(E(X)) == alpha*xm/(alpha-1) + + # computation of taylor series for MGF still too slow + #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 median(X) == FiniteSet(3*2**Rational(1, 7)) + # Skewness tests too slow. Try shortcutting function? + + +def test_PowerFunction(): + alpha = Symbol("alpha", nonpositive=True) + a, b = symbols('a, b', real=True) + raises (ValueError, lambda: PowerFunction('x', alpha, a, b)) + + a, b = symbols('a, b', real=False) + raises (ValueError, lambda: PowerFunction('x', alpha, a, b)) + + alpha = Symbol("alpha", positive=True) + a, b = symbols('a, b', real=True) + raises (ValueError, lambda: PowerFunction('x', alpha, 5, 2)) + + X = PowerFunction('X', 2, a, b) + assert density(X)(z) == (-2*a + 2*z)/(-a + b)**2 + assert cdf(X)(z) == Piecewise((a**2/(a**2 - 2*a*b + b**2) - + 2*a*z/(a**2 - 2*a*b + b**2) + z**2/(a**2 - 2*a*b + b**2), a <= z), (0, True)) + + X = PowerFunction('X', 2, 0, 1) + assert density(X)(z) == 2*z + assert cdf(X)(z) == Piecewise((z**2, z >= 0), (0,True)) + assert E(X) == Rational(2,3) + assert P(X < 0) == 0 + assert P(X < 1) == 1 + assert median(X) == FiniteSet(1/sqrt(2)) + +def test_raised_cosine(): + mu = Symbol("mu", real=True) + s = Symbol("s", positive=True) + + X = RaisedCosine("x", mu, s) + + assert pspace(X).domain.set == Interval(mu - s, mu + s) + #Tests characteristics_function + assert characteristic_function(X)(x) == \ + Piecewise((exp(-I*pi*mu/s)/2, Eq(x, -pi/s)), (exp(I*pi*mu/s)/2, Eq(x, pi/s)), (pi**2*exp(I*mu*x)*sin(s*x)/(s*x*(-s**2*x**2 + pi**2)), True)) + + 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) + + #Tests characteristic_function + assert characteristic_function(X)(x) == (-sqrt(2)*sqrt(pi)*sigma*x*(erfi(sqrt(2)*sigma*x/2) - I)*exp(-sigma**2*x**2/2)/2 + 1) + + 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 + assert cdf(X)(x) == 1 - exp(-x**2/(2*sigma**2)) + assert diff(cdf(X)(x), x) == density(X)(x) + +def test_reciprocal(): + a = Symbol("a", real=True) + b = Symbol("b", real=True) + + X = Reciprocal('x', a, b) + assert density(X)(x) == 1/(x*(-log(a) + log(b))) + assert cdf(X)(x) == Piecewise((log(a)/(log(a) - log(b)) - log(x)/(log(a) - log(b)), a <= x), (0, True)) + X = Reciprocal('x', 5, 30) + + assert E(X) == 25/(log(30) - log(5)) + assert P(X < 4) == S.Zero + assert P(X < 20) == log(20) / (log(30) - log(5)) - log(5) / (log(30) - log(5)) + assert cdf(X)(10) == log(10) / (log(30) - log(5)) - log(5) / (log(30) - log(5)) + + a = symbols('a', nonpositive=True) + raises(ValueError, lambda: Reciprocal('x', a, b)) + + a = symbols('a', positive=True) + b = symbols('b', positive=True) + raises(ValueError, lambda: Reciprocal('x', a + b, a)) + +def test_shiftedgompertz(): + b = Symbol("b", positive=True) + eta = Symbol("eta", positive=True) + X = ShiftedGompertz("x", b, eta) + assert density(X)(x) == b*(eta*(1 - exp(-b*x)) + 1)*exp(-b*x)*exp(-eta*exp(-b*x)) + + +def test_studentt(): + nu = Symbol("nu", positive=True) + + X = StudentT('x', nu) + assert density(X)(x) == (1 + x**2/nu)**(-nu/2 - S.Half)/(sqrt(nu)*beta(S.Half, nu/2)) + assert cdf(X)(x) == S.Half + x*gamma(nu/2 + S.Half)*hyper((S.Half, nu/2 + S.Half), + (Rational(3, 2),), -x**2/nu)/(sqrt(pi)*sqrt(nu)*gamma(nu/2)) + raises(NotImplementedError, lambda: moment_generating_function(X)) + +def test_trapezoidal(): + a = Symbol("a", real=True) + b = Symbol("b", real=True) + c = Symbol("c", real=True) + d = Symbol("d", real=True) + + X = Trapezoidal('x', a, b, c, d) + assert density(X)(x) == Piecewise(((-2*a + 2*x)/((-a + b)*(-a - b + c + d)), (a <= x) & (x < b)), + (2/(-a - b + c + d), (b <= x) & (x < c)), + ((2*d - 2*x)/((-c + d)*(-a - b + c + d)), (c <= x) & (x <= d)), + (0, True)) + + X = Trapezoidal('x', 0, 1, 2, 3) + assert E(X) == Rational(3, 2) + assert variance(X) == Rational(5, 12) + assert P(X < 2) == Rational(3, 4) + assert median(X) == FiniteSet(Rational(3, 2)) + +def test_triangular(): + a = Symbol("a") + b = Symbol("b") + c = Symbol("c") + + X = Triangular('x', a, b, c) + assert pspace(X).domain.set == Interval(a, b) + assert str(density(X)(x)) == ("Piecewise(((-2*a + 2*x)/((-a + b)*(-a + c)), (a <= x) & (c > x)), " + "(2/(-a + b), Eq(c, x)), ((2*b - 2*x)/((-a + b)*(b - c)), (b >= x) & (c < x)), (0, True))") + + #Tests moment_generating_function + assert moment_generating_function(X)(x).expand() == \ + ((-2*(-a + b)*exp(c*x) + 2*(-a + c)*exp(b*x) + 2*(b - c)*exp(a*x))/(x**2*(-a + b)*(-a + c)*(b - c))).expand() + assert str(characteristic_function(X)(x)) == \ + '(2*(-a + b)*exp(I*c*x) - 2*(-a + c)*exp(I*b*x) - 2*(b - c)*exp(I*a*x))/(x**2*(-a + b)*(-a + c)*(b - c))' + +def test_quadratic_u(): + a = Symbol("a", real=True) + b = Symbol("b", real=True) + + X = QuadraticU("x", a, b) + Y = QuadraticU("x", 1, 2) + + assert pspace(X).domain.set == Interval(a, b) + # Tests _moment_generating_function + assert moment_generating_function(Y)(1) == -15*exp(2) + 27*exp(1) + assert moment_generating_function(Y)(2) == -9*exp(4)/2 + 21*exp(2)/2 + + assert characteristic_function(Y)(1) == 3*I*(-1 + 4*I)*exp(I*exp(2*I)) + 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) + w = Symbol('w', positive=True) + X = Uniform('x', l, l + w) + + assert E(X) == l + w/2 + assert variance(X).expand() == w**2/12 + + # 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 median(X) == FiniteSet(4) + + z = Symbol('z') + p = density(X)(z) + assert p.subs(z, 3.7) == S.Half + assert p.subs(z, -1) == 0 + assert p.subs(z, 6) == 0 + + c = cdf(X) + assert c(2) == 0 and c(3) == 0 + assert c(Rational(7, 2)) == Rational(1, 4) + assert c(5) == 1 and c(6) == 1 + + +@XFAIL +@slow +def test_uniform_P(): + """ This stopped working because SingleContinuousPSpace.compute_density no + longer calls integrate on a DiracDelta but rather just solves directly. + integrate used to call UniformDistribution.expectation which special-cased + subsed out the Min and Max terms that Uniform produces + + I decided to regress on this class for general cleanliness (and I suspect + speed) of the algorithm. + """ + l = Symbol('l', real=True) + w = Symbol('w', positive=True) + X = Uniform('x', l, l + w) + assert P(X < l) == 0 and P(X > l + w) == 0 + + +def test_uniformsum(): + n = Symbol("n", integer=True) + _k = Dummy("k") + x = Symbol("x") + + X = UniformSum('x', n) + res = Sum((-1)**_k*(-_k + x)**(n - 1)*binomial(n, _k), (_k, 0, floor(x)))/factorial(n - 1) + assert density(X)(x).dummy_eq(res) + + #Tests set functions + assert X.pspace.domain.set == Interval(0, n) + + #Tests the characteristic_function + assert characteristic_function(X)(x) == (-I*(exp(I*x) - 1)/x)**n + + #Tests the moment_generating_function + assert moment_generating_function(X)(x) == ((exp(x) - 1)/x)**n + + +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) + # FIXME: simplify(E(X)) seems to hang without extended_positive=True + # On a Linux machine this had a rapid memory leak... + # a, b = symbols('a b', positive=True) + X = Weibull('x', a, b) + + assert E(X).expand() == a * gamma(1 + 1/b) + assert variance(X).expand() == (a**2 * gamma(1 + 2/b) - E(X)**2).expand() + assert simplify(skewness(X)) == (2*gamma(1 + 1/b)**3 - 3*gamma(1 + 1/b)*gamma(1 + 2/b) + gamma(1 + 3/b))/(-gamma(1 + 1/b)**2 + gamma(1 + 2/b))**Rational(3, 2) + assert simplify(kurtosis(X)) == (-3*gamma(1 + 1/b)**4 +\ + 6*gamma(1 + 1/b)**2*gamma(1 + 2/b) - 4*gamma(1 + 1/b)*gamma(1 + 3/b) + gamma(1 + 4/b))/(gamma(1 + 1/b)**2 - gamma(1 + 2/b))**2 + +def test_weibull_numeric(): + # Test for integers and rationals + a = 1 + bvals = [S.Half, 1, Rational(3, 2), 5] + for b in bvals: + X = Weibull('x', a, b) + assert simplify(E(X)) == expand_func(a * gamma(1 + 1/S(b))) + assert simplify(variance(X)) == simplify( + 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 pspace(X).domain.set == Interval(-R, R) + assert density(X)(x) == 2*sqrt(-x**2 + R**2)/(pi*R**2) + assert E(X) == 0 + + + #Tests ChiNoncentralDistribution + assert characteristic_function(X)(x) == \ + Piecewise((2*besselj(1, R*x)/(R*x), Ne(x, 0)), (1, True)) + + +def test_input_value_assertions(): + a, b = symbols('a b') + p, q = symbols('p q', positive=True) + m, n = symbols('m n', positive=False, real=True) + + raises(ValueError, lambda: Normal('x', 3, 0)) + raises(ValueError, lambda: Normal('x', m, n)) + Normal('X', a, p) # No error raised + raises(ValueError, lambda: Exponential('x', m)) + Exponential('Ex', p) # No error raised + for fn in [Pareto, Weibull, Beta, Gamma]: + raises(ValueError, lambda: fn('x', m, p)) + raises(ValueError, lambda: fn('x', p, n)) + fn('x', p, q) # No error raised + + +def test_unevaluated(): + X = Normal('x', 0, 1) + k = Dummy('k') + expr1 = Integral(sqrt(2)*k*exp(-k**2/2)/(2*sqrt(pi)), (k, -oo, oo)) + expr2 = Integral(sqrt(2)*exp(-k**2/2)/(2*sqrt(pi)), (k, 0, oo)) + with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed + assert E(X, evaluate=False).rewrite(Integral).dummy_eq(expr1) + assert E(X + 1, evaluate=False).rewrite(Integral).dummy_eq(expr1 + 1) + assert P(X > 0, evaluate=False).rewrite(Integral).dummy_eq(expr2) + + assert P(X > 0, X**2 < 1) == S.Half + + +def test_probability_unevaluated(): + T = Normal('T', 30, 3) + with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed + assert type(P(T > 33, evaluate=False)) == Probability + + +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.Half + assert nd.expectation(1, x) == 1 + assert nd.expectation(x, x) == 0 + assert nd.expectation(x**2, x) == 1 + #Test issue 10076 + a = SingleContinuousPSpace(x, NormalDistribution(2, 4)) + _z = Dummy('_z') + + expected1 = Integral(sqrt(2)*exp(-(_z - 2)**2/32)/(8*sqrt(pi)),(_z, -oo, 1)) + assert a.probability(x < 1, evaluate=False).dummy_eq(expected1) is True + + expected2 = Integral(sqrt(2)*exp(-(_z - 2)**2/32)/(8*sqrt(pi)),(_z, 1, oo)) + assert a.probability(x > 1, evaluate=False).dummy_eq(expected2) is True + + b = SingleContinuousPSpace(x, NormalDistribution(1, 9)) + + expected3 = Integral(sqrt(2)*exp(-(_z - 1)**2/162)/(18*sqrt(pi)),(_z, 6, oo)) + assert b.probability(x > 6, evaluate=False).dummy_eq(expected3) is True + + expected4 = Integral(sqrt(2)*exp(-(_z - 1)**2/162)/(18*sqrt(pi)),(_z, -oo, 6)) + assert b.probability(x < 6, evaluate=False).dummy_eq(expected4) is True + + +def test_random_parameters(): + mu = Normal('mu', 2, 3) + meas = Normal('T', mu, 1) + assert density(meas, evaluate=False)(z) + assert isinstance(pspace(meas), CompoundPSpace) + X = Normal('x', [1, 2], [[1, 0], [0, 1]]) + assert isinstance(pspace(X).distribution, MultivariateNormalDistribution) + assert density(meas)(z).simplify() == sqrt(5)*exp(-z**2/20 + z/5 - S(1)/5)/(10*sqrt(pi)) + + +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)), + Mul) + + +def test_difficult_univariate(): + """ Since using solve in place of deltaintegrate we're able to perform + substantially more complex density computations on single continuous random + variables """ + x = Normal('x', 0, 1) + assert density(x**3) + assert density(exp(x**2)) + assert density(log(x)) + + +def test_issue_10003(): + X = Exponential('x', 3) + G = Gamma('g', 1, 2) + assert P(X < -1) is S.Zero + assert P(G < -1) is S.Zero + + +def test_precomputed_cdf(): + x = symbols("x", real=True) + mu = symbols("mu", real=True) + sigma, xm, alpha = symbols("sigma xm alpha", positive=True) + n = symbols("n", integer=True, positive=True) + distribs = [ + Normal("X", mu, sigma), + Pareto("P", xm, alpha), + ChiSquared("C", n), + Exponential("E", sigma), + # LogNormal("L", mu, sigma), + ] + for X in distribs: + compdiff = cdf(X)(x) - simplify(X.pspace.density.compute_cdf()(x)) + compdiff = simplify(compdiff.rewrite(erfc)) + assert compdiff == 0 + + +@slow +def test_precomputed_characteristic_functions(): + import mpmath + + def test_cf(dist, support_lower_limit, support_upper_limit): + pdf = density(dist) + t = Symbol('t') + + # first function is the hardcoded CF of the distribution + cf1 = lambdify([t], characteristic_function(dist)(t), 'mpmath') + + # second function is the Fourier transform of the density function + f = lambdify([x, t], pdf(x)*exp(I*x*t), 'mpmath') + cf2 = lambda t: mpmath.quad(lambda x: f(x, t), [support_lower_limit, support_upper_limit], maxdegree=10) + + # compare the two functions at various points + for test_point in [2, 5, 8, 11]: + n1 = cf1(test_point) + n2 = cf2(test_point) + + assert abs(re(n1) - re(n2)) < 1e-12 + assert abs(im(n1) - im(n2)) < 1e-12 + + test_cf(Beta('b', 1, 2), 0, 1) + test_cf(Chi('c', 3), 0, mpmath.inf) + test_cf(ChiSquared('c', 2), 0, mpmath.inf) + test_cf(Exponential('e', 6), 0, mpmath.inf) + test_cf(Logistic('l', 1, 2), -mpmath.inf, mpmath.inf) + test_cf(Normal('n', -1, 5), -mpmath.inf, mpmath.inf) + test_cf(RaisedCosine('r', 3, 1), 2, 4) + test_cf(Rayleigh('r', 0.5), 0, mpmath.inf) + test_cf(Uniform('u', -1, 1), -1, 1) + test_cf(WignerSemicircle('w', 3), -3, 3) + + +def test_long_precomputed_cdf(): + x = symbols("x", real=True) + distribs = [ + Arcsin("A", -5, 9), + Dagum("D", 4, 10, 3), + Erlang("E", 14, 5), + Frechet("F", 2, 6, -3), + Gamma("G", 2, 7), + GammaInverse("GI", 3, 5), + Kumaraswamy("K", 6, 8), + Laplace("LA", -5, 4), + Logistic("L", -6, 7), + Nakagami("N", 2, 7), + StudentT("S", 4) + ] + for distr in distribs: + for _ in range(5): + assert tn(diff(cdf(distr)(x), x), density(distr)(x), x, a=0, b=0, c=1, d=0) + + US = UniformSum("US", 5) + pdf01 = density(US)(x).subs(floor(x), 0).doit() # pdf on (0, 1) + cdf01 = cdf(US, evaluate=False)(x).subs(floor(x), 0).doit() # cdf on (0, 1) + assert tn(diff(cdf01, x), pdf01, x, a=0, b=0, c=1, d=0) + + +def test_issue_13324(): + X = Uniform('X', 0, 1) + assert E(X, X > S.Half) == Rational(3, 4) + assert E(X, X > 0) == S.Half + +def test_issue_20756(): + X = Uniform('X', -1, +1) + Y = Uniform('Y', -1, +1) + assert E(X * Y) == S.Zero + assert E(X * ((Y + 1) - 1)) == S.Zero + assert E(Y * (X*(X + 1) - X*X)) == S.Zero + +def test_FiniteSet_prob(): + E = Exponential('E', 3) + N = Normal('N', 5, 7) + assert P(Eq(E, 1)) is S.Zero + assert P(Eq(N, 2)) is S.Zero + assert P(Eq(N, x)) is S.Zero + +def test_prob_neq(): + E = Exponential('E', 4) + X = ChiSquared('X', 4) + assert P(Ne(E, 2)) == 1 + assert P(Ne(X, 4)) == 1 + assert P(Ne(X, 4)) == 1 + assert P(Ne(X, 5)) == 1 + assert P(Ne(E, x)) == 1 + +def test_union(): + N = Normal('N', 3, 2) + assert simplify(P(N**2 - N > 2)) == \ + -erf(sqrt(2))/2 - erfc(sqrt(2)/4)/2 + Rational(3, 2) + assert simplify(P(N**2 - 4 > 0)) == \ + -erf(5*sqrt(2)/4)/2 - erfc(sqrt(2)/4)/2 + Rational(3, 2) + +def test_Or(): + N = Normal('N', 0, 1) + assert simplify(P(Or(N > 2, N < 1))) == \ + -erf(sqrt(2))/2 - erfc(sqrt(2)/2)/2 + Rational(3, 2) + assert P(Or(N < 0, N < 1)) == P(N < 1) + assert P(Or(N > 0, N < 0)) == 1 + + +def test_conditional_eq(): + E = Exponential('E', 1) + assert P(Eq(E, 1), Eq(E, 1)) == 1 + assert P(Eq(E, 1), Eq(E, 2)) == 0 + assert P(E > 1, Eq(E, 2)) == 1 + assert P(E < 1, Eq(E, 2)) == 0 + +def test_ContinuousDistributionHandmade(): + x = Symbol('x') + z = Dummy('z') + dens = Lambda(x, Piecewise((S.Half, (0<=x)&(x<1)), (0, (x>=1)&(x<2)), + (S.Half, (x>=2)&(x<3)), (0, True))) + dens = ContinuousDistributionHandmade(dens, set=Interval(0, 3)) + space = SingleContinuousPSpace(z, dens) + assert dens.pdf == Lambda(x, Piecewise((S(1)/2, (x >= 0) & (x < 1)), + (0, (x >= 1) & (x < 2)), (S(1)/2, (x >= 2) & (x < 3)), (0, True))) + assert median(space.value) == Interval(1, 2) + assert E(space.value) == Rational(3, 2) + assert variance(space.value) == Rational(13, 12) + + +def test_issue_16318(): + # test compute_expectation function of the SingleContinuousDomain + N = SingleContinuousDomain(x, Interval(0, 1)) + raises(ValueError, lambda: SingleContinuousDomain.compute_expectation(N, x+1, {x, y})) + +def test_compute_density(): + X = Normal('X', 0, Symbol("sigma")**2) + raises(ValueError, lambda: density(X**5 + X)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_discrete_rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_discrete_rv.py new file mode 100644 index 0000000000000000000000000000000000000000..39650a1a08e42840aaf8b06c1eb6e60c92a57f23 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_discrete_rv.py @@ -0,0 +1,312 @@ +from sympy.concrete.summations import Sum +from sympy.core.numbers import (I, Rational, oo, pi) +from sympy.core.singleton import S +from sympy.core.symbol import Symbol +from sympy.functions.elementary.complexes import (im, re) +from sympy.functions.elementary.exponential import log +from sympy.functions.elementary.integers import floor +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.special.bessel import besseli +from sympy.functions.special.beta_functions import beta +from sympy.functions.special.zeta_functions import zeta +from sympy.sets.sets import FiniteSet +from sympy.simplify.simplify import simplify +from sympy.utilities.lambdify import lambdify +from sympy.core.relational import Eq, Ne +from sympy.functions.elementary.exponential import exp +from sympy.logic.boolalg import Or +from sympy.sets.fancysets import Range +from sympy.stats import (P, E, variance, density, characteristic_function, + where, moment_generating_function, skewness, cdf, + kurtosis, coskewness) +from sympy.stats.drv_types import (PoissonDistribution, GeometricDistribution, + FlorySchulz, Poisson, Geometric, Hermite, Logarithmic, + NegativeBinomial, Skellam, YuleSimon, Zeta, + DiscreteRV) +from sympy.testing.pytest import slow, nocache_fail, raises, skip +from sympy.stats.symbolic_probability import Expectation +from sympy.functions.combinatorial.factorials import FallingFactorial + +x = Symbol('x') + + +def test_PoissonDistribution(): + l = 3 + p = PoissonDistribution(l) + assert abs(p.cdf(10).evalf() - 1) < .001 + assert abs(p.cdf(10.4).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 E(2*x) == 2*l + assert variance(x) == l + assert density(x) == PoissonDistribution(l) + assert isinstance(E(x, evaluate=False), Expectation) + assert isinstance(E(2*x, evaluate=False), Expectation) + # issue 8248 + assert x.pspace.compute_expectation(1) == 1 + # issue 27344 + try: + import numpy as np + except ImportError: + skip("numpy not installed") + y = Poisson('y', np.float64(4.72544290380919e-11)) + assert E(y) == 4.72544290380919e-11 + y = Poisson('y', np.float64(4.725442903809197e-11)) + assert E(y) == 4.725442903809197e-11 + l2 = 5 + z = Poisson('z', l2) + assert E(z) == l2 + assert E(FallingFactorial(z, 3)) == l2**3 + assert E(z**2) == l2 + l2**2 + + +def test_FlorySchulz(): + a = Symbol("a") + z = Symbol("z") + x = FlorySchulz('x', a) + assert E(x) == (2 - a)/a + assert (variance(x) - 2*(1 - a)/a**2).simplify() == S(0) + assert density(x)(z) == a**2*z*(1 - a)**(z - 1) + + +@slow +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 + assert abs(d.cdf(20000.8).evalf() - 1) < .001 + G = Geometric('G', p=S(1)/4) + assert cdf(G)(S(7)/2) == P(G <= S(7)/2) + + X = Geometric('X', Rational(1, 5)) + Y = Geometric('Y', Rational(3, 10)) + assert coskewness(X, X + Y, X + 2*Y).simplify() == sqrt(230)*Rational(81, 1150) + + +def test_Hermite(): + a1 = Symbol("a1", positive=True) + a2 = Symbol("a2", negative=True) + raises(ValueError, lambda: Hermite("H", a1, a2)) + + a1 = Symbol("a1", negative=True) + a2 = Symbol("a2", positive=True) + raises(ValueError, lambda: Hermite("H", a1, a2)) + + a1 = Symbol("a1", positive=True) + x = Symbol("x") + H = Hermite("H", a1, a2) + assert moment_generating_function(H)(x) == exp(a1*(exp(x) - 1) + + a2*(exp(2*x) - 1)) + assert characteristic_function(H)(x) == exp(a1*(exp(I*x) - 1) + + a2*(exp(2*I*x) - 1)) + assert E(H) == a1 + 2*a2 + + H = Hermite("H", a1=5, a2=4) + assert density(H)(2) == 33*exp(-9)/2 + assert E(H) == 13 + assert variance(H) == 21 + assert kurtosis(H) == Rational(464,147) + assert skewness(H) == 37*sqrt(21)/441 + +def test_Logarithmic(): + p = S.Half + x = Logarithmic('x', p) + assert E(x) == -p / ((1 - p) * log(1 - p)) + assert variance(x) == -1/log(2)**2 + 2/log(2) + assert E(2*x**2 + 3*x + 4) == 4 + 7 / log(2) + assert isinstance(E(x, evaluate=False), Expectation) + + +@nocache_fail +def test_negative_binomial(): + r = 5 + p = S.One / 3 + x = NegativeBinomial('x', r, p) + assert E(x) == r * (1 - p) / p + # This hangs when run with the cache disabled: + assert variance(x) == r * (1 - p) / p**2 + assert E(x**5 + 2*x + 3) == E(x**5) + 2*E(x) + 3 == Rational(796473, 1) + assert isinstance(E(x, evaluate=False), Expectation) + + +def test_skellam(): + mu1 = Symbol('mu1') + mu2 = Symbol('mu2') + z = Symbol('z') + X = Skellam('x', mu1, mu2) + + assert density(X)(z) == (mu1/mu2)**(z/2) * \ + exp(-mu1 - mu2)*besseli(z, 2*sqrt(mu1*mu2)) + assert skewness(X).expand() == mu1/(mu1*sqrt(mu1 + mu2) + mu2 * + sqrt(mu1 + mu2)) - mu2/(mu1*sqrt(mu1 + mu2) + mu2*sqrt(mu1 + mu2)) + assert variance(X).expand() == mu1 + mu2 + assert E(X) == mu1 - mu2 + assert characteristic_function(X)(z) == exp( + mu1*exp(I*z) - mu1 - mu2 + mu2*exp(-I*z)) + assert moment_generating_function(X)(z) == exp( + mu1*exp(z) - mu1 - mu2 + mu2*exp(-z)) + + +def test_yule_simon(): + from sympy.core.singleton import S + rho = S(3) + x = YuleSimon('x', rho) + assert simplify(E(x)) == rho / (rho - 1) + assert simplify(variance(x)) == rho**2 / ((rho - 1)**2 * (rho - 2)) + assert isinstance(E(x, evaluate=False), Expectation) + # To test the cdf function + assert cdf(x)(x) == Piecewise((-beta(floor(x), 4)*floor(x) + 1, x >= 1), (0, True)) + + +def test_zeta(): + s = S(5) + x = Zeta('x', s) + assert E(x) == zeta(s-1) / zeta(s) + assert simplify(variance(x)) == ( + zeta(s) * zeta(s-2) - zeta(s-1)**2) / zeta(s)**2 + + +def test_discrete_probability(): + X = Geometric('X', Rational(1, 5)) + Y = Poisson('Y', 4) + G = Geometric('e', x) + assert P(Eq(X, 3)) == Rational(16, 125) + assert P(X < 3) == Rational(9, 25) + assert P(X > 3) == Rational(64, 125) + assert P(X >= 3) == Rational(16, 25) + assert P(X <= 3) == Rational(61, 125) + assert P(Ne(X, 3)) == Rational(109, 125) + assert P(Eq(Y, 3)) == 32*exp(-4)/3 + assert P(Y < 3) == 13*exp(-4) + assert P(Y > 3).equals(32*(Rational(-71, 32) + 3*exp(4)/32)*exp(-4)/3) + assert P(Y >= 3).equals(32*(Rational(-39, 32) + 3*exp(4)/32)*exp(-4)/3) + assert P(Y <= 3) == 71*exp(-4)/3 + assert P(Ne(Y, 3)).equals( + 13*exp(-4) + 32*(Rational(-71, 32) + 3*exp(4)/32)*exp(-4)/3) + assert P(X < S.Infinity) is S.One + assert P(X > S.Infinity) is S.Zero + assert P(G < 3) == x*(2-x) + assert P(Eq(G, 3)) == x*(-x + 1)**2 + + +def test_DiscreteRV(): + p = S(1)/2 + x = Symbol('x', integer=True, positive=True) + pdf = p*(1 - p)**(x - 1) # pdf of Geometric Distribution + D = DiscreteRV(x, pdf, set=S.Naturals, check=True) + assert E(D) == E(Geometric('G', S(1)/2)) == 2 + assert P(D > 3) == S(1)/8 + assert D.pspace.domain.set == S.Naturals + raises(ValueError, lambda: DiscreteRV(x, x, FiniteSet(*range(4)), check=True)) + + # purposeful invalid pmf but it should not raise since check=False + # see test_drv_types.test_ContinuousRV for explanation + X = DiscreteRV(x, 1/x, S.Naturals) + assert P(X < 2) == 1 + assert E(X) == oo + +def test_precomputed_characteristic_functions(): + import mpmath + + def test_cf(dist, support_lower_limit, support_upper_limit): + pdf = density(dist) + t = S('t') + x = S('x') + + # first function is the hardcoded CF of the distribution + cf1 = lambdify([t], characteristic_function(dist)(t), 'mpmath') + + # second function is the Fourier transform of the density function + f = lambdify([x, t], pdf(x)*exp(I*x*t), 'mpmath') + cf2 = lambda t: mpmath.nsum(lambda x: f(x, t), [ + support_lower_limit, support_upper_limit], maxdegree=10) + + # compare the two functions at various points + for test_point in [2, 5, 8, 11]: + n1 = cf1(test_point) + n2 = cf2(test_point) + + assert abs(re(n1) - re(n2)) < 1e-12 + assert abs(im(n1) - im(n2)) < 1e-12 + + test_cf(Geometric('g', Rational(1, 3)), 1, mpmath.inf) + test_cf(Logarithmic('l', Rational(1, 5)), 1, mpmath.inf) + test_cf(NegativeBinomial('n', 5, Rational(1, 7)), 0, mpmath.inf) + test_cf(Poisson('p', 5), 0, mpmath.inf) + test_cf(YuleSimon('y', 5), 1, mpmath.inf) + test_cf(Zeta('z', 5), 1, mpmath.inf) + + +def test_moment_generating_functions(): + t = S('t') + + geometric_mgf = moment_generating_function(Geometric('g', S.Half))(t) + assert geometric_mgf.diff(t).subs(t, 0) == 2 + + logarithmic_mgf = moment_generating_function(Logarithmic('l', S.Half))(t) + assert logarithmic_mgf.diff(t).subs(t, 0) == 1/log(2) + + negative_binomial_mgf = moment_generating_function( + NegativeBinomial('n', 5, Rational(1, 3)))(t) + assert negative_binomial_mgf.diff(t).subs(t, 0) == Rational(10, 1) + + poisson_mgf = moment_generating_function(Poisson('p', 5))(t) + assert poisson_mgf.diff(t).subs(t, 0) == 5 + + skellam_mgf = moment_generating_function(Skellam('s', 1, 1))(t) + assert skellam_mgf.diff(t).subs( + t, 2) == (-exp(-2) + exp(2))*exp(-2 + exp(-2) + exp(2)) + + yule_simon_mgf = moment_generating_function(YuleSimon('y', 3))(t) + assert simplify(yule_simon_mgf.diff(t).subs(t, 0)) == Rational(3, 2) + + zeta_mgf = moment_generating_function(Zeta('z', 5))(t) + assert zeta_mgf.diff(t).subs(t, 0) == pi**4/(90*zeta(5)) + + +def test_Or(): + X = Geometric('X', S.Half) + assert P(Or(X < 3, X > 4)) == Rational(13, 16) + assert P(Or(X > 2, X > 1)) == P(X > 1) + assert P(Or(X >= 3, X < 3)) == 1 + + +def test_where(): + X = Geometric('X', Rational(1, 5)) + Y = Poisson('Y', 4) + assert where(X**2 > 4).set == Range(3, S.Infinity, 1) + assert where(X**2 >= 4).set == Range(2, S.Infinity, 1) + assert where(Y**2 < 9).set == Range(0, 3, 1) + assert where(Y**2 <= 9).set == Range(0, 4, 1) + + +def test_conditional(): + X = Geometric('X', Rational(2, 3)) + Y = Poisson('Y', 3) + assert P(X > 2, X > 3) == 1 + assert P(X > 3, X > 2) == Rational(1, 3) + assert P(Y > 2, Y < 2) == 0 + assert P(Eq(Y, 3), Y >= 0) == 9*exp(-3)/2 + assert P(Eq(Y, 3), Eq(Y, 2)) == 0 + assert P(X < 2, Eq(X, 2)) == 0 + assert P(X > 2, Eq(X, 3)) == 1 + + +def test_product_spaces(): + X1 = Geometric('X1', S.Half) + X2 = Geometric('X2', Rational(1, 3)) + assert str(P(X1 + X2 < 3).rewrite(Sum)) == ( + "Sum(Piecewise((1/(4*2**n), n >= -1), (0, True)), (n, -oo, -1))/3") + assert str(P(X1 + X2 > 3).rewrite(Sum)) == ( + 'Sum(Piecewise((2**(X2 - n - 2)*(2/3)**(X2 - 1)/6, ' + 'X2 - n <= 2), (0, True)), (X2, 1, oo), (n, 1, oo))') + assert P(Eq(X1 + X2, 3)) == Rational(1, 12) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_error_prop.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_error_prop.py new file mode 100644 index 0000000000000000000000000000000000000000..483fb4c36e202d744faeb355606ff9803a516873 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_error_prop.py @@ -0,0 +1,60 @@ +from sympy.core.function import Function +from sympy.core.symbol import symbols +from sympy.functions.elementary.exponential import exp +from sympy.stats.error_prop import variance_prop +from sympy.stats.symbolic_probability import (RandomSymbol, Variance, + Covariance) + + +def test_variance_prop(): + x, y, z = symbols('x y z') + phi, t = consts = symbols('phi t') + a = RandomSymbol(x) + var_x = Variance(a) + var_y = Variance(RandomSymbol(y)) + var_z = Variance(RandomSymbol(z)) + f = Function('f')(x) + cases = { + x + y: var_x + var_y, + a + y: var_x + var_y, + x + y + z: var_x + var_y + var_z, + 2*x: 4*var_x, + x*y: var_x*y**2 + var_y*x**2, + 1/x: var_x/x**4, + x/y: (var_x*y**2 + var_y*x**2)/y**4, + exp(x): var_x*exp(2*x), + exp(2*x): 4*var_x*exp(4*x), + exp(-x*t): t**2*var_x*exp(-2*t*x), + f: Variance(f), + } + for inp, out in cases.items(): + obs = variance_prop(inp, consts=consts) + assert out == obs + +def test_variance_prop_with_covar(): + x, y, z = symbols('x y z') + phi, t = consts = symbols('phi t') + a = RandomSymbol(x) + var_x = Variance(a) + b = RandomSymbol(y) + var_y = Variance(b) + c = RandomSymbol(z) + var_z = Variance(c) + covar_x_y = Covariance(a, b) + covar_x_z = Covariance(a, c) + covar_y_z = Covariance(b, c) + cases = { + x + y: var_x + var_y + 2*covar_x_y, + a + y: var_x + var_y + 2*covar_x_y, + x + y + z: var_x + var_y + var_z + \ + 2*covar_x_y + 2*covar_x_z + 2*covar_y_z, + 2*x: 4*var_x, + x*y: var_x*y**2 + var_y*x**2 + 2*covar_x_y/(x*y), + 1/x: var_x/x**4, + exp(x): var_x*exp(2*x), + exp(2*x): 4*var_x*exp(4*x), + exp(-x*t): t**2*var_x*exp(-2*t*x), + } + for inp, out in cases.items(): + obs = variance_prop(inp, consts=consts, include_covar=True) + assert out == obs diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_finite_rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_finite_rv.py new file mode 100644 index 0000000000000000000000000000000000000000..93bf0211a26ecc32d7f18c7e2d8236859857e445 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_finite_rv.py @@ -0,0 +1,509 @@ +from sympy.concrete.summations import Sum +from sympy.core.containers import (Dict, Tuple) +from sympy.core.function import Function +from sympy.core.numbers import (I, Rational, nan) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, Symbol, symbols) +from sympy.core.sympify import sympify +from sympy.functions.combinatorial.factorials import binomial +from sympy.functions.combinatorial.numbers import harmonic +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.elementary.trigonometric import cos +from sympy.functions.special.beta_functions import beta +from sympy.logic.boolalg import (And, Or) +from sympy.polys.polytools import cancel +from sympy.sets.sets import FiniteSet +from sympy.simplify.simplify import simplify +from sympy.matrices import Matrix +from sympy.stats import (DiscreteUniform, Die, Bernoulli, Coin, Binomial, BetaBinomial, + Hypergeometric, Rademacher, IdealSoliton, RobustSoliton, P, E, variance, + covariance, skewness, density, where, FiniteRV, pspace, cdf, + correlation, moment, cmoment, smoment, characteristic_function, + moment_generating_function, quantile, kurtosis, median, coskewness) +from sympy.stats.frv_types import DieDistribution, BinomialDistribution, \ + HypergeometricDistribution +from sympy.stats.rv import Density +from sympy.testing.pytest import raises + + +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, t = symbols('a b c t') + X = DiscreteUniform('X', [a, b, c]) + + 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', range(-5, 5)) + + # Numeric + assert E(Y) == S('-1/2') + assert variance(Y) == S('33/4') + assert median(Y) == FiniteSet(-1, 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 dict(density(Die('D', 6)).items()) == \ + dict(density(DiscreteUniform('U', range(1, 7))).items()) + + assert characteristic_function(X)(t) == exp(I*a*t)/3 + exp(I*b*t)/3 + exp(I*c*t)/3 + assert moment_generating_function(X)(t) == exp(a*t)/3 + exp(b*t)/3 + exp(c*t)/3 + # issue 18611 + raises(ValueError, lambda: DiscreteUniform('Z', [a, a, a, b, b, c])) + +def test_dice(): + # TODO: Make iid method! + X, Y, Z = Die('X', 6), Die('Y', 6), Die('Z', 6) + a, b, t, p = symbols('a b t p') + + assert E(X) == 3 + S.Half + assert variance(X) == Rational(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) == 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) is 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 + Y, 4) == kurtosis(X + Y) + assert smoment(X, 0) == 1 + assert P(X > 3) == S.Half + assert P(2*X > 6) == S.Half + assert P(X > Y) == Rational(5, 12) + assert P(Eq(X, Y)) == P(Eq(X, 1)) + + 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 quantile(X)(p) == Piecewise((nan, (p > 1) | (p < 0)),\ + (S.One, p <= Rational(1, 6)), (S(2), p <= Rational(1, 3)), (S(3), p <= S.Half),\ + (S(4), p <= Rational(2, 3)), (S(5), p <= Rational(5, 6)), (S(6), p <= 1)) + + assert P(X > 3, X > 3) is S.One + assert P(X > Y, Eq(Y, 6)) is S.Zero + assert P(Eq(X + Y, 12)) == Rational(1, 36) + assert P(Eq(X + Y, 12), Eq(X, 6)) == Rational(1, 6) + + assert density(X + Y) == density(Y + Z) != density(X + X) + d = density(2*X + Y**Z) + assert d[S(22)] == Rational(1, 108) and d[S(4100)] == Rational(1, 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]]) + + assert where(X > 3).set == FiniteSet(4, 5, 6) + + assert characteristic_function(X)(t) == exp(6*I*t)/6 + exp(5*I*t)/6 + exp(4*I*t)/6 + exp(3*I*t)/6 + exp(2*I*t)/6 + exp(I*t)/6 + assert moment_generating_function(X)(t) == exp(6*t)/6 + exp(5*t)/6 + exp(4*t)/6 + exp(3*t)/6 + exp(2*t)/6 + exp(t)/6 + assert median(X) == FiniteSet(3, 4) + D = Die('D', 7) + assert median(D) == FiniteSet(4) + # Bayes test for die + BayesTest(X > 3, X + Y < 5) + BayesTest(Eq(X - Y, Z), Z > Y) + BayesTest(X > 3, X > 2) + + # arg test for die + raises(ValueError, lambda: Die('X', -1)) # issue 8105: negative sides. + raises(ValueError, lambda: Die('X', 0)) + raises(ValueError, lambda: Die('X', 1.5)) # issue 8103: non integer sides. + + # symbolic test for die + n, k = symbols('n, k', positive=True) + D = Die('D', n) + dens = density(D).dict + assert dens == Density(DieDistribution(n)) + assert set(dens.subs(n, 4).doit().keys()) == {1, 2, 3, 4} + assert set(dens.subs(n, 4).doit().values()) == {Rational(1, 4)} + k = Dummy('k', integer=True) + assert E(D).dummy_eq( + Sum(Piecewise((k/n, k <= n), (0, True)), (k, 1, n))) + assert variance(D).subs(n, 6).doit() == Rational(35, 12) + + ki = Dummy('ki') + cumuf = cdf(D)(k) + assert cumuf.dummy_eq( + Sum(Piecewise((1/n, (ki >= 1) & (ki <= n)), (0, True)), (ki, 1, k))) + assert cumuf.subs({n: 6, k: 2}).doit() == Rational(1, 3) + + t = Dummy('t') + cf = characteristic_function(D)(t) + assert cf.dummy_eq( + Sum(Piecewise((exp(ki*I*t)/n, (ki >= 1) & (ki <= n)), (0, True)), (ki, 1, n))) + assert cf.subs(n, 3).doit() == exp(3*I*t)/3 + exp(2*I*t)/3 + exp(I*t)/3 + mgf = moment_generating_function(D)(t) + assert mgf.dummy_eq( + Sum(Piecewise((exp(ki*t)/n, (ki >= 1) & (ki <= n)), (0, True)), (ki, 1, n))) + assert mgf.subs(n, 3).doit() == exp(3*t)/3 + exp(2*t)/3 + exp(t)/3 + +def test_given(): + X = Die('X', 6) + assert density(X, X > 5) == {S(6): S.One} + assert where(X > 2, X > 5).as_boolean() == Eq(X.symbol, 6) + + +def test_domains(): + X, Y = Die('x', 6), Die('y', 6) + x, y = X.symbol, Y.symbol + # Domains + 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))) + assert len(d.elements) == 3 + + assert len(pspace(X + Y).domain.elements) == 36 + + Z = Die('x', 4) + + raises(ValueError, lambda: P(X > Z)) # Two domains with same internal symbol + + assert pspace(X + Y).domain.set == FiniteSet(1, 2, 3, 4, 5, 6)**2 + + 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)]) + + 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_bernoulli(): + p, a, b, t = symbols('p a b t') + X = Bernoulli('B', p, a, b) + + assert E(X) == a*p + b*(-p + 1) + assert density(X)[a] == p + assert density(X)[b] == 1 - p + assert characteristic_function(X)(t) == p * exp(I * a * t) + (-p + 1) * exp(I * b * t) + assert moment_generating_function(X)(t) == p * exp(a * t) + (-p + 1) * exp(b * t) + + X = Bernoulli('B', p, 1, 0) + z = Symbol("z") + + assert E(X) == p + assert simplify(variance(X)) == p*(1 - p) + assert E(a*X + b) == a*E(X) + b + assert simplify(variance(a*X + b)) == simplify(a**2 * variance(X)) + assert quantile(X)(z) == Piecewise((nan, (z > 1) | (z < 0)), (0, z <= 1 - p), (1, z <= 1)) + Y = Bernoulli('Y', Rational(1, 2)) + assert median(Y) == FiniteSet(0, 1) + Z = Bernoulli('Z', Rational(2, 3)) + assert median(Z) == FiniteSet(1) + raises(ValueError, lambda: Bernoulli('B', 1.5)) + raises(ValueError, lambda: Bernoulli('B', -0.5)) + + #issue 8248 + assert X.pspace.compute_expectation(1) == 1 + + p = Rational(1, 5) + X = Binomial('X', 5, p) + Y = Binomial('Y', 7, 2*p) + Z = Binomial('Z', 9, 3*p) + assert coskewness(Y + Z, X + Y, X + Z).simplify() == 0 + assert coskewness(Y + 2*X + Z, X + 2*Y + Z, X + 2*Z + Y).simplify() == \ + sqrt(1529)*Rational(12, 16819) + assert coskewness(Y + 2*X + Z, X + 2*Y + Z, X + 2*Z + Y, X < 2).simplify() \ + == -sqrt(357451121)*Rational(2812, 4646864573) + +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}) + + +def test_coins(): + C, D = Coin('C'), Coin('D') + H, T = symbols('H, T') + assert P(Eq(C, D)) == S.Half + assert density(Tuple(C, D)) == {(H, H): Rational(1, 4), (H, T): Rational(1, 4), + (T, H): Rational(1, 4), (T, T): Rational(1, 4)} + assert dict(density(C).items()) == {H: S.Half, T: S.Half} + + F = Coin('F', Rational(1, 10)) + assert P(Eq(F, H)) == Rational(1, 10) + + d = pspace(C).domain + + 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 + +def test_binomial_verify_parameters(): + raises(ValueError, lambda: Binomial('b', .2, .5)) + raises(ValueError, lambda: Binomial('b', 3, 1.5)) + +def test_binomial_numeric(): + nvals = range(5) + pvals = [0, Rational(1, 4), S.Half, Rational(3, 4), 1] + + for n in nvals: + for p in pvals: + X = Binomial('X', n, p) + assert E(X) == n*p + assert variance(X) == n*p*(1 - p) + if n > 0 and 0 < p < 1: + assert skewness(X) == (1 - 2*p)/sqrt(n*p*(1 - p)) + assert kurtosis(X) == 3 + (1 - 6*p*(1 - p))/(n*p*(1 - p)) + for k in range(n + 1): + assert P(Eq(X, k)) == binomial(n, k)*p**k*(1 - p)**(n - k) + +def test_binomial_quantile(): + X = Binomial('X', 50, S.Half) + assert quantile(X)(0.95) == S(31) + assert median(X) == FiniteSet(25) + + X = Binomial('X', 5, S.Half) + p = Symbol("p", positive=True) + assert quantile(X)(p) == Piecewise((nan, p > S.One), (S.Zero, p <= Rational(1, 32)),\ + (S.One, p <= Rational(3, 16)), (S(2), p <= S.Half), (S(3), p <= Rational(13, 16)),\ + (S(4), p <= Rational(31, 32)), (S(5), p <= S.One)) + assert median(X) == FiniteSet(2, 3) + + +def test_binomial_symbolic(): + n = 2 + p = symbols('p', positive=True) + X = Binomial('X', n, p) + t = Symbol('t') + + assert simplify(E(X)) == n*p == simplify(moment(X, 1)) + assert simplify(variance(X)) == n*p*(1 - p) == simplify(cmoment(X, 2)) + assert cancel(skewness(X) - (1 - 2*p)/sqrt(n*p*(1 - p))) == 0 + assert cancel((kurtosis(X)) - (3 + (1 - 6*p*(1 - p))/(n*p*(1 - p)))) == 0 + assert characteristic_function(X)(t) == p ** 2 * exp(2 * I * t) + 2 * p * (-p + 1) * exp(I * t) + (-p + 1) ** 2 + assert moment_generating_function(X)(t) == p ** 2 * exp(2 * t) + 2 * p * (-p + 1) * exp(t) + (-p + 1) ** 2 + + # Test ability to change success/failure winnings + H, T = symbols('H T') + Y = Binomial('Y', n, p, succ=H, fail=T) + assert simplify(E(Y) - (n*(H*p + T*(1 - p)))) == 0 + + # test symbolic dimensions + n = symbols('n') + B = Binomial('B', n, p) + raises(NotImplementedError, lambda: P(B > 2)) + assert density(B).dict == Density(BinomialDistribution(n, p, 1, 0)) + assert set(density(B).dict.subs(n, 4).doit().keys()) == \ + {S.Zero, S.One, S(2), S(3), S(4)} + assert set(density(B).dict.subs(n, 4).doit().values()) == \ + {(1 - p)**4, 4*p*(1 - p)**3, 6*p**2*(1 - p)**2, 4*p**3*(1 - p), p**4} + k = Dummy('k', integer=True) + assert E(B > 2).dummy_eq( + Sum(Piecewise((k*p**k*(1 - p)**(-k + n)*binomial(n, k), (k >= 0) + & (k <= n) & (k > 2)), (0, True)), (k, 0, n))) + +def test_beta_binomial(): + # verify parameters + raises(ValueError, lambda: BetaBinomial('b', .2, 1, 2)) + raises(ValueError, lambda: BetaBinomial('b', 2, -1, 2)) + raises(ValueError, lambda: BetaBinomial('b', 2, 1, -2)) + assert BetaBinomial('b', 2, 1, 1) + + # test numeric values + nvals = range(1,5) + alphavals = [Rational(1, 4), S.Half, Rational(3, 4), 1, 10] + betavals = [Rational(1, 4), S.Half, Rational(3, 4), 1, 10] + + for n in nvals: + for a in alphavals: + for b in betavals: + X = BetaBinomial('X', n, a, b) + assert E(X) == moment(X, 1) + assert variance(X) == cmoment(X, 2) + + # test symbolic + n, a, b = symbols('a b n') + assert BetaBinomial('x', n, a, b) + n = 2 # Because we're using for loops, can't do symbolic n + a, b = symbols('a b', positive=True) + X = BetaBinomial('X', n, a, b) + t = Symbol('t') + + assert E(X).expand() == moment(X, 1).expand() + assert variance(X).expand() == cmoment(X, 2).expand() + assert skewness(X) == smoment(X, 3) + assert characteristic_function(X)(t) == exp(2*I*t)*beta(a + 2, b)/beta(a, b) +\ + 2*exp(I*t)*beta(a + 1, b + 1)/beta(a, b) + beta(a, b + 2)/beta(a, b) + assert moment_generating_function(X)(t) == exp(2*t)*beta(a + 2, b)/beta(a, b) +\ + 2*exp(t)*beta(a + 1, b + 1)/beta(a, b) + beta(a, b + 2)/beta(a, b) + +def test_hypergeometric_numeric(): + for N in range(1, 5): + for m in range(0, N + 1): + for n in range(1, N + 1): + X = Hypergeometric('X', N, m, n) + N, m, n = 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) + # Only test for skewness when defined + if N > 2 and 0 < m < N and n < N: + assert skewness(X) == simplify((N - 2*m)*sqrt(N - 1)*(N - 2*n) + / (sqrt(n*m*(N - m)*(N - n))*(N - 2))) + +def test_hypergeometric_symbolic(): + N, m, n = symbols('N, m, n') + H = Hypergeometric('H', N, m, n) + dens = density(H).dict + expec = E(H > 2) + assert dens == Density(HypergeometricDistribution(N, m, n)) + assert dens.subs(N, 5).doit() == Density(HypergeometricDistribution(5, m, n)) + assert set(dens.subs({N: 3, m: 2, n: 1}).doit().keys()) == {S.Zero, S.One} + assert set(dens.subs({N: 3, m: 2, n: 1}).doit().values()) == {Rational(1, 3), Rational(2, 3)} + k = Dummy('k', integer=True) + assert expec.dummy_eq( + Sum(Piecewise((k*binomial(m, k)*binomial(N - m, -k + n) + /binomial(N, n), k > 2), (0, True)), (k, 0, n))) + +def test_rademacher(): + X = Rademacher('X') + t = Symbol('t') + + assert E(X) == 0 + assert variance(X) == 1 + assert density(X)[-1] == S.Half + assert density(X)[1] == S.Half + assert characteristic_function(X)(t) == exp(I*t)/2 + exp(-I*t)/2 + assert moment_generating_function(X)(t) == exp(t) / 2 + exp(-t) / 2 + +def test_ideal_soliton(): + raises(ValueError, lambda : IdealSoliton('sol', -12)) + raises(ValueError, lambda : IdealSoliton('sol', 13.2)) + raises(ValueError, lambda : IdealSoliton('sol', 0)) + f = Function('f') + raises(ValueError, lambda : density(IdealSoliton('sol', 10)).pmf(f)) + + k = Symbol('k', integer=True, positive=True) + x = Symbol('x', integer=True, positive=True) + t = Symbol('t') + sol = IdealSoliton('sol', k) + assert density(sol).low == S.One + assert density(sol).high == k + assert density(sol).dict == Density(density(sol)) + assert density(sol).pmf(x) == Piecewise((1/k, Eq(x, 1)), (1/(x*(x - 1)), k >= x), (0, True)) + + k_vals = [5, 20, 50, 100, 1000] + for i in k_vals: + assert E(sol.subs(k, i)) == harmonic(i) == moment(sol.subs(k, i), 1) + assert variance(sol.subs(k, i)) == (i - 1) + harmonic(i) - harmonic(i)**2 == cmoment(sol.subs(k, i),2) + assert skewness(sol.subs(k, i)) == smoment(sol.subs(k, i), 3) + assert kurtosis(sol.subs(k, i)) == smoment(sol.subs(k, i), 4) + + assert exp(I*t)/10 + Sum(exp(I*t*x)/(x*x - x), (x, 2, k)).subs(k, 10).doit() == characteristic_function(sol.subs(k, 10))(t) + assert exp(t)/10 + Sum(exp(t*x)/(x*x - x), (x, 2, k)).subs(k, 10).doit() == moment_generating_function(sol.subs(k, 10))(t) + +def test_robust_soliton(): + raises(ValueError, lambda : RobustSoliton('robSol', -12, 0.1, 0.02)) + raises(ValueError, lambda : RobustSoliton('robSol', 13, 1.89, 0.1)) + raises(ValueError, lambda : RobustSoliton('robSol', 15, 0.6, -2.31)) + f = Function('f') + raises(ValueError, lambda : density(RobustSoliton('robSol', 15, 0.6, 0.1)).pmf(f)) + + k = Symbol('k', integer=True, positive=True) + delta = Symbol('delta', positive=True) + c = Symbol('c', positive=True) + robSol = RobustSoliton('robSol', k, delta, c) + assert density(robSol).low == 1 + assert density(robSol).high == k + + k_vals = [10, 20, 50] + delta_vals = [0.2, 0.4, 0.6] + c_vals = [0.01, 0.03, 0.05] + for x in k_vals: + for y in delta_vals: + for z in c_vals: + assert E(robSol.subs({k: x, delta: y, c: z})) == moment(robSol.subs({k: x, delta: y, c: z}), 1) + assert variance(robSol.subs({k: x, delta: y, c: z})) == cmoment(robSol.subs({k: x, delta: y, c: z}), 2) + assert skewness(robSol.subs({k: x, delta: y, c: z})) == smoment(robSol.subs({k: x, delta: y, c: z}), 3) + assert kurtosis(robSol.subs({k: x, delta: y, c: z})) == smoment(robSol.subs({k: x, delta: y, c: z}), 4) + +def test_FiniteRV(): + F = FiniteRV('F', {1: S.Half, 2: Rational(1, 4), 3: Rational(1, 4)}, check=True) + p = Symbol("p", positive=True) + + assert dict(density(F).items()) == {S.One: S.Half, S(2): Rational(1, 4), S(3): Rational(1, 4)} + assert P(F >= 2) == S.Half + assert quantile(F)(p) == Piecewise((nan, p > S.One), (S.One, p <= S.Half),\ + (S(2), p <= Rational(3, 4)),(S(3), True)) + + assert pspace(F).domain.as_boolean() == Or( + *[Eq(F.symbol, i) for i in [1, 2, 3]]) + + assert F.pspace.domain.set == FiniteSet(1, 2, 3) + raises(ValueError, lambda: FiniteRV('F', {1: S.Half, 2: S.Half, 3: S.Half}, check=True)) + raises(ValueError, lambda: FiniteRV('F', {1: S.Half, 2: Rational(-1, 2), 3: S.One}, check=True)) + raises(ValueError, lambda: FiniteRV('F', {1: S.One, 2: Rational(3, 2), 3: S.Zero,\ + 4: Rational(-1, 2), 5: Rational(-3, 4), 6: Rational(-1, 4)}, check=True)) + + # purposeful invalid pmf but it should not raise since check=False + # see test_drv_types.test_ContinuousRV for explanation + X = FiniteRV('X', {1: 1, 2: 2}) + assert E(X) == 5 + assert P(X <= 2) + P(X > 2) != 1 + +def test_density_call(): + from sympy.abc import p + x = Bernoulli('x', p) + d = density(x) + assert d(0) == 1 - p + assert d(S.Zero) == 1 - p + assert d(5) == 0 + + assert 0 in d + assert 5 not in d + assert d(S.Zero) == d[S.Zero] + + +def test_DieDistribution(): + from sympy.abc import x + X = DieDistribution(6) + assert X.pmf(S.Half) is S.Zero + assert X.pmf(x).subs({x: 1}).doit() == Rational(1, 6) + assert X.pmf(x).subs({x: 7}).doit() == 0 + assert X.pmf(x).subs({x: -1}).doit() == 0 + assert X.pmf(x).subs({x: Rational(1, 3)}).doit() == 0 + raises(ValueError, lambda: X.pmf(Matrix([0, 0]))) + raises(ValueError, lambda: X.pmf(x**2 - 1)) + +def test_FinitePSpace(): + X = Die('X', 6) + space = pspace(X) + assert space.density == DieDistribution(6) + +def test_symbolic_conditions(): + B = Bernoulli('B', Rational(1, 4)) + D = Die('D', 4) + b, n = symbols('b, n') + Y = P(Eq(B, b)) + Z = E(D > n) + assert Y == \ + Piecewise((Rational(1, 4), Eq(b, 1)), (0, True)) + \ + Piecewise((Rational(3, 4), Eq(b, 0)), (0, True)) + assert Z == \ + Piecewise((Rational(1, 4), n < 1), (0, True)) + Piecewise((S.Half, n < 2), (0, True)) + \ + Piecewise((Rational(3, 4), n < 3), (0, True)) + Piecewise((S.One, n < 4), (0, True)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_joint_rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_joint_rv.py new file mode 100644 index 0000000000000000000000000000000000000000..057fc313dfbb31826b07fd1315205d22b86a7f96 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_joint_rv.py @@ -0,0 +1,436 @@ +from sympy.concrete.products import Product +from sympy.concrete.summations import Sum +from sympy.core.numbers import (Rational, oo, pi) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import symbols +from sympy.functions.combinatorial.factorials import (RisingFactorial, factorial) +from sympy.functions.elementary.complexes import polar_lift +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.special.bessel import besselk +from sympy.functions.special.gamma_functions import gamma +from sympy.matrices.dense import eye +from sympy.matrices.expressions.determinant import Determinant +from sympy.sets.fancysets import Range +from sympy.sets.sets import (Interval, ProductSet) +from sympy.simplify.simplify import simplify +from sympy.tensor.indexed import (Indexed, IndexedBase) +from sympy.core.numbers import comp +from sympy.integrals.integrals import integrate +from sympy.matrices import Matrix, MatrixSymbol +from sympy.matrices.expressions.matexpr import MatrixElement +from sympy.stats import density, median, marginal_distribution, Normal, Laplace, E, sample +from sympy.stats.joint_rv_types import (JointRV, MultivariateNormalDistribution, + JointDistributionHandmade, MultivariateT, NormalGamma, + GeneralizedMultivariateLogGammaOmega as GMVLGO, MultivariateBeta, + GeneralizedMultivariateLogGamma as GMVLG, MultivariateEwens, + Multinomial, NegativeMultinomial, MultivariateNormal, + MultivariateLaplace) +from sympy.testing.pytest import raises, XFAIL, skip, slow +from sympy.external import import_module + +from sympy.abc import x, y + + + +def test_Normal(): + m = Normal('A', [1, 2], [[1, 0], [0, 1]]) + A = MultivariateNormal('A', [1, 2], [[1, 0], [0, 1]]) + assert m == A + assert density(m)(1, 2) == 1/(2*pi) + assert m.pspace.distribution.set == ProductSet(S.Reals, S.Reals) + raises (ValueError, lambda:m[2]) + n = Normal('B', [1, 2, 3], [[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + p = Normal('C', Matrix([1, 2]), Matrix([[1, 0], [0, 1]])) + assert density(m)(x, y) == density(p)(x, y) + assert marginal_distribution(n, 0, 1)(1, 2) == 1/(2*pi) + raises(ValueError, lambda: marginal_distribution(m)) + assert integrate(density(m)(x, y), (x, -oo, oo), (y, -oo, oo)).evalf() == 1.0 + N = Normal('N', [1, 2], [[x, 0], [0, y]]) + assert density(N)(0, 0) == exp(-((4*x + y)/(2*x*y)))/(2*pi*sqrt(x*y)) + + raises (ValueError, lambda: Normal('M', [1, 2], [[1, 1], [1, -1]])) + # symbolic + n = symbols('n', integer=True, positive=True) + mu = MatrixSymbol('mu', n, 1) + sigma = MatrixSymbol('sigma', n, n) + X = Normal('X', mu, sigma) + assert density(X) == MultivariateNormalDistribution(mu, sigma) + raises (NotImplementedError, lambda: median(m)) + # Below tests should work after issue #17267 is resolved + # assert E(X) == mu + # assert variance(X) == sigma + + # test symbolic multivariate normal densities + n = 3 + + Sg = MatrixSymbol('Sg', n, n) + mu = MatrixSymbol('mu', n, 1) + obs = MatrixSymbol('obs', n, 1) + + X = MultivariateNormal('X', mu, Sg) + density_X = density(X) + + eval_a = density_X(obs).subs({Sg: eye(3), + mu: Matrix([0, 0, 0]), obs: Matrix([0, 0, 0])}).doit() + eval_b = density_X(0, 0, 0).subs({Sg: eye(3), mu: Matrix([0, 0, 0])}).doit() + + assert eval_a == sqrt(2)/(4*pi**Rational(3/2)) + assert eval_b == sqrt(2)/(4*pi**Rational(3/2)) + + n = symbols('n', integer=True, positive=True) + + Sg = MatrixSymbol('Sg', n, n) + mu = MatrixSymbol('mu', n, 1) + obs = MatrixSymbol('obs', n, 1) + + X = MultivariateNormal('X', mu, Sg) + density_X_at_obs = density(X)(obs) + + expected_density = MatrixElement( + exp((S(1)/2) * (mu.T - obs.T) * Sg**(-1) * (-mu + obs)) / \ + sqrt((2*pi)**n * Determinant(Sg)), 0, 0) + + assert density_X_at_obs == expected_density + + +def test_MultivariateTDist(): + t1 = MultivariateT('T', [0, 0], [[1, 0], [0, 1]], 2) + assert(density(t1))(1, 1) == 1/(8*pi) + assert t1.pspace.distribution.set == ProductSet(S.Reals, S.Reals) + assert integrate(density(t1)(x, y), (x, -oo, oo), \ + (y, -oo, oo)).evalf() == 1.0 + raises(ValueError, lambda: MultivariateT('T', [1, 2], [[1, 1], [1, -1]], 1)) + t2 = MultivariateT('t2', [1, 2], [[x, 0], [0, y]], 1) + assert density(t2)(1, 2) == 1/(2*pi*sqrt(x*y)) + + +def test_multivariate_laplace(): + raises(ValueError, lambda: Laplace('T', [1, 2], [[1, 2], [2, 1]])) + L = Laplace('L', [1, 0], [[1, 0], [0, 1]]) + L2 = MultivariateLaplace('L2', [1, 0], [[1, 0], [0, 1]]) + assert density(L)(2, 3) == exp(2)*besselk(0, sqrt(39))/pi + L1 = Laplace('L1', [1, 2], [[x, 0], [0, y]]) + assert density(L1)(0, 1) == \ + exp(2/y)*besselk(0, sqrt((2 + 4/y + 1/x)/y))/(pi*sqrt(x*y)) + assert L.pspace.distribution.set == ProductSet(S.Reals, S.Reals) + assert L.pspace.distribution == L2.pspace.distribution + + +def test_NormalGamma(): + ng = NormalGamma('G', 1, 2, 3, 4) + assert density(ng)(1, 1) == 32*exp(-4)/sqrt(pi) + assert ng.pspace.distribution.set == ProductSet(S.Reals, Interval(0, oo)) + raises(ValueError, lambda:NormalGamma('G', 1, 2, 3, -1)) + assert marginal_distribution(ng, 0)(1) == \ + 3*sqrt(10)*gamma(Rational(7, 4))/(10*sqrt(pi)*gamma(Rational(5, 4))) + assert marginal_distribution(ng, y)(1) == exp(Rational(-1, 4))/128 + assert marginal_distribution(ng,[0,1])(x) == x**2*exp(-x/4)/128 + + +def test_GeneralizedMultivariateLogGammaDistribution(): + h = S.Half + omega = Matrix([[1, h, h, h], + [h, 1, h, h], + [h, h, 1, h], + [h, h, h, 1]]) + v, l, mu = (4, [1, 2, 3, 4], [1, 2, 3, 4]) + y_1, y_2, y_3, y_4 = symbols('y_1:5', real=True) + delta = symbols('d', positive=True) + G = GMVLGO('G', omega, v, l, mu) + Gd = GMVLG('Gd', delta, v, l, mu) + dend = ("d**4*Sum(4*24**(-n - 4)*(1 - d)**n*exp((n + 4)*(y_1 + 2*y_2 + 3*y_3 " + "+ 4*y_4) - exp(y_1) - exp(2*y_2)/2 - exp(3*y_3)/3 - exp(4*y_4)/4)/" + "(gamma(n + 1)*gamma(n + 4)**3), (n, 0, oo))") + assert str(density(Gd)(y_1, y_2, y_3, y_4)) == dend + den = ("5*2**(2/3)*5**(1/3)*Sum(4*24**(-n - 4)*(-2**(2/3)*5**(1/3)/4 + 1)**n*" + "exp((n + 4)*(y_1 + 2*y_2 + 3*y_3 + 4*y_4) - exp(y_1) - exp(2*y_2)/2 - " + "exp(3*y_3)/3 - exp(4*y_4)/4)/(gamma(n + 1)*gamma(n + 4)**3), (n, 0, oo))/64") + assert str(density(G)(y_1, y_2, y_3, y_4)) == den + marg = ("5*2**(2/3)*5**(1/3)*exp(4*y_1)*exp(-exp(y_1))*Integral(exp(-exp(4*G[3])" + "/4)*exp(16*G[3])*Integral(exp(-exp(3*G[2])/3)*exp(12*G[2])*Integral(exp(" + "-exp(2*G[1])/2)*exp(8*G[1])*Sum((-1/4)**n*(-4 + 2**(2/3)*5**(1/3" + "))**n*exp(n*y_1)*exp(2*n*G[1])*exp(3*n*G[2])*exp(4*n*G[3])/(24**n*gamma(n + 1)" + "*gamma(n + 4)**3), (n, 0, oo)), (G[1], -oo, oo)), (G[2], -oo, oo)), (G[3]" + ", -oo, oo))/5308416") + assert str(marginal_distribution(G, G[0])(y_1)) == marg + omega_f1 = Matrix([[1, h, h]]) + omega_f2 = Matrix([[1, h, h, h], + [h, 1, 2, h], + [h, h, 1, h], + [h, h, h, 1]]) + omega_f3 = Matrix([[6, h, h, h], + [h, 1, 2, h], + [h, h, 1, h], + [h, h, h, 1]]) + v_f = symbols("v_f", positive=False, real=True) + l_f = [1, 2, v_f, 4] + m_f = [v_f, 2, 3, 4] + omega_f4 = Matrix([[1, h, h, h, h], + [h, 1, h, h, h], + [h, h, 1, h, h], + [h, h, h, 1, h], + [h, h, h, h, 1]]) + l_f1 = [1, 2, 3, 4, 5] + omega_f5 = Matrix([[1]]) + mu_f5 = l_f5 = [1] + + raises(ValueError, lambda: GMVLGO('G', omega_f1, v, l, mu)) + raises(ValueError, lambda: GMVLGO('G', omega_f2, v, l, mu)) + raises(ValueError, lambda: GMVLGO('G', omega_f3, v, l, mu)) + raises(ValueError, lambda: GMVLGO('G', omega, v_f, l, mu)) + raises(ValueError, lambda: GMVLGO('G', omega, v, l_f, mu)) + raises(ValueError, lambda: GMVLGO('G', omega, v, l, m_f)) + raises(ValueError, lambda: GMVLGO('G', omega_f4, v, l, mu)) + raises(ValueError, lambda: GMVLGO('G', omega, v, l_f1, mu)) + raises(ValueError, lambda: GMVLGO('G', omega_f5, v, l_f5, mu_f5)) + raises(ValueError, lambda: GMVLG('G', Rational(3, 2), v, l, mu)) + + +def test_MultivariateBeta(): + a1, a2 = symbols('a1, a2', positive=True) + a1_f, a2_f = symbols('a1, a2', positive=False, real=True) + mb = MultivariateBeta('B', [a1, a2]) + mb_c = MultivariateBeta('C', a1, a2) + assert density(mb)(1, 2) == S(2)**(a2 - 1)*gamma(a1 + a2)/\ + (gamma(a1)*gamma(a2)) + assert marginal_distribution(mb_c, 0)(3) == S(3)**(a1 - 1)*gamma(a1 + a2)/\ + (a2*gamma(a1)*gamma(a2)) + raises(ValueError, lambda: MultivariateBeta('b1', [a1_f, a2])) + raises(ValueError, lambda: MultivariateBeta('b2', [a1, a2_f])) + raises(ValueError, lambda: MultivariateBeta('b3', [0, 0])) + raises(ValueError, lambda: MultivariateBeta('b4', [a1_f, a2_f])) + assert mb.pspace.distribution.set == ProductSet(Interval(0, 1), Interval(0, 1)) + + +def test_MultivariateEwens(): + n, theta, i = symbols('n theta i', positive=True) + + # tests for integer dimensions + theta_f = symbols('t_f', negative=True) + a = symbols('a_1:4', positive = True, integer = True) + ed = MultivariateEwens('E', 3, theta) + assert density(ed)(a[0], a[1], a[2]) == Piecewise((6*2**(-a[1])*3**(-a[2])* + theta**a[0]*theta**a[1]*theta**a[2]/ + (theta*(theta + 1)*(theta + 2)* + factorial(a[0])*factorial(a[1])* + factorial(a[2])), Eq(a[0] + 2*a[1] + + 3*a[2], 3)), (0, True)) + assert marginal_distribution(ed, ed[1])(a[1]) == Piecewise((6*2**(-a[1])* + theta**a[1]/((theta + 1)* + (theta + 2)*factorial(a[1])), + Eq(2*a[1] + 1, 3)), (0, True)) + raises(ValueError, lambda: MultivariateEwens('e1', 5, theta_f)) + assert ed.pspace.distribution.set == ProductSet(Range(0, 4, 1), + Range(0, 2, 1), Range(0, 2, 1)) + + # tests for symbolic dimensions + eds = MultivariateEwens('E', n, theta) + a = IndexedBase('a') + j, k = symbols('j, k') + den = Piecewise((factorial(n)*Product(theta**a[j]*(j + 1)**(-a[j])/ + factorial(a[j]), (j, 0, n - 1))/RisingFactorial(theta, n), + Eq(n, Sum((k + 1)*a[k], (k, 0, n - 1)))), (0, True)) + assert density(eds)(a).dummy_eq(den) + + +def test_Multinomial(): + n, x1, x2, x3, x4 = symbols('n, x1, x2, x3, x4', nonnegative=True, integer=True) + p1, p2, p3, p4 = symbols('p1, p2, p3, p4', positive=True) + p1_f, n_f = symbols('p1_f, n_f', negative=True) + M = Multinomial('M', n, [p1, p2, p3, p4]) + C = Multinomial('C', 3, p1, p2, p3) + f = factorial + assert density(M)(x1, x2, x3, x4) == Piecewise((p1**x1*p2**x2*p3**x3*p4**x4* + f(n)/(f(x1)*f(x2)*f(x3)*f(x4)), + Eq(n, x1 + x2 + x3 + x4)), (0, True)) + assert marginal_distribution(C, C[0])(x1).subs(x1, 1) ==\ + 3*p1*p2**2 +\ + 6*p1*p2*p3 +\ + 3*p1*p3**2 + raises(ValueError, lambda: Multinomial('b1', 5, [p1, p2, p3, p1_f])) + raises(ValueError, lambda: Multinomial('b2', n_f, [p1, p2, p3, p4])) + raises(ValueError, lambda: Multinomial('b3', n, 0.5, 0.4, 0.3, 0.1)) + + +def test_NegativeMultinomial(): + k0, x1, x2, x3, x4 = symbols('k0, x1, x2, x3, x4', nonnegative=True, integer=True) + p1, p2, p3, p4 = symbols('p1, p2, p3, p4', positive=True) + p1_f = symbols('p1_f', negative=True) + N = NegativeMultinomial('N', 4, [p1, p2, p3, p4]) + C = NegativeMultinomial('C', 4, 0.1, 0.2, 0.3) + g = gamma + f = factorial + assert simplify(density(N)(x1, x2, x3, x4) - + p1**x1*p2**x2*p3**x3*p4**x4*(-p1 - p2 - p3 - p4 + 1)**4*g(x1 + x2 + + x3 + x4 + 4)/(6*f(x1)*f(x2)*f(x3)*f(x4))) is S.Zero + assert comp(marginal_distribution(C, C[0])(1).evalf(), 0.33, .01) + raises(ValueError, lambda: NegativeMultinomial('b1', 5, [p1, p2, p3, p1_f])) + raises(ValueError, lambda: NegativeMultinomial('b2', k0, 0.5, 0.4, 0.3, 0.4)) + assert N.pspace.distribution.set == ProductSet(Range(0, oo, 1), + Range(0, oo, 1), Range(0, oo, 1), Range(0, oo, 1)) + + +@slow +def test_JointPSpace_marginal_distribution(): + T = MultivariateT('T', [0, 0], [[1, 0], [0, 1]], 2) + got = marginal_distribution(T, T[1])(x) + ans = sqrt(2)*(x**2/2 + 1)/(4*polar_lift(x**2/2 + 1)**(S(5)/2)) + assert got == ans, got + assert integrate(marginal_distribution(T, 1)(x), (x, -oo, oo)) == 1 + + t = MultivariateT('T', [0, 0, 0], [[1, 0, 0], [0, 1, 0], [0, 0, 1]], 3) + assert comp(marginal_distribution(t, 0)(1).evalf(), 0.2, .01) + + +def test_JointRV(): + x1, x2 = (Indexed('x', i) for i in (1, 2)) + pdf = exp(-x1**2/2 + x1 - x2**2/2 - S.Half)/(2*pi) + X = JointRV('x', pdf) + assert density(X)(1, 2) == exp(-2)/(2*pi) + assert isinstance(X.pspace.distribution, JointDistributionHandmade) + assert marginal_distribution(X, 0)(2) == sqrt(2)*exp(Rational(-1, 2))/(2*sqrt(pi)) + + +def test_expectation(): + m = Normal('A', [x, y], [[1, 0], [0, 1]]) + assert simplify(E(m[1])) == y + + +@XFAIL +def test_joint_vector_expectation(): + m = Normal('A', [x, y], [[1, 0], [0, 1]]) + assert E(m) == (x, y) + + +def test_sample_numpy(): + distribs_numpy = [ + MultivariateNormal("M", [3, 4], [[2, 1], [1, 2]]), + MultivariateBeta("B", [0.4, 5, 15, 50, 203]), + Multinomial("N", 50, [0.3, 0.2, 0.1, 0.25, 0.15]) + ] + size = 3 + numpy = import_module('numpy') + if not numpy: + skip('Numpy is not installed. Abort tests for _sample_numpy.') + else: + for X in distribs_numpy: + samps = sample(X, size=size, library='numpy') + for sam in samps: + assert tuple(sam) in X.pspace.distribution.set + N_c = NegativeMultinomial('N', 3, 0.1, 0.1, 0.1) + raises(NotImplementedError, lambda: sample(N_c, library='numpy')) + + +def test_sample_scipy(): + distribs_scipy = [ + MultivariateNormal("M", [0, 0], [[0.1, 0.025], [0.025, 0.1]]), + MultivariateBeta("B", [0.4, 5, 15]), + Multinomial("N", 8, [0.3, 0.2, 0.1, 0.4]) + ] + + size = 3 + scipy = import_module('scipy') + if not scipy: + skip('Scipy not installed. Abort tests for _sample_scipy.') + else: + for X in distribs_scipy: + samps = sample(X, size=size) + samps2 = sample(X, size=(2, 2)) + for sam in samps: + assert tuple(sam) in X.pspace.distribution.set + for i in range(2): + for j in range(2): + assert tuple(samps2[i][j]) in X.pspace.distribution.set + N_c = NegativeMultinomial('N', 3, 0.1, 0.1, 0.1) + raises(NotImplementedError, lambda: sample(N_c)) + + +def test_sample_pymc(): + distribs_pymc = [ + MultivariateNormal("M", [5, 2], [[1, 0], [0, 1]]), + MultivariateBeta("B", [0.4, 5, 15]), + Multinomial("N", 4, [0.3, 0.2, 0.1, 0.4]) + ] + size = 3 + pymc = import_module('pymc') + if not pymc: + skip('PyMC is not installed. Abort tests for _sample_pymc.') + else: + for X in distribs_pymc: + samps = sample(X, size=size, library='pymc') + for sam in samps: + assert tuple(sam.flatten()) in X.pspace.distribution.set + N_c = NegativeMultinomial('N', 3, 0.1, 0.1, 0.1) + raises(NotImplementedError, lambda: sample(N_c, library='pymc')) + + +def test_sample_seed(): + x1, x2 = (Indexed('x', i) for i in (1, 2)) + pdf = exp(-x1**2/2 + x1 - x2**2/2 - S.Half)/(2*pi) + X = JointRV('x', pdf) + + libraries = ['scipy', 'numpy', 'pymc'] + for lib in libraries: + try: + imported_lib = import_module(lib) + if imported_lib: + s0, s1, s2 = [], [], [] + s0 = sample(X, size=10, library=lib, seed=0) + s1 = sample(X, size=10, library=lib, seed=0) + s2 = sample(X, size=10, library=lib, seed=1) + assert all(s0 == s1) + assert all(s1 != s2) + except NotImplementedError: + continue + +# +# XXX: This fails for pymc. Previously the test appeared to pass but that is +# just because the library argument was not passed so the test always used +# scipy. +# +def test_issue_21057(): + m = Normal("x", [0, 0], [[0, 0], [0, 0]]) + n = MultivariateNormal("x", [0, 0], [[0, 0], [0, 0]]) + p = Normal("x", [0, 0], [[0, 0], [0, 1]]) + assert m == n + libraries = ('scipy', 'numpy') # , 'pymc') # <-- pymc fails + for library in libraries: + try: + imported_lib = import_module(library) + if imported_lib: + s1 = sample(m, size=8, library=library) + s2 = sample(n, size=8, library=library) + s3 = sample(p, size=8, library=library) + assert tuple(s1.flatten()) == tuple(s2.flatten()) + for s in s3: + assert tuple(s.flatten()) in p.pspace.distribution.set + except NotImplementedError: + continue + + +# +# When this passes the pymc part can be uncommented in test_issue_21057 above +# and this can be deleted. +# +@XFAIL +def test_issue_21057_pymc(): + m = Normal("x", [0, 0], [[0, 0], [0, 0]]) + n = MultivariateNormal("x", [0, 0], [[0, 0], [0, 0]]) + p = Normal("x", [0, 0], [[0, 0], [0, 1]]) + assert m == n + libraries = ('pymc',) + for library in libraries: + try: + imported_lib = import_module(library) + if imported_lib: + s1 = sample(m, size=8, library=library) + s2 = sample(n, size=8, library=library) + s3 = sample(p, size=8, library=library) + assert tuple(s1.flatten()) == tuple(s2.flatten()) + for s in s3: + assert tuple(s.flatten()) in p.pspace.distribution.set + except NotImplementedError: + continue diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_matrix_distributions.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_matrix_distributions.py new file mode 100644 index 0000000000000000000000000000000000000000..a2a2dcdd853793d9f77e1a88adf63158ed68e3ba --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_matrix_distributions.py @@ -0,0 +1,186 @@ +from sympy.concrete.products import Product +from sympy.core.numbers import pi +from sympy.core.singleton import S +from sympy.core.symbol import (Dummy, symbols) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.special.gamma_functions import gamma +from sympy.matrices import Determinant, Matrix, Trace, MatrixSymbol, MatrixSet +from sympy.stats import density, sample +from sympy.stats.matrix_distributions import (MatrixGammaDistribution, + MatrixGamma, MatrixPSpace, Wishart, MatrixNormal, MatrixStudentT) +from sympy.testing.pytest import raises, skip +from sympy.external import import_module + + +def test_MatrixPSpace(): + M = MatrixGammaDistribution(1, 2, [[2, 1], [1, 2]]) + MP = MatrixPSpace('M', M, 2, 2) + assert MP.distribution == M + raises(ValueError, lambda: MatrixPSpace('M', M, 1.2, 2)) + +def test_MatrixGamma(): + M = MatrixGamma('M', 1, 2, [[1, 0], [0, 1]]) + assert M.pspace.distribution.set == MatrixSet(2, 2, S.Reals) + assert isinstance(density(M), MatrixGammaDistribution) + X = MatrixSymbol('X', 2, 2) + num = exp(Trace(Matrix([[-S(1)/2, 0], [0, -S(1)/2]])*X)) + assert density(M)(X).doit() == num/(4*pi*sqrt(Determinant(X))) + assert density(M)([[2, 1], [1, 2]]).doit() == sqrt(3)*exp(-2)/(12*pi) + X = MatrixSymbol('X', 1, 2) + Y = MatrixSymbol('Y', 1, 2) + assert density(M)([X, Y]).doit() == exp(-X[0, 0]/2 - Y[0, 1]/2)/(4*pi*sqrt( + X[0, 0]*Y[0, 1] - X[0, 1]*Y[0, 0])) + # symbolic + a, b = symbols('a b', positive=True) + d = symbols('d', positive=True, integer=True) + Y = MatrixSymbol('Y', d, d) + Z = MatrixSymbol('Z', 2, 2) + SM = MatrixSymbol('SM', d, d) + M2 = MatrixGamma('M2', a, b, SM) + M3 = MatrixGamma('M3', 2, 3, [[2, 1], [1, 2]]) + k = Dummy('k') + exprd = pi**(-d*(d - 1)/4)*b**(-a*d)*exp(Trace((-1/b)*SM**(-1)*Y) + )*Determinant(SM)**(-a)*Determinant(Y)**(a - d/2 - S(1)/2)/Product( + gamma(-k/2 + a + S(1)/2), (k, 1, d)) + assert density(M2)(Y).dummy_eq(exprd) + raises(NotImplementedError, lambda: density(M3 + M)(Z)) + raises(ValueError, lambda: density(M)(1)) + raises(ValueError, lambda: MatrixGamma('M', -1, 2, [[1, 0], [0, 1]])) + raises(ValueError, lambda: MatrixGamma('M', -1, -2, [[1, 0], [0, 1]])) + raises(ValueError, lambda: MatrixGamma('M', -1, 2, [[1, 0], [2, 1]])) + raises(ValueError, lambda: MatrixGamma('M', -1, 2, [[1, 0], [0]])) + +def test_Wishart(): + W = Wishart('W', 5, [[1, 0], [0, 1]]) + assert W.pspace.distribution.set == MatrixSet(2, 2, S.Reals) + X = MatrixSymbol('X', 2, 2) + term1 = exp(Trace(Matrix([[-S(1)/2, 0], [0, -S(1)/2]])*X)) + assert density(W)(X).doit() == term1 * Determinant(X)/(24*pi) + assert density(W)([[2, 1], [1, 2]]).doit() == exp(-2)/(8*pi) + n = symbols('n', positive=True) + d = symbols('d', positive=True, integer=True) + Y = MatrixSymbol('Y', d, d) + SM = MatrixSymbol('SM', d, d) + W = Wishart('W', n, SM) + k = Dummy('k') + exprd = 2**(-d*n/2)*pi**(-d*(d - 1)/4)*exp(Trace(-(S(1)/2)*SM**(-1)*Y) + )*Determinant(SM)**(-n/2)*Determinant(Y)**( + -d/2 + n/2 - S(1)/2)/Product(gamma(-k/2 + n/2 + S(1)/2), (k, 1, d)) + assert density(W)(Y).dummy_eq(exprd) + raises(ValueError, lambda: density(W)(1)) + raises(ValueError, lambda: Wishart('W', -1, [[1, 0], [0, 1]])) + raises(ValueError, lambda: Wishart('W', -1, [[1, 0], [2, 1]])) + raises(ValueError, lambda: Wishart('W', 2, [[1, 0], [0]])) + +def test_MatrixNormal(): + M = MatrixNormal('M', [[5, 6]], [4], [[2, 1], [1, 2]]) + assert M.pspace.distribution.set == MatrixSet(1, 2, S.Reals) + X = MatrixSymbol('X', 1, 2) + term1 = exp(-Trace(Matrix([[ S(2)/3, -S(1)/3], [-S(1)/3, S(2)/3]])*( + Matrix([[-5], [-6]]) + X.T)*Matrix([[S(1)/4]])*(Matrix([[-5, -6]]) + X))/2) + assert density(M)(X).doit() == (sqrt(3)) * term1/(24*pi) + assert density(M)([[7, 8]]).doit() == sqrt(3)*exp(-S(1)/3)/(24*pi) + d, n = symbols('d n', positive=True, integer=True) + SM2 = MatrixSymbol('SM2', d, d) + SM1 = MatrixSymbol('SM1', n, n) + LM = MatrixSymbol('LM', n, d) + Y = MatrixSymbol('Y', n, d) + M = MatrixNormal('M', LM, SM1, SM2) + exprd = (2*pi)**(-d*n/2)*exp(-Trace(SM2**(-1)*(-LM.T + Y.T)*SM1**(-1)*(-LM + Y) + )/2)*Determinant(SM1)**(-d/2)*Determinant(SM2)**(-n/2) + assert density(M)(Y).doit() == exprd + raises(ValueError, lambda: density(M)(1)) + raises(ValueError, lambda: MatrixNormal('M', [1, 2], [[1, 0], [0, 1]], [[1, 0], [2, 1]])) + raises(ValueError, lambda: MatrixNormal('M', [1, 2], [[1, 0], [2, 1]], [[1, 0], [0, 1]])) + raises(ValueError, lambda: MatrixNormal('M', [1, 2], [[1, 0], [0, 1]], [[1, 0], [0, 1]])) + raises(ValueError, lambda: MatrixNormal('M', [1, 2], [[1, 0], [2]], [[1, 0], [0, 1]])) + raises(ValueError, lambda: MatrixNormal('M', [1, 2], [[1, 0], [2, 1]], [[1, 0], [0]])) + raises(ValueError, lambda: MatrixNormal('M', [[1, 2]], [[1, 0], [0, 1]], [[1, 0]])) + raises(ValueError, lambda: MatrixNormal('M', [[1, 2]], [1], [[1, 0]])) + +def test_MatrixStudentT(): + M = MatrixStudentT('M', 2, [[5, 6]], [[2, 1], [1, 2]], [4]) + assert M.pspace.distribution.set == MatrixSet(1, 2, S.Reals) + X = MatrixSymbol('X', 1, 2) + D = pi ** (-1.0) * Determinant(Matrix([[4]])) ** (-1.0) * Determinant(Matrix([[2, 1], [1, 2]])) \ + ** (-0.5) / Determinant(Matrix([[S(1) / 4]]) * (Matrix([[-5, -6]]) + X) + * Matrix([[S(2) / 3, -S(1) / 3], [-S(1) / 3, S(2) / 3]]) * ( + Matrix([[-5], [-6]]) + X.T) + Matrix([[1]])) ** 2 + assert density(M)(X) == D + + v = symbols('v', positive=True) + n, p = 1, 2 + Omega = MatrixSymbol('Omega', p, p) + Sigma = MatrixSymbol('Sigma', n, n) + Location = MatrixSymbol('Location', n, p) + Y = MatrixSymbol('Y', n, p) + M = MatrixStudentT('M', v, Location, Omega, Sigma) + + exprd = gamma(v/2 + 1)*Determinant(Matrix([[1]]) + Sigma**(-1)*(-Location + Y)*Omega**(-1)*(-Location.T + Y.T))**(-v/2 - 1) / \ + (pi*gamma(v/2)*sqrt(Determinant(Omega))*Determinant(Sigma)) + + assert density(M)(Y) == exprd + raises(ValueError, lambda: density(M)(1)) + raises(ValueError, lambda: MatrixStudentT('M', 1, [1, 2], [[1, 0], [0, 1]], [[1, 0], [2, 1]])) + raises(ValueError, lambda: MatrixStudentT('M', 1, [1, 2], [[1, 0], [2, 1]], [[1, 0], [0, 1]])) + raises(ValueError, lambda: MatrixStudentT('M', 1, [1, 2], [[1, 0], [0, 1]], [[1, 0], [0, 1]])) + raises(ValueError, lambda: MatrixStudentT('M', 1, [1, 2], [[1, 0], [2]], [[1, 0], [0, 1]])) + raises(ValueError, lambda: MatrixStudentT('M', 1, [1, 2], [[1, 0], [2, 1]], [[1], [2]])) + raises(ValueError, lambda: MatrixStudentT('M', 1, [[1, 2]], [[1, 0], [0, 1]], [[1, 0]])) + raises(ValueError, lambda: MatrixStudentT('M', 1, [[1, 2]], [1], [[1, 0]])) + raises(ValueError, lambda: MatrixStudentT('M', -1, [1, 2], [[1, 0], [0, 1]], [4])) + +def test_sample_scipy(): + distribs_scipy = [ + MatrixNormal('M', [[5, 6]], [4], [[2, 1], [1, 2]]), + Wishart('W', 5, [[1, 0], [0, 1]]) + ] + + size = 5 + scipy = import_module('scipy') + if not scipy: + skip('Scipy not installed. Abort tests for _sample_scipy.') + else: + for X in distribs_scipy: + samps = sample(X, size=size) + for sam in samps: + assert Matrix(sam) in X.pspace.distribution.set + M = MatrixGamma('M', 1, 2, [[1, 0], [0, 1]]) + raises(NotImplementedError, lambda: sample(M, size=3)) + +def test_sample_pymc(): + distribs_pymc = [ + MatrixNormal('M', [[5, 6], [3, 4]], [[1, 0], [0, 1]], [[2, 1], [1, 2]]), + Wishart('W', 7, [[2, 1], [1, 2]]) + ] + size = 3 + pymc = import_module('pymc') + if not pymc: + skip('PyMC is not installed. Abort tests for _sample_pymc.') + else: + for X in distribs_pymc: + samps = sample(X, size=size, library='pymc') + for sam in samps: + assert Matrix(sam) in X.pspace.distribution.set + M = MatrixGamma('M', 1, 2, [[1, 0], [0, 1]]) + raises(NotImplementedError, lambda: sample(M, size=3)) + +def test_sample_seed(): + X = MatrixNormal('M', [[5, 6], [3, 4]], [[1, 0], [0, 1]], [[2, 1], [1, 2]]) + + libraries = ['scipy', 'numpy', 'pymc'] + for lib in libraries: + try: + imported_lib = import_module(lib) + if imported_lib: + s0, s1, s2 = [], [], [] + s0 = sample(X, size=10, library=lib, seed=0) + s1 = sample(X, size=10, library=lib, seed=0) + s2 = sample(X, size=10, library=lib, seed=1) + for i in range(10): + assert (s0[i] == s1[i]).all() + assert (s1[i] != s2[i]).all() + + except NotImplementedError: + continue diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_mix.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_mix.py new file mode 100644 index 0000000000000000000000000000000000000000..4334d9b144a5ddaad938f195f0276e0e8993aa35 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_mix.py @@ -0,0 +1,82 @@ +from sympy.concrete.summations import Sum +from sympy.core.add import Add +from sympy.core.mul import Mul +from sympy.core.numbers import (Integer, oo, pi) +from sympy.core.power import Pow +from sympy.core.relational import (Eq, Ne) +from sympy.core.symbol import (Dummy, Symbol, symbols) +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.special.delta_functions import DiracDelta +from sympy.functions.special.gamma_functions import gamma +from sympy.integrals.integrals import Integral +from sympy.simplify.simplify import simplify +from sympy.tensor.indexed import (Indexed, IndexedBase) +from sympy.functions.elementary.piecewise import ExprCondPair +from sympy.stats import (Poisson, Beta, Exponential, P, + Multinomial, MultivariateBeta) +from sympy.stats.crv_types import Normal +from sympy.stats.drv_types import PoissonDistribution +from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution +from sympy.stats.joint_rv import MarginalDistribution +from sympy.stats.rv import pspace, density +from sympy.testing.pytest import ignore_warnings + +def test_density(): + x = Symbol('x') + l = Symbol('l', positive=True) + rate = Beta(l, 2, 3) + X = Poisson(x, rate) + assert isinstance(pspace(X), CompoundPSpace) + assert density(X, Eq(rate, rate.symbol)) == PoissonDistribution(l) + N1 = Normal('N1', 0, 1) + N2 = Normal('N2', N1, 2) + assert density(N2)(0).doit() == sqrt(10)/(10*sqrt(pi)) + assert simplify(density(N2, Eq(N1, 1))(x)) == \ + sqrt(2)*exp(-(x - 1)**2/8)/(4*sqrt(pi)) + assert simplify(density(N2)(x)) == sqrt(10)*exp(-x**2/10)/(10*sqrt(pi)) + +def test_MarginalDistribution(): + a1, p1, p2 = symbols('a1 p1 p2', positive=True) + C = Multinomial('C', 2, p1, p2) + B = MultivariateBeta('B', a1, C[0]) + MGR = MarginalDistribution(B, (C[0],)) + mgrc = Mul(Symbol('B'), Piecewise(ExprCondPair(Mul(Integer(2), + Pow(Symbol('p1', positive=True), Indexed(IndexedBase(Symbol('C')), + Integer(0))), Pow(Symbol('p2', positive=True), + Indexed(IndexedBase(Symbol('C')), Integer(1))), + Pow(factorial(Indexed(IndexedBase(Symbol('C')), Integer(0))), Integer(-1)), + Pow(factorial(Indexed(IndexedBase(Symbol('C')), Integer(1))), Integer(-1))), + Eq(Add(Indexed(IndexedBase(Symbol('C')), Integer(0)), + Indexed(IndexedBase(Symbol('C')), Integer(1))), Integer(2))), + ExprCondPair(Integer(0), True)), Pow(gamma(Symbol('a1', positive=True)), + Integer(-1)), gamma(Add(Symbol('a1', positive=True), + Indexed(IndexedBase(Symbol('C')), Integer(0)))), + Pow(gamma(Indexed(IndexedBase(Symbol('C')), Integer(0))), Integer(-1)), + Pow(Indexed(IndexedBase(Symbol('B')), Integer(0)), + Add(Symbol('a1', positive=True), Integer(-1))), + Pow(Indexed(IndexedBase(Symbol('B')), Integer(1)), + Add(Indexed(IndexedBase(Symbol('C')), Integer(0)), Integer(-1)))) + assert MGR(C) == mgrc + +def test_compound_distribution(): + Y = Poisson('Y', 1) + Z = Poisson('Z', Y) + assert isinstance(pspace(Z), CompoundPSpace) + assert isinstance(pspace(Z).distribution, CompoundDistribution) + assert Z.pspace.distribution.pdf(1).doit() == exp(-2)*exp(exp(-1)) + +def test_mix_expression(): + Y, E = Poisson('Y', 1), Exponential('E', 1) + k = Dummy('k') + expr1 = Integral(Sum(exp(-1)*Integral(exp(-k)*DiracDelta(k - 2), (k, 0, oo) + )/factorial(k), (k, 0, oo)), (k, -oo, 0)) + expr2 = Integral(Sum(exp(-1)*Integral(exp(-k)*DiracDelta(k - 2), (k, 0, oo) + )/factorial(k), (k, 0, oo)), (k, 0, oo)) + assert P(Eq(Y + E, 1)) == 0 + assert P(Ne(Y + E, 2)) == 1 + with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed + assert P(E + Y < 2, evaluate=False).rewrite(Integral).dummy_eq(expr1) + assert P(E + Y > 2, evaluate=False).rewrite(Integral).dummy_eq(expr2) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_random_matrix.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_random_matrix.py new file mode 100644 index 0000000000000000000000000000000000000000..ba570a16bc42620d53bce19be71e7d125965ede1 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_random_matrix.py @@ -0,0 +1,135 @@ +from sympy.concrete.products import Product +from sympy.core.function import Lambda +from sympy.core.numbers import (I, Rational, pi) +from sympy.core.singleton import S +from sympy.core.symbol import Dummy +from sympy.functions.elementary.complexes import Abs +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.integrals.integrals import Integral +from sympy.matrices.dense import Matrix +from sympy.matrices.expressions.matexpr import MatrixSymbol +from sympy.matrices.expressions.trace import Trace +from sympy.tensor.indexed import IndexedBase +from sympy.stats import (GaussianUnitaryEnsemble as GUE, density, + GaussianOrthogonalEnsemble as GOE, + GaussianSymplecticEnsemble as GSE, + joint_eigen_distribution, + CircularUnitaryEnsemble as CUE, + CircularOrthogonalEnsemble as COE, + CircularSymplecticEnsemble as CSE, + JointEigenDistribution, + level_spacing_distribution, + Normal, Beta) +from sympy.stats.joint_rv_types import JointDistributionHandmade +from sympy.stats.rv import RandomMatrixSymbol +from sympy.stats.random_matrix_models import GaussianEnsemble, RandomMatrixPSpace +from sympy.testing.pytest import raises + +def test_GaussianEnsemble(): + G = GaussianEnsemble('G', 3) + assert density(G) == G.pspace.model + raises(ValueError, lambda: GaussianEnsemble('G', 3.5)) + +def test_GaussianUnitaryEnsemble(): + H = RandomMatrixSymbol('H', 3, 3) + G = GUE('U', 3) + assert density(G)(H) == sqrt(2)*exp(-3*Trace(H**2)/2)/(4*pi**Rational(9, 2)) + i, j = (Dummy('i', integer=True, positive=True), + Dummy('j', integer=True, positive=True)) + l = IndexedBase('l') + assert joint_eigen_distribution(G).dummy_eq( + Lambda((l[1], l[2], l[3]), + 27*sqrt(6)*exp(-3*(l[1]**2)/2 - 3*(l[2]**2)/2 - 3*(l[3]**2)/2)* + Product(Abs(l[i] - l[j])**2, (j, i + 1, 3), (i, 1, 2))/(16*pi**Rational(3, 2)))) + s = Dummy('s') + assert level_spacing_distribution(G).dummy_eq(Lambda(s, 32*s**2*exp(-4*s**2/pi)/pi**2)) + + +def test_GaussianOrthogonalEnsemble(): + H = RandomMatrixSymbol('H', 3, 3) + _H = MatrixSymbol('_H', 3, 3) + G = GOE('O', 3) + assert density(G)(H) == exp(-3*Trace(H**2)/4)/Integral(exp(-3*Trace(_H**2)/4), _H) + i, j = (Dummy('i', integer=True, positive=True), + Dummy('j', integer=True, positive=True)) + l = IndexedBase('l') + assert joint_eigen_distribution(G).dummy_eq( + Lambda((l[1], l[2], l[3]), + 9*sqrt(2)*exp(-3*l[1]**2/2 - 3*l[2]**2/2 - 3*l[3]**2/2)* + Product(Abs(l[i] - l[j]), (j, i + 1, 3), (i, 1, 2))/(32*pi))) + s = Dummy('s') + assert level_spacing_distribution(G).dummy_eq(Lambda(s, s*pi*exp(-s**2*pi/4)/2)) + +def test_GaussianSymplecticEnsemble(): + H = RandomMatrixSymbol('H', 3, 3) + _H = MatrixSymbol('_H', 3, 3) + G = GSE('O', 3) + assert density(G)(H) == exp(-3*Trace(H**2))/Integral(exp(-3*Trace(_H**2)), _H) + i, j = (Dummy('i', integer=True, positive=True), + Dummy('j', integer=True, positive=True)) + l = IndexedBase('l') + assert joint_eigen_distribution(G).dummy_eq( + Lambda((l[1], l[2], l[3]), + 162*sqrt(3)*exp(-3*l[1]**2/2 - 3*l[2]**2/2 - 3*l[3]**2/2)* + Product(Abs(l[i] - l[j])**4, (j, i + 1, 3), (i, 1, 2))/(5*pi**Rational(3, 2)))) + s = Dummy('s') + assert level_spacing_distribution(G).dummy_eq(Lambda(s, S(262144)*s**4*exp(-64*s**2/(9*pi))/(729*pi**3))) + +def test_CircularUnitaryEnsemble(): + CU = CUE('U', 3) + j, k = (Dummy('j', integer=True, positive=True), + Dummy('k', integer=True, positive=True)) + t = IndexedBase('t') + assert joint_eigen_distribution(CU).dummy_eq( + Lambda((t[1], t[2], t[3]), + Product(Abs(exp(I*t[j]) - exp(I*t[k]))**2, + (j, k + 1, 3), (k, 1, 2))/(48*pi**3)) + ) + +def test_CircularOrthogonalEnsemble(): + CO = COE('U', 3) + j, k = (Dummy('j', integer=True, positive=True), + Dummy('k', integer=True, positive=True)) + t = IndexedBase('t') + assert joint_eigen_distribution(CO).dummy_eq( + Lambda((t[1], t[2], t[3]), + Product(Abs(exp(I*t[j]) - exp(I*t[k])), + (j, k + 1, 3), (k, 1, 2))/(48*pi**2)) + ) + +def test_CircularSymplecticEnsemble(): + CS = CSE('U', 3) + j, k = (Dummy('j', integer=True, positive=True), + Dummy('k', integer=True, positive=True)) + t = IndexedBase('t') + assert joint_eigen_distribution(CS).dummy_eq( + Lambda((t[1], t[2], t[3]), + Product(Abs(exp(I*t[j]) - exp(I*t[k]))**4, + (j, k + 1, 3), (k, 1, 2))/(720*pi**3)) + ) + +def test_JointEigenDistribution(): + A = Matrix([[Normal('A00', 0, 1), Normal('A01', 1, 1)], + [Beta('A10', 1, 1), Beta('A11', 1, 1)]]) + assert JointEigenDistribution(A) == \ + JointDistributionHandmade(-sqrt(A[0, 0]**2 - 2*A[0, 0]*A[1, 1] + 4*A[0, 1]*A[1, 0] + A[1, 1]**2)/2 + + A[0, 0]/2 + A[1, 1]/2, sqrt(A[0, 0]**2 - 2*A[0, 0]*A[1, 1] + 4*A[0, 1]*A[1, 0] + A[1, 1]**2)/2 + A[0, 0]/2 + A[1, 1]/2) + raises(ValueError, lambda: JointEigenDistribution(Matrix([[1, 0], [2, 1]]))) + +def test_issue_19841(): + G1 = GUE('U', 2) + G2 = G1.xreplace({2: 2}) + assert G1.args == G2.args + + X = MatrixSymbol('X', 2, 2) + G = GSE('U', 2) + h_pspace = RandomMatrixPSpace('P', model=density(G)) + H = RandomMatrixSymbol('H', 2, 2, pspace=h_pspace) + H2 = RandomMatrixSymbol('H', 2, 2, pspace=None) + assert H.doit() == H + + assert (2*H).xreplace({H: X}) == 2*X + assert (2*H).xreplace({H2: X}) == 2*H + assert (2*H2).xreplace({H: X}) == 2*H2 + assert (2*H2).xreplace({H2: X}) == 2*X diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_rv.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_rv.py new file mode 100644 index 0000000000000000000000000000000000000000..185756300556f2fe70b76c402113ec2bb2501ef4 --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_rv.py @@ -0,0 +1,441 @@ +from sympy.concrete.summations import Sum +from sympy.core.basic import Basic +from sympy.core.containers import Tuple +from sympy.core.function import Lambda +from sympy.core.numbers import (Rational, nan, oo, pi) +from sympy.core.relational import Eq +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.combinatorial.factorials import (FallingFactorial, binomial) +from sympy.functions.elementary.exponential import (exp, log) +from sympy.functions.elementary.trigonometric import (cos, sin) +from sympy.functions.special.delta_functions import DiracDelta +from sympy.integrals.integrals import integrate +from sympy.logic.boolalg import (And, Or) +from sympy.matrices.dense import Matrix +from sympy.sets.sets import Interval +from sympy.tensor.indexed import Indexed +from sympy.stats import (Die, Normal, Exponential, FiniteRV, P, E, H, variance, + density, given, independent, dependent, where, pspace, GaussianUnitaryEnsemble, + random_symbols, sample, Geometric, factorial_moment, Binomial, Hypergeometric, + DiscreteUniform, Poisson, characteristic_function, moment_generating_function, + BernoulliProcess, Variance, Expectation, Probability, Covariance, covariance, cmoment, + moment, median) +from sympy.stats.rv import (IndependentProductPSpace, rs_swap, Density, NamedArgsMixin, + RandomSymbol, sample_iter, PSpace, is_random, RandomIndexedSymbol, RandomMatrixSymbol) +from sympy.testing.pytest import raises, skip, XFAIL, warns_deprecated_sympy +from sympy.external import import_module +from sympy.core.numbers import comp +from sympy.stats.frv_types import BernoulliDistribution +from sympy.core.symbol import Dummy +from sympy.functions.elementary.piecewise import Piecewise + +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 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, -oo < X.symbol, X.symbol < oo) + + with raises(TypeError): + 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)) == {X} + assert set(random_symbols(2*X + Y)) == {X, Y} + assert set(random_symbols(2*X + Y.symbol)) == {X} + assert set(random_symbols(2)) == set() + + +def test_characteristic_function(): + # Imports I from sympy + from sympy.core.numbers import I + X = Normal('X',0,1) + Y = DiscreteUniform('Y', [1,2,7]) + Z = Poisson('Z', 2) + t = symbols('_t') + P = Lambda(t, exp(-t**2/2)) + Q = Lambda(t, exp(7*t*I)/3 + exp(2*t*I)/3 + exp(t*I)/3) + R = Lambda(t, exp(2 * exp(t*I) - 2)) + + + assert characteristic_function(X).dummy_eq(P) + assert characteristic_function(Y).dummy_eq(Q) + assert characteristic_function(Z).dummy_eq(R) + + +def test_moment_generating_function(): + + X = Normal('X',0,1) + Y = DiscreteUniform('Y', [1,2,7]) + Z = Poisson('Z', 2) + t = symbols('_t') + P = Lambda(t, exp(t**2/2)) + Q = Lambda(t, (exp(7*t)/3 + exp(2*t)/3 + exp(t)/3)) + R = Lambda(t, exp(2 * exp(t) - 2)) + + + assert moment_generating_function(X).dummy_eq(P) + assert moment_generating_function(Y).dummy_eq(Q) + assert moment_generating_function(Z).dummy_eq(R) + +def test_sample_iter(): + + X = Normal('X',0,1) + Y = DiscreteUniform('Y', [1, 2, 7]) + Z = Poisson('Z', 2) + + scipy = import_module('scipy') + if not scipy: + skip('Scipy is not installed. Abort tests') + expr = X**2 + 3 + iterator = sample_iter(expr) + + expr2 = Y**2 + 5*Y + 4 + iterator2 = sample_iter(expr2) + + expr3 = Z**3 + 4 + iterator3 = sample_iter(expr3) + + def is_iterator(obj): + if ( + hasattr(obj, '__iter__') and + (hasattr(obj, 'next') or + hasattr(obj, '__next__')) and + callable(obj.__iter__) and + obj.__iter__() is obj + ): + return True + else: + return False + assert is_iterator(iterator) + assert is_iterator(iterator2) + assert is_iterator(iterator3) + +def test_pspace(): + X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) + x = Symbol('x') + + raises(ValueError, lambda: pspace(5 + 3)) + raises(ValueError, lambda: pspace(x < 1)) + assert pspace(X) == X.pspace + assert pspace(2*X + 1) == X.pspace + assert pspace(2*X + Y) == IndependentProductPSpace(Y.pspace, X.pspace) + +def test_rs_swap(): + X = Normal('x', 0, 1) + Y = Exponential('y', 1) + + 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 + + +def test_RandomSymbol(): + + X = Normal('x', 0, 1) + Y = Normal('x', 0, 2) + assert X.symbol == Y.symbol + 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_random_symbol_no_pspace(): + x = RandomSymbol(Symbol('x')) + assert x.pspace == PSpace() + +def test_overlap(): + X = Normal('x', 0, 1) + Y = Normal('x', 0, 2) + + raises(ValueError, lambda: P(X > Y)) + + +def test_IndependentProductPSpace(): + X = Normal('X', 0, 1) + Y = Normal('Y', 0, 1) + px = X.pspace + py = Y.pspace + assert pspace(X + Y) == IndependentProductPSpace(px, py) + assert pspace(X + Y) == IndependentProductPSpace(py, px) + + +def test_E(): + assert E(5) == 5 + + +def test_H(): + X = Normal('X', 0, 1) + D = Die('D', sides = 4) + G = Geometric('G', 0.5) + assert H(X, X > 0) == -log(2)/2 + S.Half + log(pi)/2 + assert H(D, D > 2) == log(2) + assert comp(H(G).evalf().round(2), 1.39) + + +def test_Sample(): + X = Die('X', 6) + Y = Normal('Y', 0, 1) + z = Symbol('z', integer=True) + + scipy = import_module('scipy') + if not scipy: + skip('Scipy is not installed. Abort tests') + assert sample(X) in [1, 2, 3, 4, 5, 6] + assert isinstance(sample(X + Y), float) + + assert P(X + Y > 0, Y < 0, numsamples=10).is_number + assert E(X + Y, numsamples=10).is_number + assert E(X**2 + Y, numsamples=10).is_number + assert E((X + Y)**2, numsamples=10).is_number + assert variance(X + Y, numsamples=10).is_number + + raises(TypeError, lambda: P(Y > z, numsamples=5)) + + assert P(sin(Y) <= 1, numsamples=10) == 1.0 + assert P(sin(Y) <= 1, cos(Y) < 1, numsamples=10) == 1.0 + + assert all(i in range(1, 7) for i in density(X, numsamples=10)) + assert all(i in range(4, 7) for i in density(X, X>3, numsamples=10)) + + numpy = import_module('numpy') + if not numpy: + skip('Numpy is not installed. Abort tests') + #Test Issue #21563: Output of sample must be a float or array + assert isinstance(sample(X), (numpy.int32, numpy.int64)) + assert isinstance(sample(Y), numpy.float64) + assert isinstance(sample(X, size=2), numpy.ndarray) + + with warns_deprecated_sympy(): + sample(X, numsamples=2) + +@XFAIL +def test_samplingE(): + scipy = import_module('scipy') + if not scipy: + skip('Scipy is not installed. Abort tests') + Y = Normal('Y', 0, 1) + z = Symbol('z', integer=True) + assert E(Sum(1/z**Y, (z, 1, oo)), Y > 2, numsamples=3).is_number + + +def test_given(): + X = Normal('X', 0, 1) + Y = Normal('Y', 0, 1) + A = given(X, True) + B = given(X, Y > 2) + + assert X == A == B + + +def test_factorial_moment(): + X = Poisson('X', 2) + Y = Binomial('Y', 2, S.Half) + Z = Hypergeometric('Z', 4, 2, 2) + assert factorial_moment(X, 2) == 4 + assert factorial_moment(Y, 2) == S.Half + assert factorial_moment(Z, 2) == Rational(1, 3) + + x, y, z, l = symbols('x y z l') + Y = Binomial('Y', 2, y) + Z = Hypergeometric('Z', 10, 2, 3) + assert factorial_moment(Y, l) == y**2*FallingFactorial( + 2, l) + 2*y*(1 - y)*FallingFactorial(1, l) + (1 - y)**2*\ + FallingFactorial(0, l) + assert factorial_moment(Z, l) == 7*FallingFactorial(0, l)/\ + 15 + 7*FallingFactorial(1, l)/15 + FallingFactorial(2, l)/15 + + +def test_dependence(): + X, Y = Die('X'), Die('Y') + assert independent(X, 2*Y) + assert not dependent(X, 2*Y) + + X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) + assert independent(X, Y) + assert dependent(X, 2*X) + + # Create a dependency + XX, YY = given(Tuple(X, Y), Eq(X + Y, 3)) + assert dependent(XX, YY) + +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) + + 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 = Symbol('x', real=True) + z = Symbol('z', real=True) + 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(S(1), S(2)) + + assert a.foo == 1 + assert a.bar == 2 + + raises(AttributeError, lambda: a.baz) + + class Bar(Basic, NamedArgsMixin): + pass + + raises(AttributeError, lambda: Bar(S(1), S(2)).foo) + +def test_density_constant(): + assert density(3)(2) == 0 + assert density(3)(3) == DiracDelta(0) + +def test_cmoment_constant(): + assert variance(3) == 0 + assert cmoment(3, 3) == 0 + assert cmoment(3, 4) == 0 + x = Symbol('x') + assert variance(x) == 0 + assert cmoment(x, 15) == 0 + assert cmoment(x, 0) == 1 + +def test_moment_constant(): + assert moment(3, 0) == 1 + assert moment(3, 1) == 3 + assert moment(3, 2) == 9 + x = Symbol('x') + assert moment(x, 2) == x**2 + +def test_median_constant(): + assert median(3) == 3 + x = Symbol('x') + assert median(x) == x + +def test_real(): + x = Normal('x', 0, 1) + assert x.is_real + + +def test_issue_10052(): + X = Exponential('X', 3) + assert P(X < oo) == 1 + assert P(X > oo) == 0 + assert P(X < 2, X > oo) == 0 + assert P(X < oo, X > oo) == 0 + assert P(X < oo, X > 2) == 1 + assert P(X < 3, X == 2) == 0 + raises(ValueError, lambda: P(1)) + raises(ValueError, lambda: P(X < 1, 2)) + +def test_issue_11934(): + density = {0: .5, 1: .5} + X = FiniteRV('X', density) + assert E(X) == 0.5 + assert P( X>= 2) == 0 + +def test_issue_8129(): + X = Exponential('X', 4) + assert P(X >= X) == 1 + assert P(X > X) == 0 + assert P(X > X+1) == 0 + +def test_issue_12237(): + X = Normal('X', 0, 1) + Y = Normal('Y', 0, 1) + U = P(X > 0, X) + V = P(Y < 0, X) + W = P(X + Y > 0, X) + assert W == P(X + Y > 0, X) + assert U == BernoulliDistribution(S.Half, S.Zero, S.One) + assert V == S.Half + +def test_is_random(): + X = Normal('X', 0, 1) + Y = Normal('Y', 0, 1) + a, b = symbols('a, b') + G = GaussianUnitaryEnsemble('U', 2) + B = BernoulliProcess('B', 0.9) + assert not is_random(a) + assert not is_random(a + b) + assert not is_random(a * b) + assert not is_random(Matrix([a**2, b**2])) + assert is_random(X) + assert is_random(X**2 + Y) + assert is_random(Y + b**2) + assert is_random(Y > 5) + assert is_random(B[3] < 1) + assert is_random(G) + assert is_random(X * Y * B[1]) + assert is_random(Matrix([[X, B[2]], [G, Y]])) + assert is_random(Eq(X, 4)) + +def test_issue_12283(): + x = symbols('x') + X = RandomSymbol(x) + Y = RandomSymbol('Y') + Z = RandomMatrixSymbol('Z', 2, 1) + W = RandomMatrixSymbol('W', 2, 1) + RI = RandomIndexedSymbol(Indexed('RI', 3)) + assert pspace(Z) == PSpace() + assert pspace(RI) == PSpace() + assert pspace(X) == PSpace() + assert E(X) == Expectation(X) + assert P(Y > 3) == Probability(Y > 3) + assert variance(X) == Variance(X) + assert variance(RI) == Variance(RI) + assert covariance(X, Y) == Covariance(X, Y) + assert covariance(W, Z) == Covariance(W, Z) + +def test_issue_6810(): + X = Die('X', 6) + Y = Normal('Y', 0, 1) + assert P(Eq(X, 2)) == S(1)/6 + assert P(Eq(Y, 0)) == 0 + assert P(Or(X > 2, X < 3)) == 1 + assert P(And(X > 3, X > 2)) == S(1)/2 + +def test_issue_20286(): + n, p = symbols('n p') + B = Binomial('B', n, p) + k = Dummy('k', integer = True) + eq = Sum(Piecewise((-p**k*(1 - p)**(-k + n)*log(p**k*(1 - p)**(-k + n)*binomial(n, k))*binomial(n, k), (k >= 0) & (k <= n)), (nan, True)), (k, 0, n)) + assert eq.dummy_eq(H(B)) diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_stochastic_process.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_stochastic_process.py new file mode 100644 index 0000000000000000000000000000000000000000..3e42ffc8632240b1d85a774467a057e9857c567c --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_stochastic_process.py @@ -0,0 +1,763 @@ +from sympy.concrete.summations import Sum +from sympy.core.containers import Tuple +from sympy.core.function import Lambda +from sympy.core.numbers import (Float, Rational, oo, pi) +from sympy.core.relational import (Eq, Ge, Gt, Le, Lt, Ne) +from sympy.core.singleton import S +from sympy.core.symbol import (Symbol, symbols) +from sympy.functions.combinatorial.factorials import factorial +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.integers import ceiling +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.piecewise import Piecewise +from sympy.functions.special.error_functions import erf +from sympy.functions.special.gamma_functions import (gamma, lowergamma) +from sympy.logic.boolalg import (And, Not) +from sympy.matrices.dense import Matrix +from sympy.matrices.expressions.matexpr import MatrixSymbol +from sympy.matrices.immutable import ImmutableMatrix +from sympy.sets.contains import Contains +from sympy.sets.fancysets import Range +from sympy.sets.sets import (FiniteSet, Interval) +from sympy.stats import (DiscreteMarkovChain, P, TransitionMatrixOf, E, + StochasticStateSpaceOf, variance, ContinuousMarkovChain, + BernoulliProcess, PoissonProcess, WienerProcess, + GammaProcess, sample_stochastic_process) +from sympy.stats.joint_rv import JointDistribution +from sympy.stats.joint_rv_types import JointDistributionHandmade +from sympy.stats.rv import RandomIndexedSymbol +from sympy.stats.symbolic_probability import Probability, Expectation +from sympy.testing.pytest import (raises, skip, ignore_warnings, + warns_deprecated_sympy) +from sympy.external import import_module +from sympy.stats.frv_types import BernoulliDistribution +from sympy.stats.drv_types import PoissonDistribution +from sympy.stats.crv_types import NormalDistribution, GammaDistribution +from sympy.core.symbol import Str + + +def test_DiscreteMarkovChain(): + + # pass only the name + X = DiscreteMarkovChain("X") + assert isinstance(X.state_space, Range) + assert X.index_set == S.Naturals0 + assert isinstance(X.transition_probabilities, MatrixSymbol) + t = symbols('t', positive=True, integer=True) + assert isinstance(X[t], RandomIndexedSymbol) + assert E(X[0]) == Expectation(X[0]) + raises(TypeError, lambda: DiscreteMarkovChain(1)) + raises(NotImplementedError, lambda: X(t)) + raises(NotImplementedError, lambda: X.communication_classes()) + raises(NotImplementedError, lambda: X.canonical_form()) + raises(NotImplementedError, lambda: X.decompose()) + + nz = Symbol('n', integer=True) + TZ = MatrixSymbol('M', nz, nz) + SZ = Range(nz) + YZ = DiscreteMarkovChain('Y', SZ, TZ) + assert P(Eq(YZ[2], 1), Eq(YZ[1], 0)) == TZ[0, 1] + + raises(ValueError, lambda: sample_stochastic_process(t)) + raises(ValueError, lambda: next(sample_stochastic_process(X))) + # pass name and state_space + # any hashable object should be a valid state + # states should be valid as a tuple/set/list/Tuple/Range + sym, rainy, cloudy, sunny = symbols('a Rainy Cloudy Sunny', real=True) + state_spaces = [(1, 2, 3), [Str('Hello'), sym, DiscreteMarkovChain("Y", (1,2,3))], + Tuple(S(1), exp(sym), Str('World'), sympify=False), Range(-1, 5, 2), + [rainy, cloudy, sunny]] + chains = [DiscreteMarkovChain("Y", state_space) for state_space in state_spaces] + + for i, Y in enumerate(chains): + assert isinstance(Y.transition_probabilities, MatrixSymbol) + assert Y.state_space == state_spaces[i] or Y.state_space == FiniteSet(*state_spaces[i]) + assert Y.number_of_states == 3 + + with ignore_warnings(UserWarning): # TODO: Restore tests once warnings are removed + assert P(Eq(Y[2], 1), Eq(Y[0], 2), evaluate=False) == Probability(Eq(Y[2], 1), Eq(Y[0], 2)) + assert E(Y[0]) == Expectation(Y[0]) + + raises(ValueError, lambda: next(sample_stochastic_process(Y))) + + raises(TypeError, lambda: DiscreteMarkovChain("Y", {1: 1})) + Y = DiscreteMarkovChain("Y", Range(1, t, 2)) + assert Y.number_of_states == ceiling((t-1)/2) + + # pass name and transition_probabilities + chains = [DiscreteMarkovChain("Y", trans_probs=Matrix([])), + DiscreteMarkovChain("Y", trans_probs=Matrix([[0, 1], [1, 0]])), + DiscreteMarkovChain("Y", trans_probs=Matrix([[pi, 1-pi], [sym, 1-sym]]))] + for Z in chains: + assert Z.number_of_states == Z.transition_probabilities.shape[0] + assert isinstance(Z.transition_probabilities, ImmutableMatrix) + + # pass name, state_space and transition_probabilities + T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]]) + TS = MatrixSymbol('T', 3, 3) + Y = DiscreteMarkovChain("Y", [0, 1, 2], T) + YS = DiscreteMarkovChain("Y", ['One', 'Two', 3], TS) + assert Y.joint_distribution(1, Y[2], 3) == JointDistribution(Y[1], Y[2], Y[3]) + raises(ValueError, lambda: Y.joint_distribution(Y[1].symbol, Y[2].symbol)) + assert P(Eq(Y[3], 2), Eq(Y[1], 1)).round(2) == Float(0.36, 2) + assert (P(Eq(YS[3], 2), Eq(YS[1], 1)) - + (TS[0, 2]*TS[1, 0] + TS[1, 1]*TS[1, 2] + TS[1, 2]*TS[2, 2])).simplify() == 0 + assert P(Eq(YS[1], 1), Eq(YS[2], 2)) == Probability(Eq(YS[1], 1)) + assert P(Eq(YS[3], 3), Eq(YS[1], 1)) == TS[0, 2]*TS[1, 0] + TS[1, 1]*TS[1, 2] + TS[1, 2]*TS[2, 2] + TO = Matrix([[0.25, 0.75, 0],[0, 0.25, 0.75],[0.75, 0, 0.25]]) + assert P(Eq(Y[3], 2), Eq(Y[1], 1) & TransitionMatrixOf(Y, TO)).round(3) == Float(0.375, 3) + with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed + assert E(Y[3], evaluate=False) == Expectation(Y[3]) + assert E(Y[3], Eq(Y[2], 1)).round(2) == Float(1.1, 3) + TSO = MatrixSymbol('T', 4, 4) + raises(ValueError, lambda: str(P(Eq(YS[3], 2), Eq(YS[1], 1) & TransitionMatrixOf(YS, TSO)))) + raises(TypeError, lambda: DiscreteMarkovChain("Z", [0, 1, 2], symbols('M'))) + raises(ValueError, lambda: DiscreteMarkovChain("Z", [0, 1, 2], MatrixSymbol('T', 3, 4))) + raises(ValueError, lambda: E(Y[3], Eq(Y[2], 6))) + raises(ValueError, lambda: E(Y[2], Eq(Y[3], 1))) + + + # extended tests for probability queries + TO1 = Matrix([[Rational(1, 4), Rational(3, 4), 0],[Rational(1, 3), Rational(1, 3), Rational(1, 3)],[0, Rational(1, 4), Rational(3, 4)]]) + assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), + Eq(Probability(Eq(Y[0], 0)), Rational(1, 4)) & TransitionMatrixOf(Y, TO1)) == Rational(1, 16) + assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), TransitionMatrixOf(Y, TO1)) == \ + Probability(Eq(Y[0], 0))/4 + assert P(Lt(X[1], 2) & Gt(X[1], 0), Eq(X[0], 2) & + StochasticStateSpaceOf(X, [0, 1, 2]) & TransitionMatrixOf(X, TO1)) == Rational(1, 4) + assert P(Lt(X[1], 2) & Gt(X[1], 0), Eq(X[0], 2) & + StochasticStateSpaceOf(X, [S(0), '0', 1]) & TransitionMatrixOf(X, TO1)) == Rational(1, 4) + assert P(Ne(X[1], 2) & Ne(X[1], 1), Eq(X[0], 2) & + StochasticStateSpaceOf(X, [0, 1, 2]) & TransitionMatrixOf(X, TO1)) is S.Zero + assert P(Ne(X[1], 2) & Ne(X[1], 1), Eq(X[0], 2) & + StochasticStateSpaceOf(X, [S(0), '0', 1]) & TransitionMatrixOf(X, TO1)) is S.Zero + assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), Eq(Y[1], 1)) == 0.1*Probability(Eq(Y[0], 0)) + + # testing properties of Markov chain + TO2 = Matrix([[S.One, 0, 0],[Rational(1, 3), Rational(1, 3), Rational(1, 3)],[0, Rational(1, 4), Rational(3, 4)]]) + TO3 = Matrix([[Rational(1, 4), Rational(3, 4), 0],[Rational(1, 3), Rational(1, 3), Rational(1, 3)], [0, Rational(1, 4), Rational(3, 4)]]) + Y2 = DiscreteMarkovChain('Y', trans_probs=TO2) + Y3 = DiscreteMarkovChain('Y', trans_probs=TO3) + assert Y3.fundamental_matrix() == ImmutableMatrix([[176, 81, -132], [36, 141, -52], [-44, -39, 208]])/125 + assert Y2.is_absorbing_chain() == True + assert Y3.is_absorbing_chain() == False + assert Y2.canonical_form() == ([0, 1, 2], TO2) + assert Y3.canonical_form() == ([0, 1, 2], TO3) + assert Y2.decompose() == ([0, 1, 2], TO2[0:1, 0:1], TO2[1:3, 0:1], TO2[1:3, 1:3]) + assert Y3.decompose() == ([0, 1, 2], TO3, Matrix(0, 3, []), Matrix(0, 0, [])) + TO4 = Matrix([[Rational(1, 5), Rational(2, 5), Rational(2, 5)], [Rational(1, 10), S.Half, Rational(2, 5)], [Rational(3, 5), Rational(3, 10), Rational(1, 10)]]) + Y4 = DiscreteMarkovChain('Y', trans_probs=TO4) + w = ImmutableMatrix([[Rational(11, 39), Rational(16, 39), Rational(4, 13)]]) + assert Y4.limiting_distribution == w + assert Y4.is_regular() == True + assert Y4.is_ergodic() == True + TS1 = MatrixSymbol('T', 3, 3) + Y5 = DiscreteMarkovChain('Y', trans_probs=TS1) + assert Y5.limiting_distribution(w, TO4).doit() == True + assert Y5.stationary_distribution(condition_set=True).subs(TS1, TO4).contains(w).doit() == S.true + TO6 = Matrix([[S.One, 0, 0, 0, 0],[S.Half, 0, S.Half, 0, 0],[0, S.Half, 0, S.Half, 0], [0, 0, S.Half, 0, S.Half], [0, 0, 0, 0, 1]]) + Y6 = DiscreteMarkovChain('Y', trans_probs=TO6) + assert Y6.fundamental_matrix() == ImmutableMatrix([[Rational(3, 2), S.One, S.Half], [S.One, S(2), S.One], [S.Half, S.One, Rational(3, 2)]]) + assert Y6.absorbing_probabilities() == ImmutableMatrix([[Rational(3, 4), Rational(1, 4)], [S.Half, S.Half], [Rational(1, 4), Rational(3, 4)]]) + with warns_deprecated_sympy(): + Y6.absorbing_probabilites() + TO7 = Matrix([[Rational(1, 2), Rational(1, 4), Rational(1, 4)], [Rational(1, 2), 0, Rational(1, 2)], [Rational(1, 4), Rational(1, 4), Rational(1, 2)]]) + Y7 = DiscreteMarkovChain('Y', trans_probs=TO7) + assert Y7.is_absorbing_chain() == False + assert Y7.fundamental_matrix() == ImmutableMatrix([[Rational(86, 75), Rational(1, 25), Rational(-14, 75)], + [Rational(2, 25), Rational(21, 25), Rational(2, 25)], + [Rational(-14, 75), Rational(1, 25), Rational(86, 75)]]) + + # test for zero-sized matrix functionality + X = DiscreteMarkovChain('X', trans_probs=Matrix([])) + assert X.number_of_states == 0 + assert X.stationary_distribution() == Matrix([[]]) + assert X.communication_classes() == [] + assert X.canonical_form() == ([], Matrix([])) + assert X.decompose() == ([], Matrix([]), Matrix([]), Matrix([])) + assert X.is_regular() == False + assert X.is_ergodic() == False + + # test communication_class + # see https://drive.google.com/drive/folders/1HbxLlwwn2b3U8Lj7eb_ASIUb5vYaNIjg?usp=sharing + # tutorial 2.pdf + TO7 = Matrix([[0, 5, 5, 0, 0], + [0, 0, 0, 10, 0], + [5, 0, 5, 0, 0], + [0, 10, 0, 0, 0], + [0, 3, 0, 3, 4]])/10 + Y7 = DiscreteMarkovChain('Y', trans_probs=TO7) + tuples = Y7.communication_classes() + classes, recurrence, periods = list(zip(*tuples)) + assert classes == ([1, 3], [0, 2], [4]) + assert recurrence == (True, False, False) + assert periods == (2, 1, 1) + + TO8 = Matrix([[0, 0, 0, 10, 0, 0], + [5, 0, 5, 0, 0, 0], + [0, 4, 0, 0, 0, 6], + [10, 0, 0, 0, 0, 0], + [0, 10, 0, 0, 0, 0], + [0, 0, 0, 5, 5, 0]])/10 + Y8 = DiscreteMarkovChain('Y', trans_probs=TO8) + tuples = Y8.communication_classes() + classes, recurrence, periods = list(zip(*tuples)) + assert classes == ([0, 3], [1, 2, 5, 4]) + assert recurrence == (True, False) + assert periods == (2, 2) + + TO9 = Matrix([[2, 0, 0, 3, 0, 0, 3, 2, 0, 0], + [0, 10, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 2, 2, 0, 0, 0, 0, 0, 3, 3], + [0, 0, 0, 3, 0, 0, 6, 1, 0, 0], + [0, 0, 0, 0, 5, 5, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 10, 0, 0, 0, 0], + [4, 0, 0, 5, 0, 0, 1, 0, 0, 0], + [2, 0, 0, 4, 0, 0, 2, 2, 0, 0], + [3, 0, 1, 0, 0, 0, 0, 0, 4, 2], + [0, 0, 4, 0, 0, 0, 0, 0, 3, 3]])/10 + Y9 = DiscreteMarkovChain('Y', trans_probs=TO9) + tuples = Y9.communication_classes() + classes, recurrence, periods = list(zip(*tuples)) + assert classes == ([0, 3, 6, 7], [1], [2, 8, 9], [5], [4]) + assert recurrence == (True, True, False, True, False) + assert periods == (1, 1, 1, 1, 1) + + # test canonical form + # see https://web.archive.org/web/20201230182007/https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf + # example 11.13 + T = Matrix([[1, 0, 0, 0, 0], + [S(1) / 2, 0, S(1) / 2, 0, 0], + [0, S(1) / 2, 0, S(1) / 2, 0], + [0, 0, S(1) / 2, 0, S(1) / 2], + [0, 0, 0, 0, S(1)]]) + DW = DiscreteMarkovChain('DW', [0, 1, 2, 3, 4], T) + states, A, B, C = DW.decompose() + assert states == [0, 4, 1, 2, 3] + assert A == Matrix([[1, 0], [0, 1]]) + assert B == Matrix([[S(1)/2, 0], [0, 0], [0, S(1)/2]]) + assert C == Matrix([[0, S(1)/2, 0], [S(1)/2, 0, S(1)/2], [0, S(1)/2, 0]]) + states, new_matrix = DW.canonical_form() + assert states == [0, 4, 1, 2, 3] + assert new_matrix == Matrix([[1, 0, 0, 0, 0], + [0, 1, 0, 0, 0], + [S(1)/2, 0, 0, S(1)/2, 0], + [0, 0, S(1)/2, 0, S(1)/2], + [0, S(1)/2, 0, S(1)/2, 0]]) + + # test regular and ergodic + # https://web.archive.org/web/20201230182007/https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf + T = Matrix([[0, 4, 0, 0, 0], + [1, 0, 3, 0, 0], + [0, 2, 0, 2, 0], + [0, 0, 3, 0, 1], + [0, 0, 0, 4, 0]])/4 + X = DiscreteMarkovChain('X', trans_probs=T) + assert not X.is_regular() + assert X.is_ergodic() + T = Matrix([[0, 1], [1, 0]]) + X = DiscreteMarkovChain('X', trans_probs=T) + assert not X.is_regular() + assert X.is_ergodic() + # http://www.math.wisc.edu/~valko/courses/331/MC2.pdf + T = Matrix([[2, 1, 1], + [2, 0, 2], + [1, 1, 2]])/4 + X = DiscreteMarkovChain('X', trans_probs=T) + assert X.is_regular() + assert X.is_ergodic() + # https://docs.ufpr.br/~lucambio/CE222/1S2014/Kemeny-Snell1976.pdf + T = Matrix([[1, 1], [1, 1]])/2 + X = DiscreteMarkovChain('X', trans_probs=T) + assert X.is_regular() + assert X.is_ergodic() + + # test is_absorbing_chain + T = Matrix([[0, 1, 0], + [1, 0, 0], + [0, 0, 1]]) + X = DiscreteMarkovChain('X', trans_probs=T) + assert not X.is_absorbing_chain() + # https://en.wikipedia.org/wiki/Absorbing_Markov_chain + T = Matrix([[1, 1, 0, 0], + [0, 1, 1, 0], + [1, 0, 0, 1], + [0, 0, 0, 2]])/2 + X = DiscreteMarkovChain('X', trans_probs=T) + assert X.is_absorbing_chain() + T = Matrix([[2, 0, 0, 0, 0], + [1, 0, 1, 0, 0], + [0, 1, 0, 1, 0], + [0, 0, 1, 0, 1], + [0, 0, 0, 0, 2]])/2 + X = DiscreteMarkovChain('X', trans_probs=T) + assert X.is_absorbing_chain() + + # test custom state space + Y10 = DiscreteMarkovChain('Y', [1, 2, 3], TO2) + tuples = Y10.communication_classes() + classes, recurrence, periods = list(zip(*tuples)) + assert classes == ([1], [2, 3]) + assert recurrence == (True, False) + assert periods == (1, 1) + assert Y10.canonical_form() == ([1, 2, 3], TO2) + assert Y10.decompose() == ([1, 2, 3], TO2[0:1, 0:1], TO2[1:3, 0:1], TO2[1:3, 1:3]) + + # testing miscellaneous queries + T = Matrix([[S.Half, Rational(1, 4), Rational(1, 4)], + [Rational(1, 3), 0, Rational(2, 3)], + [S.Half, S.Half, 0]]) + X = DiscreteMarkovChain('X', [0, 1, 2], T) + assert P(Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0), + Eq(P(Eq(X[1], 0)), Rational(1, 4)) & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12) + assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3) + assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero + assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3) + assert E(X[1]**2, Eq(X[0], 1)) == Rational(8, 3) + assert variance(X[1], Eq(X[0], 1)) == Rational(8, 9) + raises(ValueError, lambda: E(X[1], Eq(X[2], 1))) + raises(ValueError, lambda: DiscreteMarkovChain('X', [0, 1], T)) + + # testing miscellaneous queries with different state space + X = DiscreteMarkovChain('X', ['A', 'B', 'C'], T) + assert P(Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0), + Eq(P(Eq(X[1], 0)), Rational(1, 4)) & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12) + assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3) + assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero + assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3) + a = X.state_space.args[0] + c = X.state_space.args[2] + assert (E(X[1] ** 2, Eq(X[0], 1)) - (a**2/3 + 2*c**2/3)).simplify() == 0 + assert (variance(X[1], Eq(X[0], 1)) - (2*(-a/3 + c/3)**2/3 + (2*a/3 - 2*c/3)**2/3)).simplify() == 0 + raises(ValueError, lambda: E(X[1], Eq(X[2], 1))) + + #testing queries with multiple RandomIndexedSymbols + T = Matrix([[Rational(5, 10), Rational(3, 10), Rational(2, 10)], [Rational(2, 10), Rational(7, 10), Rational(1, 10)], [Rational(3, 10), Rational(3, 10), Rational(4, 10)]]) + Y = DiscreteMarkovChain("Y", [0, 1, 2], T) + assert P(Eq(Y[7], Y[5]), Eq(Y[2], 0)).round(5) == Float(0.44428, 5) + assert P(Gt(Y[3], Y[1]), Eq(Y[0], 0)).round(2) == Float(0.36, 2) + assert P(Le(Y[5], Y[10]), Eq(Y[4], 2)).round(6) == Float(0.583120, 6) + assert Float(P(Eq(Y[10], Y[5]), Eq(Y[4], 1)), 14) == Float(1 - P(Ne(Y[10], Y[5]), Eq(Y[4], 1)), 14) + assert Float(P(Gt(Y[8], Y[9]), Eq(Y[3], 2)), 14) == Float(1 - P(Le(Y[8], Y[9]), Eq(Y[3], 2)), 14) + assert Float(P(Lt(Y[1], Y[4]), Eq(Y[0], 0)), 14) == Float(1 - P(Ge(Y[1], Y[4]), Eq(Y[0], 0)), 14) + assert P(Eq(Y[5], Y[10]), Eq(Y[2], 1)) == P(Eq(Y[10], Y[5]), Eq(Y[2], 1)) + assert P(Gt(Y[1], Y[2]), Eq(Y[0], 1)) == P(Lt(Y[2], Y[1]), Eq(Y[0], 1)) + assert P(Ge(Y[7], Y[6]), Eq(Y[4], 1)) == P(Le(Y[6], Y[7]), Eq(Y[4], 1)) + + #test symbolic queries + a, b, c, d = symbols('a b c d') + T = Matrix([[Rational(1, 10), Rational(4, 10), Rational(5, 10)], [Rational(3, 10), Rational(4, 10), Rational(3, 10)], [Rational(7, 10), Rational(2, 10), Rational(1, 10)]]) + Y = DiscreteMarkovChain("Y", [0, 1, 2], T) + query = P(Eq(Y[a], b), Eq(Y[c], d)) + assert query.subs({a:10, b:2, c:5, d:1}).evalf().round(4) == P(Eq(Y[10], 2), Eq(Y[5], 1)).round(4) + assert query.subs({a:15, b:0, c:10, d:1}).evalf().round(4) == P(Eq(Y[15], 0), Eq(Y[10], 1)).round(4) + query_gt = P(Gt(Y[a], b), Eq(Y[c], d)) + query_le = P(Le(Y[a], b), Eq(Y[c], d)) + assert query_gt.subs({a:5, b:2, c:1, d:0}).evalf() + query_le.subs({a:5, b:2, c:1, d:0}).evalf() == 1.0 + query_ge = P(Ge(Y[a], b), Eq(Y[c], d)) + query_lt = P(Lt(Y[a], b), Eq(Y[c], d)) + assert query_ge.subs({a:4, b:1, c:0, d:2}).evalf() + query_lt.subs({a:4, b:1, c:0, d:2}).evalf() == 1.0 + + #test issue 20078 + assert (2*Y[1] + 3*Y[1]).simplify() == 5*Y[1] + assert (2*Y[1] - 3*Y[1]).simplify() == -Y[1] + assert (2*(0.25*Y[1])).simplify() == 0.5*Y[1] + assert ((2*Y[1]) * (0.25*Y[1])).simplify() == 0.5*Y[1]**2 + assert (Y[1]**2 + Y[1]**3).simplify() == (Y[1] + 1)*Y[1]**2 + +def test_sample_stochastic_process(): + if not import_module('scipy'): + skip('SciPy Not installed. Skip sampling tests') + import random + random.seed(0) + numpy = import_module('numpy') + if numpy: + numpy.random.seed(0) # scipy uses numpy to sample so to set its seed + T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]]) + Y = DiscreteMarkovChain("Y", [0, 1, 2], T) + for samps in range(10): + assert next(sample_stochastic_process(Y)) in Y.state_space + Z = DiscreteMarkovChain("Z", ['1', 1, 0], T) + for samps in range(10): + assert next(sample_stochastic_process(Z)) in Z.state_space + + T = Matrix([[S.Half, Rational(1, 4), Rational(1, 4)], + [Rational(1, 3), 0, Rational(2, 3)], + [S.Half, S.Half, 0]]) + X = DiscreteMarkovChain('X', [0, 1, 2], T) + for samps in range(10): + assert next(sample_stochastic_process(X)) in X.state_space + W = DiscreteMarkovChain('W', [1, pi, oo], T) + for samps in range(10): + assert next(sample_stochastic_process(W)) in W.state_space + + +def test_ContinuousMarkovChain(): + T1 = Matrix([[S(-2), S(2), S.Zero], + [S.Zero, S.NegativeOne, S.One], + [Rational(3, 2), Rational(3, 2), S(-3)]]) + C1 = ContinuousMarkovChain('C', [0, 1, 2], T1) + assert C1.limiting_distribution() == ImmutableMatrix([[Rational(3, 19), Rational(12, 19), Rational(4, 19)]]) + + T2 = Matrix([[-S.One, S.One, S.Zero], [S.One, -S.One, S.Zero], [S.Zero, S.One, -S.One]]) + C2 = ContinuousMarkovChain('C', [0, 1, 2], T2) + A, t = C2.generator_matrix, symbols('t', positive=True) + assert C2.transition_probabilities(A)(t) == Matrix([[S.Half + exp(-2*t)/2, S.Half - exp(-2*t)/2, 0], + [S.Half - exp(-2*t)/2, S.Half + exp(-2*t)/2, 0], + [S.Half - exp(-t) + exp(-2*t)/2, S.Half - exp(-2*t)/2, exp(-t)]]) + with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed + assert P(Eq(C2(1), 1), Eq(C2(0), 1), evaluate=False) == Probability(Eq(C2(1), 1), Eq(C2(0), 1)) + assert P(Eq(C2(1), 1), Eq(C2(0), 1)) == exp(-2)/2 + S.Half + assert P(Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 1), + Eq(P(Eq(C2(1), 0)), S.Half)) == (Rational(1, 4) - exp(-2)/4)*(exp(-2)/2 + S.Half) + assert P(Not(Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 2)) | + (Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 2)), + Eq(P(Eq(C2(1), 0)), Rational(1, 4)) & Eq(P(Eq(C2(1), 1)), Rational(1, 4))) is S.One + assert E(C2(Rational(3, 2)), Eq(C2(0), 2)) == -exp(-3)/2 + 2*exp(Rational(-3, 2)) + S.Half + assert variance(C2(Rational(3, 2)), Eq(C2(0), 1)) == ((S.Half - exp(-3)/2)**2*(exp(-3)/2 + S.Half) + + (Rational(-1, 2) - exp(-3)/2)**2*(S.Half - exp(-3)/2)) + raises(KeyError, lambda: P(Eq(C2(1), 0), Eq(P(Eq(C2(1), 1)), S.Half))) + assert P(Eq(C2(1), 0), Eq(P(Eq(C2(5), 1)), S.Half)) == Probability(Eq(C2(1), 0)) + TS1 = MatrixSymbol('G', 3, 3) + CS1 = ContinuousMarkovChain('C', [0, 1, 2], TS1) + A = CS1.generator_matrix + assert CS1.transition_probabilities(A)(t) == exp(t*A) + + C3 = ContinuousMarkovChain('C', [Symbol('0'), Symbol('1'), Symbol('2')], T2) + assert P(Eq(C3(1), 1), Eq(C3(0), 1)) == exp(-2)/2 + S.Half + assert P(Eq(C3(1), Symbol('1')), Eq(C3(0), Symbol('1'))) == exp(-2)/2 + S.Half + + #test probability queries + G = Matrix([[-S(1), Rational(1, 10), Rational(9, 10)], [Rational(2, 5), -S(1), Rational(3, 5)], [Rational(1, 2), Rational(1, 2), -S(1)]]) + C = ContinuousMarkovChain('C', state_space=[0, 1, 2], gen_mat=G) + assert P(Eq(C(7.385), C(3.19)), Eq(C(0.862), 0)).round(5) == Float(0.35469, 5) + assert P(Gt(C(98.715), C(19.807)), Eq(C(11.314), 2)).round(5) == Float(0.32452, 5) + assert P(Le(C(5.9), C(10.112)), Eq(C(4), 1)).round(6) == Float(0.675214, 6) + assert Float(P(Eq(C(7.32), C(2.91)), Eq(C(2.63), 1)), 14) == Float(1 - P(Ne(C(7.32), C(2.91)), Eq(C(2.63), 1)), 14) + assert Float(P(Gt(C(3.36), C(1.101)), Eq(C(0.8), 2)), 14) == Float(1 - P(Le(C(3.36), C(1.101)), Eq(C(0.8), 2)), 14) + assert Float(P(Lt(C(4.9), C(2.79)), Eq(C(1.61), 0)), 14) == Float(1 - P(Ge(C(4.9), C(2.79)), Eq(C(1.61), 0)), 14) + assert P(Eq(C(5.243), C(10.912)), Eq(C(2.174), 1)) == P(Eq(C(10.912), C(5.243)), Eq(C(2.174), 1)) + assert P(Gt(C(2.344), C(9.9)), Eq(C(1.102), 1)) == P(Lt(C(9.9), C(2.344)), Eq(C(1.102), 1)) + assert P(Ge(C(7.87), C(1.008)), Eq(C(0.153), 1)) == P(Le(C(1.008), C(7.87)), Eq(C(0.153), 1)) + + #test symbolic queries + a, b, c, d = symbols('a b c d') + query = P(Eq(C(a), b), Eq(C(c), d)) + assert query.subs({a:3.65, b:2, c:1.78, d:1}).evalf().round(10) == P(Eq(C(3.65), 2), Eq(C(1.78), 1)).round(10) + query_gt = P(Gt(C(a), b), Eq(C(c), d)) + query_le = P(Le(C(a), b), Eq(C(c), d)) + assert query_gt.subs({a:13.2, b:0, c:3.29, d:2}).evalf() + query_le.subs({a:13.2, b:0, c:3.29, d:2}).evalf() == 1.0 + query_ge = P(Ge(C(a), b), Eq(C(c), d)) + query_lt = P(Lt(C(a), b), Eq(C(c), d)) + assert query_ge.subs({a:7.43, b:1, c:1.45, d:0}).evalf() + query_lt.subs({a:7.43, b:1, c:1.45, d:0}).evalf() == 1.0 + + #test issue 20078 + assert (2*C(1) + 3*C(1)).simplify() == 5*C(1) + assert (2*C(1) - 3*C(1)).simplify() == -C(1) + assert (2*(0.25*C(1))).simplify() == 0.5*C(1) + assert (2*C(1) * 0.25*C(1)).simplify() == 0.5*C(1)**2 + assert (C(1)**2 + C(1)**3).simplify() == (C(1) + 1)*C(1)**2 + +def test_BernoulliProcess(): + + B = BernoulliProcess("B", p=0.6, success=1, failure=0) + assert B.state_space == FiniteSet(0, 1) + assert B.index_set == S.Naturals0 + assert B.success == 1 + assert B.failure == 0 + + X = BernoulliProcess("X", p=Rational(1,3), success='H', failure='T') + assert X.state_space == FiniteSet('H', 'T') + H, T = symbols("H,T") + assert E(X[1]+X[2]*X[3]) == H**2/9 + 4*H*T/9 + H/3 + 4*T**2/9 + 2*T/3 + + t, x = symbols('t, x', positive=True, integer=True) + assert isinstance(B[t], RandomIndexedSymbol) + + raises(ValueError, lambda: BernoulliProcess("X", p=1.1, success=1, failure=0)) + raises(NotImplementedError, lambda: B(t)) + + raises(IndexError, lambda: B[-3]) + assert B.joint_distribution(B[3], B[9]) == JointDistributionHandmade(Lambda((B[3], B[9]), + Piecewise((0.6, Eq(B[3], 1)), (0.4, Eq(B[3], 0)), (0, True)) + *Piecewise((0.6, Eq(B[9], 1)), (0.4, Eq(B[9], 0)), (0, True)))) + + assert B.joint_distribution(2, B[4]) == JointDistributionHandmade(Lambda((B[2], B[4]), + Piecewise((0.6, Eq(B[2], 1)), (0.4, Eq(B[2], 0)), (0, True)) + *Piecewise((0.6, Eq(B[4], 1)), (0.4, Eq(B[4], 0)), (0, True)))) + + # Test for the sum distribution of Bernoulli Process RVs + Y = B[1] + B[2] + B[3] + assert P(Eq(Y, 0)).round(2) == Float(0.06, 1) + assert P(Eq(Y, 2)).round(2) == Float(0.43, 2) + assert P(Eq(Y, 4)).round(2) == 0 + assert P(Gt(Y, 1)).round(2) == Float(0.65, 2) + # Test for independency of each Random Indexed variable + assert P(Eq(B[1], 0) & Eq(B[2], 1) & Eq(B[3], 0) & Eq(B[4], 1)).round(2) == Float(0.06, 1) + + assert E(2 * B[1] + B[2]).round(2) == Float(1.80, 3) + assert E(2 * B[1] + B[2] + 5).round(2) == Float(6.80, 3) + assert E(B[2] * B[4] + B[10]).round(2) == Float(0.96, 2) + assert E(B[2] > 0, Eq(B[1],1) & Eq(B[2],1)).round(2) == Float(0.60,2) + assert E(B[1]) == 0.6 + assert P(B[1] > 0).round(2) == Float(0.60, 2) + assert P(B[1] < 1).round(2) == Float(0.40, 2) + assert P(B[1] > 0, B[2] <= 1).round(2) == Float(0.60, 2) + assert P(B[12] * B[5] > 0).round(2) == Float(0.36, 2) + assert P(B[12] * B[5] > 0, B[4] < 1).round(2) == Float(0.36, 2) + assert P(Eq(B[2], 1), B[2] > 0) == 1.0 + assert P(Eq(B[5], 3)) == 0 + assert P(Eq(B[1], 1), B[1] < 0) == 0 + assert P(B[2] > 0, Eq(B[2], 1)) == 1 + assert P(B[2] < 0, Eq(B[2], 1)) == 0 + assert P(B[2] > 0, B[2]==7) == 0 + assert P(B[5] > 0, B[5]) == BernoulliDistribution(0.6, 0, 1) + raises(ValueError, lambda: P(3)) + raises(ValueError, lambda: P(B[3] > 0, 3)) + + # test issue 19456 + expr = Sum(B[t], (t, 0, 4)) + expr2 = Sum(B[t], (t, 1, 3)) + expr3 = Sum(B[t]**2, (t, 1, 3)) + assert expr.doit() == B[0] + B[1] + B[2] + B[3] + B[4] + assert expr2.doit() == Y + assert expr3.doit() == B[1]**2 + B[2]**2 + B[3]**2 + assert B[2*t].free_symbols == {B[2*t], t} + assert B[4].free_symbols == {B[4]} + assert B[x*t].free_symbols == {B[x*t], x, t} + + #test issue 20078 + assert (2*B[t] + 3*B[t]).simplify() == 5*B[t] + assert (2*B[t] - 3*B[t]).simplify() == -B[t] + assert (2*(0.25*B[t])).simplify() == 0.5*B[t] + assert (2*B[t] * 0.25*B[t]).simplify() == 0.5*B[t]**2 + assert (B[t]**2 + B[t]**3).simplify() == (B[t] + 1)*B[t]**2 + +def test_PoissonProcess(): + X = PoissonProcess("X", 3) + assert X.state_space == S.Naturals0 + assert X.index_set == Interval(0, oo) + assert X.lamda == 3 + + t, d, x, y = symbols('t d x y', positive=True) + assert isinstance(X(t), RandomIndexedSymbol) + assert X.distribution(t) == PoissonDistribution(3*t) + with warns_deprecated_sympy(): + X.distribution(X(t)) + raises(ValueError, lambda: PoissonProcess("X", -1)) + raises(NotImplementedError, lambda: X[t]) + raises(IndexError, lambda: X(-5)) + + assert X.joint_distribution(X(2), X(3)) == JointDistributionHandmade(Lambda((X(2), X(3)), + 6**X(2)*9**X(3)*exp(-15)/(factorial(X(2))*factorial(X(3))))) + + assert X.joint_distribution(4, 6) == JointDistributionHandmade(Lambda((X(4), X(6)), + 12**X(4)*18**X(6)*exp(-30)/(factorial(X(4))*factorial(X(6))))) + + assert P(X(t) < 1) == exp(-3*t) + assert P(Eq(X(t), 0), Contains(t, Interval.Lopen(3, 5))) == exp(-6) # exp(-2*lamda) + res = P(Eq(X(t), 1), Contains(t, Interval.Lopen(3, 4))) + assert res == 3*exp(-3) + + # Equivalent to P(Eq(X(t), 1))**4 because of non-overlapping intervals + assert P(Eq(X(t), 1) & Eq(X(d), 1) & Eq(X(x), 1) & Eq(X(y), 1), Contains(t, Interval.Lopen(0, 1)) + & Contains(d, Interval.Lopen(1, 2)) & Contains(x, Interval.Lopen(2, 3)) + & Contains(y, Interval.Lopen(3, 4))) == res**4 + + # Return Probability because of overlapping intervals + assert P(Eq(X(t), 2) & Eq(X(d), 3), Contains(t, Interval.Lopen(0, 2)) + & Contains(d, Interval.Ropen(2, 4))) == \ + Probability(Eq(X(d), 3) & Eq(X(t), 2), Contains(t, Interval.Lopen(0, 2)) + & Contains(d, Interval.Ropen(2, 4))) + + raises(ValueError, lambda: P(Eq(X(t), 2) & Eq(X(d), 3), + Contains(t, Interval.Lopen(0, 4)) & Contains(d, Interval.Lopen(3, oo)))) # no bound on d + assert P(Eq(X(3), 2)) == 81*exp(-9)/2 + assert P(Eq(X(t), 2), Contains(t, Interval.Lopen(0, 5))) == 225*exp(-15)/2 + + # Check that probability works correctly by adding it to 1 + res1 = P(X(t) <= 3, Contains(t, Interval.Lopen(0, 5))) + res2 = P(X(t) > 3, Contains(t, Interval.Lopen(0, 5))) + assert res1 == 691*exp(-15) + assert (res1 + res2).simplify() == 1 + + # Check Not and Or + assert P(Not(Eq(X(t), 2) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) & \ + Contains(d, Interval.Lopen(7, 8))).simplify() == -18*exp(-6) + 234*exp(-9) + 1 + assert P(Eq(X(t), 2) | Ne(X(t), 4), Contains(t, Interval.Ropen(2, 4))) == 1 - 36*exp(-6) + raises(ValueError, lambda: P(X(t) > 2, X(t) + X(d))) + assert E(X(t)) == 3*t # property of the distribution at a given timestamp + assert E(X(t)**2 + X(d)*2 + X(y)**3, Contains(t, Interval.Lopen(0, 1)) + & Contains(d, Interval.Lopen(1, 2)) & Contains(y, Interval.Ropen(3, 4))) == 75 + assert E(X(t)**2, Contains(t, Interval.Lopen(0, 1))) == 12 + assert E(x*(X(t) + X(d))*(X(t)**2+X(d)**2), Contains(t, Interval.Lopen(0, 1)) + & Contains(d, Interval.Ropen(1, 2))) == \ + Expectation(x*(X(d) + X(t))*(X(d)**2 + X(t)**2), Contains(t, Interval.Lopen(0, 1)) + & Contains(d, Interval.Ropen(1, 2))) + + # Value Error because of infinite time bound + raises(ValueError, lambda: E(X(t)**3, Contains(t, Interval.Lopen(1, oo)))) + + # Equivalent to E(X(t)**2) - E(X(d)**2) == E(X(1)**2) - E(X(1)**2) == 0 + assert E((X(t) + X(d))*(X(t) - X(d)), Contains(t, Interval.Lopen(0, 1)) + & Contains(d, Interval.Lopen(1, 2))) == 0 + assert E(X(2) + x*E(X(5))) == 15*x + 6 + assert E(x*X(1) + y) == 3*x + y + assert P(Eq(X(1), 2) & Eq(X(t), 3), Contains(t, Interval.Lopen(1, 2))) == 81*exp(-6)/4 + Y = PoissonProcess("Y", 6) + Z = X + Y + assert Z.lamda == X.lamda + Y.lamda == 9 + raises(ValueError, lambda: X + 5) # should be added be only PoissonProcess instance + N, M = Z.split(4, 5) + assert N.lamda == 4 + assert M.lamda == 5 + raises(ValueError, lambda: Z.split(3, 2)) # 2+3 != 9 + + raises(ValueError, lambda :P(Eq(X(t), 0), Contains(t, Interval.Lopen(1, 3)) & Eq(X(1), 0))) + # check if it handles queries with two random variables in one args + res1 = P(Eq(N(3), N(5))) + assert res1 == P(Eq(N(t), 0), Contains(t, Interval(3, 5))) + res2 = P(N(3) > N(1)) + assert res2 == P((N(t) > 0), Contains(t, Interval(1, 3))) + assert P(N(3) < N(1)) == 0 # condition is not possible + res3 = P(N(3) <= N(1)) # holds only for Eq(N(3), N(1)) + assert res3 == P(Eq(N(t), 0), Contains(t, Interval(1, 3))) + + # tests from https://www.probabilitycourse.com/chapter11/11_1_2_basic_concepts_of_the_poisson_process.php + X = PoissonProcess('X', 10) # 11.1 + assert P(Eq(X(S(1)/3), 3) & Eq(X(1), 10)) == exp(-10)*Rational(8000000000, 11160261) + assert P(Eq(X(1), 1), Eq(X(S(1)/3), 3)) == 0 + assert P(Eq(X(1), 10), Eq(X(S(1)/3), 3)) == P(Eq(X(S(2)/3), 7)) + + X = PoissonProcess('X', 2) # 11.2 + assert P(X(S(1)/2) < 1) == exp(-1) + assert P(X(3) < 1, Eq(X(1), 0)) == exp(-4) + assert P(Eq(X(4), 3), Eq(X(2), 3)) == exp(-4) + + X = PoissonProcess('X', 3) + assert P(Eq(X(2), 5) & Eq(X(1), 2)) == Rational(81, 4)*exp(-6) + + # check few properties + assert P(X(2) <= 3, X(1)>=1) == 3*P(Eq(X(1), 0)) + 2*P(Eq(X(1), 1)) + P(Eq(X(1), 2)) + assert P(X(2) <= 3, X(1) > 1) == 2*P(Eq(X(1), 0)) + 1*P(Eq(X(1), 1)) + assert P(Eq(X(2), 5) & Eq(X(1), 2)) == P(Eq(X(1), 3))*P(Eq(X(1), 2)) + assert P(Eq(X(3), 4), Eq(X(1), 3)) == P(Eq(X(2), 1)) + + #test issue 20078 + assert (2*X(t) + 3*X(t)).simplify() == 5*X(t) + assert (2*X(t) - 3*X(t)).simplify() == -X(t) + assert (2*(0.25*X(t))).simplify() == 0.5*X(t) + assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2 + assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2 + +def test_WienerProcess(): + X = WienerProcess("X") + assert X.state_space == S.Reals + assert X.index_set == Interval(0, oo) + + t, d, x, y = symbols('t d x y', positive=True) + assert isinstance(X(t), RandomIndexedSymbol) + assert X.distribution(t) == NormalDistribution(0, sqrt(t)) + with warns_deprecated_sympy(): + X.distribution(X(t)) + raises(ValueError, lambda: PoissonProcess("X", -1)) + raises(NotImplementedError, lambda: X[t]) + raises(IndexError, lambda: X(-2)) + + assert X.joint_distribution(X(2), X(3)) == JointDistributionHandmade( + Lambda((X(2), X(3)), sqrt(6)*exp(-X(2)**2/4)*exp(-X(3)**2/6)/(12*pi))) + assert X.joint_distribution(4, 6) == JointDistributionHandmade( + Lambda((X(4), X(6)), sqrt(6)*exp(-X(4)**2/8)*exp(-X(6)**2/12)/(24*pi))) + + assert P(X(t) < 3).simplify() == erf(3*sqrt(2)/(2*sqrt(t)))/2 + S(1)/2 + assert P(X(t) > 2, Contains(t, Interval.Lopen(3, 7))).simplify() == S(1)/2 -\ + erf(sqrt(2)/2)/2 + + # Equivalent to P(X(1)>1)**4 + assert P((X(t) > 4) & (X(d) > 3) & (X(x) > 2) & (X(y) > 1), + Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2)) + & Contains(x, Interval.Lopen(2, 3)) & Contains(y, Interval.Lopen(3, 4))).simplify() ==\ + (1 - erf(sqrt(2)/2))*(1 - erf(sqrt(2)))*(1 - erf(3*sqrt(2)/2))*(1 - erf(2*sqrt(2)))/16 + + # Contains an overlapping interval so, return Probability + assert P((X(t)< 2) & (X(d)> 3), Contains(t, Interval.Lopen(0, 2)) + & Contains(d, Interval.Ropen(2, 4))) == Probability((X(d) > 3) & (X(t) < 2), + Contains(d, Interval.Ropen(2, 4)) & Contains(t, Interval.Lopen(0, 2))) + + assert str(P(Not((X(t) < 5) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) & + Contains(d, Interval.Lopen(7, 8))).simplify()) == \ + '-(1 - erf(3*sqrt(2)/2))*(2 - erfc(5/2))/4 + 1' + # Distribution has mean 0 at each timestamp + assert E(X(t)) == 0 + assert E(x*(X(t) + X(d))*(X(t)**2+X(d)**2), Contains(t, Interval.Lopen(0, 1)) + & Contains(d, Interval.Ropen(1, 2))) == Expectation(x*(X(d) + X(t))*(X(d)**2 + X(t)**2), + Contains(d, Interval.Ropen(1, 2)) & Contains(t, Interval.Lopen(0, 1))) + assert E(X(t) + x*E(X(3))) == 0 + + #test issue 20078 + assert (2*X(t) + 3*X(t)).simplify() == 5*X(t) + assert (2*X(t) - 3*X(t)).simplify() == -X(t) + assert (2*(0.25*X(t))).simplify() == 0.5*X(t) + assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2 + assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2 + + +def test_GammaProcess_symbolic(): + t, d, x, y, g, l = symbols('t d x y g l', positive=True) + X = GammaProcess("X", l, g) + + raises(NotImplementedError, lambda: X[t]) + raises(IndexError, lambda: X(-1)) + assert isinstance(X(t), RandomIndexedSymbol) + assert X.state_space == Interval(0, oo) + assert X.distribution(t) == GammaDistribution(g*t, 1/l) + with warns_deprecated_sympy(): + X.distribution(X(t)) + assert X.joint_distribution(5, X(3)) == JointDistributionHandmade(Lambda( + (X(5), X(3)), l**(8*g)*exp(-l*X(3))*exp(-l*X(5))*X(3)**(3*g - 1)*X(5)**(5*g + - 1)/(gamma(3*g)*gamma(5*g)))) + # property of the gamma process at any given timestamp + assert E(X(t)) == g*t/l + assert variance(X(t)).simplify() == g*t/l**2 + + # Equivalent to E(2*X(1)) + E(X(1)**2) + E(X(1)**3), where E(X(1)) == g/l + assert E(X(t)**2 + X(d)*2 + X(y)**3, Contains(t, Interval.Lopen(0, 1)) + & Contains(d, Interval.Lopen(1, 2)) & Contains(y, Interval.Ropen(3, 4))) == \ + 2*g/l + (g**2 + g)/l**2 + (g**3 + 3*g**2 + 2*g)/l**3 + + assert P(X(t) > 3, Contains(t, Interval.Lopen(3, 4))).simplify() == \ + 1 - lowergamma(g, 3*l)/gamma(g) # equivalent to P(X(1)>3) + + + #test issue 20078 + assert (2*X(t) + 3*X(t)).simplify() == 5*X(t) + assert (2*X(t) - 3*X(t)).simplify() == -X(t) + assert (2*(0.25*X(t))).simplify() == 0.5*X(t) + assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2 + assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2 +def test_GammaProcess_numeric(): + t, d, x, y = symbols('t d x y', positive=True) + X = GammaProcess("X", 1, 2) + assert X.state_space == Interval(0, oo) + assert X.index_set == Interval(0, oo) + assert X.lamda == 1 + assert X.gamma == 2 + + raises(ValueError, lambda: GammaProcess("X", -1, 2)) + raises(ValueError, lambda: GammaProcess("X", 0, -2)) + raises(ValueError, lambda: GammaProcess("X", -1, -2)) + + # all are independent because of non-overlapping intervals + assert P((X(t) > 4) & (X(d) > 3) & (X(x) > 2) & (X(y) > 1), Contains(t, + Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2)) & Contains(x, + Interval.Lopen(2, 3)) & Contains(y, Interval.Lopen(3, 4))).simplify() == \ + 120*exp(-10) + + # Check working with Not and Or + assert P(Not((X(t) < 5) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) & + Contains(d, Interval.Lopen(7, 8))).simplify() == -4*exp(-3) + 472*exp(-8)/3 + 1 + assert P((X(t) > 2) | (X(t) < 4), Contains(t, Interval.Ropen(1, 4))).simplify() == \ + -643*exp(-4)/15 + 109*exp(-2)/15 + 1 + + assert E(X(t)) == 2*t # E(X(t)) == gamma*t/l + assert E(X(2) + x*E(X(5))) == 10*x + 4 diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_symbolic_multivariate.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_symbolic_multivariate.py new file mode 100644 index 0000000000000000000000000000000000000000..79979e20a6f10d2a2ddfe85ce4c8df145e98c3fd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_symbolic_multivariate.py @@ -0,0 +1,172 @@ +from sympy.stats import Expectation, Normal, Variance, Covariance +from sympy.testing.pytest import raises +from sympy.core.symbol import symbols +from sympy.matrices.exceptions import ShapeError +from sympy.matrices.dense import Matrix +from sympy.matrices.expressions.matexpr import MatrixSymbol +from sympy.matrices.expressions.special import ZeroMatrix +from sympy.stats.rv import RandomMatrixSymbol +from sympy.stats.symbolic_multivariate_probability import (ExpectationMatrix, + VarianceMatrix, CrossCovarianceMatrix) + +j, k = symbols("j,k") + +A = MatrixSymbol("A", k, k) +B = MatrixSymbol("B", k, k) +C = MatrixSymbol("C", k, k) +D = MatrixSymbol("D", k, k) + +a = MatrixSymbol("a", k, 1) +b = MatrixSymbol("b", k, 1) + +A2 = MatrixSymbol("A2", 2, 2) +B2 = MatrixSymbol("B2", 2, 2) + +X = RandomMatrixSymbol("X", k, 1) +Y = RandomMatrixSymbol("Y", k, 1) +Z = RandomMatrixSymbol("Z", k, 1) +W = RandomMatrixSymbol("W", k, 1) + +R = RandomMatrixSymbol("R", k, k) + +X2 = RandomMatrixSymbol("X2", 2, 1) + +normal = Normal("normal", 0, 1) + +m1 = Matrix([ + [1, j*Normal("normal2", 2, 1)], + [normal, 0] +]) + +def test_multivariate_expectation(): + expr = Expectation(a) + assert expr == Expectation(a) == ExpectationMatrix(a) + assert expr.expand() == a + + expr = Expectation(X) + assert expr == Expectation(X) == ExpectationMatrix(X) + assert expr.shape == (k, 1) + assert expr.rows == k + assert expr.cols == 1 + assert isinstance(expr, ExpectationMatrix) + + expr = Expectation(A*X + b) + assert expr == ExpectationMatrix(A*X + b) + assert expr.expand() == A*ExpectationMatrix(X) + b + assert isinstance(expr, ExpectationMatrix) + assert expr.shape == (k, 1) + + expr = Expectation(m1*X2) + assert expr.expand() == expr + + expr = Expectation(A2*m1*B2*X2) + assert expr.args[0].args == (A2, m1, B2, X2) + assert expr.expand() == A2*ExpectationMatrix(m1*B2*X2) + + expr = Expectation((X + Y)*(X - Y).T) + assert expr.expand() == ExpectationMatrix(X*X.T) - ExpectationMatrix(X*Y.T) +\ + ExpectationMatrix(Y*X.T) - ExpectationMatrix(Y*Y.T) + + expr = Expectation(A*X + B*Y) + assert expr.expand() == A*ExpectationMatrix(X) + B*ExpectationMatrix(Y) + + assert Expectation(m1).doit() == Matrix([[1, 2*j], [0, 0]]) + + x1 = Matrix([ + [Normal('N11', 11, 1), Normal('N12', 12, 1)], + [Normal('N21', 21, 1), Normal('N22', 22, 1)] + ]) + x2 = Matrix([ + [Normal('M11', 1, 1), Normal('M12', 2, 1)], + [Normal('M21', 3, 1), Normal('M22', 4, 1)] + ]) + + assert Expectation(Expectation(x1 + x2)).doit(deep=False) == ExpectationMatrix(x1 + x2) + assert Expectation(Expectation(x1 + x2)).doit() == Matrix([[12, 14], [24, 26]]) + + +def test_multivariate_variance(): + raises(ShapeError, lambda: Variance(A)) + + expr = Variance(a) + assert expr == Variance(a) == VarianceMatrix(a) + assert expr.expand() == ZeroMatrix(k, k) + expr = Variance(a.T) + assert expr == Variance(a.T) == VarianceMatrix(a.T) + assert expr.expand() == ZeroMatrix(k, k) + + expr = Variance(X) + assert expr == Variance(X) == VarianceMatrix(X) + assert expr.shape == (k, k) + assert expr.rows == k + assert expr.cols == k + assert isinstance(expr, VarianceMatrix) + + expr = Variance(A*X) + assert expr == VarianceMatrix(A*X) + assert expr.expand() == A*VarianceMatrix(X)*A.T + assert isinstance(expr, VarianceMatrix) + assert expr.shape == (k, k) + + expr = Variance(A*B*X) + assert expr.expand() == A*B*VarianceMatrix(X)*B.T*A.T + + expr = Variance(m1*X2) + assert expr.expand() == expr + + expr = Variance(A2*m1*B2*X2) + assert expr.args[0].args == (A2, m1, B2, X2) + assert expr.expand() == expr + + expr = Variance(A*X + B*Y) + assert expr.expand() == 2*A*CrossCovarianceMatrix(X, Y)*B.T +\ + A*VarianceMatrix(X)*A.T + B*VarianceMatrix(Y)*B.T + +def test_multivariate_crosscovariance(): + raises(ShapeError, lambda: Covariance(X, Y.T)) + raises(ShapeError, lambda: Covariance(X, A)) + + + expr = Covariance(a.T, b.T) + assert expr.shape == (1, 1) + assert expr.expand() == ZeroMatrix(1, 1) + + expr = Covariance(a, b) + assert expr == Covariance(a, b) == CrossCovarianceMatrix(a, b) + assert expr.expand() == ZeroMatrix(k, k) + assert expr.shape == (k, k) + assert expr.rows == k + assert expr.cols == k + assert isinstance(expr, CrossCovarianceMatrix) + + expr = Covariance(A*X + a, b) + assert expr.expand() == ZeroMatrix(k, k) + + expr = Covariance(X, Y) + assert isinstance(expr, CrossCovarianceMatrix) + assert expr.expand() == expr + + expr = Covariance(X, X) + assert isinstance(expr, CrossCovarianceMatrix) + assert expr.expand() == VarianceMatrix(X) + + expr = Covariance(X + Y, Z) + assert isinstance(expr, CrossCovarianceMatrix) + assert expr.expand() == CrossCovarianceMatrix(X, Z) + CrossCovarianceMatrix(Y, Z) + + expr = Covariance(A*X, Y) + assert isinstance(expr, CrossCovarianceMatrix) + assert expr.expand() == A*CrossCovarianceMatrix(X, Y) + + expr = Covariance(X, B*Y) + assert isinstance(expr, CrossCovarianceMatrix) + assert expr.expand() == CrossCovarianceMatrix(X, Y)*B.T + + expr = Covariance(A*X + a, B.T*Y + b) + assert isinstance(expr, CrossCovarianceMatrix) + assert expr.expand() == A*CrossCovarianceMatrix(X, Y)*B + + expr = Covariance(A*X + B*Y + a, C.T*Z + D.T*W + b) + assert isinstance(expr, CrossCovarianceMatrix) + assert expr.expand() == A*CrossCovarianceMatrix(X, W)*D + A*CrossCovarianceMatrix(X, Z)*C \ + + B*CrossCovarianceMatrix(Y, W)*D + B*CrossCovarianceMatrix(Y, Z)*C diff --git a/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_symbolic_probability.py b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_symbolic_probability.py new file mode 100644 index 0000000000000000000000000000000000000000..edac942ac081c0d44cafd31761b77bc577b6a3fd --- /dev/null +++ b/Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/sympy/stats/tests/test_symbolic_probability.py @@ -0,0 +1,175 @@ +from sympy.concrete.summations import Sum +from sympy.core.mul import Mul +from sympy.core.numbers import (oo, pi) +from sympy.core.relational import Eq +from sympy.core.symbol import (Dummy, symbols) +from sympy.functions.elementary.exponential import exp +from sympy.functions.elementary.miscellaneous import sqrt +from sympy.functions.elementary.trigonometric import sin +from sympy.integrals.integrals import Integral +from sympy.core.expr import unchanged +from sympy.stats import (Normal, Poisson, variance, Covariance, Variance, + Probability, Expectation, Moment, CentralMoment) +from sympy.stats.rv import probability, expectation + + +def test_literal_probability(): + X = Normal('X', 2, 3) + Y = Normal('Y', 3, 4) + Z = Poisson('Z', 4) + W = Poisson('W', 3) + x = symbols('x', real=True) + y, w, z = symbols('y, w, z') + + assert Probability(X > 0).evaluate_integral() == probability(X > 0) + assert Probability(X > x).evaluate_integral() == probability(X > x) + assert Probability(X > 0).rewrite(Integral).doit() == probability(X > 0) + assert Probability(X > x).rewrite(Integral).doit() == probability(X > x) + + assert Expectation(X).evaluate_integral() == expectation(X) + assert Expectation(X).rewrite(Integral).doit() == expectation(X) + assert Expectation(X**2).evaluate_integral() == expectation(X**2) + assert Expectation(x*X).args == (x*X,) + assert Expectation(x*X).expand() == x*Expectation(X) + assert Expectation(2*X + 3*Y + z*X*Y).expand() == 2*Expectation(X) + 3*Expectation(Y) + z*Expectation(X*Y) + assert Expectation(2*X + 3*Y + z*X*Y).args == (2*X + 3*Y + z*X*Y,) + assert Expectation(sin(X)) == Expectation(sin(X)).expand() + assert Expectation(2*x*sin(X)*Y + y*X**2 + z*X*Y).expand() == 2*x*Expectation(sin(X)*Y) \ + + y*Expectation(X**2) + z*Expectation(X*Y) + assert Expectation(X + Y).expand() == Expectation(X) + Expectation(Y) + assert Expectation((X + Y)*(X - Y)).expand() == Expectation(X**2) - Expectation(Y**2) + assert Expectation((X + Y)*(X - Y)).expand().doit() == -12 + assert Expectation(X + Y, evaluate=True).doit() == 5 + assert Expectation(X + Expectation(Y)).doit() == 5 + assert Expectation(X + Expectation(Y)).doit(deep=False) == 2 + Expectation(Expectation(Y)) + assert Expectation(X + Expectation(Y + Expectation(2*X))).doit(deep=False) == 2 \ + + Expectation(Expectation(Y + Expectation(2*X))) + assert Expectation(X + Expectation(Y + Expectation(2*X))).doit() == 9 + assert Expectation(Expectation(2*X)).doit() == 4 + assert Expectation(Expectation(2*X)).doit(deep=False) == Expectation(2*X) + assert Expectation(4*Expectation(2*X)).doit(deep=False) == 4*Expectation(2*X) + assert Expectation((X + Y)**3).expand() == 3*Expectation(X*Y**2) +\ + 3*Expectation(X**2*Y) + Expectation(X**3) + Expectation(Y**3) + assert Expectation((X - Y)**3).expand() == 3*Expectation(X*Y**2) -\ + 3*Expectation(X**2*Y) + Expectation(X**3) - Expectation(Y**3) + assert Expectation((X - Y)**2).expand() == -2*Expectation(X*Y) +\ + Expectation(X**2) + Expectation(Y**2) + + assert Variance(w).args == (w,) + assert Variance(w).expand() == 0 + assert Variance(X).evaluate_integral() == Variance(X).rewrite(Integral).doit() == variance(X) + assert Variance(X + z).args == (X + z,) + assert Variance(X + z).expand() == Variance(X) + assert Variance(X*Y).args == (Mul(X, Y),) + assert type(Variance(X*Y)) == Variance + assert Variance(z*X).expand() == z**2*Variance(X) + assert Variance(X + Y).expand() == Variance(X) + Variance(Y) + 2*Covariance(X, Y) + assert Variance(X + Y + Z + W).expand() == (Variance(X) + Variance(Y) + Variance(Z) + Variance(W) + + 2 * Covariance(X, Y) + 2 * Covariance(X, Z) + 2 * Covariance(X, W) + + 2 * Covariance(Y, Z) + 2 * Covariance(Y, W) + 2 * Covariance(W, Z)) + assert Variance(X**2).evaluate_integral() == variance(X**2) + assert unchanged(Variance, X**2) + assert Variance(x*X**2).expand() == x**2*Variance(X**2) + assert Variance(sin(X)).args == (sin(X),) + assert Variance(sin(X)).expand() == Variance(sin(X)) + assert Variance(x*sin(X)).expand() == x**2*Variance(sin(X)) + + assert Covariance(w, z).args == (w, z) + assert Covariance(w, z).expand() == 0 + assert Covariance(X, w).expand() == 0 + assert Covariance(w, X).expand() == 0 + assert Covariance(X, Y).args == (X, Y) + assert type(Covariance(X, Y)) == Covariance + assert Covariance(z*X + 3, Y).expand() == z*Covariance(X, Y) + assert Covariance(X, X).args == (X, X) + assert Covariance(X, X).expand() == Variance(X) + assert Covariance(z*X + 3, w*Y + 4).expand() == w*z*Covariance(X,Y) + assert Covariance(X, Y) == Covariance(Y, X) + assert Covariance(X + Y, Z + W).expand() == Covariance(W, X) + Covariance(W, Y) + Covariance(X, Z) + Covariance(Y, Z) + assert Covariance(x*X + y*Y, z*Z + w*W).expand() == (x*w*Covariance(W, X) + w*y*Covariance(W, Y) + + x*z*Covariance(X, Z) + y*z*Covariance(Y, Z)) + assert Covariance(x*X**2 + y*sin(Y), z*Y*Z**2 + w*W).expand() == (w*x*Covariance(W, X**2) + w*y*Covariance(sin(Y), W) + + x*z*Covariance(Y*Z**2, X**2) + y*z*Covariance(Y*Z**2, sin(Y))) + assert Covariance(X, X**2).expand() == Covariance(X, X**2) + assert Covariance(X, sin(X)).expand() == Covariance(sin(X), X) + assert Covariance(X**2, sin(X)*Y).expand() == Covariance(sin(X)*Y, X**2) + assert Covariance(w, X).evaluate_integral() == 0 + + +def test_probability_rewrite(): + X = Normal('X', 2, 3) + Y = Normal('Y', 3, 4) + Z = Poisson('Z', 4) + W = Poisson('W', 3) + x, y, w, z = symbols('x, y, w, z') + + assert Variance(w).rewrite(Expectation) == 0 + assert Variance(X).rewrite(Expectation) == Expectation(X ** 2) - Expectation(X) ** 2 + assert Variance(X, condition=Y).rewrite(Expectation) == Expectation(X ** 2, Y) - Expectation(X, Y) ** 2 + assert Variance(X, Y) != Expectation(X**2) - Expectation(X)**2 + assert Variance(X + z).rewrite(Expectation) == Expectation((X + z) ** 2) - Expectation(X + z) ** 2 + assert Variance(X * Y).rewrite(Expectation) == Expectation(X ** 2 * Y ** 2) - Expectation(X * Y) ** 2 + + assert Covariance(w, X).rewrite(Expectation) == -w*Expectation(X) + Expectation(w*X) + assert Covariance(X, Y).rewrite(Expectation) == Expectation(X*Y) - Expectation(X)*Expectation(Y) + assert Covariance(X, Y, condition=W).rewrite(Expectation) == Expectation(X * Y, W) - Expectation(X, W) * Expectation(Y, W) + + w, x, z = symbols("W, x, z") + px = Probability(Eq(X, x)) + pz = Probability(Eq(Z, z)) + + assert Expectation(X).rewrite(Probability) == Integral(x*px, (x, -oo, oo)) + assert Expectation(Z).rewrite(Probability) == Sum(z*pz, (z, 0, oo)) + assert Variance(X).rewrite(Probability) == Integral(x**2*px, (x, -oo, oo)) - Integral(x*px, (x, -oo, oo))**2 + assert Variance(Z).rewrite(Probability) == Sum(z**2*pz, (z, 0, oo)) - Sum(z*pz, (z, 0, oo))**2 + assert Covariance(w, X).rewrite(Probability) == \ + -w*Integral(x*Probability(Eq(X, x)), (x, -oo, oo)) + Integral(w*x*Probability(Eq(X, x)), (x, -oo, oo)) + + # To test rewrite as sum function + assert Variance(X).rewrite(Sum) == Variance(X).rewrite(Integral) + assert Expectation(X).rewrite(Sum) == Expectation(X).rewrite(Integral) + + assert Covariance(w, X).rewrite(Sum) == 0 + + assert Covariance(w, X).rewrite(Integral) == 0 + + assert Variance(X, condition=Y).rewrite(Probability) == Integral(x**2*Probability(Eq(X, x), Y), (x, -oo, oo)) - \ + Integral(x*Probability(Eq(X, x), Y), (x, -oo, oo))**2 + + +def test_symbolic_Moment(): + mu = symbols('mu', real=True) + sigma = symbols('sigma', positive=True) + x = symbols('x') + X = Normal('X', mu, sigma) + M = Moment(X, 4, 2) + assert M.rewrite(Expectation) == Expectation((X - 2)**4) + assert M.rewrite(Probability) == Integral((x - 2)**4*Probability(Eq(X, x)), + (x, -oo, oo)) + k = Dummy('k') + expri = Integral(sqrt(2)*(k - 2)**4*exp(-(k - \ + mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (k, -oo, oo)) + assert M.rewrite(Integral).dummy_eq(expri) + assert M.doit() == (mu**4 - 8*mu**3 + 6*mu**2*sigma**2 + \ + 24*mu**2 - 24*mu*sigma**2 - 32*mu + 3*sigma**4 + 24*sigma**2 + 16) + M = Moment(2, 5) + assert M.doit() == 2**5 + + +def test_symbolic_CentralMoment(): + mu = symbols('mu', real=True) + sigma = symbols('sigma', positive=True) + x = symbols('x') + X = Normal('X', mu, sigma) + CM = CentralMoment(X, 6) + assert CM.rewrite(Expectation) == Expectation((X - Expectation(X))**6) + assert CM.rewrite(Probability) == Integral((x - Integral(x*Probability(True), + (x, -oo, oo)))**6*Probability(Eq(X, x)), (x, -oo, oo)) + k = Dummy('k') + expri = Integral(sqrt(2)*(k - Integral(sqrt(2)*k*exp(-(k - \ + mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (k, -oo, oo)))**6*exp(-(k - \ + mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (k, -oo, oo)) + assert CM.rewrite(Integral).dummy_eq(expri) + assert CM.doit().simplify() == 15*sigma**6 + CM = Moment(5, 5) + assert CM.doit() == 5**5